From 930e7d7e1a8b3b832e841204a4f56d7c2f656a9d Mon Sep 17 00:00:00 2001 From: Denis Davidyuk Date: Tue, 7 Jun 2022 11:36:59 +0400 Subject: [PATCH] refactor(wallet-rpc)!: rewrite to TypeScript BREAKING CHANGE: `txObject` parameter of `onSign` callback is removed Use `unpackTx(tx)` on wallet side instead. --- src/account/multiple.ts | 6 +- src/node-pool/index.ts | 4 +- .../rpc/RpcClient.ts | 11 +- .../aepp-wallet-communication/rpc/aepp-rpc.ts | 8 +- .../aepp-wallet-communication/rpc/types.ts | 18 +- .../rpc/wallet-rpc.ts | 388 ++++++++++-------- test/integration/rpc.js | 6 +- 7 files changed, 254 insertions(+), 187 deletions(-) diff --git a/src/account/multiple.ts b/src/account/multiple.ts index 25d116baa2..78dbdd6294 100644 --- a/src/account/multiple.ts +++ b/src/account/multiple.ts @@ -28,7 +28,7 @@ import AccountResolver, { _AccountResolver, Account } from './resolver' import { UnavailableAccountError } from '../utils/errors' import type stampit from '@stamp/it' // eslint-disable-line @typescript-eslint/no-unused-vars -class _AccountMultiple extends _AccountResolver { +export class _AccountMultiple extends _AccountResolver { accounts: { [key: EncodedData<'ak'>]: _AccountBase } selectedAddress?: EncodedData<'ak'> @@ -60,8 +60,8 @@ class _AccountMultiple extends _AccountResolver { * @return {String[]} * @example addresses() */ - addresses (): string[] { - return Object.keys(this.accounts) + addresses (): Array> { + return Object.keys(this.accounts) as Array> } /** diff --git a/src/node-pool/index.ts b/src/node-pool/index.ts index 4002ec9bf6..2418633679 100644 --- a/src/node-pool/index.ts +++ b/src/node-pool/index.ts @@ -31,7 +31,7 @@ interface NodePool { readonly api: Node['api'] } -class _NodePool implements NodePool { +export class _NodePool implements NodePool { readonly api: Node['api'] pool: Map selectedNode?: Node @@ -159,7 +159,7 @@ export default stampit({ selectNode: _NodePool.prototype.selectNode, getNodeInfo: _NodePool.prototype.getNodeInfo, isNodeConnected: _NodePool.prototype.isNodeConnected, - getNetworkId: _NodePool.prototype.getNetworkId, + getNetworkId, getNodesInPool: _NodePool.prototype.getNodesInPool } }) diff --git a/src/utils/aepp-wallet-communication/rpc/RpcClient.ts b/src/utils/aepp-wallet-communication/rpc/RpcClient.ts index d77f476bb5..6eed046255 100644 --- a/src/utils/aepp-wallet-communication/rpc/RpcClient.ts +++ b/src/utils/aepp-wallet-communication/rpc/RpcClient.ts @@ -21,8 +21,11 @@ interface JsonRpcResponse { } } -type RpcApiHandler = (p?: any, origin?: string) => any | undefined -type RpcApi = { [k in keyof Keys]: RpcApiHandler } +type RpcApiHandler = (p?: any) => any | undefined +type RpcApi = { [k in keyof Api]: RpcApiHandler } +type WithOrigin> = { + [k in keyof Api]: (p: Parameters[0], origin: string) => ReturnType +} /** * Contain functionality for using RPC conection @@ -36,12 +39,12 @@ export default class RpcClient < connection: BrowserConnection #callbacks = new Map void, reject: (e: Error) => void }>() #messageId = 0 - #methods: LocalApi + #methods: WithOrigin constructor ( connection: BrowserConnection, onDisconnect: () => void, - methods: LocalApi + methods: WithOrigin ) { this.connection = connection this.#methods = methods diff --git a/src/utils/aepp-wallet-communication/rpc/aepp-rpc.ts b/src/utils/aepp-wallet-communication/rpc/aepp-rpc.ts index 62f70a94d2..2519b9f11a 100644 --- a/src/utils/aepp-wallet-communication/rpc/aepp-rpc.ts +++ b/src/utils/aepp-wallet-communication/rpc/aepp-rpc.ts @@ -13,7 +13,7 @@ import AccountRpc from '../../../account/rpc' import { decode, EncodedData } from '../../encoder' import { Accounts, WalletInfo, Network, WalletApi, AeppApi } from './types' import RpcClient from './RpcClient' -import { METHODS, VERSION } from '../schema' +import { METHODS, VERSION, SUBSCRIPTION_TYPES } from '../schema' import { AlreadyConnectedError, NoWalletConnectedError, @@ -155,12 +155,12 @@ abstract class _AeppRpc extends _AccountResolver { /** * Subscribe for addresses from wallet - * @param type Should be one of 'current' (the selected account), 'connected' (all) - * @param value Subscription action + * @param type Subscription type + * @param value Should be one of 'current' (the selected account), 'connected' (all) * @return Accounts from wallet */ async subscribeAddress ( - type: 'current' | 'connected', value: 'subscribe' | 'unsubscribe' + type: SUBSCRIPTION_TYPES, value: 'current' | 'connected' ): Promise> { this._ensureConnected() const result = await this.rpcClient.request(METHODS.subscribeAddress, { type, value }) diff --git a/src/utils/aepp-wallet-communication/rpc/types.ts b/src/utils/aepp-wallet-communication/rpc/types.ts index cc30187dcd..9fa03d3be6 100644 --- a/src/utils/aepp-wallet-communication/rpc/types.ts +++ b/src/utils/aepp-wallet-communication/rpc/types.ts @@ -1,5 +1,5 @@ import { EncodedData } from '../../encoder' -import { METHODS, WALLET_TYPE } from '../schema' +import { METHODS, SUBSCRIPTION_TYPES, WALLET_TYPE } from '../schema' export interface WalletInfo { id: string @@ -29,25 +29,23 @@ type Icons = Array<{ src: string, sizes?: string, type?: string, purpose?: strin export interface WalletApi { [METHODS.connect]: ( p: { name: string, icons?: Icons, version: 1, connectNode: boolean } - ) => WalletInfo & { node?: Node } + ) => Promise [METHODS.closeConnection]: (p: any) => void [METHODS.subscribeAddress]: ( - p: { type: 'connected' | 'current', value: 'subscribe' | 'unsubscribe' } - ) => { subscription: Array<'subscribe' | 'unsubscribe'>, address: Accounts } + p: { type: SUBSCRIPTION_TYPES, value: 'connected' | 'current' } + ) => Promise<{ subscription: Array<'connected' | 'current'>, address: Accounts }> - [METHODS.address]: () => Array> + [METHODS.address]: () => Promise>> [METHODS.sign]: (( - p: { tx: EncodedData<'tx'>, onAccount: EncodedData<'ak'>, returnSigned: false } - ) => { transactionHash: EncodedData<'th'> }) & (( - p: { tx: EncodedData<'tx'>, onAccount: EncodedData<'ak'>, returnSigned: true } - ) => { signedTransaction: EncodedData<'tx'> }) + p: { tx: EncodedData<'tx'>, onAccount: EncodedData<'ak'>, returnSigned: boolean } + ) => Promise<{ transactionHash?: EncodedData<'th'>, signedTransaction?: EncodedData<'tx'> }>) [METHODS.signMessage]: ( p: { message: string, onAccount: EncodedData<'ak'> } - ) => { signature: string } + ) => Promise<{ signature: string }> } export interface AeppApi { diff --git a/src/utils/aepp-wallet-communication/rpc/wallet-rpc.ts b/src/utils/aepp-wallet-communication/rpc/wallet-rpc.ts index 1ae1bc4b44..dc50ffe45b 100644 --- a/src/utils/aepp-wallet-communication/rpc/wallet-rpc.ts +++ b/src/utils/aepp-wallet-communication/rpc/wallet-rpc.ts @@ -7,159 +7,230 @@ * import WalletRpc from '@aeternity/aepp-sdk/es/utils/aepp-wallet-communication/rpc/wallet-rpc' */ import { v4 as uuid } from '@aeternity/uuid' +// @ts-expect-error TODO remove import Ae from '../../../ae' +// @ts-expect-error TODO remove import verifyTransaction from '../../../tx/validator' -import AccountMultiple from '../../../account/multiple' +import AccountMultiple, { _AccountMultiple } from '../../../account/multiple' import RpcClient from './RpcClient' import { - METHODS, RPC_STATUS, VERSION, + METHODS, RPC_STATUS, VERSION, SUBSCRIPTION_TYPES, WALLET_TYPE, RpcBroadcastError, RpcInvalidTransactionError, - RpcNotAuthorizeError, RpcPermissionDenyError, RpcUnsupportedProtocolError, SUBSCRIPTION_TYPES + RpcNotAuthorizeError, RpcPermissionDenyError, RpcUnsupportedProtocolError } from '../schema' -import { ArgumentError, UnknownRpcClientError } from '../../errors' -import { mapObject } from '../../other' -import { unpackTx } from '../../../tx/builder' +import { UnknownRpcClientError } from '../../errors' +import { _AccountBase } from '../../../account/base' +import { Account } from '../../../account/resolver' +import NodePool, { _NodePool } from '../../../node-pool' +import BrowserConnection from '../connection/Browser' +import { Accounts, AeppApi, WalletApi, WalletInfo } from './types' +import { EncodedData } from '../../encoder' + +type RpcClientWallet = RpcClient + +type OnConnection = ( + clientId: string, params: Omit[0], 'version'>, origin: string +) => void + +type OnSubscription = ( + clientId: string, params: Parameters[0], origin: string +) => void + +type OnSign = ( + clientId: string, params: Parameters[0], origin: string +) => Promise<{ tx?: EncodedData<'tx'>, onAccount?: Account } | undefined> + +type OnDisconnect = ( + clientId: string, params: Parameters[0] +) => void + +type OnAskAccounts = ( + clientId: string, params: undefined, origin: string +) => void + +type OnMessageSign = ( + clientId: string, params: Parameters[0], origin: string +) => Promise<{ onAccount?: Account } | undefined> + +interface RpcClientsInfo { + id: string + status: RPC_STATUS + connectNode: boolean + addressSubscription: Set<'connected' | 'current'> + rpc: RpcClientWallet +} + +const nodePool = new _NodePool() /** * Contain functionality for aepp interaction and managing multiple aepps - * @alias module:@aeternity/aepp-sdk/es/utils/aepp-wallet-communication/rpc/wallet-rpc - * @function - * @rtype Stamp - * @param {Object} param Init params object - * @param {String=} [param.name] Wallet name - * @param {Function} onConnection Call-back function for incoming AEPP connection - * @param {Function} onSubscription Call-back function for incoming AEPP account subscription - * @param {Function} onSign Call-back function for incoming AEPP sign request - * @param {Function} onAskAccounts Call-back function for incoming AEPP get address request - * @param {Function} onMessageSign Call-back function for incoming AEPP sign message request - * Second argument of incoming call-backs contain function for accept/deny request - * @param {Function} onDisconnect Call-back function for disconnect event - * @return {Object} + * @param param Init params object + * @param param.name Wallet name + * @param onConnection Call-back function for incoming AEPP connection + * @param onSubscription Call-back function for incoming AEPP account subscription + * @param onSign Call-back function for incoming AEPP sign request + * @param onAskAccounts Call-back function for incoming AEPP get address request + * @param onMessageSign Call-back function for incoming AEPP sign message request + * Second argument of incoming call-backs contain function for accept/deny request + * @param onDisconnect Call-back function for disconnect event */ -export default Ae.compose(AccountMultiple, { - init ({ +abstract class _WalletRpc extends _AccountMultiple { + id: string + _type: WALLET_TYPE + name: string + _clients: Map + onConnection: OnConnection + onSubscription: OnSubscription + onSign: OnSign + onDisconnect: OnDisconnect + onAskAccounts: OnAskAccounts + onMessageSign: OnMessageSign + + get selectedNode (): any { return null } + abstract send (tx: EncodedData<'tx'>, options: any): EncodedData<'th'> + + async init ({ name, id, type, - ...other - } = {}) { - [ - 'onConnection', 'onSubscription', 'onSign', 'onDisconnect', 'onAskAccounts', 'onMessageSign' - ].forEach(event => { - const handler = other[event] - if (typeof handler !== 'function') throw new ArgumentError(event, 'a function', handler) - this[event] = handler - }) - + onConnection, + onSubscription, + onSign, + onDisconnect, + onAskAccounts, + onMessageSign, + ...options + }: { + id: string + type: WALLET_TYPE + name: string + onConnection: OnConnection + onSubscription: OnSubscription + onSign: OnSign + onDisconnect: OnDisconnect + onAskAccounts: OnAskAccounts + onMessageSign: OnMessageSign + } & Parameters<_AccountMultiple['init']>[0]): Promise { + await super.init(options) + this.onConnection = onConnection + this.onSubscription = onSubscription + this.onSign = onSign + this.onDisconnect = onDisconnect + this.onAskAccounts = onAskAccounts + this.onMessageSign = onMessageSign this._clients = new Map() this.name = name this.id = id this._type = type + } - const _selectAccount = this.selectAccount.bind(this) - const _addAccount = this.addAccount.bind(this) - const _selectNode = this.selectNode.bind(this) - - const pushAccountsToApps = () => Array.from(this._clients.keys()) + _pushAccountsToApps (): void { + Array.from(this._clients.keys()) .filter(clientId => this._isRpcClientSubscribed(clientId)) .map(clientId => this._getClient(clientId).rpc) .forEach(client => client.notify(METHODS.updateAddress, this.getAccounts())) - this.selectAccount = (address) => { - _selectAccount(address) - pushAccountsToApps() - } - this.addAccount = async (account, { select } = {}) => { - await _addAccount(account, { select }) - pushAccountsToApps() - } - this.selectNode = (name) => { - _selectNode(name) - Array.from(this._clients.keys()) - .filter(clientId => this._isRpcClientConnected(clientId)) - .map(clientId => this._getClient(clientId)) - .forEach(client => { - client.rpc.notify(METHODS.updateNetwork, { - networkId: this.getNetworkId(), - ...client.connectNode && { node: this.selectedNode } - }) + } + + selectAccount (address: EncodedData<'ak'>): void { + super.selectAccount(address) + this._pushAccountsToApps() + } + + async addAccount ( + account: _AccountBase, + options: Parameters<_AccountMultiple['addAccount']>[1] + ): Promise { + await super.addAccount(account, options) + this._pushAccountsToApps() + } + + selectNode (name: string): void { + nodePool.selectNode.call(this, name) + Array.from(this._clients.keys()) + .filter(clientId => this._isRpcClientConnected(clientId)) + .map(clientId => this._getClient(clientId)) + .forEach(client => { + client.rpc.notify(METHODS.updateNetwork, { + networkId: this.getNetworkId(), + ...client.connectNode && { node: this.selectedNode } }) - } - }, -methods: { - _getClient (clientId) { + }) + } + + _getClient (clientId: string): RpcClientsInfo { const client = this._clients.get(clientId) if (client == null) throw new UnknownRpcClientError(clientId) return client - }, + } - _isRpcClientSubscribed (clientId) { + _isRpcClientSubscribed (clientId: string): boolean { return this._isRpcClientConnected(clientId) && this._getClient(clientId).addressSubscription.size !== 0 - }, + } - _isRpcClientConnected (clientId) { + _isRpcClientConnected (clientId: string): boolean { return RPC_STATUS.CONNECTED === this._getClient(clientId).status && this._getClient(clientId).rpc.connection.isConnected() - }, + } - _disconnectRpcClient (clientId) { + _disconnectRpcClient (clientId: string): void { const client = this._getClient(clientId) client.rpc.connection.disconnect() client.status = RPC_STATUS.DISCONNECTED client.addressSubscription = new Set() - }, + } /** * Remove specific RpcClient by ID - * @function removeRpcClient - * @instance - * @rtype (id: string) => void - * @param {String} id Client ID - * @return {void} + * @param id Client ID */ - removeRpcClient (id) { + removeRpcClient (id: string): void { this._disconnectRpcClient(id) this._clients.delete(id) - }, + } /** * Add new client by AEPP connection - * @function addRpcClient - * @instance - * @rtype (clientConnection: Object) => Object - * @param {Object} clientConnection AEPP connection object - * @return {String} Client ID + * @param clientConnection AEPP connection object + * @return Client ID */ - addRpcClient (clientConnection) { + addRpcClient (clientConnection: BrowserConnection): string { // @TODO detect if aepp has some history based on origin???? // if yes use this instance for connection const id = uuid() - const METHOD_HANDLERS = { - [METHODS.closeConnection]: async (callInstance, instance, client, params) => { - instance._disconnectRpcClient(client.id) - instance.onDisconnect(params, client.id) + let disconnectParams: any + const client: RpcClientsInfo = { + id, + status: RPC_STATUS.WAITING_FOR_CONNECTION_REQUEST, + addressSubscription: new Set(), + connectNode: false, + rpc: new RpcClient( + clientConnection, + () => { + this._clients.delete(id) + this.onDisconnect(id, disconnectParams) // also related info + }, { + [METHODS.closeConnection]: async (params) => { + disconnectParams = params + this._disconnectRpcClient(id) }, // Store client info and prepare two fn for each client `connect` and `denyConnection` // which automatically prepare and send response for that client - async [METHODS.connect] ( - callInstance, - instance, - client, - { name, version, icons, connectNode }) { + [METHODS.connect]: async ({ name, version, icons, connectNode }, origin) => { if (version !== VERSION) throw new RpcUnsupportedProtocolError() - await callInstance('onConnection', { name, icons, connectNode }) + await this.onConnection(id, { name, icons, connectNode }, origin) client.status = RPC_STATUS.CONNECTED client.connectNode = connectNode return { - ...instance.getWalletInfo(), - ...connectNode && { node: instance.selectedNode } + ...this.getWalletInfo(), + ...connectNode && { node: this.selectedNode } } }, - async [METHODS.subscribeAddress] (callInstance, instance, client, { type, value }) { - if (!instance._isRpcClientConnected(client.id)) throw new RpcNotAuthorizeError() + [METHODS.subscribeAddress]: async ({ type, value }, origin) => { + if (!this._isRpcClientConnected(id)) throw new RpcNotAuthorizeError() - await callInstance('onSubscription', { type, value }) + await this.onSubscription(id, { type, value }, origin) switch (type) { case SUBSCRIPTION_TYPES.subscribe: @@ -172,90 +243,69 @@ methods: { return { subscription: Array.from(client.addressSubscription), - address: instance.getAccounts() + address: this.getAccounts() } }, - async [METHODS.address] (callInstance, instance, client) { - if (!instance._isRpcClientSubscribed(client.id)) throw new RpcNotAuthorizeError() - await callInstance('onAskAccounts') - return instance.addresses() + [METHODS.address]: async (params, origin) => { + if (!this._isRpcClientSubscribed(id)) throw new RpcNotAuthorizeError() + await this.onAskAccounts(id, params, origin) + return this.addresses() }, - async [METHODS.sign] ( - callInstance, instance, client, { tx, onAccount, returnSigned } - ) { - if (!instance._isRpcClientConnected(client.id)) throw new RpcNotAuthorizeError() - onAccount ??= await instance.address() - if (!instance.addresses().includes(onAccount)) throw new RpcPermissionDenyError(onAccount) - - const overrides = await callInstance( - 'onSign', { tx, returnSigned, onAccount, txObject: unpackTx(tx) } - ) + [METHODS.sign]: async ({ tx, onAccount, returnSigned }, origin) => { + if (!this._isRpcClientConnected(id)) throw new RpcNotAuthorizeError() + onAccount ??= await this.address() + if (!this.addresses().includes(onAccount)) { + throw new RpcPermissionDenyError(onAccount) + } + + const overrides = await this.onSign(id, { tx, returnSigned, onAccount }, origin) onAccount = overrides?.onAccount ?? onAccount tx = overrides?.tx ?? tx if (returnSigned) { - return { signedTransaction: await instance.signTransaction(tx, { onAccount }) } + return { signedTransaction: await this.signTransaction(tx, { onAccount }) } } try { - return { transactionHash: await instance.send(tx, { onAccount, verify: false }) } + return { transactionHash: await this.send(tx, { onAccount, verify: false }) } } catch (error) { - const validation = await verifyTransaction(tx, instance.selectedNode.instance) - if (validation.length) throw new RpcInvalidTransactionError(validation) + const validation = await verifyTransaction(tx, this.selectedNode.instance) + if (validation.length > 0) throw new RpcInvalidTransactionError(validation) throw new RpcBroadcastError(error.message) } }, - async [METHODS.signMessage] (callInstance, instance, client, { message, onAccount }) { - if (!instance._isRpcClientConnected(client.id)) throw new RpcNotAuthorizeError() - onAccount ??= await instance.address() - if (!instance.addresses().includes(onAccount)) throw new RpcPermissionDenyError(onAccount) + [METHODS.signMessage]: async ({ message, onAccount }, origin) => { + if (!this._isRpcClientConnected(id)) throw new RpcNotAuthorizeError() + onAccount ??= await this.address() + if (!this.addresses().includes(onAccount)) { + throw new RpcPermissionDenyError(onAccount) + } - const overrides = await callInstance('onMessageSign', { message, onAccount }) + const overrides = await this.onMessageSign(id, { message, onAccount }, origin) onAccount = overrides?.onAccount ?? onAccount - return { signature: await instance.signMessage(message, { onAccount, returnHex: true }) } + return { + // TODO: fix signMessage return type + signature: await this.signMessage(message, { onAccount, returnHex: true }) as + unknown as string + } } - } - const client = new RpcClient( - clientConnection, - this.onDisconnect, - mapObject(METHOD_HANDLERS, ([key, value]) => [key, (params, origin) => { - const callInstance = (methodName, params) => - this[methodName]( - id, - params, - origin - ) - return value(callInstance, this, this._getClient(id), params) - }]) - ) - this._clients.set(id, { - id, - status: RPC_STATUS.WAITING_FOR_CONNECTION_REQUEST, - addressSubscription: new Set(), - rpc: client - }) + }) + } + this._clients.set(id, client) return id - }, + } /** - * Share wallet info * Send shareWalletInfo message to notify AEPP about wallet - * @function shareWalletInfo - * @instance - * @rtype (postFn: Function) => void - * @param {Function} clientId ID of RPC client send message to - * @return {void} + * @param clientId ID of RPC client send message to */ - shareWalletInfo (clientId) { + shareWalletInfo (clientId: string): void { this._getClient(clientId).rpc.notify(METHODS.readyToConnect, this.getWalletInfo()) - }, + } /** * Get Wallet info object - * @function getWalletInfo - * @instance - * @rtype () => Object - * @return {Object} Object with wallet information(id, name, network, ...) + * @return Object with wallet information */ - getWalletInfo () { + getWalletInfo (): WalletInfo { return { id: this.id, name: this.name, @@ -263,22 +313,38 @@ methods: { origin: window.location.origin, type: this._type } - }, - + } + /** * Get Wallet accounts - * @function getAccounts - * @instance - * @rtype () => Object - * @return {Object} Object with accounts information({ connected: Object, current: Object }) + * @return Object with accounts information ({ connected: Object, current: Object }) */ - getAccounts () { + getAccounts (): Accounts { return { - current: this.selectedAddress ? { [this.selectedAddress]: {} } : {}, + current: this.selectedAddress != null ? { [this.selectedAddress]: {} } : {}, connected: this.addresses() - .filter(a => a !== this.selectedAddress) + .filter((a) => a !== this.selectedAddress) .reduce((acc, a) => ({ ...acc, [a]: {} }), {}) } } } + +export default Ae.compose(AccountMultiple, NodePool, { + init: _WalletRpc.prototype.init, + props: { _clients: new Map() }, + methods: { + _disconnectRpcClient: _WalletRpc.prototype._disconnectRpcClient, + _isRpcClientSubscribed: _WalletRpc.prototype._isRpcClientSubscribed, + _isRpcClientConnected: _WalletRpc.prototype._isRpcClientConnected, + _getClient: _WalletRpc.prototype._getClient, + _pushAccountsToApps: _WalletRpc.prototype._pushAccountsToApps, + removeRpcClient: _WalletRpc.prototype.removeRpcClient, + addRpcClient: _WalletRpc.prototype.addRpcClient, + shareWalletInfo: _WalletRpc.prototype.shareWalletInfo, + getWalletInfo: _WalletRpc.prototype.getWalletInfo, + getAccounts: _WalletRpc.prototype.getAccounts, + selectAccount: _WalletRpc.prototype.selectAccount, + addAccount: _WalletRpc.prototype.addAccount, + selectNode: _WalletRpc.prototype.selectNode + } }) diff --git a/test/integration/rpc.js b/test/integration/rpc.js index 1ea8112cd5..a40dc65306 100644 --- a/test/integration/rpc.js +++ b/test/integration/rpc.js @@ -107,6 +107,7 @@ describe('Aepp<->Wallet', function () { }) const clientId = wallet.addRpcClient(connectionFromWalletToAepp) + Array.from(wallet._clients.keys()).length.should.be.equal(1) await wallet.shareWalletInfo(clientId) const is = await isReceived is.should.be.equal(true) @@ -371,9 +372,8 @@ describe('Aepp<->Wallet', function () { connectionFromAeppToWallet.sendMessage({ method: METHODS.closeConnection, params: { reason: 'bye' }, jsonrpc: '2.0' }) - const [walletMessage, rpcClientId] = await walletDisconnect + const [, walletMessage] = await walletDisconnect walletMessage.reason.should.be.equal('bye') - wallet._clients.get(rpcClientId).status.should.be.equal('DISCONNECTED') }) it('Remove rpc client', async () => { @@ -390,7 +390,7 @@ describe('Aepp<->Wallet', function () { ) wallet.removeRpcClient(id) - Array.from(wallet._clients.keys()).length.should.be.equal(1) + Array.from(wallet._clients.keys()).length.should.be.equal(0) }) it('Remove rpc client: client not found', () => {