Browse Source

Better balances handling / displaying

Leszek Wiesner 4 years ago
parent
commit
7551285f3c

+ 7 - 20
cli/src/Api.ts

@@ -3,10 +3,10 @@ import { registerJoystreamTypes } from '@joystream/types';
 import { ApiPromise, WsProvider } from '@polkadot/api';
 import { QueryableStorageMultiArg } from '@polkadot/api/types';
 import { formatBalance } from '@polkadot/util';
-import { Balance, Hash } from '@polkadot/types/interfaces';
+import { Hash } from '@polkadot/types/interfaces';
 import { KeyringPair } from '@polkadot/keyring/types';
 import { Codec } from '@polkadot/types/types';
-import { AccountBalances, AccountSummary, CouncilInfoObj, CouncilInfoTuple, createCouncilInfoObj } from './Types';
+import { AccountSummary, CouncilInfoObj, CouncilInfoTuple, createCouncilInfoObj } from './Types';
 import { DerivedFees, DerivedBalances } from '@polkadot/api-derive/types';
 import { CLIError } from '@oclif/errors';
 import ExitCodes from './ExitCodes';
@@ -56,30 +56,17 @@ export default class Api {
         return results;
     }
 
-    async getAccountsBalancesInfo(accountAddresses:string[]): Promise<AccountBalances[]> {
-        let apiQueries:any = [];
-        for (let address of accountAddresses) {
-            apiQueries.push([this._api.query.balances.freeBalance, address]);
-            apiQueries.push([this._api.query.balances.reservedBalance, address]);
-        }
-
-        let balances: AccountBalances[] = [];
-        let balancesRes = await this.queryMultiOnce(apiQueries);
-        for (let key in accountAddresses) {
-            let numKey: number = parseInt(key);
-            const free: Balance = <Balance> balancesRes[numKey*2];
-            const reserved: Balance = <Balance> balancesRes[numKey*2 + 1];
-            const total: Balance = this._api.createType('Balance', free.add(reserved));
-            balances[key] = { free, reserved, total };
-        }
+    async getAccountsBalancesInfo(accountAddresses:string[]): Promise<DerivedBalances[]> {
+        let accountsBalances: DerivedBalances[] = await this._api.derive.balances.votingBalances(accountAddresses);
 
-        return balances;
+        return accountsBalances;
     }
 
     // Get on-chain data related to given account.
     // For now it's just account balances
     async getAccountSummary(accountAddresses:string): Promise<AccountSummary> {
-        const balances: DerivedBalances = await this._api.derive.balances.all(accountAddresses);
+        const balances: DerivedBalances = (await this.getAccountsBalancesInfo([accountAddresses]))[0];
+        // TODO: Some more information can be fetched here in the future
 
         return { balances };
     }

+ 0 - 8
cli/src/Types.ts

@@ -14,14 +14,6 @@ export type NamedKeyringPair = KeyringPair & {
     }
 }
 
-// Simplified account balances (used when listing multiple accounts etc.)
-// Combines results returned by api.query.balances.freeBalance and api.query.balances.reservedBalance
-export type AccountBalances = {
-    free: Balance,
-    reserved: Balance,
-    total: Balance
-};
-
 // Summary of the account information fetched from the api for "account:current" purposes (currently just balances)
 export type AccountSummary = {
     balances: DerivedBalances

+ 16 - 7
cli/src/base/AccountsCommandBase.ts

@@ -7,7 +7,9 @@ import { CLIError } from '@oclif/errors';
 import ApiCommandBase from './ApiCommandBase';
 import { Keyring } from '@polkadot/api';
 import { formatBalance } from '@polkadot/util';
-import { AccountBalances, NamedKeyringPair } from '../Types';
+import { NamedKeyringPair } from '../Types';
+import { DerivedBalances } from '@polkadot/api-derive/types';
+import { toFixedLength } from '../helpers/display';
 
 const ACCOUNTS_DIRNAME = '/accounts';
 
@@ -167,20 +169,27 @@ export default abstract class AccountsCommandBase extends ApiCommandBase {
         message: string = 'Select an account',
         showBalances: boolean = true
     ): Promise<NamedKeyringPair> {
-        let balances: AccountBalances[];
+        let balances: DerivedBalances[];
         if (showBalances) {
             balances = await this.getApi().getAccountsBalancesInfo(accounts.map(acc => acc.address));
         }
+        const longestAccNameLength: number = accounts.reduce((prev, curr) => Math.max(curr.meta.name.length, prev), 0);
+        const accNameColLength: number = Math.min(longestAccNameLength + 1, 20);
         const { chosenAccountFilename } = await inquirer.prompt([{
             name: 'chosenAccountFilename',
             message,
             type: 'list',
             choices: accounts.map((account: NamedKeyringPair, i) => ({
-                name:
-                    `${ account.meta.name }: `+
-                    ( showBalances ? `${ formatBalance(balances[i].free) } / ${ formatBalance(balances[i].total) } ` : ' ')+
-                    account.address,
-                value: this.generateAccountFilename(account)
+                name: (
+                    `${ toFixedLength(account.meta.name, accNameColLength) } | `+
+                    `${ account.address } | ` +
+                    ((showBalances || '') && (
+                        `${ formatBalance(balances[i].availableBalance) } / `+
+                        `${ formatBalance(balances[i].votingBalance) }`
+                    ))
+                ),
+                value: this.generateAccountFilename(account),
+                short: `${ account.meta.name } (${ account.address })`
             })),
             default: defaultAccount && this.generateAccountFilename(defaultAccount)
         }]);

+ 11 - 4
cli/src/commands/account/current.ts

@@ -1,5 +1,6 @@
 import AccountsCommandBase from '../../base/AccountsCommandBase';
 import { AccountSummary, NameValueObj, NamedKeyringPair } from '../../Types';
+import { DerivedBalances } from '@polkadot/api-derive/types';
 import { displayHeader, displayNameValueTable } from '../../helpers/display';
 import { formatBalance } from '@polkadot/util';
 import moment from 'moment';
@@ -24,11 +25,17 @@ export default class AccountCurrent extends AccountsCommandBase {
         displayNameValueTable(accountRows);
 
         displayHeader('Balances');
-        const balancesRows: NameValueObj[] = [
-            { name: 'Available balance:', value: formatBalance(summary.balances.availableBalance) },
-            { name: 'Free balance:', value: formatBalance(summary.balances.freeBalance) },
-            { name: 'Locked balance:', value: formatBalance(summary.balances.lockedBalance) }
+        const balances: DerivedBalances = summary.balances;
+        let balancesRows: NameValueObj[] = [
+            { name: 'Total balance:', value: formatBalance(balances.votingBalance) },
+            { name: 'Transferable balance:', value: formatBalance(balances.availableBalance) }
         ];
+        if (balances.lockedBalance.gtn(0)) {
+            balancesRows.push({ name: 'Locked balance:', value: formatBalance(balances.lockedBalance) });
+        }
+        if (balances.reservedBalance.gtn(0)) {
+            balancesRows.push({ name: 'Reserved balance:', value: formatBalance(balances.reservedBalance) });
+        }
         displayNameValueTable(balancesRows);
     }
   }

+ 3 - 3
cli/src/commands/account/transferTokens.ts

@@ -4,9 +4,9 @@ import chalk from 'chalk';
 import ExitCodes from '../../ExitCodes';
 import { formatBalance } from '@polkadot/util';
 import { Hash } from '@polkadot/types/interfaces';
-import Api from '../../Api';
-import { AccountBalances, NamedKeyringPair } from '../../Types';
+import { NamedKeyringPair } from '../../Types';
 import { checkBalance, validateAddress } from '../../helpers/validation';
+import { DerivedBalances } from '@polkadot/api-derive/types';
 
 type AccountTransferArgs = {
     recipient: string,
@@ -36,7 +36,7 @@ export default class AccountTransferTokens extends AccountsCommandBase {
 
         // Initial validation
         validateAddress(args.recipient, 'Invalid recipient address');
-        const accBalances: AccountBalances = (await this.getApi().getAccountsBalancesInfo([ selectedAccount.address ]))[0];
+        const accBalances: DerivedBalances = (await this.getApi().getAccountsBalancesInfo([ selectedAccount.address ]))[0];
         checkBalance(accBalances, amountBN);
 
         await this.requestAccountDecoding(selectedAccount);

+ 8 - 0
cli/src/helpers/display.ts

@@ -23,3 +23,11 @@ export function displayNameValueTable(rows: NameValueObj[]) {
     );
 }
 
+export function toFixedLength(text: string, length: number, spacesOnLeft = false): string {
+    if (text.length > length && length > 3) {
+        return text.slice(0, length-3) + '...';
+    }
+    while(text.length < length) { spacesOnLeft ? text = ' '+text : text += ' ' };
+
+    return text;
+}

+ 3 - 3
cli/src/helpers/validation.ts

@@ -1,7 +1,7 @@
 import BN from 'bn.js';
 import ExitCodes from '../ExitCodes';
 import { decodeAddress } from '@polkadot/util-crypto';
-import { AccountBalances } from '../Types';
+import { DerivedBalances } from '@polkadot/api-derive/types';
 import { CLIError } from '@oclif/errors';
 
 export function validateAddress(address: string, errorMessage: string = 'Invalid address'): void {
@@ -12,8 +12,8 @@ export function validateAddress(address: string, errorMessage: string = 'Invalid
     }
 }
 
-export function checkBalance(accBalances: AccountBalances, requiredBalance: BN): void {
-    if (requiredBalance.gt(accBalances.free)) {
+export function checkBalance(accBalances: DerivedBalances, requiredBalance: BN): void {
+    if (requiredBalance.gt(accBalances.availableBalance)) {
         throw new CLIError('Not enough balance available', { exit: ExitCodes.InvalidInput });
     }
 }