From d338fcb58cdebc7ce05abd9b34474e139eb7d236 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 30 Mar 2020 13:48:14 +0200 Subject: [PATCH] Add derive for council voting info (#2115) * Add derive for council voting info * Update packages/api-derive/src/council/votes.ts --- CHANGELOG.md | 1 + packages/api-derive/src/council/index.ts | 2 + packages/api-derive/src/council/types.ts | 12 +++ packages/api-derive/src/council/votes.ts | 88 ++++++++++++++++++++++ packages/api-derive/src/council/votesOf.ts | 23 ++++++ packages/api-derive/src/types.ts | 1 + 6 files changed, 127 insertions(+) create mode 100644 packages/api-derive/src/council/types.ts create mode 100644 packages/api-derive/src/council/votes.ts create mode 100644 packages/api-derive/src/council/votesOf.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 75d1cf048c..60ba815fd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Adjust `Error.message` on RPC failures to not include the (already known) method signature - Internal adjustment of interface types to align with modules (no external impact via `@polkadot/types/interfaces`) - Extended `api.derive.democracy` to cater for dispatchQueue and externals +- Extended `api.derive.council` to cater for new phragmen elections # 1.8.1 Mar 22, 2020 diff --git a/packages/api-derive/src/council/index.ts b/packages/api-derive/src/council/index.ts index 0282e981c8..942cbcd708 100644 --- a/packages/api-derive/src/council/index.ts +++ b/packages/api-derive/src/council/index.ts @@ -3,3 +3,5 @@ // of the Apache-2.0 license. See the LICENSE file for details. export * from './proposals'; +export * from './votes'; +export * from './votesOf'; diff --git a/packages/api-derive/src/council/types.ts b/packages/api-derive/src/council/types.ts new file mode 100644 index 0000000000..9c75cf03df --- /dev/null +++ b/packages/api-derive/src/council/types.ts @@ -0,0 +1,12 @@ +// Copyright 2017-2020 @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, Balance } from '@polkadot/types/interfaces'; + +export interface DeriveCouncilVote { + stake: Balance; + votes: AccountId[]; +} + +export type DeriveCouncilVotes = [AccountId, DeriveCouncilVote][]; diff --git a/packages/api-derive/src/council/votes.ts b/packages/api-derive/src/council/votes.ts new file mode 100644 index 0000000000..c28b170d24 --- /dev/null +++ b/packages/api-derive/src/council/votes.ts @@ -0,0 +1,88 @@ +// Copyright 2017-2020 @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, Balance } from '@polkadot/types/interfaces'; +import { ITuple } from '@polkadot/types/types'; +import { ApiInterfaceRx } from '@polkadot/api/types'; +import { DeriveCouncilVote, DeriveCouncilVotes } from '../types'; + +import { Observable, combineLatest } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { Vec } from '@polkadot/types'; + +function retrieveStakeOf (api: ApiInterfaceRx): Observable<[AccountId, Balance][]> { + const elections = (api.query.electionsPhragmen || api.query.elections); + + return elections.stakeOf.creator.meta.type.asMap.linked.isTrue + ? elections.stakeOf, Vec]>>().pipe( + map(([voters, stake]) => + voters.map((voter, index): [AccountId, Balance] => [voter, stake[index]]) + ) + ) + : elections.stakeOf.entries().pipe( + map((entries) => + entries.map(([key, stake]) => [key.args[0] as AccountId, stake]) + ) + ); +} + +function retrieveVoteOf (api: ApiInterfaceRx): Observable<[AccountId, AccountId[]][]> { + const elections = (api.query.electionsPhragmen || api.query.elections); + + return elections.votesOf.creator.meta.type.asMap.linked.isTrue + ? elections.votesOf, Vec>]>>().pipe( + map(([voters, votes]) => + voters.map((voter, index) => [voter, votes[index]]) + ) + ) + : elections.votesOf.entries>().pipe( + map((entries) => + entries.map(([key, votes]) => [key.args[0] as AccountId, votes]) + ) + ); +} + +function retrievePrev (api: ApiInterfaceRx): Observable { + return combineLatest([retrieveStakeOf(api), retrieveVoteOf(api)]).pipe( + map(([stakes, votes]): DeriveCouncilVotes => { + const result: DeriveCouncilVotes = []; + + votes.forEach(([voter, votes]): void => { + result.push([voter, { stake: api.registry.createType('Balance'), votes }]); + }); + + stakes.forEach(([staker, stake]): void => { + const entry = result.find(([voter]) => voter.eq(staker)); + + if (entry) { + entry[1].stake = stake; + } else { + result.push([staker, { stake, votes: [] }]); + } + }); + + return result; + }) + ); +} + +function retrieveCurrent (api: ApiInterfaceRx): Observable { + const elections = (api.query.electionsPhragmen || api.query.elections); + + return elections.voting.entries]>>().pipe( + map((entries): DeriveCouncilVotes => + entries.map(([key, [stake, votes]]): [AccountId, DeriveCouncilVote] => + [key.args[0] as AccountId, { stake, votes }] + ) + ) + ); +} + +export function votes (api: ApiInterfaceRx): () => Observable { + // since we are using entries, we are not adding a memo + return (): Observable => + (api.query.electionsPhragmen || api.query.elections).stakeOf + ? retrievePrev(api) + : retrieveCurrent(api); +} diff --git a/packages/api-derive/src/council/votesOf.ts b/packages/api-derive/src/council/votesOf.ts new file mode 100644 index 0000000000..981ab042c3 --- /dev/null +++ b/packages/api-derive/src/council/votesOf.ts @@ -0,0 +1,23 @@ +// Copyright 2017-2020 @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 { DeriveCouncilVote } from '../types'; + +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +export function votesOf (api: ApiInterfaceRx): (accountId: string | Uint8Array | AccountId) => Observable { + // no memo, votes actually pulls the entries without a memo (using entries) + return (accountId: string | Uint8Array | AccountId): Observable => + api.derive.council.votes().pipe( + map((votes): DeriveCouncilVote => + ( + votes.find(([from]) => from.eq(accountId)) || + [null, { stake: api.registry.createType('Balance'), votes: [] as AccountId[] }] + )[1] + ) + ); +} diff --git a/packages/api-derive/src/types.ts b/packages/api-derive/src/types.ts index 06864fa76a..a81bdbe7b6 100644 --- a/packages/api-derive/src/types.ts +++ b/packages/api-derive/src/types.ts @@ -7,6 +7,7 @@ import { AccountId, AccountIndex, Balance, BalanceLock, BalanceLockTo212, Balanc import BN from 'bn.js'; import { u32 } from '@polkadot/types'; +export * from './council/types'; export * from './democracy/types'; export * from './parachains/types'; export * from './session/types';