Staking overview derive (#1537)

* Staking overview derive

* Expand derives

* Extract currentIndex/currentEra

* WIP

* Controllers opt

* Add memo

* Memomize the whole lot

* Doc building fixes

* Doc fixes #2
This commit is contained in:
Jaco Greeff
2019-11-02 23:10:10 +01:00
committed by GitHub
parent 1d92b7bead
commit 7cc961f789
44 changed files with 493 additions and 307 deletions
@@ -10,9 +10,10 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { isU8a } from '@polkadot/util';
import { decodeAddress } from '@polkadot/util-crypto';
import { createType } from '@polkadot/types';
import { idToIndex } from './idToIndex';
import { indexToId } from './indexToId';
import { drr } from '../util';
import { drr, memo } from '../util';
interface Calls {
idToIndexCall (accountId: string | AccountId): Observable<AccountIndex | undefined>;
@@ -59,12 +60,13 @@ function retrieve (address: Address | AccountId | AccountIndex | string | null |
* });
* ```
*/
export function idAndIndex (api: ApiInterfaceRx): (address?: Address | AccountId | AccountIndex | string | null) => Observable<AccountIdAndIndex> {
export const idAndIndex = memo((api: ApiInterfaceRx): (address?: Address | AccountId | AccountIndex | string | null) => Observable<AccountIdAndIndex> => {
const calls = {
idToIndexCall: idToIndex(api),
indexToIdCall: indexToId(api)
};
return (address?: Address | AccountId | AccountIndex | string | null): Observable<AccountIdAndIndex> =>
retrieve(address, calls).pipe(drr());
}
return memo((address?: Address | AccountId | AccountIndex | string | null): Observable<AccountIdAndIndex> =>
retrieve(address, calls).pipe(drr())
);
}, true);
@@ -9,7 +9,7 @@ import { map, startWith } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { indexes, AccountIndexes } from './indexes';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @name idToIndex
@@ -25,15 +25,16 @@ import { drr } from '../util';
* });
* ```
*/
export function idToIndex (api: ApiInterfaceRx): (accountId: AccountId | string) => Observable<AccountIndex | undefined> {
export const idToIndex = memo((api: ApiInterfaceRx): (accountId: AccountId | string) => Observable<AccountIndex | undefined> => {
const indexesCall = indexes(api);
return (accountId: AccountId | string): Observable<AccountIndex | undefined> =>
return memo((accountId: AccountId | string): Observable<AccountIndex | undefined> =>
indexesCall().pipe(
startWith({}),
map((indexes: AccountIndexes): AccountIndex | undefined =>
(indexes || {})[accountId.toString()]
),
drr()
);
}
)
);
}, true);
@@ -10,7 +10,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { ENUMSET_SIZE } from '@polkadot/types/primitive/Generic/AccountIndex';
import { createType, ClassOf, Vec } from '@polkadot/types';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @name indexToId
@@ -25,8 +25,8 @@ import { drr } from '../util';
* });
* ```
*/
export function indexToId (api: ApiInterfaceRx): (accountIndex: AccountIndex | string) => Observable<AccountId | undefined> {
return (_accountIndex: AccountIndex | string): Observable<AccountId | undefined> => {
export const indexToId = memo((api: ApiInterfaceRx): (accountIndex: AccountIndex | string) => Observable<AccountId | undefined> => {
return memo((_accountIndex: AccountIndex | string): Observable<AccountId | undefined> => {
const querySection = api.query.indices || api.query.balances;
const accountIndex = _accountIndex instanceof ClassOf('AccountIndex')
? _accountIndex
@@ -41,5 +41,5 @@ export function indexToId (api: ApiInterfaceRx): (accountIndex: AccountIndex | s
),
drr()
);
};
}
});
}, true);
+5 -5
View File
@@ -10,7 +10,7 @@ import { map, switchMap } from 'rxjs/operators';
import { ENUMSET_SIZE } from '@polkadot/types/primitive/Generic/AccountIndex';
import { createType } from '@polkadot/types';
import { drr } from '../util';
import { drr, memo } from '../util';
export type AccountIndexes = Record<string, AccountIndex>;
@@ -31,8 +31,8 @@ const enumsetSize = ENUMSET_SIZE.toNumber();
* });
* ```
*/
export function indexes (api: ApiInterfaceRx): () => Observable<AccountIndexes> {
return (): Observable<AccountIndexes> => {
export const indexes = memo((api: ApiInterfaceRx): () => Observable<AccountIndexes> => {
return memo((): Observable<AccountIndexes> => {
return api.query.indices
.nextEnumSet<AccountIndex>()
.pipe(
@@ -57,5 +57,5 @@ export function indexes (api: ApiInterfaceRx): () => Observable<AccountIndexes>
}, {} as AccountIndexes)),
drr()
);
};
}
});
}, true);
+6 -5
View File
@@ -12,7 +12,7 @@ import { map, switchMap } from 'rxjs/operators';
import { Bytes, Option, u32 } from '@polkadot/types';
import { u8aToString } from '@polkadot/util';
import { drr } from '../util';
import { drr, memo } from '../util';
import { idAndIndex } from './idAndIndex';
function retrieveNick (api: ApiInterfaceRx): (accountId?: AccountId) => Observable<Option<[Bytes, Balance] & Codec> | undefined> {
@@ -26,11 +26,11 @@ function retrieveNick (api: ApiInterfaceRx): (accountId?: AccountId) => Observab
* @name info
* @description Returns aux. info with regards to an account, current that includes the accountId, accountIndex and nickname
*/
export function info (api: ApiInterfaceRx): (address?: AccountIndex | AccountId | Address | string | null) => Observable<DeriveAccountInfo> {
export const info = memo((api: ApiInterfaceRx): (address?: AccountIndex | AccountId | Address | string | null) => Observable<DeriveAccountInfo> => {
const idAndIndexCall = idAndIndex(api);
const nickCall = retrieveNick(api);
return (address?: AccountIndex | AccountId | Address | string | null): Observable<DeriveAccountInfo> =>
return memo((address?: AccountIndex | AccountId | Address | string | null): Observable<DeriveAccountInfo> =>
idAndIndexCall(address).pipe(
switchMap(([accountId, accountIndex]): Observable<[DeriveAccountInfo, Option<[Bytes, Balance] & Codec>?]> => {
return combineLatest([
@@ -46,5 +46,6 @@ export function info (api: ApiInterfaceRx): (address?: AccountIndex | AccountId
: undefined
})),
drr()
);
}
)
);
}, true);
+5 -5
View File
@@ -14,7 +14,7 @@ import { bnMax } from '@polkadot/util';
import { info } from '../accounts/info';
import { bestNumber } from '../chain/bestNumber';
import { DerivedBalances } from '../types';
import { drr } from '../util';
import { drr, memo } from '../util';
type ResultBalance = [Balance, Balance, BalanceLock[], Option<VestingSchedule>];
type Result = [AccountId, BlockNumber, ResultBalance, Index];
@@ -77,11 +77,11 @@ function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable<R
* });
* ```
*/
export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId | Address | string) => Observable<DerivedBalances> {
export const all = memo((api: ApiInterfaceRx): (address: AccountIndex | AccountId | Address | string) => Observable<DerivedBalances> => {
const bestNumberCall = bestNumber(api);
const infoCall = info(api);
return (address: AccountIndex | AccountId | Address | string): Observable<DerivedBalances> => {
return memo((address: AccountIndex | AccountId | Address | string): Observable<DerivedBalances> => {
return infoCall(address).pipe(
switchMap(({ accountId }): Observable<Result> =>
(accountId
@@ -102,5 +102,5 @@ export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId |
map(calcBalances),
drr()
);
};
}
});
}, true);
+5 -5
View File
@@ -9,7 +9,7 @@ import { DerivedFees } from '../types';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { drr } from '../util';
import { drr, memo } from '../util';
type Result = [Balance, Balance, Balance, Balance, Balance];
@@ -51,8 +51,8 @@ function queryV1 (api: ApiInterfaceRx): Observable<Result> {
* });
* ```
*/
export function fees (api: ApiInterfaceRx): () => Observable<DerivedFees> {
return (): Observable<DerivedFees> => {
export const fees = memo((api: ApiInterfaceRx): () => Observable<DerivedFees> => {
return memo((): Observable<DerivedFees> => {
return (
api.consts.balances
? queryV2(api)
@@ -67,5 +67,5 @@ export function fees (api: ApiInterfaceRx): () => Observable<DerivedFees> {
})),
drr()
);
};
}
});
}, true);
@@ -8,11 +8,11 @@ import { combineLatest, Observable, of } from 'rxjs';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DerivedBalances } from '../types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { all } from './all';
export function votingBalances (api: ApiInterfaceRx): (addresses?: (AccountId | AccountIndex | Address | string)[]) => Observable<DerivedBalances[]> {
return (addresses?: (AccountId | AccountIndex | Address | string)[]): Observable<DerivedBalances[]> => {
export const votingBalances = memo((api: ApiInterfaceRx): (addresses?: (AccountId | AccountIndex | Address | string)[]) => Observable<DerivedBalances[]> => {
return memo((addresses?: (AccountId | AccountIndex | Address | string)[]): Observable<DerivedBalances[]> => {
return (
!addresses || !addresses.length
? of([] as DerivedBalances[])
@@ -20,5 +20,5 @@ export function votingBalances (api: ApiInterfaceRx): (addresses?: (AccountId |
).pipe(
drr()
);
};
}
});
}, true);
@@ -11,13 +11,13 @@ import { Vec } from '@polkadot/types';
import { info } from '../accounts/info';
import { DerivedBalances } from '../types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { votingBalances } from './votingBalances';
export function votingBalancesNominatorsFor (api: ApiInterfaceRx): (address: AccountId | AccountIndex | Address | string) => Observable<DerivedBalances[]> {
export const votingBalancesNominatorsFor = memo((api: ApiInterfaceRx): (address: AccountId | AccountIndex | Address | string) => Observable<DerivedBalances[]> => {
const infoCall = info(api);
return (address: AccountId | AccountIndex | Address | string): Observable<DerivedBalances[]> => {
return memo((address: AccountId | AccountIndex | Address | string): Observable<DerivedBalances[]> => {
return infoCall(address).pipe(
switchMap(({ accountId }): Observable<AccountId[]> =>
accountId
@@ -27,5 +27,5 @@ export function votingBalancesNominatorsFor (api: ApiInterfaceRx): (address: Acc
switchMap(votingBalances(api)),
drr()
);
};
}
});
}, true);
+6 -5
View File
@@ -8,7 +8,7 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @name bestNumber
@@ -22,10 +22,11 @@ import { drr } from '../util';
* });
* ```
*/
export function bestNumber (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): Observable<BlockNumber> =>
export const bestNumber = memo((api: ApiInterfaceRx): () => Observable<BlockNumber> => {
return memo((): Observable<BlockNumber> =>
api.rpc.chain.subscribeNewHeads().pipe(
map((header): BlockNumber => header.number.unwrap()),
drr()
);
}
)
);
}, true);
@@ -8,7 +8,7 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @name bestNumberFinalized
@@ -23,10 +23,11 @@ import { drr } from '../util';
* });
* ```
*/
export function bestNumberFinalized (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): Observable<BlockNumber> =>
export const bestNumberFinalized = memo((api: ApiInterfaceRx): () => Observable<BlockNumber> => {
return memo((): Observable<BlockNumber> =>
api.rpc.chain.subscribeFinalizedHeads().pipe(
map((header): BlockNumber => header.number.unwrap()),
drr()
);
}
)
);
}, true);
@@ -9,7 +9,7 @@ import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { createType } from '@polkadot/types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { bestNumber } from './bestNumber';
import { bestNumberFinalized } from './bestNumberFinalized';
@@ -26,11 +26,11 @@ import { bestNumberFinalized } from './bestNumberFinalized';
* });
* ```
*/
export function bestNumberLag (api: ApiInterfaceRx): () => Observable<BlockNumber> {
export const bestNumberLag = memo((api: ApiInterfaceRx): () => Observable<BlockNumber> => {
const bestNumberCall = bestNumber(api);
const bestNumberFinalizedCall = bestNumberFinalized(api);
return (): Observable<BlockNumber> =>
return memo((): Observable<BlockNumber> =>
combineLatest([
bestNumberCall(),
bestNumberFinalizedCall()
@@ -39,5 +39,6 @@ export function bestNumberLag (api: ApiInterfaceRx): () => Observable<BlockNumbe
createType('BlockNumber', bestNumber.sub(bestNumberFinalized))
),
drr()
);
}
)
);
}, true);
+15 -13
View File
@@ -2,13 +2,16 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Observable, combineLatest, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AccountId } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Observable, combineLatest, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Vec } from '@polkadot/types';
import { HeaderExtended } from '../type';
import { drr } from '../util';
import { HeaderAndValidators } from './subscribeNewHeads';
import { drr, memo } from '../util';
/**
* @name bestNumberFinalized
@@ -24,14 +27,12 @@ import { HeaderAndValidators } from './subscribeNewHeads';
* console.log(`block #${number} was authored by ${author}`);
* ```
*/
export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) => Observable<HeaderExtended | undefined> {
return (hash: Uint8Array | string): Observable<HeaderExtended | undefined> =>
(combineLatest([
export const getHeader = memo((api: ApiInterfaceRx): (hash: Uint8Array | string) => Observable<HeaderExtended | undefined> => {
return memo((hash: Uint8Array | string): Observable<HeaderExtended | undefined> =>
combineLatest([
api.rpc.chain.getHeader(hash),
api.query.session
? api.query.session.validators.at(hash)
: of([])
]) as Observable<HeaderAndValidators>).pipe(
api.query.session.validators.at(hash) as Observable<Vec<AccountId>>
]).pipe(
map(([header, validators]): HeaderExtended =>
new HeaderExtended(header, validators)
),
@@ -42,5 +43,6 @@ export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) =>
of()
),
drr()
);
}
)
);
}, true);
@@ -2,16 +2,15 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, Header } from '@polkadot/types/interfaces';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { Vec } from '@polkadot/types';
import { HeaderExtended } from '../type';
import { drr } from '../util';
export type HeaderAndValidators = [Header, AccountId[]];
import { drr, memo } from '../util';
/**
* @name subscribeNewHeads
@@ -26,23 +25,16 @@ export type HeaderAndValidators = [Header, AccountId[]];
* });
* ```
*/
export function subscribeNewHeads (api: ApiInterfaceRx): () => Observable<HeaderExtended> {
return (): Observable<HeaderExtended> =>
api.rpc.chain.subscribeNewHeads().pipe(
switchMap((header: Header): Observable<HeaderAndValidators> =>
(combineLatest([
of(header),
// theoretically we could combine at the first call with session.validators(), however
// we make 100% sure we actually get the validators at a specific block so when these
// change at an era boundary, we have the previous values to ensure our indexes are correct
api.query.session
? api.query.session.validators.at(header.hash)
: of([])
]) as Observable<HeaderAndValidators>)
),
export const subscribeNewHeads = memo((api: ApiInterfaceRx): () => Observable<HeaderExtended> => {
return memo((): Observable<HeaderExtended> =>
combineLatest([
api.rpc.chain.subscribeNewHeads(),
api.query.session.validators<Vec<AccountId>>()
]).pipe(
map(([header, validators]): HeaderExtended =>
new HeaderExtended(header, validators)
),
drr()
);
}
)
);
}, true);
+5 -5
View File
@@ -9,7 +9,7 @@ import BN from 'bn.js';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { drr } from '../util';
import { drr, memo } from '../util';
type ResultV2 = [BN, BN, BN, BN, BN, BN, BN, BN, BN, BN];
@@ -103,8 +103,8 @@ function queryConstants (api: ApiInterfaceRx): Observable<ResultV2> {
* });
* ```
*/
export function fees (api: ApiInterfaceRx): () => Observable<DerivedContractFees> {
return (): Observable<DerivedContractFees> => {
export const fees = memo((api: ApiInterfaceRx): () => Observable<DerivedContractFees> => {
return memo((): Observable<DerivedContractFees> => {
if (api.query.contract && !api.query.contract.rentByteFee) {
return queryV1(api);
}
@@ -122,5 +122,5 @@ export function fees (api: ApiInterfaceRx): () => Observable<DerivedContractFees
),
drr()
);
};
}
});
}, true);
@@ -12,7 +12,7 @@ import { Option } from '@polkadot/types';
import { isNull } from '@polkadot/util';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util';
import { drr, memo } from '../util';
export function constructInfo (index: BN | number, optionInfo?: Option<ReferendumInfo>): Option<ReferendumInfoExtended> {
const info = optionInfo
@@ -27,8 +27,8 @@ export function constructInfo (index: BN | number, optionInfo?: Option<Referendu
);
}
export function referendumInfo (api: ApiInterfaceRx): (index: BN | number) => Observable<Option<ReferendumInfoExtended>> {
return (index: BN | number): Observable<Option<ReferendumInfoExtended>> => {
export const referendumInfo = memo((api: ApiInterfaceRx): (index: BN | number) => Observable<Option<ReferendumInfoExtended>> => {
return memo((index: BN | number): Observable<Option<ReferendumInfoExtended>> => {
return (api.query.democracy.referendumInfoOf<Option<ReferendumInfo>>(index))
.pipe(
map((optionInfo): Option<ReferendumInfoExtended> =>
@@ -36,5 +36,5 @@ export function referendumInfo (api: ApiInterfaceRx): (index: BN | number) => Ob
),
drr()
);
};
}
});
}, true);
@@ -11,11 +11,11 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, Vec } from '@polkadot/types';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util';
import { drr, memo } from '../util';
import { constructInfo } from './referendumInfo';
export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) => Observable<Option<ReferendumInfoExtended>[]> {
return (ids: (BN | number)[] = []): Observable<Option<ReferendumInfoExtended>[]> => {
export const referendumInfos = memo((api: ApiInterfaceRx): (ids?: (BN | number)[]) => Observable<Option<ReferendumInfoExtended>[]> => {
return memo((ids: (BN | number)[] = []): Observable<Option<ReferendumInfoExtended>[]> => {
return (
!ids || !ids.length
? of([] as Option<ReferendumInfo>[])
@@ -28,5 +28,5 @@ export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) =
),
drr()
);
};
}
});
}, true);
@@ -11,15 +11,15 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec, createType } from '@polkadot/types';
import { DerivedBalances, DerivedReferendumVote } from '../types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { votes } from './votes';
import { votingBalances } from '../balances/votingBalances';
export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | number) => Observable<DerivedReferendumVote[]> {
export const referendumVotesFor = memo((api: ApiInterfaceRx): (referendumId: BN | number) => Observable<DerivedReferendumVote[]> => {
const votesCall = votes(api);
const votingBalancesCall = votingBalances(api);
return (referendumId: BN | number): Observable<DerivedReferendumVote[]> =>
return memo((referendumId: BN | number): Observable<DerivedReferendumVote[]> =>
(api.query.democracy.votersFor<Vec<AccountId>>(referendumId)).pipe(
switchMap((votersFor): Observable<[Vec<AccountId>, Vote[], DerivedBalances[]]> =>
combineLatest([
@@ -36,5 +36,6 @@ export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | nu
} as unknown as DerivedReferendumVote))
),
drr()
);
}
)
);
}, true);
@@ -11,13 +11,13 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option } from '@polkadot/types';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util';
import { drr, memo } from '../util';
import { referendumInfos } from './referendumInfos';
export function referendums (api: ApiInterfaceRx): () => Observable<Option<ReferendumInfoExtended>[]> {
export const referendums = memo((api: ApiInterfaceRx): () => Observable<Option<ReferendumInfoExtended>[]> => {
const referendumInfosCall = referendumInfos(api);
return (): Observable<Option<ReferendumInfoExtended>[]> =>
return memo((): Observable<Option<ReferendumInfoExtended>[]> =>
(api.queryMulti([
api.query.democracy.nextTally,
api.query.democracy.referendumCount
@@ -32,5 +32,6 @@ export function referendums (api: ApiInterfaceRx): () => Observable<Option<Refer
: of([])
),
drr()
);
}
)
);
}, true);
+5 -5
View File
@@ -9,10 +9,10 @@ import { Observable, of } from 'rxjs';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec } from '@polkadot/types';
import { drr } from '../util';
import { drr, memo } from '../util';
export function votes (api: ApiInterfaceRx): (referendumId: BN, accountIds?: AccountId[]) => Observable<Vote[]> {
return (referendumId: BN, accountIds: AccountId[] = []): Observable<Vote[]> => {
export const votes = memo((api: ApiInterfaceRx): (referendumId: BN, accountIds?: AccountId[]) => Observable<Vote[]> => {
return memo((referendumId: BN, accountIds: AccountId[] = []): Observable<Vote[]> => {
return ((
!accountIds || !accountIds.length
? of([])
@@ -22,5 +22,5 @@ export function votes (api: ApiInterfaceRx): (referendumId: BN, accountIds?: Acc
)
)
) as Observable<Vec<Vote>>).pipe(drr());
};
}
});
}, true);
@@ -9,7 +9,7 @@ import { Observable } from 'rxjs';
import { Vec } from '@polkadot/types';
import { switchMap, map } from 'rxjs/operators';
import { approvalFlagsToBools } from '../util/approvalFlagsToBools';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @name approvalsOf
@@ -23,8 +23,8 @@ import { drr } from '../util';
* });
* ```
*/
export function approvalsOf (api: ApiInterfaceRx): (who: AccountId) => Observable<boolean[][]> {
return (who: AccountId | string): Observable<boolean[][]> =>
export const approvalsOf = memo((api: ApiInterfaceRx): (who: AccountId) => Observable<boolean[][]> => {
return memo((who: AccountId | string): Observable<boolean[][]> =>
api.query.elections.nextVoterSet<SetIndex>().pipe(
switchMap((nextVoterSet: SetIndex): Observable<Vec<ApprovalFlag>[]> =>
api.query.elections.approvalsOf.multi(
@@ -39,5 +39,6 @@ export function approvalsOf (api: ApiInterfaceRx): (who: AccountId) => Observabl
)
),
drr()
);
}
)
);
}, true);
@@ -11,7 +11,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec } from '@polkadot/types';
import { approvalFlagsToBools } from '../util/approvalFlagsToBools';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @name approvalsOfAt
@@ -25,10 +25,11 @@ import { drr } from '../util';
* });
* ```
*/
export function approvalsOfAt (api: ApiInterfaceRx): (who: AccountId, at: SetIndex) => Observable<boolean[]> {
return (who: AccountId | string, at: SetIndex | BN | number): Observable<boolean[]> =>
export const approvalsOfAt = memo((api: ApiInterfaceRx): (who: AccountId, at: SetIndex) => Observable<boolean[]> => {
return memo((who: AccountId | string, at: SetIndex | BN | number): Observable<boolean[]> =>
api.query.elections.approvalsOf<Vec<ApprovalFlag>>([who.toString(), at]).pipe(
map((flags: Vec<ApprovalFlag>): boolean[] => approvalFlagsToBools(flags)),
drr()
);
}
)
);
}, true);
+5 -5
View File
@@ -11,7 +11,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { createType, Vec, u32 } from '@polkadot/types';
import { DerivedElectionsInfo } from '../types';
import { drr } from '../util';
import { drr, memo } from '../util';
type ResultElectionsInner = [u32, u32, Vec<[AccountId, BlockNumber] & Codec>, SetIndex, BlockNumber, VoteIndex, SetIndex];
type ResultElections = [Vec<AccountId>, ResultElectionsInner];
@@ -89,10 +89,10 @@ function queryPhragmen (api: ApiInterfaceRx): Observable<DerivedElectionsInfo> {
* });
* ```
*/
export function info (api: ApiInterfaceRx): () => Observable<DerivedElectionsInfo> {
return (): Observable<DerivedElectionsInfo> => {
export const info = memo((api: ApiInterfaceRx): () => Observable<DerivedElectionsInfo> => {
return memo((): Observable<DerivedElectionsInfo> => {
return api.query.electionsPhragmen
? queryPhragmen(api)
: queryElections(api);
};
}
});
}, true);
@@ -10,7 +10,8 @@ import { DerivedVoterPositions } from '../types';
import BN from 'bn.js';
import { of, combineLatest, Observable } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @name voterPositions
@@ -25,8 +26,8 @@ import { drr } from '../util';
* });
* ```
*/
export function voterPositions (api: ApiInterfaceRx): () => Observable<DerivedVoterPositions> {
return (): Observable<DerivedVoterPositions> =>
export const voterPositions = memo((api: ApiInterfaceRx): () => Observable<DerivedVoterPositions> => {
return memo((): Observable<DerivedVoterPositions> =>
api.query.elections.nextVoterSet<SetIndex>().pipe(
switchMap((nextVoterSet: SetIndex): Observable<[BN, Vec<Option<AccountId>>[]]> => combineLatest(
of(api.consts.elections.voterSetSize) as any as Observable<BN>,
@@ -53,5 +54,6 @@ export function voterPositions (api: ApiInterfaceRx): () => Observable<DerivedVo
}, {});
}),
drr()
);
}
)
);
}, true);
+6 -5
View File
@@ -10,7 +10,7 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { createType, Vec } from '@polkadot/types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { voterPositions } from './voterPositions';
/**
@@ -25,10 +25,10 @@ import { voterPositions } from './voterPositions';
* });
* ```
*/
export function voters (api: ApiInterfaceRx): () => Observable<Vec<AccountId>> {
export const voters = memo((api: ApiInterfaceRx): () => Observable<Vec<AccountId>> => {
const voterPositionsCall = voterPositions(api);
return (): Observable<Vec<AccountId>> =>
return memo((): Observable<Vec<AccountId>> =>
voterPositionsCall().pipe(
map(
(voterPositions: DerivedVoterPositions): Vec<AccountId> =>
@@ -40,5 +40,6 @@ export function voters (api: ApiInterfaceRx): () => Observable<Vec<AccountId>> {
)
),
drr()
);
}
)
);
}, true);
@@ -8,24 +8,24 @@ import { DerivedHeartbeats } from '../types';
import { of, Observable, combineLatest } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Bytes, Vec, u32 } from '@polkadot/types';
import { Bytes, Option, u32 } from '@polkadot/types';
import { drr } from '../util';
import { overview as stakingOverview } from '../staking';
import { drr, memo } from '../util';
/**
* @description Return a boolean array indicating whether the passed accounts had received heartbeats in the current session
*/
export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable<DerivedHeartbeats> {
return (): Observable<DerivedHeartbeats> => {
export const receivedHeartbeats = memo((api: ApiInterfaceRx): () => Observable<DerivedHeartbeats> => {
const stakingOverviewvCall = stakingOverview(api);
return memo((): Observable<DerivedHeartbeats> => {
return api.query.imOnline && api.query.imOnline.receivedHeartbeats && api.query.imOnline.authoredBlocks
? api.queryMulti<[SessionIndex, Vec<AccountId>]>([
api.query.session.currentIndex,
api.query.session.validators
]).pipe(
switchMap(([currentIndex, validators]): Observable<[AccountId[], Bytes[], u32[]]> =>
? stakingOverviewvCall().pipe(
switchMap(({ currentIndex, validators }): Observable<[AccountId[], Option<Bytes>[], u32[]]> =>
combineLatest([
of(validators),
api.query.imOnline.receivedHeartbeats.multi<Bytes>(validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])),
api.query.imOnline.receivedHeartbeats.multi<Option<Bytes>>(validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])),
api.query.imOnline.authoredBlocks.multi<u32>(validators.map((address): [SessionIndex, AccountId] => [currentIndex, address]))
])
),
@@ -42,5 +42,5 @@ export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable<Deriv
drr()
)
: of({});
};
}
});
}, true);
+6 -5
View File
@@ -8,15 +8,16 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { info } from './info';
export function eraLength (api: ApiInterfaceRx): () => Observable<BlockNumber> {
export const eraLength = memo((api: ApiInterfaceRx): () => Observable<BlockNumber> => {
const infoCall = info(api);
return (): Observable<BlockNumber> =>
return memo((): Observable<BlockNumber> =>
infoCall().pipe(
map(({ eraLength }): BlockNumber => eraLength),
drr()
);
}
)
);
}, true);
@@ -2,20 +2,22 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import BN from 'bn.js';
import { BlockNumber } from '@polkadot/types/interfaces';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { info } from './info';
export function eraProgress (api: ApiInterfaceRx): () => Observable<BN> {
export const eraProgress = memo((api: ApiInterfaceRx): () => Observable<BlockNumber> => {
const infoCall = info(api);
return (): Observable<BN> =>
return memo((): Observable<BlockNumber> =>
infoCall().pipe(
map(({ eraProgress }): BN => eraProgress),
map(({ eraProgress }): BlockNumber => eraProgress),
drr()
);
}
)
);
}, true);
+1
View File
@@ -4,5 +4,6 @@
export * from './eraLength';
export * from './eraProgress';
export * from './indexes';
export * from './info';
export * from './sessionProgress';
@@ -0,0 +1,28 @@
// 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 { ApiInterfaceRx } from '@polkadot/api/types';
import { EraIndex, SessionIndex } from '@polkadot/types/interfaces';
import { DeriveSessionIndexes } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { u32 } from '@polkadot/types';
import { drr, memo } from '../util';
export const indexes = memo((api: ApiInterfaceRx): () => Observable<DeriveSessionIndexes> => {
return memo((): Observable<DeriveSessionIndexes> =>
api.queryMulti<[SessionIndex, EraIndex, u32]>([
api.query.session.currentIndex,
api.query.staking.currentEra,
api.query.staking.validatorCount
]).pipe(
map(([currentIndex, currentEra, validatorCount]): DeriveSessionIndexes => ({
currentIndex, currentEra, validatorCount
})),
drr()
)
);
}, true);
+50 -38
View File
@@ -2,27 +2,32 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { BlockNumber, EraIndex, SessionIndex } from '@polkadot/types/interfaces';
import { DerivedSessionInfo } from '../types';
import { BlockNumber, SessionIndex } from '@polkadot/types/interfaces';
import { DerivedSessionInfo, DeriveSessionIndexes } from '../types';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, u64, createType } from '@polkadot/types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { bestNumber } from '../chain';
import { indexes } from './indexes';
type ResultV1Session = [SessionIndex, Option<BlockNumber>, BlockNumber, BlockNumber, SessionIndex];
type ResultV1 = [BlockNumber, ResultV1Session];
type ResultV1Session = [Option<BlockNumber>, BlockNumber, BlockNumber, SessionIndex];
type ResultV1 = [BlockNumber, DeriveSessionIndexes, ResultV1Session];
type ResultIndex = [SessionIndex, EraIndex];
type ResultSlots = [u64, u64, u64, SessionIndex, EraIndex, SessionIndex];
type ResultSlots = [u64, u64, u64, SessionIndex];
type ResultType = [boolean, u64, SessionIndex];
type Result = [ResultType, ResultSlots];
type Result = [ResultType, DeriveSessionIndexes, ResultSlots];
interface Calls {
bestNumberCall (): Observable<BlockNumber>;
indexesCall (): Observable<DeriveSessionIndexes>;
}
// internal helper to just split the logic - take all inputs, do the calculations and combine
function createDerivedV1 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: ResultV1): DerivedSessionInfo {
function createDerivedV1 ([bestNumber, { currentIndex, validatorCount }, [_lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: ResultV1): DerivedSessionInfo {
const lastLengthChange = (_lastLengthChange && _lastLengthChange.unwrapOr(null)) || createType('BlockNumber');
const sessionProgress = bestNumber
.sub(lastLengthChange)
@@ -45,15 +50,18 @@ function createDerivedV1 ([bestNumber, [currentIndex, _lastLengthChange, session
lastLengthChange,
sessionLength,
sessionsPerEra,
sessionProgress: createType('BlockNumber', sessionProgress)
sessionProgress: createType('BlockNumber', sessionProgress),
validatorCount
};
}
function createDerivedLatest ([[hasBabe, epochDuration, sessionsPerEra], [currentSlot, epochIndex, epochOrGenesisStartSlot, currentIndex, currentEra, currentEraStartSessionIndex]]: Result): DerivedSessionInfo {
function createDerivedLatest ([[hasBabe, epochDuration, sessionsPerEra], { currentIndex, currentEra, validatorCount }, [currentSlot, epochIndex, epochOrGenesisStartSlot, currentEraStartSessionIndex]]: Result): DerivedSessionInfo {
const epochStartSlot = epochIndex.mul(epochDuration).add(epochOrGenesisStartSlot);
const sessionProgress = currentSlot.sub(epochStartSlot);
const eraProgress = currentIndex.sub(currentEraStartSessionIndex).add(sessionProgress);
// console.log(sessionProgress);
return {
currentEra,
currentIndex,
@@ -64,15 +72,16 @@ function createDerivedLatest ([[hasBabe, epochDuration, sessionsPerEra], [curren
lastLengthChange: createType('BlockNumber', epochStartSlot),
sessionLength: epochDuration,
sessionsPerEra,
sessionProgress: createType('BlockNumber', sessionProgress)
sessionProgress: createType('BlockNumber', sessionProgress),
validatorCount
};
}
function infoV1 (api: ApiInterfaceRx, bestNumberCall: () => Observable<BlockNumber>): Observable<DerivedSessionInfo> {
function infoV1 (api: ApiInterfaceRx, { bestNumberCall, indexesCall }: Calls): Observable<DerivedSessionInfo> {
return combineLatest([
bestNumberCall(),
indexesCall(),
api.queryMulti<ResultV1Session>([
api.query.session.currentIndex,
api.query.session.lastLengthChange,
api.query.session.sessionLength,
api.query.staking.lastEraLengthChange,
@@ -84,33 +93,33 @@ function infoV1 (api: ApiInterfaceRx, bestNumberCall: () => Observable<BlockNumb
);
}
function infoLatestAura (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return api.queryMulti<ResultIndex>([
api.query.session.currentIndex,
api.query.staking.currentEra
]).pipe(
map(([currentIndex, currentEra]): DerivedSessionInfo =>
function infoLatestAura (api: ApiInterfaceRx, { indexesCall }: Calls): Observable<DerivedSessionInfo> {
return indexesCall().pipe(
map((indexes): DerivedSessionInfo =>
createDerivedLatest([
[false, createType('u64', 1), api.consts.staking.sessionsPerEra as SessionIndex],
[createType('u64', 1), createType('u64', 1), createType('u64', 1), currentIndex, currentEra, createType('SessionIndex', 1)]
indexes,
[createType('u64', 1), createType('u64', 1), createType('u64', 1), createType('SessionIndex', 1)]
])
),
drr()
);
}
function infoLatestBabe (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return api.queryMulti<ResultSlots>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot,
api.query.session.currentIndex,
api.query.staking.currentEra,
api.query.staking.currentEraStartSessionIndex
function infoLatestBabe (api: ApiInterfaceRx, { indexesCall }: Calls): Observable<DerivedSessionInfo> {
return combineLatest([
indexesCall(),
api.queryMulti<ResultSlots>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot,
api.query.staking.currentEraStartSessionIndex
])
]).pipe(
map((slots: ResultSlots): DerivedSessionInfo =>
map(([indexes, slots]: [DeriveSessionIndexes, ResultSlots]): DerivedSessionInfo =>
createDerivedLatest([
[true, api.consts.babe.epochDuration as u64, api.consts.staking.sessionsPerEra as SessionIndex],
indexes,
slots
])
),
@@ -121,14 +130,17 @@ function infoLatestBabe (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
/**
* @description Retrieves all the session and era info and calculates specific values on it as the length of the session and eras
*/
export function info (api: ApiInterfaceRx): () => Observable<DerivedSessionInfo> {
const bestNumberCall = bestNumber(api);
export const info = memo((api: ApiInterfaceRx): () => Observable<DerivedSessionInfo> => {
const calls = {
bestNumberCall: bestNumber(api),
indexesCall: indexes(api)
};
return (): Observable<DerivedSessionInfo> => {
return memo((): Observable<DerivedSessionInfo> => {
return api.consts.staking
? api.consts.babe
? infoLatestBabe(api) // 2.x with Babe
: infoLatestAura(api) // 2.x with Aura (not all info there)
: infoV1(api, bestNumberCall); // 1.x
};
}
? infoLatestBabe(api, calls) // 2.x with Babe
: infoLatestAura(api, calls) // 2.x with Aura (not all info there)
: infoV1(api, calls); // 1.x
});
}, true);
@@ -8,15 +8,16 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util';
import { drr, memo } from '../util';
import { info } from './info';
export function sessionProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
export const sessionProgress = memo((api: ApiInterfaceRx): () => Observable<BlockNumber> => {
const infoCall = info(api);
return (): Observable<BlockNumber> =>
return memo((): Observable<BlockNumber> =>
infoCall().pipe(
map(({ sessionProgress }): BlockNumber => sessionProgress),
drr()
);
}
)
);
}, true);
-31
View File
@@ -1,31 +0,0 @@
// 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 { DerivedStaking } from '../types';
import { Observable, combineLatest } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util';
import { controllers } from './controllers';
import { info } from './info';
/**
* @description Retrieve all the staking info available for the chain
*/
export function all (api: ApiInterfaceRx): () => Observable<DerivedStaking[]> {
const infoCall = info(api);
const controllersCall = controllers(api);
return (): Observable<DerivedStaking[]> =>
controllersCall().pipe(
switchMap(([accountIds]): Observable<DerivedStaking[]> =>
combineLatest(
accountIds.map((accountId): Observable<DerivedStaking> => infoCall(accountId))
)
),
drr()
);
}
+18 -17
View File
@@ -2,31 +2,32 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import { Observable, combineLatest, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option } from '@polkadot/types';
import { drr } from '../util';
import { drr, memo } from '../util';
/**
* @description From the list of stash accounts, retrieve the list of controllers
*/
export function controllers (api: ApiInterfaceRx): () => Observable<[AccountId[], Option<AccountId>[]]> {
return (): Observable<[AccountId[], Option<AccountId>[]]> =>
api.query.staking
.validators<[AccountId[]] & Codec>()
.pipe(
switchMap(([stashIds]): Observable<[AccountId[], Option<AccountId>[]]> =>
combineLatest([
of(stashIds),
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
api.query.staking.bonded.multi(stashIds) as Observable<Option<AccountId>[]>
])
),
drr()
);
}
export const controllers = memo((api: ApiInterfaceRx): () => Observable<[AccountId[], Option<AccountId>[]]> => {
return memo((): Observable<[AccountId[], Option<AccountId>[]]> =>
api.query.staking.validators<[AccountId[]] & Codec>().pipe(
switchMap(([stashIds]): Observable<[AccountId[], Option<AccountId>[]]> =>
combineLatest([
of(stashIds),
// for V2, don't return all the controllers, we call bonded at a later point
api.consts.session
? of([])
: api.query.staking.bonded.multi<Option<AccountId>>(stashIds)
])
),
drr()
)
);
}, true);
+2 -1
View File
@@ -2,7 +2,8 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
export * from './all';
export * from './controllers';
export * from './info';
export * from './overview';
export * from './recentlyOffline';
export * from './validators';
+7 -13
View File
@@ -2,9 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Balance, BlockNumber } from '@polkadot/types/interfaces/runtime';
import { Keys } from '@polkadot/types/interfaces/session';
import { Exposure, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs } from '@polkadot/types/interfaces/staking';
import { AccountId, Balance, BlockNumber, Exposure, Keys, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import { ApiInterfaceRx } from '@polkadot/api/types';
@@ -20,7 +18,7 @@ import { isUndefined } from '@polkadot/util';
import { bestNumber } from '../chain/bestNumber';
import { eraLength } from '../session/eraLength';
import { recentlyOffline } from './recentlyOffline';
import { drr } from '../util';
import { drr, memo } from '../util';
interface Calls {
bestNumberCall (): Observable<BlockNumber>;
@@ -103,7 +101,7 @@ function redeemableSum (stakingLedger: StakingLedger | undefined, eraLength: BN,
}, new BN(0)));
}
function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | [AccountId, Keys][], nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; nextSessionId?: AccountId; sessionIds: AccountId[]; sessionId?: AccountId } {
function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | [AccountId, Keys][], nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; sessionIds: AccountId[] } {
// for 2.x we have a Vec<(ValidatorId,Keys)> of the keys
if (Array.isArray(queuedKeys)) {
const sessionIds = (queuedKeys.find(([currentId]): boolean =>
@@ -112,9 +110,7 @@ function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | [
const nextSessionIds = nextKeys.unwrapOr([] as AccountId[]);
return {
nextSessionId: nextSessionIds[0],
nextSessionIds,
sessionId: sessionIds[0],
sessionIds
};
}
@@ -125,9 +121,7 @@ function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | [
: [];
return {
nextSessionId: nextSessionIds[0],
nextSessionIds,
sessionId: nextSessionIds[0],
sessionIds: nextSessionIds
};
}
@@ -230,18 +224,18 @@ function retrieveV2 (api: ApiInterfaceRx, calls: Calls, stashId: AccountId): Obs
/**
* @description From a stash, retrieve the controllerId and fill in all the relevant staking details
*/
export function info (api: ApiInterfaceRx): (_accountId: Uint8Array | string) => Observable<DerivedStaking> {
export const info = memo((api: ApiInterfaceRx): (_accountId: Uint8Array | string) => Observable<DerivedStaking> => {
const calls = {
eraLengthCall: eraLength(api),
bestNumberCall: bestNumber(api),
recentlyOfflineCall: recentlyOffline(api)
};
return (_accountId: Uint8Array | string): Observable<DerivedStaking> => {
return memo((_accountId: Uint8Array | string): Observable<DerivedStaking> => {
const accountId = createType('AccountId', _accountId);
return api.consts.session
? retrieveV2(api, calls, accountId)
: retrieveV1(api, calls, accountId);
};
}
});
}, true);
@@ -0,0 +1,66 @@
// 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 { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, Exposure, Keys, RewardDestination, ValidatorPrefs } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DerivedStakingStash } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Option, Vec } from '@polkadot/types';
import { drr, memo } from '../util';
// NOTE Unused ATM, preparing for V2-only
type Result = [Option<AccountId>, [Vec<AccountId>], RewardDestination, Exposure, ValidatorPrefs, Option<Keys>?];
type ResultV1 = [Option<AccountId>, ITuple<[Vec<AccountId>]>, RewardDestination, Exposure, ValidatorPrefs];
type ResultV2 = [Option<AccountId>, ITuple<[Vec<AccountId>]>, RewardDestination, Exposure, ValidatorPrefs, Option<Keys>];
function parse (stashId: AccountId, [_controllerId, [nominators], rewardDestination, stakers, validatorPrefs, _nextKeys]: Result): DerivedStakingStash {
return {
controllerId: _controllerId.unwrapOr(undefined),
nextKeys: _nextKeys && _nextKeys.unwrapOr(undefined),
nominators,
rewardDestination,
stakers,
stashId,
validatorPrefs
};
}
function retrieveV1 (api: ApiInterfaceRx, stashId: AccountId): Observable<Result> {
return api.queryMulti<ResultV1>([
[api.query.staking.bonded, stashId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId]
]);
}
function retrieveV2 (api: ApiInterfaceRx, stashId: AccountId): Observable<Result> {
return api.queryMulti<ResultV2>([
[api.query.staking.bonded, stashId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId],
[api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]]
]);
}
export const infoStash = memo((api: ApiInterfaceRx): (stashId: AccountId) => Observable<DerivedStakingStash> => {
return memo((stashId: AccountId): Observable<DerivedStakingStash> => {
return (
api.consts.session
? retrieveV2(api, stashId)
: retrieveV1(api, stashId)
).pipe(
map((result): DerivedStakingStash => parse(stashId, result)),
drr()
);
});
}, true);
@@ -0,0 +1,43 @@
// 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, EraPoints } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DerivedStakingOverview } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Vec } from '@polkadot/types';
import { drr, memo } from '../util';
import { indexes as sessionIndexes } from '../session';
/**
* @description Retrieve the staking overview, including elected and points earned
*/
export const overview = memo((api: ApiInterfaceRx): () => Observable<DerivedStakingOverview> => {
const sessionIndexesCall = sessionIndexes(api);
return memo((): Observable<DerivedStakingOverview> =>
combineLatest([
sessionIndexesCall(),
api.queryMulti<[Vec<AccountId>, Vec<AccountId>]>([
api.query.session.validators,
api.query.staking.currentElected
])
]).pipe(
switchMap(([{ currentEra, currentIndex, validatorCount }, [validators, currentElected]]) =>
combineLatest([
of({ currentElected, currentEra, currentIndex, validators, validatorCount }),
// this will change on a per block basis, keep it innermost (and it needs eraIndex)
api.query.staking.currentEraPointsEarned<EraPoints>(currentEra)
])
),
map(([{ currentElected, currentEra, currentIndex, validators, validatorCount }, eraPoints]): DerivedStakingOverview => ({
currentElected, currentEra, currentIndex, eraPoints, validators, validatorCount
})),
drr()
)
);
}, true);
@@ -11,7 +11,7 @@ import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DerivedRecentlyOffline } from '../types';
import { drr } from '../util';
import { drr, memo } from '../util';
type OfflineResult = [AccountId, BlockNumber, BN][] & Codec;
@@ -35,8 +35,8 @@ function expandDerived (recentlyOffline: OfflineResult): DerivedRecentlyOffline
/**
* @description Retrieve a keyed record of accounts recently reported to be offline
*/
export function recentlyOffline (api: ApiInterfaceRx): () => Observable<DerivedRecentlyOffline> {
return (): Observable<DerivedRecentlyOffline> =>
export const recentlyOffline = memo((api: ApiInterfaceRx): () => Observable<DerivedRecentlyOffline> => {
return memo((): Observable<DerivedRecentlyOffline> =>
(
// TODO recentlyOffline has been dropped for 2.x and replaced, figure out the
// replacement as actually use and implement it
@@ -46,5 +46,6 @@ export function recentlyOffline (api: ApiInterfaceRx): () => Observable<DerivedR
).pipe(
map(expandDerived),
drr()
);
}
)
);
}, true);
@@ -0,0 +1,26 @@
// 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 } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { drr, memo } from '../util';
import { overview } from './overview';
/**
* @description Retrieve latest list of validators
*/
export const validators = memo((api: ApiInterfaceRx): () => Observable<AccountId[]> => {
const overviewCall = overview(api);
return memo((): Observable<AccountId[]> =>
overviewCall().pipe(
map(({ validators }): AccountId[] => validators),
drr()
)
);
}, true);
+23 -13
View File
@@ -2,7 +2,7 @@
// 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, Balance, BalanceLock, BlockNumber, EraIndex, Exposure, Index, RewardDestination, SessionIndex, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
import { AccountId, AccountIndex, Balance, BalanceLock, BlockNumber, EraIndex, EraPoints, Exposure, Index, Keys, RewardDestination, SessionIndex, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { u32 } from '@polkadot/types';
@@ -83,9 +83,13 @@ export interface DerivedReferendumVote {
vote: Vote;
}
export interface DerivedSessionInfo {
export interface DeriveSessionIndexes {
currentEra: EraIndex;
currentIndex: SessionIndex;
validatorCount: u32;
}
export interface DerivedSessionInfo extends DeriveSessionIndexes {
eraLength: BlockNumber;
eraProgress: BlockNumber;
isEpoch: boolean;
@@ -111,25 +115,31 @@ export interface DerivedStakingOnlineStatus {
}[];
}
export interface DerivedStaking extends DerivedStakingOnlineStatus {
accountId: AccountId;
export interface DerivedStakingStash {
controllerId?: AccountId;
// @deprecated Use nextSessionIds instead
nextSessionId?: AccountId;
nextSessionIds: AccountId[];
nominators?: AccountId[];
redeemable?: Balance;
rewardDestination?: RewardDestination;
// @deprecated Use sessionIds instead
sessionId?: AccountId;
sessionIds: AccountId[];
nextKeys?: Keys;
stakers?: Exposure;
stakingLedger?: StakingLedger;
stashId?: AccountId;
unlocking?: DerivedUnlocking[];
validatorPrefs?: ValidatorPrefs;
}
export interface DerivedStaking extends DerivedStakingOnlineStatus, DerivedStakingStash {
accountId: AccountId;
nextSessionIds: AccountId[];
redeemable?: Balance;
sessionIds: AccountId[];
stakingLedger?: StakingLedger;
unlocking?: DerivedUnlocking[];
}
export interface DerivedStakingOverview extends DeriveSessionIndexes {
currentElected: AccountId[];
eraPoints: EraPoints;
validators: AccountId[];
}
export type DerivedUnlocking = { remainingBlocks: BlockNumber; value: Balance };
export interface VoterPosition {
+1
View File
@@ -5,3 +5,4 @@
export { drr } from '@polkadot/rpc-core/rxjs';
export * from './approvalFlagsToBools';
export * from './memo';
+14
View File
@@ -0,0 +1,14 @@
// 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.v
import createMemo from 'memoizee';
export function memo <T extends Function> (fn: T, withoutJSON?: boolean): T {
return withoutJSON
? createMemo(fn)
: createMemo(fn, {
// eslint-disable-next-line @typescript-eslint/unbound-method
normalizer: JSON.stringify
});
}