diff --git a/packages/api-derive/src/balances/all.ts b/packages/api-derive/src/balances/all.ts index 77c2ad4623..e93477437f 100644 --- a/packages/api-derive/src/balances/all.ts +++ b/packages/api-derive/src/balances/all.ts @@ -16,9 +16,16 @@ import { memo } from '../util'; type ResultBalance = [VestingInfo | null, (BalanceLock | BalanceLockTo212)[]]; type Result = [DeriveBalancesAccount, BlockNumber, ResultBalance]; +interface AllLocked { + allLocked: boolean, + lockedBalance: Balance, + lockedBreakdown: (BalanceLock | BalanceLockTo212)[], + vestingLocked: Balance +} + const VESTING_ID = '0x76657374696e6720'; -function calcBalances (api: ApiInterfaceRx, [{ accountId, accountNonce, freeBalance, frozenFee, frozenMisc, reservedBalance, votingBalance }, bestNumber, [vesting, locks]]: Result): DeriveBalancesAll { +function calcLocked (api: ApiInterfaceRx, bestNumber: BlockNumber, locks: (BalanceLock | BalanceLockTo212)[]): AllLocked { let lockedBalance = api.registry.createType('Balance'); let lockedBreakdown: (BalanceLock | BalanceLockTo212)[] = []; let vestingLocked = api.registry.createType('Balance'); @@ -27,18 +34,22 @@ function calcBalances (api: ApiInterfaceRx, [{ accountId, accountNonce, freeBala if (Array.isArray(locks)) { // only get the locks that are valid until passed the current block lockedBreakdown = (locks as BalanceLockTo212[]).filter(({ until }): boolean => !until || (bestNumber && until.gt(bestNumber))); - - const notAll = lockedBreakdown.filter(({ amount }) => !amount.isMax()); - allLocked = lockedBreakdown.some(({ amount }) => amount.isMax()); vestingLocked = api.registry.createType('Balance', lockedBreakdown.filter(({ id }) => id.eq(VESTING_ID)).reduce((result: BN, { amount }) => result.iadd(amount), new BN(0))); // get the maximum of the locks according to https://github.com/paritytech/substrate/blob/master/srml/balances/src/lib.rs#L699 + const notAll = lockedBreakdown.filter(({ amount }) => !amount.isMax()); + if (notAll.length) { lockedBalance = api.registry.createType('Balance', bnMax(...notAll.map(({ amount }): Balance => amount))); } } + return { allLocked, lockedBalance, lockedBreakdown, vestingLocked }; +} + +function calcBalances (api: ApiInterfaceRx, [{ accountId, accountNonce, freeBalance, frozenFee, frozenMisc, reservedBalance, votingBalance }, bestNumber, [vesting, locks]]: Result): DeriveBalancesAll { + const { allLocked, lockedBalance, lockedBreakdown, vestingLocked } = calcLocked(api, bestNumber, locks); // Calculate the vesting balances, // - offset = balance locked at startingBlock // - perBlock is the unlock amount diff --git a/packages/api-derive/src/collective/proposals.ts b/packages/api-derive/src/collective/proposals.ts index beffea44e7..0dfe27baca 100644 --- a/packages/api-derive/src/collective/proposals.ts +++ b/packages/api-derive/src/collective/proposals.ts @@ -28,7 +28,7 @@ function parse (api: ApiInterfaceRx, [hashes, proposals, votes]: Result): Derive .filter((proposal): proposal is DeriveCollectiveProposal => !!proposal); } -function _proposalsFrom (instanceId: string, api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): (hashes: (Hash | Uint8Array | string)[]) => Observable { +function _proposalsFrom (instanceId: string, api: ApiInterfaceRx, section: 'council' | 'technicalCommittee' = 'council'): (hashes: (Hash | Uint8Array | string)[]) => Observable { return memo(instanceId, (hashes: (Hash | Uint8Array | string)[]): Observable => (isFunction(api.query[section]?.proposals) && hashes.length ? combineLatest([ @@ -43,7 +43,7 @@ function _proposalsFrom (instanceId: string, api: ApiInterfaceRx, section: 'coun ); } -export function proposals (instanceId: string, api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): () => Observable { +export function proposals (instanceId: string, api: ApiInterfaceRx, section: 'council' | 'technicalCommittee' = 'council'): () => Observable { const proposalsFrom = _proposalsFrom(instanceId, api, section); return memo(instanceId, (): Observable => @@ -55,7 +55,7 @@ export function proposals (instanceId: string, api: ApiInterfaceRx, section: 'co ); } -export function proposal (instanceId: string, api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): (hash: Hash | Uint8Array | string) => Observable { +export function proposal (instanceId: string, api: ApiInterfaceRx, section: 'council' | 'technicalCommittee' = 'council'): (hash: Hash | Uint8Array | string) => Observable { const proposalsFrom = _proposalsFrom(instanceId, api, section); return memo(instanceId, (hash: Hash | Uint8Array | string): Observable => diff --git a/packages/api-derive/src/council/proposals.ts b/packages/api-derive/src/council/proposals.ts index 4b45a074f9..a3a8f4e111 100644 --- a/packages/api-derive/src/council/proposals.ts +++ b/packages/api-derive/src/council/proposals.ts @@ -10,9 +10,9 @@ import { proposal as collectiveProposal, proposals as collectiveProposals } from import { memo } from '../util'; export function proposal (instanceId: string, api: ApiInterfaceRx): (hash: Hash | Uint8Array | string) => Observable { - return memo(instanceId, collectiveProposal(instanceId, api, 'council')); + return memo(instanceId, collectiveProposal(instanceId, api)); } export function proposals (instanceId: string, api: ApiInterfaceRx): () => Observable { - return memo(instanceId, collectiveProposals(instanceId, api, 'council')); + return memo(instanceId, collectiveProposals(instanceId, api)); } diff --git a/packages/api-derive/src/democracy/locks.ts b/packages/api-derive/src/democracy/locks.ts index 65dd36f59b..79dbcda7fa 100644 --- a/packages/api-derive/src/democracy/locks.ts +++ b/packages/api-derive/src/democracy/locks.ts @@ -1,7 +1,7 @@ // Copyright 2017-2020 @polkadot/api-derive authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { AccountId, ReferendumInfo, ReferendumInfoTo239, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces'; +import { AccountId, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, Vote, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { DeriveDemocracyLock } from '../types'; @@ -9,27 +9,26 @@ import BN from 'bn.js'; import { Observable, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import { Option } from '@polkadot/types'; -import { isUndefined } from '@polkadot/util'; +import { BN_ZERO, isUndefined } from '@polkadot/util'; import { memo } from '../util'; const LOCKUPS = [0, 1, 2, 4, 8, 16, 32]; -const ZERO = new BN(0); + +function parseEnd (api: ApiInterfaceRx, vote: Vote, { approved, end }: ReferendumInfoFinished): [BN, BN] { + return [ + end, + (approved.isTrue && vote.isAye) || (approved.isFalse && vote.isNay) + ? end.add(api.consts.democracy.enactmentPeriod.muln(LOCKUPS[vote.conviction.index])) + : BN_ZERO + ]; +} function parseLock (api: ApiInterfaceRx, [referendumId, accountVote]: VotingDirectVote, referendum: ReferendumInfo): DeriveDemocracyLock { const { balance, vote } = accountVote.asStandard; - let unlockAt = ZERO; - let referendumEnd = ZERO; - - if (referendum.isFinished) { - const { approved, end } = referendum.asFinished; - - referendumEnd = end; - - if ((approved.isTrue && vote.isAye) || (approved.isFalse && vote.isNay)) { - unlockAt = end.add(api.consts.democracy.enactmentPeriod.muln(LOCKUPS[vote.conviction.index])); - } - } + const [referendumEnd, unlockAt] = referendum.isFinished + ? parseEnd(api, vote, referendum.asFinished) + : [BN_ZERO, BN_ZERO]; return { balance, isDelegated: false, isFinished: referendum.isFinished, referendumEnd, referendumId, unlockAt, vote }; } diff --git a/packages/api-derive/src/democracy/referendumsInfo.ts b/packages/api-derive/src/democracy/referendumsInfo.ts index 702a041736..b1ab3a5e81 100644 --- a/packages/api-derive/src/democracy/referendumsInfo.ts +++ b/packages/api-derive/src/democracy/referendumsInfo.ts @@ -40,31 +40,35 @@ function votesPrev (api: ApiInterfaceRx, referendumId: BN): Observable voting.isDirect) + .map(([accountId, voting]): [AccountId, VotingDirectVote[]] => [ + accountId, + voting.asDirect.votes.filter(([idx]) => idx.eq(referendumId)) + ]) + .filter(([, directVotes]) => !!directVotes.length) + .reduce((result: DeriveReferendumVote[], [accountId, votes]) => + // FIXME We are ignoring split votes + votes.reduce((result: DeriveReferendumVote[], [, vote]): DeriveReferendumVote[] => { + if (vote.isStandard) { + result.push({ + accountId, + isDelegating: false, + ...vote.asStandard + }); + } + + return result; + }, result), [] + ); +} + function votesCurr (api: ApiInterfaceRx, referendumId: BN): Observable { return api.query.democracy.votingOf.entries().pipe( map((allVoting): DeriveReferendumVote[] => { const mapped = allVoting.map(([key, voting]): [AccountId, Voting] => [key.args[0] as AccountId, voting]); - const votes = mapped - .filter(([, voting]) => voting.isDirect) - .map(([accountId, voting]): [AccountId, VotingDirectVote[]] => [ - accountId, - voting.asDirect.votes.filter(([idx]) => idx.eq(referendumId)) - ]) - .filter(([, directVotes]) => !!directVotes.length) - .reduce((result: DeriveReferendumVote[], [accountId, votes]) => - // FIXME We are ignoring split votes - votes.reduce((result: DeriveReferendumVote[], [, vote]): DeriveReferendumVote[] => { - if (vote.isStandard) { - result.push({ - accountId, - isDelegating: false, - ...vote.asStandard - }); - } - - return result; - }, result), [] - ); + const votes = extractVotes(mapped, referendumId); const delegations = mapped .filter(([, voting]) => voting.isDelegating) .map(([accountId, voting]): [AccountId, VotingDelegating] => [accountId, voting.asDelegating]); diff --git a/packages/api-derive/src/democracy/util.ts b/packages/api-derive/src/democracy/util.ts index a0f6a0be93..b4922f0a14 100644 --- a/packages/api-derive/src/democracy/util.ts +++ b/packages/api-derive/src/democracy/util.ts @@ -58,16 +58,20 @@ export function compareRationals (n1: BN, d1: BN, n2: BN, d2: BN): boolean { } } -export function calcPassing (threshold: VoteThreshold, sqrtElectorate: BN, { votedAye, votedNay, votedTotal }: ApproxState): boolean { +function calcPassingOther (threshold: VoteThreshold, sqrtElectorate: BN, { votedAye, votedNay, votedTotal }: ApproxState): boolean { const sqrtVoters = bnSqrt(votedTotal); return sqrtVoters.isZero() ? false - : threshold.isSimplemajority - ? votedAye.gt(votedNay) - : threshold.isSupermajorityapproval - ? compareRationals(votedNay, sqrtVoters, votedAye, sqrtElectorate) - : compareRationals(votedNay, sqrtElectorate, votedAye, sqrtVoters); + : threshold.isSupermajorityapproval + ? compareRationals(votedNay, sqrtVoters, votedAye, sqrtElectorate) + : compareRationals(votedNay, sqrtElectorate, votedAye, sqrtVoters); +} + +export function calcPassing (threshold: VoteThreshold, sqrtElectorate: BN, state: ApproxState): boolean { + return threshold.isSimplemajority + ? state.votedAye.gt(state.votedNay) + : calcPassingOther(threshold, sqrtElectorate, state); } function calcVotesPrev (votesFor: DeriveReferendumVote[]): DeriveReferendumVoteState { diff --git a/packages/api-derive/src/parachains/info.ts b/packages/api-derive/src/parachains/info.ts index a6ba56d388..2c19c40ffc 100644 --- a/packages/api-derive/src/parachains/info.ts +++ b/packages/api-derive/src/parachains/info.ts @@ -10,6 +10,7 @@ import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { memo } from '../util'; +import { didUpdateToBool } from './util'; type Result = [ Active, @@ -23,7 +24,7 @@ type Result = [ ]; function parseActive (id: ParaId, active: Active): DeriveParachainActive | null { - const found = active.find(([paraId]): boolean => paraId === id); + const found = active.find(([paraId]) => paraId === id); if (found && found[1].isSome) { const [collatorId, retriable] = found[1].unwrap(); @@ -48,12 +49,11 @@ function parseActive (id: ParaId, active: Active): DeriveParachainActive | null } function parseCollators (id: ParaId, collatorQueue: SelectedThreads | RetryQueue): (CollatorId | null)[] { - return collatorQueue - .map((queue): CollatorId | null => { - const found = queue.find(([paraId]): boolean => paraId === id); + return collatorQueue.map((queue): CollatorId | null => { + const found = queue.find(([paraId]) => paraId === id); - return found ? found[1] : null; - }); + return found ? found[1] : null; + }); } function parse (id: ParaId, [active, retryQueue, selectedThreads, didUpdate, info, pendingSwap, heads, relayDispatchQueue]: Result): DeriveParachainFull | null { @@ -63,9 +63,7 @@ function parse (id: ParaId, [active, retryQueue, selectedThreads, didUpdate, inf return { active: parseActive(id, active), - didUpdate: didUpdate.isSome - ? !!didUpdate.unwrap().some((paraId): boolean => paraId.eq(id)) - : false, + didUpdate: didUpdateToBool(didUpdate, id), heads, id, info: { id, ...info.unwrap() } as DeriveParachainInfo, diff --git a/packages/api-derive/src/parachains/overview.ts b/packages/api-derive/src/parachains/overview.ts index 96c39e9ac3..5c7adbb015 100644 --- a/packages/api-derive/src/parachains/overview.ts +++ b/packages/api-derive/src/parachains/overview.ts @@ -10,6 +10,7 @@ import { map, switchMap } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { memo } from '../util'; +import { didUpdateToBool } from './util'; type Result = [ ParaId[], @@ -20,17 +21,13 @@ type Result = [ ]; function parse ([ids, didUpdate, infos, pendingSwaps, relayDispatchQueueSizes]: Result): DeriveParachain[] { - return ids.map((id, index): DeriveParachain => { - return { - didUpdate: didUpdate.isSome - ? !!didUpdate.unwrap().some((paraId): boolean => paraId.eq(id)) - : false, - id, - info: { id, ...infos[index].unwrapOr(null) } as DeriveParachainInfo, - pendingSwapId: pendingSwaps[index].unwrapOr(null), - relayDispatchQueueSize: relayDispatchQueueSizes[index][0].toNumber() - }; - }); + return ids.map((id, index): DeriveParachain => ({ + didUpdate: didUpdateToBool(didUpdate, id), + id, + info: { id, ...infos[index].unwrapOr(null) } as DeriveParachainInfo, + pendingSwapId: pendingSwaps[index].unwrapOr(null), + relayDispatchQueueSize: relayDispatchQueueSizes[index][0].toNumber() + })); } export function overview (instanceId: string, api: ApiInterfaceRx): () => Observable { @@ -46,9 +43,7 @@ export function overview (instanceId: string, api: ApiInterfaceRx): () => Observ api.query.parachains.relayDispatchQueueSize.multi(paraIds) ]) ), - map((result: Result): DeriveParachain[] => - parse(result) - ) + map(parse) ) : of([] as DeriveParachain[]) ); diff --git a/packages/api-derive/src/parachains/util.ts b/packages/api-derive/src/parachains/util.ts new file mode 100644 index 0000000000..107fe6041b --- /dev/null +++ b/packages/api-derive/src/parachains/util.ts @@ -0,0 +1,11 @@ +// Copyright 2017-2020 @polkadot/api-derive authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { ParaId } from '@polkadot/types/interfaces'; +import { DidUpdate } from './types'; + +export function didUpdateToBool (didUpdate: DidUpdate, id: ParaId): boolean { + return didUpdate.isSome + ? didUpdate.unwrap().some((paraId) => paraId.eq(id)) + : false; +} diff --git a/packages/api-derive/src/staking/erasPoints.ts b/packages/api-derive/src/staking/erasPoints.ts index 17b9325060..702e7639de 100644 --- a/packages/api-derive/src/staking/erasPoints.ts +++ b/packages/api-derive/src/staking/erasPoints.ts @@ -10,6 +10,7 @@ import { map, switchMap } from 'rxjs/operators'; import { BN_ZERO } from '@polkadot/util'; import { deriveCache, memo } from '../util'; +import { filterEras } from './util'; const CACHE_KEY = 'eraPoints'; @@ -42,7 +43,7 @@ export function _erasPoints (instanceId: string, api: ApiInterfaceRx): (eras: Er : eras .map((era) => deriveCache.get(`${CACHE_KEY}-${era.toString()}`)) .filter((value): value is DeriveEraPoints => !!value); - const remaining = eras.filter((era) => !cached.some((cached) => era.eq(cached.era))); + const remaining = filterEras(eras, cached); return !remaining.length ? of(cached) diff --git a/packages/api-derive/src/staking/erasRewards.ts b/packages/api-derive/src/staking/erasRewards.ts index 502bd8553e..e8fd783963 100644 --- a/packages/api-derive/src/staking/erasRewards.ts +++ b/packages/api-derive/src/staking/erasRewards.ts @@ -10,6 +10,7 @@ import { map, switchMap } from 'rxjs/operators'; import { Option } from '@polkadot/types'; import { deriveCache, memo } from '../util'; +import { filterEras } from './util'; const CACHE_KEY = 'eraRewards'; @@ -31,7 +32,7 @@ export function _erasRewards (instanceId: string, api: ApiInterfaceRx): (eras: E : eras .map((era) => deriveCache.get(`${CACHE_KEY}-${era.toString()}`)) .filter((value): value is DeriveEraRewards => !!value); - const remaining = eras.filter((era) => !cached.some((cached) => era.eq(cached.era))); + const remaining = filterEras(eras, cached); if (!remaining.length) { return of(cached); diff --git a/packages/api-derive/src/staking/stakerRewards.ts b/packages/api-derive/src/staking/stakerRewards.ts index 47e93f93f5..f02f853c99 100644 --- a/packages/api-derive/src/staking/stakerRewards.ts +++ b/packages/api-derive/src/staking/stakerRewards.ts @@ -12,6 +12,7 @@ import { Option } from '@polkadot/types'; import { isFunction } from '@polkadot/util'; import { memo } from '../util'; +import { DeriveStakingQuery } from './types'; type ErasResult = [{ unwrapOr: (value: BN) => BN }, DeriveEraPoints[], DeriveEraPrefs[], DeriveEraRewards[]]; @@ -99,24 +100,37 @@ function filterEras (eras: EraIndex[], stakingLedger: StakingLedger): EraIndex[] return eras.filter((era) => filterEra(era, stakingLedger)); } -function filterRewards (api: ApiInterfaceRx, eras: EraIndex[], migrateEra: BN, rewards: DeriveStakerReward[], stakingLedger: StakingLedger, withActive: boolean): Observable { - if (withActive) { - return of(rewards); - } +function removeClaimed (validators: string[], queryValidators: DeriveStakingQuery[], reward: DeriveStakerReward): void { + const rm: string[] = []; + Object.keys(reward.validators).forEach((validatorId): void => { + const index = validators.indexOf(validatorId); + + if (index !== -1) { + const valLedger = queryValidators[index].stakingLedger; + + if (valLedger?.claimedRewards.some((era) => reward.era.eq(era))) { + rm.push(validatorId); + } + } + }); + + rm.forEach((validatorId): void => { + delete reward.validators[validatorId]; + }); +} + +function filterRewards (api: ApiInterfaceRx, eras: EraIndex[], { migrateEra, rewards, stakingLedger }: { migrateEra: BN, rewards: DeriveStakerReward[]; stakingLedger: StakingLedger }): Observable { const validators = uniqValidators(rewards); + const filter = filterEras(eras, stakingLedger); return ( isFunction(api.tx.staking.payoutStakers) ? api.derive.staking.queryMulti(validators) : of([]) ).pipe( - map((queryValidators): DeriveStakerReward[] => { - const filter = withActive - ? eras - : filterEras(eras, stakingLedger); - - return rewards + map((queryValidators): DeriveStakerReward[] => + rewards .filter(({ isEmpty }) => !isEmpty) .filter((reward): boolean => { if (!filter.some((filter) => reward.era.eq(filter))) { @@ -128,32 +142,16 @@ function filterRewards (api: ApiInterfaceRx, eras: EraIndex[], migrateEra: BN, r reward.isStakerPayout = true; - const rm: string[] = []; - - Object.keys(reward.validators).forEach((validatorId): void => { - const index = validators.indexOf(validatorId); - - if (index !== -1) { - const valLedger = queryValidators[index].stakingLedger; - - if (valLedger?.claimedRewards.some((era) => reward.era.eq(era))) { - rm.push(validatorId); - } - } - }); - - rm.forEach((validatorId): void => { - delete reward.validators[validatorId]; - }); + removeClaimed(validators, queryValidators, reward); return true; }) .filter(({ validators }) => Object.keys(validators).length !== 0) .map((reward) => ({ ...reward, - nominators: reward.nominating.filter(({ validatorId }) => !!reward.validators[validatorId]) - })); - }) + nominators: reward.nominating.filter((n) => !!reward.validators[n.validatorId]) + })) + ) ); } @@ -178,13 +176,15 @@ export function _stakerRewards (instanceId: string, api: ApiInterfaceRx): (accou api.derive.staking._stakerRewardsEras(eras, withActive) ]).pipe( switchMap(([{ stakingLedger, stashId }, exposures, erasResult]): Observable => { - const migrateEra: BN = erasResult[0].unwrapOr(ZERO); - if (!stashId || !stakingLedger) { return of([]); } - return filterRewards(api, eras, migrateEra, parseRewards(api, stashId, erasResult, exposures), stakingLedger, withActive); + const rewards = parseRewards(api, stashId, erasResult, exposures); + + return withActive + ? of(rewards) + : filterRewards(api, eras, { migrateEra: erasResult[0].unwrapOr(ZERO), rewards, stakingLedger }); }) ) ); diff --git a/packages/api-derive/src/staking/util.ts b/packages/api-derive/src/staking/util.ts new file mode 100644 index 0000000000..69c38128df --- /dev/null +++ b/packages/api-derive/src/staking/util.ts @@ -0,0 +1,8 @@ +// Copyright 2017-2020 @polkadot/api-derive authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { EraIndex } from '@polkadot/types/interfaces'; + +export function filterEras (eras: EraIndex[], list: T[]): EraIndex[] { + return eras.filter((era) => !list.some((entry) => era.eq(entry.era))); +} diff --git a/packages/types/src/codec/BTreeMap.ts b/packages/types/src/codec/BTreeMap.ts index cf05e82379..4d259504da 100644 --- a/packages/types/src/codec/BTreeMap.ts +++ b/packages/types/src/codec/BTreeMap.ts @@ -9,7 +9,7 @@ export default class BTreeMap public static with (keyType: Constructor | keyof InterfaceTypes, valType: Constructor | keyof InterfaceTypes): Constructor> { return class extends BTreeMap { constructor (registry: Registry, value?: Uint8Array | string | Map) { - super(registry, 'BTreeMap', keyType, valType, value); + super(registry, keyType, valType, value, 'BTreeMap'); } }; } diff --git a/packages/types/src/codec/HashMap.ts b/packages/types/src/codec/HashMap.ts index 01620cfcd2..dc0c672e9e 100644 --- a/packages/types/src/codec/HashMap.ts +++ b/packages/types/src/codec/HashMap.ts @@ -9,7 +9,7 @@ export default class HashMap e public static with (keyType: Constructor | keyof InterfaceTypes, valType: Constructor | keyof InterfaceTypes): Constructor> { return class extends HashMap { constructor (registry: Registry, value?: Uint8Array | string | Map) { - super(registry, 'HashMap', keyType, valType, value); + super(registry, keyType, valType, value); } }; } diff --git a/packages/types/src/codec/Map.spec.ts b/packages/types/src/codec/Map.spec.ts index 32277424d2..9ae4afb98e 100644 --- a/packages/types/src/codec/Map.spec.ts +++ b/packages/types/src/codec/Map.spec.ts @@ -34,7 +34,7 @@ describe('CodecMap', (): void => { describe('decoding', (): void => { const testDecode = (type: string, input: any, output: string): void => it(`can decode from ${type}`, (): void => { - const s = new CodecMap(registry, 'HashMap', Text, U32, input); + const s = new CodecMap(registry, Text, U32, input); expect(s.toString()).toBe(output); }); @@ -51,7 +51,7 @@ describe('CodecMap', (): void => { describe('encoding', (): void => { const testEncode = (to: CodecTo, expected: any): void => it(`can encode ${to}`, (): void => { - const s = new CodecMap(registry, 'BTreeMap', Text, U32, mockU32TextMap); + const s = new CodecMap(registry, Text, U32, mockU32TextMap, 'BTreeMap'); expect(s[to]()).toEqual(expected); }); @@ -65,7 +65,7 @@ describe('CodecMap', (): void => { describe('encoding muple values', (): void => { const testEncode = (to: CodecTo, expected: any): void => it(`can encode ${to}`, (): void => { - const s = new CodecMap(registry, 'BTreeMap', Text, U32, mockU32U32Map); + const s = new CodecMap(registry, Text, U32, mockU32U32Map, 'BTreeMap'); expect(s[to]()).toEqual(expected); }); diff --git a/packages/types/src/codec/Map.ts b/packages/types/src/codec/Map.ts index 1492f8088a..8460d9baf7 100644 --- a/packages/types/src/codec/Map.ts +++ b/packages/types/src/codec/Map.ts @@ -99,7 +99,7 @@ export default class CodecMap readonly #type: string; - constructor (registry: Registry, type: 'BTreeMap' | 'HashMap', keyType: Constructor | keyof InterfaceTypes, valType: Constructor | keyof InterfaceTypes, rawValue?: Uint8Array | string | Map) { + constructor (registry: Registry, keyType: Constructor | keyof InterfaceTypes, valType: Constructor | keyof InterfaceTypes, rawValue: Uint8Array | string | Map | undefined, type: 'BTreeMap' | 'HashMap' = 'HashMap') { super(decodeMap(registry, keyType, valType, rawValue)); this.registry = registry; diff --git a/packages/types/src/generic/Vote.ts b/packages/types/src/generic/Vote.ts index 0c5683459e..234246b028 100644 --- a/packages/types/src/generic/Vote.ts +++ b/packages/types/src/generic/Vote.ts @@ -10,11 +10,13 @@ import { isBoolean, isNumber, isU8a, isUndefined } from '@polkadot/util'; import U8aFixed from '../codec/U8aFixed'; import Bool from '../primitive/Bool'; -// eslint-disable-next-line @typescript-eslint/ban-types -type InputTypes = boolean | number | Boolean | Uint8Array | { +interface VoteType { aye: boolean; conviction?: number | ArrayElementType; -}; +} + +// eslint-disable-next-line @typescript-eslint/ban-types +type InputTypes = boolean | number | Boolean | Uint8Array | VoteType; // For votes, the topmost bit indicated aye/nay, the lower bits indicate the conviction const AYE_BITS = 0b10000000; @@ -36,6 +38,14 @@ function decodeVoteU8a (value: Uint8Array): Uint8Array { : new Uint8Array([NAY_BITS]); } +/** @internal */ +function decodeVoteType (registry: Registry, value: VoteType): Uint8Array { + const vote = new Bool(registry, value.aye).isTrue ? AYE_BITS : NAY_BITS; + const conviction = registry.createType('Conviction', value.conviction || DEF_CONV); + + return new Uint8Array([vote | conviction.index]); +} + /** @internal */ function decodeVote (registry: Registry, value?: InputTypes): Uint8Array { if (isUndefined(value) || value instanceof Boolean || isBoolean(value)) { @@ -46,10 +56,7 @@ function decodeVote (registry: Registry, value?: InputTypes): Uint8Array { return decodeVoteU8a(value); } - const vote = new Bool(registry, value.aye).isTrue ? AYE_BITS : NAY_BITS; - const conviction = registry.createType('Conviction', value.conviction || DEF_CONV); - - return new Uint8Array([vote | conviction.index]); + return decodeVoteType(registry, value); } /**