difftreelog
Tests/fin council (#1070)
in: master
7 files changed
js-packages/.vscode/settings.jsondiffbeforeafterboth--- a/js-packages/.vscode/settings.json
+++ b/js-packages/.vscode/settings.json
@@ -5,6 +5,8 @@
},
"mochaExplorer.files": "tests/**/*.test.ts",
"mochaExplorer.require": "ts-node/register",
+ "mochaExplorer.esmLoader": true,
+ "mochaExplorer.nodeArgv": ["--loader", "ts-node/esm"],
"eslint.format.enable": true,
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
js-packages/test-utils/index.tsdiffbeforeafterboth--- a/js-packages/test-utils/index.ts
+++ b/js-packages/test-utils/index.ts
@@ -214,6 +214,23 @@
}));
};
+ static FinCouncil = class extends EventSection('financialCouncil') {
+ static Proposed = this.Method('Proposed', data => ({
+ account: eventHumanData(data, 0),
+ proposalIndex: eventJsonData<number>(data, 1),
+ proposalHash: eventHumanData(data, 2),
+ threshold: eventJsonData<number>(data, 3),
+ }));
+ static Closed = this.Method('Closed', data => ({
+ proposalHash: eventHumanData(data, 0),
+ yes: eventJsonData<number>(data, 1),
+ no: eventJsonData<number>(data, 2),
+ }));
+ static Executed = this.Method('Executed', data => ({
+ proposalHash: eventHumanData(data, 0),
+ }));
+ };
+
static TechnicalCommittee = class extends EventSection('technicalCommittee') {
static Proposed = this.Method('Proposed', data => ({
account: eventHumanData(data, 0),
@@ -475,6 +492,7 @@
scheduler: SchedulerGroup;
collatorSelection: CollatorSelectionGroup;
council: ICollectiveGroup;
+ finCouncil: ICollectiveGroup;
technicalCommittee: ICollectiveGroup;
fellowship: IFellowshipGroup;
democracy: DemocracyGroup;
@@ -498,6 +516,10 @@
collective: new CollectiveGroup(this, 'council'),
membership: new CollectiveMembershipGroup(this, 'councilMembership'),
};
+ this.finCouncil = {
+ collective: new CollectiveGroup(this, 'financialCouncil'),
+ membership: new CollectiveMembershipGroup(this, 'financialCouncilMembership'),
+ };
this.technicalCommittee = {
collective: new CollectiveGroup(this, 'technicalCommittee'),
membership: new CollectiveMembershipGroup(this, 'technicalCommitteeMembership'),
js-packages/test-utils/util.tsdiffbeforeafterboth117 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',js-packages/tests/sub/governance/council.test.tsdiffbeforeafterboth--- a/js-packages/tests/sub/governance/council.test.ts
+++ b/js-packages/tests/sub/governance/council.test.ts
@@ -2,7 +2,7 @@
import type {IKeyringPair} from '@polkadot/types/types';
import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '@unique/test-utils/util.js';
import {Event} from '@unique/test-utils';
-import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util.js';
+import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin, initFinCouncil} from './util.js';
import type {ICounselors} from './util.js';
describeGov('Governance: Council tests', () => {
@@ -192,6 +192,25 @@
expect(techCommMembers).to.not.contains(techComm.andy.address);
});
+ itSub('Council can remove FinCouncil member', async ({helper}) => {
+ const finCouncil = await initFinCouncil(donor, sudoer);
+ const removeMemberPrpoposal = helper.finCouncil.membership.removeMemberCall(finCouncil.andy.address);
+ await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);
+
+ const finCouncilMembers = await helper.finCouncil.membership.getMembers();
+ expect(finCouncilMembers).to.not.contains(finCouncil.andy.address);
+ });
+
+ itSub('Council can add FinCouncil member', async ({helper}) => {
+ await initFinCouncil(donor, sudoer);
+ const newFinCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberPrpoposal = helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address);
+ await proposalFromMoreThanHalfCouncil(addMemberPrpoposal);
+
+ const finCouncilMembers = await helper.finCouncil.membership.getMembers();
+ expect(finCouncilMembers).to.contains(newFinCouncilMember.address);
+ });
+
itSub.skip('Council member can add Fellowship member', async ({helper}) => {
const newFellowshipMember = helper.arrange.createEmptyAccount();
await expect(helper.council.collective.execute(
@@ -328,6 +347,22 @@
)).to.be.rejectedWith('BadOrigin');
});
+ itSub('[Negative] Council member can\'t add FinCouncil member', async ({helper}) => {
+ const newFinCouncilMember = helper.arrange.createEmptyAccount();
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address),
+ )).rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] Council member can\'t remove FinCouncil member', async ({helper}) => {
+ const finCouncil = await initFinCouncil(donor, sudoer);
+ await expect(helper.council.collective.execute(
+ counselors.alex,
+ helper.finCouncil.membership.removeMemberCall(finCouncil.ildar.address),
+ )).rejectedWith('BadOrigin');
+ });
+
itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {
const fellowship = await initFellowship(donor, sudoer);
const memberWithRankOne = fellowship[1][0];
js-packages/tests/sub/governance/financialCouncil.test.tsdiffbeforeafterboth--- /dev/null
+++ b/js-packages/tests/sub/governance/financialCouncil.test.ts
@@ -0,0 +1,406 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '@unique/test-utils/util.js';
+import {Event} from '@unique/test-utils';
+import {democracyFastTrackVotingPeriod, IFinCounselors, clearTechComm, dummyProposalCall, initFinCouncil, clearFinCouncil, democracyLaunchPeriod, initFellowship, dummyProposal, fellowshipPropositionOrigin, defaultEnactmentMoment, initCouncil, clearCouncil, clearFellowship} from './util.js';
+
+
+describeGov('Governance: Financial Council tests', () => {
+ let donor: IKeyringPair;
+ let finCounselors: IFinCounselors;
+ let sudoer: IKeyringPair;
+
+ const moreThanHalfCouncilThreshold = 2;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.FinancialCouncil]);
+ sudoer = await privateKey('//Alice');
+ donor = await privateKey({url: import.meta.url});
+ });
+ });
+
+ beforeEach(async () => {
+ finCounselors = await initFinCouncil(donor, sudoer);
+ });
+
+ afterEach(async () => {
+ await clearFinCouncil(sudoer);
+ await clearTechComm(sudoer);
+ });
+
+ async function proposalFromMoreThanHalfCouncil(proposal: any) {
+ return await usingPlaygrounds(async (helper) => {
+ expect((await helper.finCouncil.membership.getMembers()).length).to.be.equal(3);
+ const proposeResult = await helper.finCouncil.collective.propose(
+ finCounselors.ildar,
+ proposal,
+ moreThanHalfCouncilThreshold,
+ );
+
+ const councilProposedEvent = Event.FinCouncil.Proposed.expect(proposeResult);
+ const proposalIndex = councilProposedEvent.proposalIndex;
+ const proposalHash = councilProposedEvent.proposalHash;
+
+ await helper.finCouncil.collective.vote(finCounselors.greg, proposalHash, proposalIndex, true);
+ await helper.finCouncil.collective.vote(finCounselors.ildar, proposalHash, proposalIndex, true);
+
+ return await helper.finCouncil.collective.close(finCounselors.ildar, proposalHash, proposalIndex);
+ });
+ }
+
+ async function proposalFromAllCouncil(proposal: any) {
+ return await usingPlaygrounds(async (helper) => {
+ expect((await helper.finCouncil.membership.getMembers()).length).to.be.equal(3);
+ const proposeResult = await helper.finCouncil.collective.propose(
+ finCounselors.ildar,
+ proposal,
+ moreThanHalfCouncilThreshold,
+ );
+
+ const councilProposedEvent = Event.FinCouncil.Proposed.expect(proposeResult);
+ const proposalIndex = councilProposedEvent.proposalIndex;
+ const proposalHash = councilProposedEvent.proposalHash;
+
+ await helper.finCouncil.collective.vote(finCounselors.greg, proposalHash, proposalIndex, true);
+ await helper.finCouncil.collective.vote(finCounselors.ildar, proposalHash, proposalIndex, true);
+ await helper.finCouncil.collective.vote(finCounselors.andy, proposalHash, proposalIndex, true);
+
+ return await helper.finCouncil.collective.close(finCounselors.andy, proposalHash, proposalIndex);
+ });
+ }
+
+ itSub('FinCouncil member can register foreign asset', async ({helper}) => {
+ const location = {
+ parents: 1,
+ interior: {X3: [
+ {
+ Parachain: 1000,
+ },
+ {
+ PalletInstance: 50,
+ },
+ {
+ GeneralIndex: 1984,
+ },
+ ]},
+ };
+ const assetId = {Concrete: location};
+
+ const registerForeignAssetCall = helper.constructApiCall(
+ 'api.tx.foreignAssets.forceRegisterForeignAsset',
+ [{V3: assetId}, helper.util.str2vec('New Asset'), 'NEW', {Fungible: 10}],
+ );
+
+ await helper.finCouncil.collective.execute(finCounselors.andy, registerForeignAssetCall);
+
+ const asset = await helper.foreignAssets.foreignCollectionId(location);
+ expect(asset).not.null;
+ });
+
+ itSub('[Negative] FinCouncil can\'t fast-track Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.wait.parachainBlockMultiplesOf(35n);
+
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))
+ .rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot fast-track Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil can\'t cancel Democracy proposals', async ({helper}) => {
+ const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+ const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+ await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))
+ .rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot cancel Democracy proposals', async ({helper}) => {
+ const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+ const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.democracy.cancelProposalCall(proposalIndex),
+ ))
+ .to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil can\'t cancel ongoing Democracy referendums', async ({helper}) => {
+ await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))
+ .rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot cancel ongoing Democracy referendums', async ({helper}) => {
+ await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+ const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+ const referendumIndex = startedEvent.referendumIndex;
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.democracy.emergencyCancelCall(referendumIndex),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member can\'t veto Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.democracy.vetoExternalCall(preimageHash),
+ )).rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot blacklist Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash))).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot blacklist Democracy proposals', async ({helper}) => {
+ const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+ await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.democracy.blacklistCall(preimageHash),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil can\' cancel Fellowship referendums', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const fellowshipProposer = fellowship[5][0];
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ fellowshipProposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+ await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))
+ .rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot cancel Fellowship referendums', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+ const fellowshipProposer = fellowship[5][0];
+ const proposal = dummyProposal(helper);
+
+ const submitResult = await helper.fellowship.referenda.submit(
+ fellowshipProposer,
+ fellowshipPropositionOrigin,
+ proposal,
+ defaultEnactmentMoment,
+ );
+
+ const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.fellowship.referenda.cancelCall(referendumIndex),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member can\' add a Fellowship member', async ({helper}) => {
+ const newFellowshipMember = helper.arrange.createEmptyAccount();
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot submit regular democracy proposal', async ({helper}) => {
+ const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+ await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+ const commiteeProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot submit regular democracy proposal', async ({helper}) => {
+ const memberProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot externally propose SimpleMajority', async ({helper}) => {
+ const commiteeProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot externally propose SuperMajorityApprove', async ({helper}) => {
+ const commiteeProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+ await expect(proposalFromAllCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+ const memberProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot externally propose SimpleMajority', async ({helper}) => {
+ const memberProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot externally propose SuperMajorityApprove', async ({helper}) => {
+ const memberProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ memberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot add/remove a Council member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
+
+ await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');
+ await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot add/remove a Council member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ addMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ removeMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot add/remove a FinCouncil member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.finCouncil.membership.addMemberCall(newCouncilMember.address);
+ const removeMemberProposal = helper.finCouncil.membership.removeMemberCall(finCounselors.ildar.address);
+
+ await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');
+ await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot add/remove a FinCouncil member', async ({helper}) => {
+ const newCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.finCouncil.membership.addMemberCall(newCouncilMember.address);
+ const removeMemberProposal = helper.finCouncil.membership.removeMemberCall(finCounselors.ildar.address);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ addMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ removeMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot set/clear Council prime member', async ({helper}) => {
+ const counselors = await initCouncil(donor, sudoer);
+ const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+ const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+ await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith('BadOrigin');
+ await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith('BadOrigin');
+ await clearCouncil(sudoer);
+ });
+
+ itSub('[Negative] FinCouncil member cannot set/clear Council prime member', async ({helper}) => {
+ const counselors = await initCouncil(donor, sudoer);
+ const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+ const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ proposalForSet,
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ proposalForClear,
+ )).to.be.rejectedWith('BadOrigin');
+ await clearCouncil(sudoer);
+ });
+
+ itSub('[Negative] FinCouncil cannot add/remove a TechComm member', async ({helper}) => {
+ const newCommMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
+
+ await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');
+ await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil member cannot add/remove a TechComm member', async ({helper}) => {
+ const newCommMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
+ const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ addMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ removeMemberProposal,
+ )).to.be.rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] FinCouncil cannot remove a Fellowship member', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+
+ await expect(proposalFromAllCouncil(helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5))).to.be.rejectedWith('BadOrigin');
+ await clearFellowship(sudoer);
+ });
+
+ itSub('[Negative] FinCouncil member cannot remove a Fellowship member', async ({helper}) => {
+ const fellowship = await initFellowship(donor, sudoer);
+
+ await expect(helper.finCouncil.collective.execute(
+ finCounselors.andy,
+ helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5),
+ )).to.be.rejectedWith('BadOrigin');
+ await clearFellowship(sudoer);
+ });
+
+
+});
js-packages/tests/sub/governance/technicalCommittee.test.tsdiffbeforeafterboth--- a/js-packages/tests/sub/governance/technicalCommittee.test.ts
+++ b/js-packages/tests/sub/governance/technicalCommittee.test.ts
@@ -130,6 +130,50 @@
await clearFellowship(sudoer);
});
+ itSub('[Negative] TechComm can\'t add FinCouncil member', async ({helper}) => {
+ const newFinCouncilMember = helper.arrange.createEmptyAccount();
+ const addMemberProposal = helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address);
+ await proposalFromAllCommittee(addMemberProposal);
+
+ const finCouncilMembers = await helper.finCouncil.membership.getMembers();
+ expect(finCouncilMembers).to.contains(newFinCouncilMember.address);
+ });
+
+
+ itSub('[Negative] TechComm member can\'t add FinCouncil member', async ({helper}) => {
+ const newFinCouncilMember = helper.arrange.createEmptyAccount();
+ await expect(helper.technicalCommittee.collective.execute(
+ techcomms.greg,
+ helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address),
+ )).rejectedWith('BadOrigin');
+ });
+
+ itSub('[Negative] TechComm member cannot register foreign asset', async ({helper}) => {
+ const location = {
+ parents: 1,
+ interior: {X3: [
+ {
+ Parachain: 1000,
+ },
+ {
+ PalletInstance: 50,
+ },
+ {
+ GeneralIndex: 1985,
+ },
+ ]},
+ };
+ const assetId = {Concrete: location};
+
+ const foreignAssetProposal = helper.constructApiCall(
+ 'api.tx.foreignAssets.forceRegisterForeignAsset',
+ [{V3: assetId}, helper.util.str2vec('New Asset2'), 'NEW', {Fungible: 10}],
+ );
+
+ await expect(helper.technicalCommittee.collective.execute(techcomms.andy, foreignAssetProposal))
+ .to.be.rejectedWith('BadOrigin');
+ });
+
itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {
const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
js-packages/tests/sub/governance/util.tsdiffbeforeafterboth--- a/js-packages/tests/sub/governance/util.ts
+++ b/js-packages/tests/sub/governance/util.ts
@@ -29,12 +29,62 @@
filip: IKeyringPair;
irina: IKeyringPair;
}
+
+export interface IFinCounselors {
+ greg: IKeyringPair;
+ ildar: IKeyringPair;
+ andy: IKeyringPair;
+}
+
export interface ITechComms {
greg: IKeyringPair;
andy: IKeyringPair;
constantine: IKeyringPair;
}
+export function initFinCouncil(donor: IKeyringPair, superuser: IKeyringPair): Promise<IFinCounselors> {
+ return usingPlaygrounds(async (helper) => {
+ const [greg, ildar, andy] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n], donor);
+ const sudo = helper.getSudo();
+ {
+ const members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON() as [];
+ if(members.length != 0) {
+ await clearFinCouncil(superuser);
+ }
+ }
+ const expectedMembers = [greg, ildar, andy];
+ for(const member of expectedMembers) {
+ await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.addMember', [member.address]);
+ }
+ await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.setPrime', [greg.address]);
+ {
+ const members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
+ expect(members).to.containSubset(expectedMembers.map((x: IKeyringPair) => x.address));
+ expect(members.length).to.be.equal(expectedMembers.length);
+ }
+
+ return {
+ greg,
+ ildar,
+ andy,
+ };
+ });
+}
+
+export async function clearFinCouncil(superuser: IKeyringPair) {
+ await usingPlaygrounds(async (helper) => {
+ let members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
+ if(members.length) {
+ const sudo = helper.getSudo();
+ for(const address of members) {
+ await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.removeMember', [address]);
+ }
+ members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
+ }
+ expect(members).to.be.deep.equal([]);
+ });
+}
+
export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {
let counselors: IKeyringPair[] = [];