git.delta.rocks / unique-network / refs/commits / ed0719fab73d

difftreelog

Tests/fin council (#1070)

Max Andreev2024-06-05parent: #c9b1f9a.patch.diff
in: master

7 files changed

modifiedjs-packages/.vscode/settings.jsondiffbeforeafterboth
5 },5 },
6 "mochaExplorer.files": "tests/**/*.test.ts",6 "mochaExplorer.files": "tests/**/*.test.ts",
7 "mochaExplorer.require": "ts-node/register",7 "mochaExplorer.require": "ts-node/register",
8 "mochaExplorer.esmLoader": true,
9 "mochaExplorer.nodeArgv": ["--loader", "ts-node/esm"],
8 "eslint.format.enable": true,10 "eslint.format.enable": true,
9 "[javascript]": {11 "[javascript]": {
10 "editor.defaultFormatter": "dbaeumer.vscode-eslint"12 "editor.defaultFormatter": "dbaeumer.vscode-eslint"
modifiedjs-packages/test-utils/index.tsdiffbeforeafterboth
214 }));214 }));
215 };215 };
216
217 static FinCouncil = class extends EventSection('financialCouncil') {
218 static Proposed = this.Method('Proposed', data => ({
219 account: eventHumanData(data, 0),
220 proposalIndex: eventJsonData<number>(data, 1),
221 proposalHash: eventHumanData(data, 2),
222 threshold: eventJsonData<number>(data, 3),
223 }));
224 static Closed = this.Method('Closed', data => ({
225 proposalHash: eventHumanData(data, 0),
226 yes: eventJsonData<number>(data, 1),
227 no: eventJsonData<number>(data, 2),
228 }));
229 static Executed = this.Method('Executed', data => ({
230 proposalHash: eventHumanData(data, 0),
231 }));
232 };
216233
217 static TechnicalCommittee = class extends EventSection('technicalCommittee') {234 static TechnicalCommittee = class extends EventSection('technicalCommittee') {
218 static Proposed = this.Method('Proposed', data => ({235 static Proposed = this.Method('Proposed', data => ({
475 scheduler: SchedulerGroup;492 scheduler: SchedulerGroup;
476 collatorSelection: CollatorSelectionGroup;493 collatorSelection: CollatorSelectionGroup;
477 council: ICollectiveGroup;494 council: ICollectiveGroup;
495 finCouncil: ICollectiveGroup;
478 technicalCommittee: ICollectiveGroup;496 technicalCommittee: ICollectiveGroup;
479 fellowship: IFellowshipGroup;497 fellowship: IFellowshipGroup;
480 democracy: DemocracyGroup;498 democracy: DemocracyGroup;
498 collective: new CollectiveGroup(this, 'council'),516 collective: new CollectiveGroup(this, 'council'),
499 membership: new CollectiveMembershipGroup(this, 'councilMembership'),517 membership: new CollectiveMembershipGroup(this, 'councilMembership'),
500 };518 };
519 this.finCouncil = {
520 collective: new CollectiveGroup(this, 'financialCouncil'),
521 membership: new CollectiveMembershipGroup(this, 'financialCouncilMembership'),
522 };
501 this.technicalCommittee = {523 this.technicalCommittee = {
502 collective: new CollectiveGroup(this, 'technicalCommittee'),524 collective: new CollectiveGroup(this, 'technicalCommittee'),
503 membership: new CollectiveMembershipGroup(this, 'technicalCommitteeMembership'),525 membership: new CollectiveMembershipGroup(this, 'technicalCommitteeMembership'),
modifiedjs-packages/test-utils/util.tsdiffbeforeafterboth
117 Identity = 'identity',117 Identity = 'identity',
118 Democracy = 'democracy',118 Democracy = 'democracy',
119 Council = 'council',119 Council = 'council',
120 FinancialCouncil = 'financialcouncil',
120 //CouncilMembership = 'councilmembership',121 //CouncilMembership = 'councilmembership',
121 TechnicalCommittee = 'technicalcommittee',122 TechnicalCommittee = 'technicalcommittee',
122 Fellowship = 'fellowshipcollective',123 Fellowship = 'fellowshipcollective',
modifiedjs-packages/tests/sub/governance/council.test.tsdiffbeforeafterboth
2import type {IKeyringPair} from '@polkadot/types/types';2import type {IKeyringPair} from '@polkadot/types/types';
3import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '@unique/test-utils/util.js';3import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '@unique/test-utils/util.js';
4import {Event} from '@unique/test-utils';4import {Event} from '@unique/test-utils';
5import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util.js';5import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin, initFinCouncil} from './util.js';
6import type {ICounselors} from './util.js';6import type {ICounselors} from './util.js';
77
8describeGov('Governance: Council tests', () => {8describeGov('Governance: Council tests', () => {
192 expect(techCommMembers).to.not.contains(techComm.andy.address);192 expect(techCommMembers).to.not.contains(techComm.andy.address);
193 });193 });
194
195 itSub('Council can remove FinCouncil member', async ({helper}) => {
196 const finCouncil = await initFinCouncil(donor, sudoer);
197 const removeMemberPrpoposal = helper.finCouncil.membership.removeMemberCall(finCouncil.andy.address);
198 await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);
199
200 const finCouncilMembers = await helper.finCouncil.membership.getMembers();
201 expect(finCouncilMembers).to.not.contains(finCouncil.andy.address);
202 });
203
204 itSub('Council can add FinCouncil member', async ({helper}) => {
205 await initFinCouncil(donor, sudoer);
206 const newFinCouncilMember = helper.arrange.createEmptyAccount();
207 const addMemberPrpoposal = helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address);
208 await proposalFromMoreThanHalfCouncil(addMemberPrpoposal);
209
210 const finCouncilMembers = await helper.finCouncil.membership.getMembers();
211 expect(finCouncilMembers).to.contains(newFinCouncilMember.address);
212 });
194213
195 itSub.skip('Council member can add Fellowship member', async ({helper}) => {214 itSub.skip('Council member can add Fellowship member', async ({helper}) => {
196 const newFellowshipMember = helper.arrange.createEmptyAccount();215 const newFellowshipMember = helper.arrange.createEmptyAccount();
328 )).to.be.rejectedWith('BadOrigin');347 )).to.be.rejectedWith('BadOrigin');
329 });348 });
349
350 itSub('[Negative] Council member can\'t add FinCouncil member', async ({helper}) => {
351 const newFinCouncilMember = helper.arrange.createEmptyAccount();
352 await expect(helper.council.collective.execute(
353 counselors.alex,
354 helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address),
355 )).rejectedWith('BadOrigin');
356 });
357
358 itSub('[Negative] Council member can\'t remove FinCouncil member', async ({helper}) => {
359 const finCouncil = await initFinCouncil(donor, sudoer);
360 await expect(helper.council.collective.execute(
361 counselors.alex,
362 helper.finCouncil.membership.removeMemberCall(finCouncil.ildar.address),
363 )).rejectedWith('BadOrigin');
364 });
330365
331 itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {366 itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {
332 const fellowship = await initFellowship(donor, sudoer);367 const fellowship = await initFellowship(donor, sudoer);
addedjs-packages/tests/sub/governance/financialCouncil.test.tsdiffbeforeafterboth

no changes

modifiedjs-packages/tests/sub/governance/technicalCommittee.test.tsdiffbeforeafterboth
130 await clearFellowship(sudoer);130 await clearFellowship(sudoer);
131 });131 });
132
133 itSub('[Negative] TechComm can\'t add FinCouncil member', async ({helper}) => {
134 const newFinCouncilMember = helper.arrange.createEmptyAccount();
135 const addMemberProposal = helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address);
136 await proposalFromAllCommittee(addMemberProposal);
137
138 const finCouncilMembers = await helper.finCouncil.membership.getMembers();
139 expect(finCouncilMembers).to.contains(newFinCouncilMember.address);
140 });
141
142
143 itSub('[Negative] TechComm member can\'t add FinCouncil member', async ({helper}) => {
144 const newFinCouncilMember = helper.arrange.createEmptyAccount();
145 await expect(helper.technicalCommittee.collective.execute(
146 techcomms.greg,
147 helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address),
148 )).rejectedWith('BadOrigin');
149 });
150
151 itSub('[Negative] TechComm member cannot register foreign asset', async ({helper}) => {
152 const location = {
153 parents: 1,
154 interior: {X3: [
155 {
156 Parachain: 1000,
157 },
158 {
159 PalletInstance: 50,
160 },
161 {
162 GeneralIndex: 1985,
163 },
164 ]},
165 };
166 const assetId = {Concrete: location};
167
168 const foreignAssetProposal = helper.constructApiCall(
169 'api.tx.foreignAssets.forceRegisterForeignAsset',
170 [{V3: assetId}, helper.util.str2vec('New Asset2'), 'NEW', {Fungible: 10}],
171 );
172
173 await expect(helper.technicalCommittee.collective.execute(techcomms.andy, foreignAssetProposal))
174 .to.be.rejectedWith('BadOrigin');
175 });
132176
133 itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {177 itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {
134 const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);178 const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
modifiedjs-packages/tests/sub/governance/util.tsdiffbeforeafterboth
30 irina: IKeyringPair;30 irina: IKeyringPair;
31}31}
32
33export interface IFinCounselors {
34 greg: IKeyringPair;
35 ildar: IKeyringPair;
36 andy: IKeyringPair;
37}
38
32export interface ITechComms {39export interface ITechComms {
33 greg: IKeyringPair;40 greg: IKeyringPair;
34 andy: IKeyringPair;41 andy: IKeyringPair;
35 constantine: IKeyringPair;42 constantine: IKeyringPair;
36}43}
44
45export function initFinCouncil(donor: IKeyringPair, superuser: IKeyringPair): Promise<IFinCounselors> {
46 return usingPlaygrounds(async (helper) => {
47 const [greg, ildar, andy] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n], donor);
48 const sudo = helper.getSudo();
49 {
50 const members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON() as [];
51 if(members.length != 0) {
52 await clearFinCouncil(superuser);
53 }
54 }
55 const expectedMembers = [greg, ildar, andy];
56 for(const member of expectedMembers) {
57 await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.addMember', [member.address]);
58 }
59 await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.setPrime', [greg.address]);
60 {
61 const members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
62 expect(members).to.containSubset(expectedMembers.map((x: IKeyringPair) => x.address));
63 expect(members.length).to.be.equal(expectedMembers.length);
64 }
65
66 return {
67 greg,
68 ildar,
69 andy,
70 };
71 });
72}
73
74export async function clearFinCouncil(superuser: IKeyringPair) {
75 await usingPlaygrounds(async (helper) => {
76 let members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
77 if(members.length) {
78 const sudo = helper.getSudo();
79 for(const address of members) {
80 await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.removeMember', [address]);
81 }
82 members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
83 }
84 expect(members).to.be.deep.equal([]);
85 });
86}
3787
38export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {88export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {
39 let counselors: IKeyringPair[] = [];89 let counselors: IKeyringPair[] = [];