Skip to content

Commit

Permalink
Refactor architecture with toolkits and wallets
Browse files Browse the repository at this point in the history
  • Loading branch information
maxima-net committed Aug 11, 2022
1 parent 9b4a42f commit 1c4ac66
Show file tree
Hide file tree
Showing 39 changed files with 382 additions and 406 deletions.
12 changes: 3 additions & 9 deletions src/atomex/atomex.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AuthorizationManager } from '../authorization/index';
import type { Signer, SignersManager } from '../blockchain/index';
import type { WalletsManager } from '../blockchain/index';
import type { AtomexService, Currency } from '../common/index';
import type { ExchangeManager } from '../exchange/exchangeManager';
import type { Swap, SwapManager } from '../swaps/index';
Expand All @@ -13,14 +13,14 @@ export class Atomex implements AtomexService {
readonly authorization: AuthorizationManager;
readonly exchangeManager: ExchangeManager;
readonly swapManager: SwapManager;
readonly signers: SignersManager;
readonly wallets: WalletsManager;
readonly atomexContext: AtomexContext;

private _isStarted = false;

constructor(readonly options: AtomexOptions) {
this.atomexContext = options.atomexContext;
this.signers = options.managers.signersManager;
this.wallets = options.managers.walletsManager;
this.authorization = options.managers.authorizationManager;
this.exchangeManager = options.managers.exchangeManager;
this.swapManager = options.managers.swapManager;
Expand Down Expand Up @@ -61,12 +61,6 @@ export class Atomex implements AtomexService {
this._isStarted = false;
}

async addSigner(signer: Signer) {
await this.signers.addSigner(signer);
const blockchainToolkitProvider = this.atomexContext.providers.blockchainProvider.getBlockchainToolkitProvider(signer.blockchain);
await blockchainToolkitProvider?.addSigner(signer);
}

addBlockchain(factoryMethod: (context: AtomexContext) => [blockchain: string, options: AtomexBlockchainOptions]) {
const [blockchain, blockchainOptions] = factoryMethod(this.atomexContext);
const networkOptions = this.atomexNetwork == 'mainnet' ? blockchainOptions.mainnet : blockchainOptions.testnet;
Expand Down
16 changes: 8 additions & 8 deletions src/atomex/atomexContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AuthorizationManager } from '../authorization/index';
import type { SignersManager, AtomexBlockchainProvider } from '../blockchain/index';
import type { WalletsManager, AtomexBlockchainProvider } from '../blockchain/index';
import type { AtomexNetwork, CurrenciesProvider } from '../common/index';
import type { ExchangeManager, ExchangeService, ManagedExchangeSymbolsProvider } from '../exchange/index';
import type { SwapManager, SwapService } from '../swaps/index';
Expand All @@ -23,23 +23,23 @@ export class AtomexContext {
}

class AtomexContextManagersSection {
private _signersManager: SignersManager | undefined;
private _walletsManager: WalletsManager | undefined;
private _authorizationManager: AuthorizationManager | undefined;
private _exchangeManager: ExchangeManager | undefined;
private _swapManager: SwapManager | undefined;

constructor(readonly context: AtomexContext) {
}

get signersManager(): SignersManager {
if (!this._signersManager)
throw new AtomexComponentNotResolvedError('managers.signersManager');
get walletsManager(): WalletsManager {
if (!this._walletsManager)
throw new AtomexComponentNotResolvedError('managers.walletsManager');

return this._signersManager;
return this._walletsManager;
}

private set signersManager(signersManager: SignersManager) {
this._signersManager = signersManager;
private set walletsManager(walletsManager: WalletsManager) {
this._walletsManager = walletsManager;
}

get authorizationManager(): AuthorizationManager {
Expand Down
5 changes: 3 additions & 2 deletions src/atomex/models/atomexOptions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { AuthorizationManager } from '../../authorization/index';
import type {
AtomexProtocol, BalancesProvider, BlockchainToolkitProvider,
CurrencyBalanceProvider, SignersManager, SwapTransactionsProvider
CurrencyBalanceProvider, WalletsManager, SwapTransactionsProvider
} from '../../blockchain/index';
import type { Currency } from '../../common/index';
import type { ExchangeManager, ExchangeService } from '../../exchange/index';
Expand All @@ -16,7 +16,7 @@ export interface AtomexOptions {

export interface AtomexManagers {
authorizationManager: AuthorizationManager;
signersManager: SignersManager;
walletsManager: WalletsManager;
exchangeManager: ExchangeManager;
swapManager: SwapManager;
}
Expand All @@ -31,6 +31,7 @@ export interface AtomexBlockchainOptions {
}

export interface AtomexBlockchainNetworkOptions {
rpcUrl: string;
blockchainToolkitProvider: BlockchainToolkitProvider;
balancesProvider: BalancesProvider;
swapTransactionsProvider: SwapTransactionsProvider;
Expand Down
20 changes: 10 additions & 10 deletions src/atomexBuilder/atomexBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Atomex, AtomexContext } from '../atomex/index';
import type { AtomexBlockchainOptions } from '../atomex/models/index';
import type { AuthorizationManager } from '../authorization/index';
import { AtomexBlockchainProvider, SignersManager } from '../blockchain/index';
import { AtomexBlockchainProvider, WalletsManager } from '../blockchain/index';
import type { DeepReadonly } from '../core/index';
import { createDefaultEthereumBlockchainOptions } from '../ethereum/index';
import { ExchangeManager, InMemoryExchangeSymbolsProvider } from '../exchange/index';
Expand All @@ -16,7 +16,7 @@ import type { CustomAtomexComponentFactory } from './customAtomexComponentFactor

export class AtomexBuilder {
protected customAuthorizationManagerFactory?: CustomAtomexComponentFactory<AuthorizationManager, AuthorizationManagerDefaultComponentOptions>;
protected customSignersManagerFactory?: CustomAtomexComponentFactory<SignersManager>;
protected customWalletsManagerFactory?: CustomAtomexComponentFactory<WalletsManager>;
protected customExchangeManagerFactory?: CustomAtomexComponentFactory<ExchangeManager>;

private get controlledAtomexContext(): ControlledAtomexContext {
Expand All @@ -34,8 +34,8 @@ export class AtomexBuilder {
return this;
}

useSignersManager(customSignersManagerFactory: NonNullable<AtomexBuilder['customSignersManagerFactory']>): AtomexBuilder {
this.customSignersManagerFactory = customSignersManagerFactory;
useWalletsManager(customWalletsManagerFactory: NonNullable<AtomexBuilder['customWalletsManagerFactory']>): AtomexBuilder {
this.customWalletsManagerFactory = customWalletsManagerFactory;
return this;
}

Expand All @@ -49,7 +49,7 @@ export class AtomexBuilder {
this.controlledAtomexContext.providers.blockchainProvider = blockchainProvider;
this.controlledAtomexContext.providers.currenciesProvider = blockchainProvider;
this.controlledAtomexContext.providers.exchangeSymbolsProvider = this.createExchangeSymbolsProvider();
this.controlledAtomexContext.managers.signersManager = this.createSignersManager();
this.controlledAtomexContext.managers.walletsManager = this.createWalletsManager();
this.controlledAtomexContext.managers.authorizationManager = this.createAuthorizationManager();
const atomexClient = this.createDefaultExchangeService();
this.controlledAtomexContext.services.exchangeService = atomexClient;
Expand All @@ -61,7 +61,7 @@ export class AtomexBuilder {
return new Atomex({
atomexContext: this.atomexContext,
managers: {
signersManager: this.atomexContext.managers.signersManager,
walletsManager: this.atomexContext.managers.walletsManager,
authorizationManager: this.atomexContext.managers.authorizationManager,
exchangeManager: this.atomexContext.managers.exchangeManager,
swapManager: this.atomexContext.managers.swapManager
Expand All @@ -82,10 +82,10 @@ export class AtomexBuilder {
: createDefaultAuthorizationManager(this.atomexContext, defaultAuthorizationManagerOptions, this.options);
}

protected createSignersManager() {
return this.customSignersManagerFactory
? this.customSignersManagerFactory(this.atomexContext, this.options)
: new SignersManager(this.atomexContext.atomexNetwork);
protected createWalletsManager() {
return this.customWalletsManagerFactory
? this.customWalletsManagerFactory(this.atomexContext, this.options)
: new WalletsManager(this.atomexContext.atomexNetwork);
}

protected createDefaultExchangeService() {
Expand Down
2 changes: 1 addition & 1 deletion src/atomexBuilder/atomexComponents/authorizationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const createDefaultAuthorizationManager = (

return new AuthorizationManager({
atomexNetwork: atomexContext.atomexNetwork,
signersManager: atomexContext.managers.signersManager,
walletsManager: atomexContext.managers.walletsManager,
authorizationBaseUrl: options.authorizationBaseUrl,
store: environment === 'browser'
? new LocalStorageAuthorizationManagerStore(options.store.browser.storeStrategy)
Expand Down
6 changes: 3 additions & 3 deletions src/atomexBuilder/controlledAtomexContext.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { AuthorizationManager } from '../authorization/index';
import type { AtomexBlockchainProvider } from '../blockchain/atomexBlockchainProvider';
import type { SignersManager } from '../blockchain/index';
import type { WalletsManager } from '../blockchain/index';
import type { AtomexNetwork, CurrenciesProvider } from '../common/index';
import type { ExchangeManager, ExchangeService, ExchangeSymbolsProvider } from '../exchange/index';
import type { SwapManager, SwapService } from '../swaps/index';
Expand All @@ -15,8 +15,8 @@ export interface ControlledAtomexContext {
}

interface ControlledAtomexContextManagersSection {
get signersManager(): SignersManager;
set signersManager(value: SignersManager);
get walletsManager(): WalletsManager;
set walletsManager(value: WalletsManager);

get authorizationManager(): AuthorizationManager;
set authorizationManager(value: AuthorizationManager);
Expand Down
16 changes: 8 additions & 8 deletions src/authorization/authorizationManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SignersManager } from '../blockchain/index';
import type { WalletsManager } from '../blockchain/index';
import type { AtomexService, AtomexNetwork } from '../common/index';
import { EventEmitter, type ToEventEmitters, type PublicEventEmitter } from '../core/index';
import type { AuthorizationManagerStore } from '../stores/index';
Expand Down Expand Up @@ -29,7 +29,7 @@ export class AuthorizationManager implements AtomexService {

readonly atomexNetwork: AtomexNetwork;

protected readonly signersManager: SignersManager;
protected readonly walletsManager: WalletsManager;
protected readonly store: AuthorizationManagerStore;
protected readonly authorizationUrl: URL;
protected readonly expiringNotificationTimeInSeconds: number;
Expand All @@ -41,9 +41,9 @@ export class AuthorizationManager implements AtomexService {
constructor(options: AuthorizationManagerOptions) {
this.atomexNetwork = options.atomexNetwork;
this.store = options.store;
this.signersManager = options.signersManager;
this.walletsManager = options.walletsManager;

atomexUtils.ensureNetworksAreSame(this, this.signersManager);
atomexUtils.ensureNetworksAreSame(this, this.walletsManager);

this.authorizationUrl = new URL(AuthorizationManager.DEFAULT_GET_AUTH_TOKEN_URI, options.authorizationBaseUrl);
this.expiringNotificationTimeInSeconds = options.expiringNotificationTimeInSeconds || AuthorizationManager.DEFAULT_EXPIRING_NOTIFICATION_TIME_IN_SECONDS;
Expand Down Expand Up @@ -94,12 +94,12 @@ export class AuthorizationManager implements AtomexService {
if ((authTokenSource & AuthTokenSource.Remote) !== AuthTokenSource.Remote)
return undefined;

const signer = await this.signersManager.findSigner(address, blockchain);
if (!signer)
throw new Error(`Not found: the corresponding signer by the ${address} address`);
const wallet = await this.walletsManager.getWallet(address, blockchain);
if (!wallet)
throw new Error(`Not found: the corresponding wallet by the ${address} address`);

const timeStamp = this.getAuthorizationTimeStamp(authMessage);
const atomexSignature = await signer.sign(authMessage + timeStamp);
const atomexSignature = await wallet.sign(authMessage + timeStamp);

if (atomexSignature.address !== address)
throw new Error('Invalid address in the signed data');
Expand Down
4 changes: 2 additions & 2 deletions src/authorization/models/authorizationManagerOptions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { SignersManager } from '../../blockchain/signersManager';
import type { WalletsManager } from '../../blockchain/walletsManager';
import type { AtomexNetwork } from '../../common/index';
import type { AuthorizationManagerStore } from '../../stores/index';

export interface AuthorizationManagerOptions {
atomexNetwork: AtomexNetwork;
signersManager: SignersManager
walletsManager: WalletsManager;
store: AuthorizationManagerStore;
authorizationBaseUrl: string;
expiringNotificationTimeInSeconds?: number;
Expand Down
40 changes: 21 additions & 19 deletions src/blockchain/atomexBlockchainProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ export interface CurrencyInfo {

export class AtomexBlockchainProvider implements CurrenciesProvider {
protected readonly currencyInfoMap: Map<Currency['id'], CurrencyInfo> = new Map();
protected readonly blockchainToolkitProviderMap: Map<string, BlockchainToolkitProvider> = new Map();
protected readonly networkOptionsMap: Map<string, AtomexBlockchainNetworkOptions> = new Map();
protected readonly blockchainToolkitProviders: Set<BlockchainToolkitProvider> = new Set();

addBlockchain(blockchain: string, networkOptions: AtomexBlockchainNetworkOptions) {
if (this.blockchainToolkitProviderMap.has(blockchain))
if (this.networkOptionsMap.has(blockchain))
throw new Error('There is already blockchain added with the same key');

this.blockchainToolkitProviderMap.set(blockchain, networkOptions.blockchainToolkitProvider);
this.networkOptionsMap.set(blockchain, networkOptions);
this.blockchainToolkitProviders.add(networkOptions.blockchainToolkitProvider);

for (const currency of networkOptions.currencies) {
if (this.currencyInfoMap.has(currency.id))
Expand All @@ -41,28 +43,28 @@ export class AtomexBlockchainProvider implements CurrenciesProvider {
}
}

getCurrency(currencyId: Currency['id']): Currency | undefined {
return this.getCurrencyInfo(currencyId)?.currency;
getNetworkOptions(blockchain: string): AtomexBlockchainNetworkOptions | undefined {
return this.networkOptionsMap.get(blockchain);
}

getBlockchainToolkitProvider(blockchain: string): BlockchainToolkitProvider | undefined {
return this.blockchainToolkitProviderMap.get(blockchain);
getCurrency(currencyId: Currency['id']): Currency | undefined {
return this.getCurrencyInfo(currencyId)?.currency;
}

getReadonlyToolkit(blockchain: string, toolkitId: string): Promise<unknown | undefined> {
const provider = this.blockchainToolkitProviderMap.get(blockchain);
if (!provider || provider.toolkitId !== toolkitId)
return Promise.resolve(undefined);

return provider.getReadonlyToolkit();
}
async getReadonlyToolkit(toolkitId: string, blockchain?: string): Promise<unknown | undefined> {
const providerToolkitPromises: Array<Promise<unknown | undefined>> = [];
for (const provider of this.blockchainToolkitProviders) {
if (provider.toolkitId === toolkitId)
providerToolkitPromises.push(provider.getReadonlyToolkit(blockchain));
}

getToolkit(blockchain: string, toolkitId: string, address?: string): Promise<unknown | undefined> {
const provider = this.blockchainToolkitProviderMap.get(blockchain);
if (!provider || provider.toolkitId !== toolkitId)
return Promise.resolve(undefined);
const providerToolkitResults = await Promise.all(providerToolkitPromises);
for (const providerResult of providerToolkitResults) {
if (providerResult)
return providerResult;
}

return provider.getToolkit(address);
return Promise.resolve(undefined);
}

getCurrencyInfo(currencyId: Currency['id']): CurrencyInfo | undefined {
Expand Down
10 changes: 2 additions & 8 deletions src/blockchain/blockchainToolkitProvider.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import type { Signer } from './signer';

export interface BlockchainToolkitProvider {
export interface BlockchainToolkitProvider<T = unknown> {
readonly toolkitId: string;

getReadonlyToolkit(): Promise<unknown | undefined>;
getToolkit(address?: string): Promise<unknown | undefined>;

addSigner(signer: Signer): Promise<boolean>;
removeSigner(signer: Signer): Promise<boolean>;
getReadonlyToolkit(blockchain?: string): Promise<T | undefined>;
}
14 changes: 14 additions & 0 deletions src/blockchain/blockchainWallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { AtomexNetwork } from '../common';
import type { AtomexSignature } from './models';

export interface BlockchainWallet<T = unknown> {
readonly atomexNetwork: AtomexNetwork;
readonly id: string;
get toolkit(): T;

getBlockchain(): Promise<string> | string;
getAddress(): Promise<string> | string;
getPublicKey(): Promise<string | undefined> | string | undefined;

sign(message: string): Promise<AtomexSignature>;
}
4 changes: 2 additions & 2 deletions src/blockchain/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { SignersManager } from './signersManager';
export { WalletsManager } from './walletsManager';

export type { AtomexSignature, Transaction } from './models/index';
export type { AtomexProtocol } from './atomexProtocol';
Expand All @@ -11,5 +11,5 @@ export type { CurrencyBalanceProvider } from './currencyBalanceProvider';
export type { TransactionsProvider } from './transactionsProvider';
export type { BlockchainToolkitProvider } from './blockchainToolkitProvider';
export type { SwapTransactionsProvider } from './swapTransactionProvider';
export type { Signer } from './signer';
export type { BlockchainWallet } from './blockchainWallet';
export { AtomexBlockchainProvider, type CurrencyInfo } from './atomexBlockchainProvider';
12 changes: 0 additions & 12 deletions src/blockchain/signer.ts

This file was deleted.

Loading

0 comments on commit 1c4ac66

Please sign in to comment.