From 6ebb3f44b1a4bd0939ba045ed53fc96e56ba464e Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Tue, 25 Jun 2019 07:41:15 -0400 Subject: [PATCH] feat(raiden): channel balance by currency This modifies the logic around querying raiden for channel balances. Rather than summing up all balances across all tokens, it allows for specifying a currency and retrieving only the balance for that currency. Calling `ChannelBalance` without specifying a currency will return each currency separately. It also scales the balance returned by raiden to satoshis (10^-8). This is because the default units of 10^-18 for currencies such as WETH can exceed the maximum value of a `uint64` used by the gRPC layer. Closes #1051. --- lib/raidenclient/RaidenClient.ts | 19 ++++++++++++++----- lib/service/Service.ts | 26 +++++++++++++++----------- lib/swaps/SwapClient.ts | 4 +++- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/lib/raidenclient/RaidenClient.ts b/lib/raidenclient/RaidenClient.ts index 54450d18c..46bbe1f94 100644 --- a/lib/raidenclient/RaidenClient.ts +++ b/lib/raidenclient/RaidenClient.ts @@ -41,6 +41,12 @@ class RaidenClient extends SwapClient { private host: string; private disable: boolean; + // TODO: Populate the mapping from the database (Currency.decimalPlaces). + private static readonly UNITS_PER_CURRENCY: { [key: string]: number } = { + WETH: 10 ** 10, + DAI: 10 ** 10, + }; + /** * Creates a raiden client. */ @@ -272,14 +278,17 @@ class RaidenClient extends SwapClient { } /** - * Returns the total balance available across all channels. + * Returns the total balance available across all channels for a specified currency. */ - public channelBalance = async (): Promise => { - // TODO: refine logic to determine balance per token rather than all combined - const channels = await this.getChannels(); + public channelBalance = async (currency?: string): Promise => { + if (!currency) { + return { balance: 0, pendingOpenBalance: 0 }; + } + + const channels = await this.getChannels(this.tokenAddresses.get(currency)); const balance = channels.filter(channel => channel.state === 'opened') .map(channel => channel.balance) - .reduce((acc, sum) => sum + acc, 0); + .reduce((acc, sum) => sum + (acc / RaidenClient.UNITS_PER_CURRENCY[currency]), 0); return { balance, pendingOpenBalance: 0 }; } diff --git a/lib/service/Service.ts b/lib/service/Service.ts index 0a4363a79..4476a12b7 100644 --- a/lib/service/Service.ts +++ b/lib/service/Service.ts @@ -119,23 +119,27 @@ class Service { public channelBalance = async (args: { currency: string }) => { const { currency } = args; const balances = new Map(); - const getBalance = async (currency: string) => { + + if (currency) { + argChecks.VALID_CURRENCY(args); + const swapClient = this.swapClientManager.get(currency.toUpperCase()); if (swapClient) { - const channelBalance = await swapClient.channelBalance(); - return channelBalance; + const channelBalance = await swapClient.channelBalance(currency); + balances.set(currency, channelBalance); } else { throw swapsErrors.SWAP_CLIENT_NOT_FOUND(currency); } - }; - - if (currency) { - argChecks.VALID_CURRENCY(args); - balances.set(currency, await getBalance(currency)); } else { - for (const currency of this.orderBook.currencies) { - balances.set(currency, await getBalance(currency)); - } + const balancePromises: Promise[] = []; + this.swapClientManager.swapClients.forEach((swapClient, currency) => { + if (swapClient.isConnected()) { + balancePromises.push(swapClient.channelBalance(currency).then((channelBalance) => { + balances.set(currency, channelBalance); + })); + } + }); + await Promise.all(balancePromises); } return balances; diff --git a/lib/swaps/SwapClient.ts b/lib/swaps/SwapClient.ts index 503fc0221..2031dfbcd 100644 --- a/lib/swaps/SwapClient.ts +++ b/lib/swaps/SwapClient.ts @@ -44,8 +44,10 @@ abstract class SwapClient extends EventEmitter { /** * Returns the total balance available across all channels. + * @param currency the currency whose balance to query for, otherwise all/any + * currencies supported by this client are included in the balance. */ - public abstract channelBalance(): Promise; + public abstract channelBalance(currency?: string): Promise; protected setStatus = async (status: ClientStatus): Promise => { this.logger.info(`${this.constructor.name} status: ${ClientStatus[status]}`);