Files
api/packages/api-derive/src/balances/all.ts
T
Amaury Martiny fadb1ffdd8 Make derive types work, and a bit more readable (#1430)
* Fix typings for derive

* Fix typings

* Spacing
2019-10-01 14:30:53 +02:00

99 lines
4.1 KiB
TypeScript

// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, AccountIndex, Address, Balance, BalanceLock, BlockNumber, Index, VestingSchedule } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { combineLatest, of, Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { ClassOf, Option, createType } from '@polkadot/types';
import { bnMax } from '@polkadot/util';
import { idAndIndex } from '../accounts/idAndIndex';
import { bestNumber } from '../chain/bestNumber';
import { DerivedBalances } from '../types';
import { drr } from '../util/drr';
type Result = [AccountId | undefined, BlockNumber | undefined, [Balance?, Balance?, BalanceLock[]?, Option<VestingSchedule>?, Index?]];
function calcBalances ([accountId = createType('AccountId'), bestNumber = createType('Balance'), [freeBalance = createType('Balance'), reservedBalance = createType('Balance'), locks = [], vesting = new Option<VestingSchedule>(ClassOf('VestingSchedule'), null), accountNonce = createType('Balance')]]: Result): DerivedBalances {
let lockedBalance = createType('Balance');
if (Array.isArray(locks)) {
// only get the locks that are valid until passed the current block
const totals = locks.filter((value): boolean => bestNumber && value.until.gt(bestNumber));
// get the maximum of the locks according to https://github.com/paritytech/substrate/blob/master/srml/balances/src/lib.rs#L699
lockedBalance = totals[0]
? bnMax(...totals.map(({ amount }): Balance => amount)) as Balance
: createType('Balance');
}
// offset = balance locked at genesis, perBlock is the unlock amount
const { offset, perBlock } = vesting.unwrapOr(createType('VestingSchedule'));
const vestedNow: BN = perBlock.mul(bestNumber);
const vestedBalance: BN = vestedNow.gt(offset)
? freeBalance
: freeBalance.sub(offset).add(vestedNow);
// NOTE Workaround for this account on Alex (one of a couple reported) -
// 5F7BJL6Z4m8RLtK7nXEqqpEqhBbd535Z3CZeYF6ccvaQAY6N
// The locked is > the vested and ended up with the locked > free,
// i.e. related to https://github.com/paritytech/polkadot/issues/225
// (most probably due to movements from stash -> controller -> free)
const availableBalance: BN = bnMax(createType('Balance'), vestedBalance.sub(lockedBalance));
return {
accountId,
accountNonce,
availableBalance,
freeBalance,
lockedBalance,
reservedBalance,
vestedBalance,
votingBalance: freeBalance.add(reservedBalance)
} as DerivedBalances;
}
/**
* @name all
* @param {( AccountIndex | AccountId | Address | string )} address - An accounts Id in different formats.
* @returns An object containing the combined results of the storage queries for
* all relevant fees as declared in the substrate chain spec.
* @example
* <BR>
*
* ```javascript
* const ALICE = 'F7Hs';
*
* api.derive.balances.all(ALICE, ([accountId, lockedBalance]) => {
* console.log(`The account ${accountId} has a locked balance ${lockedBalance} units.`);
* });
* ```
*/
export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId | Address | string) => Observable<DerivedBalances> {
return (address: AccountIndex | AccountId | Address | string): Observable<DerivedBalances> => {
return idAndIndex(api)(address).pipe(
switchMap(([accountId]): Observable<Result> =>
(accountId
? combineLatest([
of(accountId),
bestNumber(api)(),
api.queryMulti([
[api.query.balances.freeBalance, accountId],
[api.query.balances.reservedBalance, accountId],
[api.query.balances.locks, accountId],
[api.query.balances.vesting, accountId],
[api.query.system.accountNonce, accountId]
])
])
: of([undefined, undefined, [undefined, undefined, undefined, undefined, undefined]])
) as Observable<Result>
),
map(calcBalances),
drr()
);
};
}