Add council & treasury derives (#1654)

This commit is contained in:
Jaco Greeff
2019-12-09 14:18:13 +01:00
committed by GitHub
parent 50e115f6a1
commit 4653cc0d84
6 changed files with 176 additions and 2 deletions
+5
View File
@@ -0,0 +1,5 @@
// 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.
export * from './proposals';
@@ -0,0 +1,48 @@
// 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 { Hash, Proposal, Votes } from '@polkadot/types/interfaces';
import { DerivedCouncilProposals } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Option } from '@polkadot/types';
import { memo } from '../util';
function retrieveProposals (api: ApiInterfaceRx, hashes: Hash[]): Observable<DerivedCouncilProposals> {
return combineLatest([
api.query.council.proposalOf.multi<Option<Proposal>>(hashes),
api.query.council.voting.multi<Option<Votes>>(hashes)
]).pipe(
map(([proposals, votes]: [Option<Proposal>[], Option<Votes>[]]): DerivedCouncilProposals => {
const result: DerivedCouncilProposals = [];
proposals.forEach((proposalOpt, index): void => {
if (proposalOpt.isSome) {
result.push({
hash: hashes[index],
proposal: proposalOpt.unwrap(),
votes: votes[index].unwrapOr(null)
});
}
});
return result;
})
);
}
export function proposals (api: ApiInterfaceRx): () => Observable<DerivedCouncilProposals> {
return memo((): Observable<DerivedCouncilProposals> =>
api.query.council
? api.query.council.proposals().pipe(
switchMap((proposals: Hash[]): Observable<DerivedCouncilProposals> =>
retrieveProposals(api, proposals)
)
)
: of([] as DerivedCouncilProposals)
);
}
+3 -1
View File
@@ -11,11 +11,13 @@ import * as accounts from './accounts';
import * as balances from './balances';
import * as chain from './chain';
import * as contracts from './contracts';
import * as council from './council';
import * as democracy from './democracy';
import * as elections from './elections';
import * as imOnline from './imOnline';
import * as session from './session';
import * as staking from './staking';
import * as treasury from './treasury';
export * from './type';
@@ -56,7 +58,7 @@ function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSect
}, {} as DeriveAllSections<AllSections>);
}
export const derive = { accounts, balances, chain, contracts, democracy, elections, imOnline, session, staking };
export const derive = { accounts, balances, chain, contracts, council, democracy, elections, imOnline, session, staking, treasury };
export type ExactDerive = DeriveAllSections<typeof derive>;
// FIXME The return type of this function should be {...ExactDerive, ...DeriveCustom}
@@ -0,0 +1,5 @@
// 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.
export * from './proposals';
@@ -0,0 +1,94 @@
// 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 { ProposalIndex, TreasuryProposal } from '@polkadot/types/interfaces';
import { DerivedCouncilProposals, DerivedTreasuryProposal, DerivedTreasuryProposals } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { createType, Option } from '@polkadot/types';
import { memo } from '../util';
interface Result {
allIds: ProposalIndex[];
allProposals: Option<TreasuryProposal>[];
approvalIds: ProposalIndex[];
councilProposals: DerivedCouncilProposals;
proposalCount: ProposalIndex;
}
function parseResult (_api: ApiInterfaceRx, { allIds, allProposals, approvalIds, councilProposals, proposalCount }: Result): DerivedTreasuryProposals {
const approvals: DerivedTreasuryProposal[] = [];
const proposals: DerivedTreasuryProposal[] = [];
const councilTreasury = councilProposals.filter(({ proposal: { methodName, sectionName } }): boolean =>
sectionName === 'treasury' &&
['approveProposal', 'rejectProposal'].includes(methodName)
);
allIds.forEach((id, index): void => {
if (allProposals[index].isSome) {
const council = councilTreasury
.filter(({ proposal }): boolean => id.eq(proposal.args[0]))
.sort((a, b): number => a.proposal.methodName.localeCompare(b.proposal.methodName));
const isApproval = approvalIds.some((approvalId): boolean => approvalId.eq(id));
const derived = { council, id, proposal: allProposals[index].unwrap() };
if (isApproval) {
approvals.push(derived);
} else {
proposals.push(derived);
}
}
});
return { approvals, proposalCount, proposals };
}
function retrieveProposals (api: ApiInterfaceRx, proposalCount: ProposalIndex, approvalIds: ProposalIndex[]): Observable<DerivedTreasuryProposals> {
const proposalIds: ProposalIndex[] = [];
const count = proposalCount.toNumber();
for (let index = 0; index < count; index++) {
const isApproval = approvalIds.some((id): boolean => id.eqn(index));
if (!isApproval) {
proposalIds.push(createType(api.registry, 'ProposalIndex', index));
}
}
const allIds = [...proposalIds, ...approvalIds];
return combineLatest([
api.query.treasury.proposals.multi<Option<TreasuryProposal>>(allIds),
api.derive.council.proposals()
]).pipe(
map(([allProposals, councilProposals]: [Option<TreasuryProposal>[], DerivedCouncilProposals]): DerivedTreasuryProposals =>
parseResult(api, { allIds, allProposals, approvalIds, councilProposals, proposalCount })
)
);
}
/**
* @description Retrieve all active and approved treasury proposals, along with their info
*/
export function proposals (api: ApiInterfaceRx): () => Observable<DerivedTreasuryProposals> {
return memo((): Observable<DerivedTreasuryProposals> =>
api.query.treasury
? combineLatest([
api.query.treasury.proposalCount(),
api.query.treasury.approvals()
]).pipe(
switchMap(([proposalCount, approvalIds]: [ProposalIndex, ProposalIndex[]]) =>
retrieveProposals(api, proposalCount, approvalIds)
)
)
: of({
approvals: [],
proposalCount: createType(api.registry, 'ProposalIndex'),
proposals: []
} as DerivedTreasuryProposals)
);
}
+21 -1
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, EraPoints, Exposure, Hash, Index, Keys, Proposal, PropIndex, ReferendumInfo, RewardDestination, SessionIndex, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
import { AccountId, AccountIndex, Balance, BalanceLock, BlockNumber, EraIndex, EraPoints, Exposure, Hash, Index, Keys, Proposal, PropIndex, ProposalIndex, ReferendumInfo, RewardDestination, SessionIndex, SetIndex, StakingLedger, TreasuryProposal, ValidatorPrefs, Vote, Votes, VoteIndex } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { u32, Vec } from '@polkadot/types';
@@ -44,6 +44,14 @@ export interface DerivedContractFees {
transferFee: BN;
}
export interface DerivedCouncilProposal {
hash: Hash;
proposal: Proposal;
votes: Votes | null;
}
export type DerivedCouncilProposals = DerivedCouncilProposal[];
export interface DerivedElectionsInfo {
candidates: AccountId[];
candidateCount: u32;
@@ -164,6 +172,18 @@ export interface DerivedStakingOverview extends DeriveSessionIndexes {
validators: AccountId[];
}
export interface DerivedTreasuryProposal {
council: DerivedCouncilProposal[];
id: ProposalIndex;
proposal: TreasuryProposal;
}
export interface DerivedTreasuryProposals {
approvals: DerivedTreasuryProposal[];
proposalCount: ProposalIndex;
proposals: DerivedTreasuryProposal[];
}
export type DerivedUnlocking = {
remainingBlocks: BlockNumber;
value: Balance;