diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb0d4b0d5..cf2348bf8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,14 @@ # 1.4.0-beta.x - **Breaking change** (TypeScript only) The `*.d.ts` files now contain TypeScript 3.8 features, `#private`, which is not usable in older versions +- **Breaking change** - `api.derive.staking.*` has updated result types and detects support for lazy payouts queries - Add `api.rpc.chain.subscribeAllHeads` (not just best) (Thanks to https://github.com/jak-pan) - Add `api.rpc.engine.*` for manual seal support - Add `api.injectMetadata(metadata)` to initialize API with a specific metadata version - The api now checks for runtime upgrades, augmenting the interfaces with new metadata when found +- Support types & interfaces required for lazy reaping, lazy payouts & offchain phragmen - Support JS `BigInt` inputs in any derived `UInt` and `Int` object, `api.tx.balances.transfer(..., 9876543210123456789n)` - Registry now exposes `.createType(, ...args)` as an additional helper (like the API) -- Support types & interfaces required for lazy reaping & offchain phragmen - Expand `.toHuman` on `ExtrinsicEra`, `SubmittableResult` & `Vote` - Move `DigestItem`, `Fixed64`, `H160`, `H256` & `H512` to interfaces in `@polkadot/types/interfaces` - Align construction of unknown types in `registry.get` consistently warn on detection, throw on use diff --git a/packages/api-derive/src/balances/fees.ts b/packages/api-derive/src/balances/fees.ts index c50ec55807..9af28f77c0 100644 --- a/packages/api-derive/src/balances/fees.ts +++ b/packages/api-derive/src/balances/fees.ts @@ -12,21 +12,6 @@ import { createType } from '@polkadot/types'; import { memo } from '../util'; -type Result = [Balance, Balance, Balance, Balance, Balance]; - -function query (api: ApiInterfaceRx): Observable { - return of([ - // deprecated - remove - (api.consts.balances.creationFee as Balance) || createType(api.registry, 'Balance'), - (api.consts.balances.transferFee as Balance) || createType(api.registry, 'Balance'), - - // current - api.consts.balances.existentialDeposit, - api.consts.transactionPayment.transactionBaseFee, - api.consts.transactionPayment.transactionByteFee - ]); -} - /** * @name fees * @returns An object containing the combined results of the storage queries for @@ -42,7 +27,16 @@ function query (api: ApiInterfaceRx): Observable { */ export function fees (api: ApiInterfaceRx): () => Observable { return memo((): Observable => - query(api).pipe( + of([ + // deprecated - remove + (api.consts.balances.creationFee as Balance) || createType(api.registry, 'Balance'), + (api.consts.balances.transferFee as Balance) || createType(api.registry, 'Balance'), + + // current + api.consts.balances.existentialDeposit, + api.consts.transactionPayment.transactionBaseFee, + api.consts.transactionPayment.transactionByteFee + ]).pipe( map(([creationFee, transferFee, existentialDeposit, transactionBaseFee, transactionByteFee]): DerivedFees => ({ creationFee, existentialDeposit, diff --git a/packages/api-derive/src/session/indexes.ts b/packages/api-derive/src/session/indexes.ts index dad7db65b7..1c1cecf19b 100644 --- a/packages/api-derive/src/session/indexes.ts +++ b/packages/api-derive/src/session/indexes.ts @@ -3,29 +3,83 @@ // 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 { EraIndex, MomentOf, SessionIndex } from '@polkadot/types/interfaces'; import { DeriveSessionIndexes } from '../types'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; -import { createType, u32 as U32 } from '@polkadot/types'; +import { createType, Option, u32 } from '@polkadot/types'; import { memo } from '../util'; +type Result = [EraIndex, Option, EraIndex, SessionIndex, u32]; + +// parse into Indexes +function parse ([activeEra, activeEraStart, currentEra, currentIndex, validatorCount]: Result): DeriveSessionIndexes { + return { + activeEra, + activeEraStart, + currentEra, + currentIndex, + validatorCount + }; +} + +// query for previous V2 +function queryNoActive (api: ApiInterfaceRx): Observable { + return api.queryMulti<[EraIndex, SessionIndex, u32]>([ + api.query.staking.currentEra, + api.query.session.currentIndex, + api.query.staking.validatorCount + ]).pipe( + map(([currentEra, currentIndex, validatorCount]): Result => [ + currentEra, + createType(api.registry, 'Option'), + currentEra, + currentIndex, + validatorCount + ]) + ); +} + +// query based on latest +function query (api: ApiInterfaceRx): Observable { + return api.queryMulti<[Option, Option, Option, SessionIndex, u32]>([ + api.query.staking.activeEra, + api.query.staking.activeEraStart, + api.query.staking.currentEra, + api.query.session.currentIndex, + api.query.staking.validatorCount + ]).pipe( + map(([activeEra, activeEraStart, currentEra, currentIndex, validatorCount]): Result => [ + activeEra.unwrapOr(createType(api.registry, 'EraIndex', 1)), + activeEraStart, + currentEra.unwrapOr(createType(api.registry, 'EraIndex', 1)), + currentIndex, + validatorCount + ]) + ); +} + +// empty set when none is available +function empty (api: ApiInterfaceRx): Observable { + return of([ + createType(api.registry, 'EraIndex', 1), + createType(api.registry, 'Option'), + createType(api.registry, 'EraIndex', 1), + createType(api.registry, 'SessionIndex', 1), + createType(api.registry, 'u32') + ]); +} + export function indexes (api: ApiInterfaceRx): () => Observable { return memo((): Observable => ( - // Some chains (eg. very limited node-template), does not have session api.query.session && api.query.staking - ? api.queryMulti<[SessionIndex, EraIndex, U32]>([ - api.query.session.currentIndex, - api.query.staking.currentEra, - api.query.staking.validatorCount - ]) - : of([createType(api.registry, 'SessionIndex', 1), createType(api.registry, 'EraIndex', 1), createType(api.registry, 'u32')]) - ).pipe( - map(([currentIndex, currentEra, validatorCount]): DeriveSessionIndexes => ({ - currentIndex, currentEra, validatorCount - })) - )); + ? api.query.staking.activeEra + ? query(api) + : queryNoActive(api) + : empty(api) + ).pipe(map(parse)) + ); } diff --git a/packages/api-derive/src/session/info.ts b/packages/api-derive/src/session/info.ts index e4e6c951cc..2f26b2c41b 100644 --- a/packages/api-derive/src/session/info.ts +++ b/packages/api-derive/src/session/info.ts @@ -5,23 +5,26 @@ import { SessionIndex } from '@polkadot/types/interfaces'; import { DerivedSessionInfo, DeriveSessionIndexes } from '../types'; -import { Observable, combineLatest } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { Observable, combineLatest, of } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { u64, createType } from '@polkadot/types'; +import { createType, Option, u64 } from '@polkadot/types'; import { memo } from '../util'; -type ResultSlots = [u64, u64, u64, SessionIndex]; +type ResultSlots = [u64, u64, u64, Option]; +type ResultSlotsFlat = [u64, u64, u64, SessionIndex]; type ResultType = [boolean, u64, SessionIndex]; -type Result = [ResultType, DeriveSessionIndexes, ResultSlots]; +type Result = [ResultType, DeriveSessionIndexes, ResultSlotsFlat]; -function createDerivedLatest (api: ApiInterfaceRx, [[hasBabe, epochDuration, sessionsPerEra], { currentIndex, currentEra, validatorCount }, [currentSlot, epochIndex, epochOrGenesisStartSlot, currentEraStartSessionIndex]]: Result): DerivedSessionInfo { +function createDerived (api: ApiInterfaceRx, [[hasBabe, epochDuration, sessionsPerEra], { activeEra, activeEraStart, currentEra, currentIndex, validatorCount }, [currentSlot, epochIndex, epochOrGenesisStartSlot, activeEraStartSessionIndex]]: Result): DerivedSessionInfo { const epochStartSlot = epochIndex.mul(epochDuration).add(epochOrGenesisStartSlot); const sessionProgress = currentSlot.sub(epochStartSlot); - const eraProgress = currentIndex.sub(currentEraStartSessionIndex).mul(epochDuration).add(sessionProgress); + const eraProgress = currentIndex.sub(activeEraStartSessionIndex).mul(epochDuration).add(sessionProgress); return { + activeEra, + activeEraStart, currentEra, currentIndex, eraLength: createType(api.registry, 'BlockNumber', sessionsPerEra.mul(epochDuration)), @@ -34,46 +37,76 @@ function createDerivedLatest (api: ApiInterfaceRx, [[hasBabe, epochDuration, ses }; } -function infoLatestAura (api: ApiInterfaceRx): Observable { +function queryAura (api: ApiInterfaceRx): Observable { return api.derive.session.indexes().pipe( map((indexes): DerivedSessionInfo => - createDerivedLatest(api, [ - [false, createType(api.registry, 'u64', 1), api.consts.staking?.sessionsPerEra || createType(api.registry, 'SessionIndex', 1)], + createDerived(api, [ + [ + false, + createType(api.registry, 'u64', 1), + api.consts.staking?.sessionsPerEra || createType(api.registry, 'SessionIndex', 1) + ], indexes, - [createType(api.registry, 'u64', 1), createType(api.registry, 'u64', 1), createType(api.registry, 'u64', 1), createType(api.registry, 'SessionIndex', 1)] + [ + createType(api.registry, 'u64', 1), + createType(api.registry, 'u64', 1), + createType(api.registry, 'u64', 1), + createType(api.registry, 'SessionIndex', 1) + ] ]) ) ); } -function infoLatestBabe (api: ApiInterfaceRx): Observable { +function queryBabe (api: ApiInterfaceRx): Observable<[DeriveSessionIndexes, ResultSlotsFlat]> { + return api.derive.session.indexes().pipe( + switchMap((indexes): Observable<[DeriveSessionIndexes, ResultSlots]> => + combineLatest([ + of(indexes), + api.queryMulti([ + api.query.babe.currentSlot, + api.query.babe.epochIndex, + api.query.babe.genesisSlot, + [api.query.staking.erasStartSessionIndex, indexes.activeEra] + ]) + ]) + ), + map(([indexes, [currentSlot, epochIndex, genesisSlot, optStartIndex]]): [DeriveSessionIndexes, ResultSlotsFlat] => [ + indexes, [currentSlot, epochIndex, genesisSlot, optStartIndex.unwrapOr(createType(api.registry, 'SessionIndex', 1))] + ]) + ); +} + +function queryBabeNoHistory (api: ApiInterfaceRx): Observable<[DeriveSessionIndexes, ResultSlotsFlat]> { return combineLatest([ api.derive.session.indexes(), - api.queryMulti([ + api.queryMulti([ api.query.babe.currentSlot, api.query.babe.epochIndex, api.query.babe.genesisSlot, api.query.staking.currentEraStartSessionIndex ]) - ]).pipe( - map(([indexes, slots]: [DeriveSessionIndexes, ResultSlots]): DerivedSessionInfo => - createDerivedLatest(api, [ - [true, api.consts.babe.epochDuration, api.consts.staking.sessionsPerEra], - indexes, - slots - ]) - ) - ); + ]); } /** - * @description Retrieves all the session and era info and calculates specific values on it as the length of the session and eras + * @description Retrieves all the session and era query and calculates specific values on it as the length of the session and eras */ export function info (api: ApiInterfaceRx): () => Observable { - const query = api.consts.babe - ? infoLatestBabe // 2.x with Babe - : infoLatestAura; // 2.x with Aura (not all info there) - return memo((): Observable => - query(api)); + api.consts.babe + ? (api.query.staking.erasStartSessionIndex + ? queryBabe(api) // 2.x with Babe + : queryBabeNoHistory(api) + ).pipe( + map(([indexes, slots]: [DeriveSessionIndexes, ResultSlotsFlat]): DerivedSessionInfo => + createDerived(api, [ + [true, api.consts.babe.epochDuration, api.consts.staking.sessionsPerEra], + indexes, + slots + ]) + ) + ) + : queryAura(api) + ); } diff --git a/packages/api-derive/src/staking/electedInfo.ts b/packages/api-derive/src/staking/electedInfo.ts index 90a841f7af..5fcf92eb5a 100644 --- a/packages/api-derive/src/staking/electedInfo.ts +++ b/packages/api-derive/src/staking/electedInfo.ts @@ -14,16 +14,17 @@ import { memo } from '../util'; export function electedInfo (api: ApiInterfaceRx): () => Observable { return memo((): Observable => api.derive.staking.validators().pipe( - switchMap(({ currentElected }): Observable<[AccountId[], DerivedStakingQuery[]]> => + switchMap(({ nextElected }): Observable<[AccountId[], DerivedStakingQuery[]]> => combineLatest([ - of(currentElected), - combineLatest(currentElected.map((accountId): Observable => + of(nextElected), + combineLatest(nextElected.map((accountId): Observable => api.derive.staking.query(accountId) )) ]) ), - map(([currentElected, info]): DerivedStakingElected => ({ - currentElected, info + map(([nextElected, info]): DerivedStakingElected => ({ + info, + nextElected })) ) ); diff --git a/packages/api-derive/src/staking/overview.ts b/packages/api-derive/src/staking/overview.ts index a2174d65c9..777edbe2eb 100644 --- a/packages/api-derive/src/staking/overview.ts +++ b/packages/api-derive/src/staking/overview.ts @@ -2,15 +2,31 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { EraPoints } from '@polkadot/types/interfaces'; +import { AccountId, EraIndex, EraPoints, EraRewardPoints, RewardPoint } 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 { createType } from '@polkadot/types'; import { memo } from '../util'; +function retrievePointsPrev (api: ApiInterfaceRx, activeEra: EraIndex, currentElected: AccountId[]): Observable { + return api.query.staking.currentEraPointsEarned(activeEra).pipe( + map(({ individual, total }): EraRewardPoints => + createType(api.registry, 'EraRewardPoints', { + total, + individual: new Map( + individual + .map((points): RewardPoint => createType(api.registry, 'RewardPoint', points)) + .map((points, index): [AccountId, RewardPoint] => [currentElected[index], points]) + ) + }) + ) + ); +} + /** * @description Retrieve the staking overview, including elected and points earned */ @@ -20,14 +36,16 @@ export function overview (api: ApiInterfaceRx): () => Observable + switchMap(([indexes, { nextElected, validators }]) => combineLatest([ - of({ currentElected, currentEra, currentIndex, validators, validatorCount }), - api.query.staking.currentEraPointsEarned(currentEra) + of({ ...indexes, nextElected, validators }), + api.query.staking.erasRewardPoints + ? api.query.staking.erasRewardPoints(indexes.activeEra) + : retrievePointsPrev(api, indexes.activeEra, nextElected) ]) ), - map(([{ currentElected, currentEra, currentIndex, validators, validatorCount }, eraPoints]): DerivedStakingOverview => ({ - currentElected, currentEra, currentIndex, eraPoints, validators, validatorCount + map(([info, eraPoints]): DerivedStakingOverview => ({ + ...info, eraPoints })) )); } diff --git a/packages/api-derive/src/staking/query.ts b/packages/api-derive/src/staking/query.ts index fed726e312..fd49c5d14a 100644 --- a/packages/api-derive/src/staking/query.ts +++ b/packages/api-derive/src/staking/query.ts @@ -3,7 +3,7 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { ApiInterfaceRx } from '@polkadot/api/types'; -import { AccountId, Exposure, Keys, Nominations, RewardDestination, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces'; +import { AccountId, Exposure, Keys, Nominations, RewardDestination, ValidatorPrefs } from '@polkadot/types/interfaces'; import { ITuple } from '@polkadot/types/types'; import { DerivedStakingQuery } from '../types'; @@ -13,7 +13,7 @@ import { createType, Option, Vec } from '@polkadot/types'; import { memo } from '../util'; -type MultiResultV2 = [Option, Option>, RewardDestination, Exposure, [ValidatorPrefs], Option, Option]; +type MultiResult = [Option, Option>, RewardDestination, ITuple<[ValidatorPrefs]>, Option, Exposure]; function unwrapSessionIds (stashId: AccountId, queuedKeys: [AccountId, Keys][], nextKeys: Option): { nextSessionIds: AccountId[]; sessionIds: AccountId[] } { const sessionIds = (queuedKeys.find(([currentId]): boolean => @@ -27,20 +27,52 @@ function unwrapSessionIds (stashId: AccountId, queuedKeys: [AccountId, Keys][], }; } -function retrieve (api: ApiInterfaceRx, stashId: AccountId): Observable<[Vec>, MultiResultV2]> { - return combineLatest([ - api.query.session.queuedKeys>>(), - api.queryMulti([ - [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]] - ]) as Observable +function retrievePrev (api: ApiInterfaceRx, stashId: AccountId): Observable { + return api.queryMulti([ + [api.query.staking.bonded, stashId], + [api.query.staking.nominators, stashId], + [api.query.staking.payee, stashId], + [api.query.staking.validators, stashId], + [api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]], + [api.query.staking.stakers, stashId] ]); } +function retrieveCurr (api: ApiInterfaceRx, stashId: AccountId): Observable { + return api.derive.session.indexes().pipe( + switchMap(({ activeEra }) => + api.queryMulti([ + [api.query.staking.bonded, stashId], + [api.query.staking.nominators, stashId], + [api.query.staking.payee, stashId], + [api.query.staking.validators, stashId], + [api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]], + [api.query.staking.erasStakers, [activeEra, stashId]] + ]) + ) + ); +} + +function retrieveController (api: ApiInterfaceRx, stashId: AccountId, [queuedKeys, [controllerIdOpt, nominatorsOpt, rewardDestination, [validatorPrefs], nextKeys, exposure]]: [Vec>, MultiResult]): Observable { + const controllerId = controllerIdOpt.unwrapOr(null); + + return controllerId + ? api.query.staking.ledger(controllerId).pipe( + map((stakingLedgerOpt): DerivedStakingQuery => ({ + accountId: stashId, + controllerId, + exposure, + nominators: nominatorsOpt.unwrapOr([{ targets: [] }])[0].targets, + rewardDestination, + stakingLedger: stakingLedgerOpt.unwrapOr(undefined), + stashId, + validatorPrefs, + ...unwrapSessionIds(stashId, queuedKeys, nextKeys) + })) + ) + : of({ accountId: stashId, nextSessionIds: [], sessionIds: [] }); +} + /** * @description From a stash, retrieve the controllerId and all relevant details */ @@ -48,26 +80,15 @@ export function query (api: ApiInterfaceRx): (accountId: Uint8Array | string) => return memo((accountId: Uint8Array | string): Observable => { const stashId = createType(api.registry, 'AccountId', accountId); - return retrieve(api, stashId).pipe( - switchMap(([queuedKeys, [controllerIdOpt, nominatorsOpt, rewardDestination, stakers, [validatorPrefs], nextKeys]]): Observable => { - const controllerId = controllerIdOpt.unwrapOr(null); - - return controllerId - ? api.query.staking.ledger(controllerId).pipe( - map((stakingLedgerOpt): DerivedStakingQuery => ({ - accountId: stashId, - controllerId, - nominators: nominatorsOpt.unwrapOr([{ targets: [] }])[0].targets, - rewardDestination, - stakers, - stakingLedger: stakingLedgerOpt.unwrapOr(undefined), - stashId, - validatorPrefs, - ...unwrapSessionIds(stashId, queuedKeys, nextKeys) - })) - ) - : of({ accountId: stashId, nextSessionIds: [], sessionIds: [] }); - }) + return combineLatest([ + api.query.session.queuedKeys>>(), + api.query.staking.erasStakers + ? retrieveCurr(api, stashId) + : retrievePrev(api, stashId) + ]).pipe( + switchMap((result): Observable => + retrieveController(api, stashId, result) + ) ); }); } diff --git a/packages/api-derive/src/staking/validators.ts b/packages/api-derive/src/staking/validators.ts index 8680da8ea3..13340d5ee2 100644 --- a/packages/api-derive/src/staking/validators.ts +++ b/packages/api-derive/src/staking/validators.ts @@ -22,12 +22,16 @@ export function validators (api: ApiInterfaceRx): () => Observable ({ - currentElected, validators + map(([validators, nextElected]): DeriveStakingValidators => ({ + nextElected: nextElected || validators, + validators })) )); } diff --git a/packages/api-derive/src/types.ts b/packages/api-derive/src/types.ts index 8cc84a6c9c..59173e7f05 100644 --- a/packages/api-derive/src/types.ts +++ b/packages/api-derive/src/types.ts @@ -2,10 +2,10 @@ // 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, BalanceLockTo212, BalanceOf, Bid, BidKind, BlockNumber, CollatorId, EraIndex, EraPoints, Exposure, Hash, Index, Keys, ParaId, ParaInfo, Proposal, PropIndex, ProposalIndex, ReferendumInfo, RegistrationJudgement, RewardDestination, SessionIndex, SetIndex, SocietyVote, StakingLedger, StrikeCount, TreasuryProposal, UpwardMessage, ValidatorPrefs, Vote, Votes, VoteIndex, VouchingStatus } from '@polkadot/types/interfaces'; +import { AccountId, AccountIndex, Balance, BalanceLock, BalanceLockTo212, BalanceOf, Bid, BidKind, BlockNumber, CollatorId, EraIndex, EraRewardPoints, Exposure, Hash, Index, Keys, MomentOf, ParaId, ParaInfo, Proposal, PropIndex, ProposalIndex, ReferendumInfo, RegistrationJudgement, RewardDestination, SessionIndex, SetIndex, SocietyVote, StakingLedger, StrikeCount, TreasuryProposal, UpwardMessage, ValidatorPrefs, Vote, Votes, VoteIndex, VouchingStatus } from '@polkadot/types/interfaces'; import BN from 'bn.js'; -import { Bytes, u32, Vec } from '@polkadot/types'; +import { Bytes, Option, u32, Vec } from '@polkadot/types'; export type AccountIndexes = Record; @@ -159,6 +159,8 @@ export interface DerivedReferendumVote { } export interface DeriveSessionIndexes { + activeEra: EraIndex; + activeEraStart: Option; currentEra: EraIndex; currentIndex: SessionIndex; validatorCount: u32; @@ -200,22 +202,22 @@ export interface DeriveSocietyMember { } export interface DerivedStakingElected { - currentElected: AccountId[]; + nextElected: AccountId[]; info: DerivedStakingQuery[]; } export interface DeriveStakingValidators { - currentElected: AccountId[]; + nextElected: AccountId[]; validators: AccountId[]; } export interface DerivedStakingStash { controllerId?: AccountId; + exposure?: Exposure; nominators?: AccountId[]; nominateAt?: EraIndex; rewardDestination?: RewardDestination; nextKeys?: Keys; - stakers?: Exposure; stashId?: AccountId; validatorPrefs?: ValidatorPrefs; } @@ -233,8 +235,8 @@ export interface DerivedStakingAccount extends DerivedStakingQuery { } export interface DerivedStakingOverview extends DeriveSessionIndexes { - currentElected: AccountId[]; - eraPoints: EraPoints; + eraPoints: EraRewardPoints; + nextElected: AccountId[]; validators: AccountId[]; } diff --git a/packages/types/src/augment/registry.ts b/packages/types/src/augment/registry.ts index b990c5f2cb..6197128712 100644 --- a/packages/types/src/augment/registry.ts +++ b/packages/types/src/augment/registry.ts @@ -30,7 +30,7 @@ import { ApiId, BlockHash, ChainProperties, ExtrinsicOrHash, ExtrinsicStatus, He import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, ChangesTrieConfiguration, Consensus, ConsensusEngineId, Digest, DigestItem, DispatchClass, DispatchInfo, DispatchInfoTo190, Fixed64, H160, H256, H512, Hash, Header, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, Moment, Origin, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Seal, SealV0, SignedBlock, StorageData, ValidatorId, Weight, WeightMultiplier } from '@polkadot/types/interfaces/runtime'; import { FullIdentification, IdentificationTuple, Keys, SessionIndex, SessionKeys1, SessionKeys2, SessionKeys3, SessionKeys4, SessionKeys5, SessionKeys6 } from '@polkadot/types/interfaces/session'; import { Bid, BidKind, BidKindVouch, SocietyJudgement, SocietyVote, StrikeCount, VouchingStatus } from '@polkadot/types/interfaces/society'; -import { CompactAssignments, CompactScore, ElectionCompute, ElectionResult, ElectionStatus, EraIndex, EraPoints, EraRewards, Exposure, Forcing, IndividualExposure, KeyType, MomentOf, Nominations, PhragmenScore, Points, RewardDestination, SlashJournalEntry, SlashingSpans, SlashingSpansTo204, SpanIndex, SpanRecord, StakingLedger, UnappliedSlash, UnappliedSlashOther, UnlockChunk, ValidatorIndex, ValidatorPrefs, ValidatorPrefsTo145, ValidatorPrefsTo196 } from '@polkadot/types/interfaces/staking'; +import { CompactAssignments, CompactScore, ElectionCompute, ElectionResult, ElectionStatus, EraIndex, EraPoints, EraRewardPoints, EraRewards, Exposure, Forcing, IndividualExposure, KeyType, MomentOf, Nominations, PhragmenScore, Points, RewardDestination, RewardPoint, SlashJournalEntry, SlashingSpans, SlashingSpansTo204, SpanIndex, SpanRecord, StakingLedger, StakingLedgerNew, StakingLedgerTo223, UnappliedSlash, UnappliedSlashOther, UnlockChunk, ValidatorIndex, ValidatorPrefs, ValidatorPrefsTo145, ValidatorPrefsTo196 } from '@polkadot/types/interfaces/staking'; import { AccountInfo, DigestOf, DispatchError, DispatchErrorModule, DispatchErrorTo198, DispatchResult, DispatchResultOf, DispatchResultTo198, Event, EventId, EventIndex, EventRecord, EventRecordTo76, Key, Phase, RefCount } from '@polkadot/types/interfaces/system'; import { OpenTip, OpenTipFinder, OpenTipTip, TreasuryProposal } from '@polkadot/types/interfaces/treasury'; import { Multiplier } from '@polkadot/types/interfaces/txpayment'; @@ -726,6 +726,13 @@ declare module '@polkadot/types/types/registry' { VouchingStatus: VouchingStatus; 'Option': Option; 'Vec': Vec; + Points: Points; + 'Compact': Compact; + 'Option': Option; + 'Vec': Vec; + EraPoints: EraPoints; + 'Option': Option; + 'Vec': Vec; CompactAssignments: CompactAssignments; 'Option': Option; 'Vec': Vec; @@ -745,9 +752,9 @@ declare module '@polkadot/types/types/registry' { 'Compact': Compact; 'Option': Option; 'Vec': Vec; - EraPoints: EraPoints; - 'Option': Option; - 'Vec': Vec; + EraRewardPoints: EraRewardPoints; + 'Option': Option; + 'Vec': Vec; EraRewards: EraRewards; 'Option': Option; 'Vec': Vec; @@ -772,13 +779,13 @@ declare module '@polkadot/types/types/registry' { PhragmenScore: PhragmenScore; 'Option': Option; 'Vec': Vec; - Points: Points; - 'Compact': Compact; - 'Option': Option; - 'Vec': Vec; RewardDestination: RewardDestination; 'Option': Option; 'Vec': Vec; + RewardPoint: RewardPoint; + 'Compact': Compact; + 'Option': Option; + 'Vec': Vec; SlashJournalEntry: SlashJournalEntry; 'Option': Option; 'Vec': Vec; @@ -795,6 +802,12 @@ declare module '@polkadot/types/types/registry' { SpanRecord: SpanRecord; 'Option': Option; 'Vec': Vec; + StakingLedgerTo223: StakingLedgerTo223; + 'Option': Option; + 'Vec': Vec; + StakingLedgerNew: StakingLedgerNew; + 'Option': Option; + 'Vec': Vec; StakingLedger: StakingLedger; 'Option': Option; 'Vec': Vec; diff --git a/packages/types/src/codec/BTreeMap.ts b/packages/types/src/codec/BTreeMap.ts index 5995451cf1..177dd16857 100644 --- a/packages/types/src/codec/BTreeMap.ts +++ b/packages/types/src/codec/BTreeMap.ts @@ -12,92 +12,92 @@ import Compact from './Compact'; import Raw from './Raw'; import { compareMap, decodeU8a, typeToConstructor } from './utils'; +/** @internal */ +function decodeBTreeMapFromU8a (registry: Registry, KeyClass: Constructor, ValClass: Constructor, u8a: Uint8Array): Map { + const output = new Map(); + const [offset, length] = Compact.decodeU8a(u8a); + const types = []; + + for (let i = 0; i < length.toNumber(); i++) { + types.push(KeyClass, ValClass); + } + + const values = decodeU8a(registry, u8a.subarray(offset), types); + + for (let i = 0; i < values.length; i += 2) { + output.set(values[i] as K, values[i + 1] as V); + } + + return output; +} + +/** @internal */ +function decodeBTreeMapFromMap (registry: Registry, KeyClass: Constructor, ValClass: Constructor, value: Map): Map { + const output = new Map(); + + value.forEach((v: any, k: any) => { + let key, val; + try { + key = (k instanceof KeyClass) ? k : new KeyClass(registry, k); + val = (v instanceof ValClass) ? v : new ValClass(registry, v); + } catch (error) { + console.error('Failed to decode BTreeMap key or value:', error.message); + throw error; + } + + output.set(key, val); + }); + + return output; +} + +/** + * Decode input to pass into constructor. + * + * @param KeyClass - Type of the map key + * @param ValClass - Type of the map value + * @param value - Value to decode, one of: + * - null + * - undefined + * - hex + * - Uint8Array + * - Map, where both key and value types are either + * constructors or decodeable values for their types. + * @param jsonMap + * @internal + */ +function decodeBTreeMap (registry: Registry, KeyClass: Constructor, ValClass: Constructor, value: Uint8Array | string | Map): Map { + if (!value) { + return new Map(); + } else if (isHex(value)) { + return decodeBTreeMap(registry, KeyClass, ValClass, hexToU8a(value)); + } else if (isU8a(value)) { + return decodeBTreeMapFromU8a(registry, KeyClass, ValClass, u8aToU8a(value)); + } else if (value instanceof Map) { + return decodeBTreeMapFromMap(registry, KeyClass, ValClass, value); + } + + throw new Error('BTreeMap: cannot decode type'); +} + export default class BTreeMap extends Map implements Codec { public readonly registry: Registry; - private readonly _KeyClass: Constructor; + protected _KeyClass: Constructor; - private readonly _ValClass: Constructor; + protected _ValClass: Constructor; constructor (registry: Registry, keyType: Constructor | keyof InterfaceTypes, valType: Constructor | keyof InterfaceTypes, rawValue: any) { const KeyClass = typeToConstructor(registry, keyType); const ValClass = typeToConstructor(registry, valType); - super(BTreeMap.decodeBTreeMap(registry, KeyClass, ValClass, rawValue)); + super(decodeBTreeMap(registry, KeyClass, ValClass, rawValue)); this.registry = registry; this._KeyClass = KeyClass; this._ValClass = ValClass; } - /** - * Decode input to pass into constructor. - * - * @param KeyClass - Type of the map key - * @param ValClass - Type of the map value - * @param value - Value to decode, one of: - * - null - * - undefined - * - hex - * - Uint8Array - * - Map, where both key and value types are either - * constructors or decodeable values for their types. - * @param jsonMap - * @internal - */ - private static decodeBTreeMap (registry: Registry, KeyClass: Constructor, ValClass: Constructor, value: Uint8Array | string | Map): Map { - if (!value) { - return new Map(); - } else if (isHex(value)) { - return BTreeMap.decodeBTreeMap(registry, KeyClass, ValClass, hexToU8a(value)); - } else if (isU8a(value)) { - return BTreeMap.decodeBTreeMapFromU8a(registry, KeyClass, ValClass, u8aToU8a(value)); - } else if (value instanceof Map) { - return BTreeMap.decodeBTreeMapFromMap(registry, KeyClass, ValClass, value); - } - - throw new Error('BTreeMap: cannot decode type'); - } - - /** @internal */ - private static decodeBTreeMapFromU8a (registry: Registry, KeyClass: Constructor, ValClass: Constructor, u8a: Uint8Array): Map { - const output = new Map(); - const [offset, length] = Compact.decodeU8a(u8a); - const types = []; - - for (let i = 0; i < length.toNumber(); i++) { - types.push(KeyClass, ValClass); - } - - const values = decodeU8a(registry, u8a.subarray(offset), types); - - for (let i = 0; i < values.length; i += 2) { - output.set(values[i] as K, values[i + 1] as V); - } - - return output; - } - - /** @internal */ - private static decodeBTreeMapFromMap (registry: Registry, KeyClass: Constructor, ValClass: Constructor, value: Map): Map { - const output = new Map(); - - value.forEach((v: any, k: any) => { - let key, val; - try { - key = (k instanceof KeyClass) ? k : new KeyClass(registry, k); - val = (v instanceof ValClass) ? v : new ValClass(registry, v); - } catch (error) { - console.error('Failed to decode BTreeMap key or value:', error.message); - throw error; - } - - output.set(key, val); - }); - - return output; - } - public static with (keyType: Constructor | keyof InterfaceTypes, valType: Constructor | keyof InterfaceTypes): Constructor> { return class extends BTreeMap { constructor (registry: Registry, value?: any) { diff --git a/packages/types/src/interfaces/staking/definitions.ts b/packages/types/src/interfaces/staking/definitions.ts index f2560d1d53..07390885c2 100644 --- a/packages/types/src/interfaces/staking/definitions.ts +++ b/packages/types/src/interfaces/staking/definitions.ts @@ -2,8 +2,17 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +const deprecated = { + Points: 'u32', + EraPoints: { + total: 'Points', + individual: 'Vec' + } +}; + export default { types: { + ...deprecated, CompactAssignments: { votes1: 'Vec<(AccountId, [CompactScore; 0], AccountId)>', votes2: 'Vec<(AccountId, [CompactScore; 1], AccountId)>', @@ -39,9 +48,9 @@ export default { } }, EraIndex: 'u32', - EraPoints: { - total: 'Points', - individual: 'Vec' + EraRewardPoints: { + total: 'RewardPoint', + individual: 'BTreeMap' }, EraRewards: { total: 'u32', @@ -80,6 +89,7 @@ export default { 'Controller' ] }, + RewardPoint: 'u32', SlashJournalEntry: { who: 'AccountId', amount: 'Balance', @@ -101,12 +111,21 @@ export default { slashed: 'Balance', paidOut: 'Balance' }, - StakingLedger: { + StakingLedgerTo223: { stash: 'AccountId', total: 'Compact', active: 'Compact', unlocking: 'Vec' }, + // TODO Enable as default when new staking payouts go live + StakingLedgerNew: { + stash: 'AccountId', + total: 'Compact', + active: 'Compact', + unlocking: 'Vec', + nextReward: 'EraIndex' + }, + StakingLedger: 'StakingLedgerTo223', UnappliedSlashOther: '(AccountId, Balance)', UnappliedSlash: { validator: 'AccountId', diff --git a/packages/types/src/interfaces/staking/types.ts b/packages/types/src/interfaces/staking/types.ts index 7977b9878d..b307cc67a3 100644 --- a/packages/types/src/interfaces/staking/types.ts +++ b/packages/types/src/interfaces/staking/types.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-empty-interface */ import { ITuple } from '@polkadot/types/types'; -import { Compact, Enum, Struct, Vec } from '@polkadot/types/codec'; +import { BTreeMap, Compact, Enum, Struct, Vec } from '@polkadot/types/codec'; import { bool, u128, u16, u32 } from '@polkadot/types/primitive'; import { AccountId, Balance, BlockNumber, Moment, Perbill } from '@polkadot/types/interfaces/runtime'; @@ -60,6 +60,12 @@ export interface EraPoints extends Struct { readonly individual: Vec; } +/** @name EraRewardPoints */ +export interface EraRewardPoints extends Struct { + readonly total: RewardPoint; + readonly individual: BTreeMap; +} + /** @name EraRewards */ export interface EraRewards extends Struct { readonly total: u32; @@ -113,6 +119,9 @@ export interface RewardDestination extends Enum { readonly isController: boolean; } +/** @name RewardPoint */ +export interface RewardPoint extends u32 {} + /** @name SlashingSpans */ export interface SlashingSpans extends Struct { readonly spanIndex: SpanIndex; @@ -145,7 +154,19 @@ export interface SpanRecord extends Struct { } /** @name StakingLedger */ -export interface StakingLedger extends Struct { +export interface StakingLedger extends StakingLedgerTo223 {} + +/** @name StakingLedgerNew */ +export interface StakingLedgerNew extends Struct { + readonly stash: AccountId; + readonly total: Compact; + readonly active: Compact; + readonly unlocking: Vec; + readonly nextReward: EraIndex; +} + +/** @name StakingLedgerTo223 */ +export interface StakingLedgerTo223 extends Struct { readonly stash: AccountId; readonly total: Compact; readonly active: Compact; diff --git a/packages/types/src/known/overrides.ts b/packages/types/src/known/overrides.ts index 973fa70196..cc26ce20df 100644 --- a/packages/types/src/known/overrides.ts +++ b/packages/types/src/known/overrides.ts @@ -43,7 +43,8 @@ const TYPES_POLKADOT_VERSIONED: OverrideVersionedType[] = [ types: { Address: 'GenericAddress', BalanceLock: 'BalanceLockTo212', - Keys: 'SessionKeys5' + Keys: 'SessionKeys5', + StakingLedger: 'StakingLedgerTo223' } }, { @@ -51,7 +52,8 @@ const TYPES_POLKADOT_VERSIONED: OverrideVersionedType[] = [ types: { // Indices optional, not in transaction Address: 'AccountId', - Keys: 'SessionKeys5' + Keys: 'SessionKeys5', + StakingLedger: 'StakingLedgerTo223' } } ]; @@ -64,7 +66,8 @@ const TYPES_KUSAMA_VERSIONED: OverrideVersionedType[] = [ BalanceLock: 'BalanceLockTo212', DispatchError: 'DispatchErrorTo198', Keys: 'SessionKeys5', - SlashingSpans: 'SlashingSpansTo204' + SlashingSpans: 'SlashingSpansTo204', + StakingLedger: 'StakingLedgerTo223' } }, { @@ -73,7 +76,8 @@ const TYPES_KUSAMA_VERSIONED: OverrideVersionedType[] = [ Address: 'GenericAddress', BalanceLock: 'BalanceLockTo212', Keys: 'SessionKeys5', - SlashingSpans: 'SlashingSpansTo204' + SlashingSpans: 'SlashingSpansTo204', + StakingLedger: 'StakingLedgerTo223' } }, { @@ -81,7 +85,8 @@ const TYPES_KUSAMA_VERSIONED: OverrideVersionedType[] = [ types: { Address: 'GenericAddress', BalanceLock: 'BalanceLockTo212', - Keys: 'SessionKeys5' + Keys: 'SessionKeys5', + StakingLedger: 'StakingLedgerTo223' } }, { @@ -89,7 +94,8 @@ const TYPES_KUSAMA_VERSIONED: OverrideVersionedType[] = [ types: { // Indices optional, not in transaction Address: 'AccountId', - Keys: 'SessionKeys5' + Keys: 'SessionKeys5', + StakingLedger: 'StakingLedgerTo223' } } ]; @@ -110,7 +116,8 @@ const TYPES_META: OverrideVersionedType[] = [ BlockNumber: 'u64', Index: 'u64', EventRecord: 'EventRecordTo76', - ValidatorPrefs: 'ValidatorPrefsTo145' + ValidatorPrefs: 'ValidatorPrefsTo145', + StakingLedger: 'StakingLedgerTo223' } } ];