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

difftreelog

Merge pull request #977 from UniqueNetwork/fix/gov-council-test

Yaroslav Bolyukin2023-09-04parents: #3e9a8d1 #edf428e.patch.diff
in: master
test(gov): added neg votes

1 file changed

modifiedtests/src/governance/council.test.tsdiffbeforeafterboth
before · tests/src/governance/council.test.ts
12import {IKeyringPair} from '@polkadot/types/types';3import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util';4import {Event} from '../util/playgrounds/unique.dev';5import {ICounselors, initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util';67describeGov('Governance: Council tests', () => {8  let donor: IKeyringPair;9  let counselors: ICounselors;10  let sudoer: IKeyringPair;1112  const moreThanHalfCouncilThreshold = 3;1314  before(async function() {15    await usingPlaygrounds(async (helper, privateKey) => {16      requirePalletsOrSkip(this, helper, [Pallets.Council]);1718      donor = await privateKey({url: import.meta.url});19      sudoer = await privateKey('//Alice');20    });21  });2223  beforeEach(async () => {24    counselors = await initCouncil(donor, sudoer);25  });2627  afterEach(async () => {28    await clearCouncil(sudoer);29    await clearTechComm(sudoer);30  });3132  async function proposalFromMoreThanHalfCouncil(proposal: any) {33    return await usingPlaygrounds(async (helper) => {34      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);35      const proposeResult = await helper.council.collective.propose(36        counselors.filip,37        proposal,38        moreThanHalfCouncilThreshold,39      );4041      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);42      const proposalIndex = councilProposedEvent.proposalIndex;43      const proposalHash = councilProposedEvent.proposalHash;444546      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);47      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);48      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);4950      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);51    });52  }5354  async function proposalFromAllCouncil(proposal: any) {55    return await usingPlaygrounds(async (helper) => {56      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);57      const proposeResult = await helper.council.collective.propose(58        counselors.filip,59        proposal,60        moreThanHalfCouncilThreshold,61      );6263      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);64      const proposalIndex = councilProposedEvent.proposalIndex;65      const proposalHash = councilProposedEvent.proposalHash;666768      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);69      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);70      await helper.council.collective.vote(counselors.ildar, proposalHash, proposalIndex, true);71      await helper.council.collective.vote(counselors.irina, proposalHash, proposalIndex, true);72      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);7374      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);75    });76  }7778  itSub('>50% of Council can externally propose SuperMajorityAgainst', async ({helper}) => {79    const forceSetBalanceReceiver = helper.arrange.createEmptyAccount();80    const forceSetBalanceTestValue = 20n * 10n ** 25n;8182    const democracyProposal = await helper.constructApiCall('api.tx.balances.forceSetBalance', [83      forceSetBalanceReceiver.address, forceSetBalanceTestValue,84    ]);8586    const councilProposal = await helper.democracy.externalProposeDefaultCall(democracyProposal);8788    const proposeResult = await helper.council.collective.propose(89      counselors.filip,90      councilProposal,91      moreThanHalfCouncilThreshold,92    );9394    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);95    const proposalIndex = councilProposedEvent.proposalIndex;96    const proposalHash = councilProposedEvent.proposalHash;9798    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);99    await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);100    await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);101102    await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);103104    const democracyStartedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);105    const democracyReferendumIndex = democracyStartedEvent.referendumIndex;106    const democracyThreshold = democracyStartedEvent.threshold;107108    expect(democracyThreshold).to.be.equal('SuperMajorityAgainst');109110    await helper.democracy.vote(counselors.filip, democracyReferendumIndex, {111      Standard: {112        vote: {113          aye: true,114          conviction: 1,115        },116        balance: 10_000n,117      },118    });119120    const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);121    expect(passedReferendumEvent.referendumIndex).to.be.equal(democracyReferendumIndex);122123    await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);124    const receiverBalance = await helper.balance.getSubstrate(forceSetBalanceReceiver.address);125    expect(receiverBalance).to.be.equal(forceSetBalanceTestValue);126  });127128  itSub('Council prime member vote is the default', async ({helper}) => {129    const newTechCommMember = helper.arrange.createEmptyAccount();130    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);131    const proposeResult = await helper.council.collective.propose(132      counselors.filip,133      addMemberProposal,134      moreThanHalfCouncilThreshold,135    );136137    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);138    const proposalIndex = councilProposedEvent.proposalIndex;139    const proposalHash = councilProposedEvent.proposalHash;140141    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);142143    await helper.wait.newBlocks(councilMotionDuration);144    const closeResult = await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);145    const closeEvent = Event.Council.Closed.expect(closeResult);146    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as string[];147    expect(closeEvent.yes).to.be.equal(members.length);148  });149150  itSub('Superuser can add a member', async ({helper}) => {151    const newMember = helper.arrange.createEmptyAccount();152    await expect(helper.getSudo().council.membership.addMember(sudoer, newMember.address)).to.be.fulfilled;153154    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();155    expect(members).to.contains(newMember.address);156  });157158  itSub('Superuser can remove a member', async ({helper}) => {159    await expect(helper.getSudo().council.membership.removeMember(sudoer, counselors.alex.address)).to.be.fulfilled;160161    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();162    expect(members).to.not.contains(counselors.alex.address);163  });164165  itSub('>50% Council can add TechComm member', async ({helper}) => {166    const newTechCommMember = helper.arrange.createEmptyAccount();167    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);168169    await proposalFromMoreThanHalfCouncil(addMemberProposal);170171    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();172    expect(techCommMembers).to.contains(newTechCommMember.address);173  });174175  itSub('Council can remove TechComm member', async ({helper}) => {176    const techComm = await initTechComm(donor, sudoer);177    const removeMemberPrpoposal = helper.technicalCommittee.membership.removeMemberCall(techComm.andy.address);178    await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);179180    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();181    expect(techCommMembers).to.not.contains(techComm.andy.address);182  });183184  itSub.skip('Council member can add Fellowship member', async ({helper}) => {185    const newFellowshipMember = helper.arrange.createEmptyAccount();186    await expect(helper.council.collective.execute(187      counselors.alex,188      helper.fellowship.collective.addMemberCall(newFellowshipMember.address),189    )).to.be.fulfilled;190    const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();191    expect(fellowshipMembers).to.contains(newFellowshipMember.address);192  });193194  itSub('>50% Council can promote Fellowship member', async ({helper}) => {195    const fellowship = await initFellowship(donor, sudoer);196    const memberWithZeroRank = fellowship[0][0];197198    const proposal = helper.fellowship.collective.promoteCall(memberWithZeroRank.address);199    await proposalFromMoreThanHalfCouncil(proposal);200    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithZeroRank.address])).toJSON();201    expect(record).to.be.deep.equal({rank: 1});202203    await clearFellowship(sudoer);204  });205206  itSub('>50% Council can demote Fellowship member', async ({helper}) => {207    const fellowship = await initFellowship(donor, sudoer);208    const memberWithRankOne = fellowship[1][0];209210    const proposal = helper.fellowship.collective.demoteCall(memberWithRankOne.address);211    await proposalFromMoreThanHalfCouncil(proposal);212213    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithRankOne.address])).toJSON();214    expect(record).to.be.deep.equal({rank: 0});215216    await clearFellowship(sudoer);217  });218219  itSub('>50% Council can add\remove Fellowship member', async ({helper}) => {220    try {221      const newMember = helper.arrange.createEmptyAccount();222223      const proposalAdd = helper.fellowship.collective.addMemberCall(newMember.address);224      const proposalRemove = helper.fellowship.collective.removeMemberCall(newMember.address, fellowshipRankLimit);225      await expect(proposalFromMoreThanHalfCouncil(proposalAdd)).to.be.fulfilled;226      expect(await helper.fellowship.collective.getMembers()).to.be.deep.contain(newMember.address);227      await expect(proposalFromMoreThanHalfCouncil(proposalRemove)).to.be.fulfilled;228      expect(await helper.fellowship.collective.getMembers()).to.be.not.deep.contain(newMember.address);229    }230    finally {231      await clearFellowship(sudoer);232    }233  });234235  itSub('Council can blacklist Democracy proposals', async ({helper}) => {236    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);237    await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash, null))).to.be.fulfilled;238  });239240  itSub('Sudo can blacklist Democracy proposals', async ({helper}) => {241    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);242    await expect(helper.getSudo().democracy.blacklist(sudoer, preimageHash)).to.be.fulfilled;243  });244245  itSub('[Negative] Council cannot add Council member', async ({helper}) => {246    const newCouncilMember = helper.arrange.createEmptyAccount();247    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);248249    await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejected;250  });251252  itSub('[Negative] Council cannot remove Council member', async ({helper}) => {253    const removeMemberProposal = helper.council.membership.removeMemberCall(counselors.alex.address);254255    await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejected;256  });257258  itSub('[Negative] Council cannot submit regular democracy proposal', async ({helper}) => {259    const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);260261    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);262  });263264  itSub('[Negative] Council cannot externally propose SimpleMajority', async ({helper}) => {265    const councilProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));266267    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);268  });269270  itSub('[Negative] Council cannot externally propose SuperMajorityApprove', async ({helper}) => {271    const councilProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));272273    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);274  });275276  itSub('[Negative] Council member cannot add/remove a Council member', async ({helper}) => {277    const newCouncilMember = helper.arrange.createEmptyAccount();278    await expect(helper.council.collective.execute(279      counselors.alex,280      helper.council.membership.addMemberCall(newCouncilMember.address),281    )).to.be.rejectedWith('BadOrigin');282    await expect(helper.council.collective.execute(283      counselors.alex,284      helper.council.membership.removeMemberCall(counselors.charu.address),285    )).to.be.rejectedWith('BadOrigin');286  });287288  itSub('[Negative] Council cannot set/clear Council prime member', async ({helper}) => {289    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);290    const proposalForClear = await helper.council.membership.clearPrimeCall();291292    await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith(/BadOrigin/);293    await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith(/BadOrigin/);294295  });296297  itSub('[Negative] Council member cannot set/clear Council prime member', async ({helper}) => {298    await expect(helper.council.collective.execute(299      counselors.alex,300      helper.council.membership.setPrimeCall(counselors.charu.address),301    )).to.be.rejectedWith('BadOrigin');302    await expect(helper.council.collective.execute(303      counselors.alex,304      helper.council.membership.clearPrimeCall(),305    )).to.be.rejectedWith('BadOrigin');306  });307308  itSub('[Negative] Council member cannot add/remove a TechComm member', async ({helper}) => {309    const newTechCommMember = helper.arrange.createEmptyAccount();310    await expect(helper.council.collective.execute(311      counselors.alex,312      helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address),313    )).to.be.rejectedWith('BadOrigin');314    await expect(helper.council.collective.execute(315      counselors.alex,316      helper.technicalCommittee.membership.removeMemberCall(newTechCommMember.address),317    )).to.be.rejectedWith('BadOrigin');318  });319320  itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {321    const fellowship = await initFellowship(donor, sudoer);322    const memberWithRankOne = fellowship[1][0];323324    await expect(helper.council.collective.execute(325      counselors.alex,326      helper.fellowship.collective.promoteCall(memberWithRankOne.address),327    )).to.be.rejectedWith('BadOrigin');328    await expect(helper.council.collective.execute(329      counselors.alex,330      helper.fellowship.collective.demoteCall(memberWithRankOne.address),331    )).to.be.rejectedWith('BadOrigin');332    await clearFellowship(sudoer);333  });334335  itSub('[Negative] Council cannot fast-track Democracy proposals', async ({helper}) => {336    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);337    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);338339    await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))340      .to.be.rejectedWith(/BadOrigin/);341  });342343  itSub('[Negative] Council member cannot fast-track Democracy proposals', async ({helper}) => {344    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);345    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);346347    await expect(helper.council.collective.execute(348      counselors.alex,349      helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),350    )).to.be.rejectedWith('BadOrigin');351  });352353  itSub('[Negative] Council cannot cancel Democracy proposals', async ({helper}) => {354    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);355    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;356357    await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))358      .to.be.rejectedWith(/BadOrigin/);359  });360361  itSub('[Negative] Council member cannot cancel Democracy proposals', async ({helper}) => {362363    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);364    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;365366    await expect(helper.council.collective.execute(367      counselors.alex,368      helper.democracy.cancelProposalCall(proposalIndex),369    )).to.be.rejectedWith('BadOrigin');370  });371372  itSub('[Negative] Council cannot cancel ongoing Democracy referendums', async ({helper}) => {373    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));374    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);375    const referendumIndex = startedEvent.referendumIndex;376377    await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))378      .to.be.rejectedWith(/BadOrigin/);379  });380381  itSub('[Negative] Council member cannot cancel ongoing Democracy referendums', async ({helper}) => {382    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));383    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);384    const referendumIndex = startedEvent.referendumIndex;385386    await expect(helper.council.collective.execute(387      counselors.alex,388      helper.democracy.emergencyCancelCall(referendumIndex),389    )).to.be.rejectedWith('BadOrigin');390  });391392  itSub('[Negative] Council cannot cancel Fellowship referendums', async ({helper}) => {393    const fellowship = await initFellowship(donor, sudoer);394    const fellowshipProposer = fellowship[5][0];395    const proposal = dummyProposal(helper);396397    const submitResult = await helper.fellowship.referenda.submit(398      fellowshipProposer,399      fellowshipPropositionOrigin,400      proposal,401      defaultEnactmentMoment,402    );403404    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;405406    await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))407      .to.be.rejectedWith(/BadOrigin/);408  });409410  itSub('[Negative] Council member cannot cancel Fellowship referendums', async ({helper}) => {411    const fellowship = await initFellowship(donor, sudoer);412    const fellowshipProposer = fellowship[5][0];413    const proposal = dummyProposal(helper);414415    const submitResult = await helper.fellowship.referenda.submit(416      fellowshipProposer,417      fellowshipPropositionOrigin,418      proposal,419      defaultEnactmentMoment,420    );421    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;422    await expect(helper.council.collective.execute(423      counselors.alex,424      helper.fellowship.referenda.cancelCall(referendumIndex),425    )).to.be.rejectedWith('BadOrigin');426  });427428  itSub('[Negative] Council referendum cannot be closed until the voting threshold is met', async ({helper}) => {429    const councilSize = (await helper.callRpc('api.query.councilMembership.members')).toJSON().length as any as number;430    expect(councilSize).is.greaterThan(1);431    const proposeResult = await helper.council.collective.propose(432      counselors.filip,433      dummyProposalCall(helper),434      councilSize,435    );436437    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);438    const proposalIndex = councilProposedEvent.proposalIndex;439    const proposalHash = councilProposedEvent.proposalHash;440441442    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);443    await expect(helper.council.collective.close(counselors.filip, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');444  });445446});
after · tests/src/governance/council.test.ts
12import {IKeyringPair} from '@polkadot/types/types';3import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util';4import {Event} from '../util/playgrounds/unique.dev';5import {ICounselors, initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util';67describeGov('Governance: Council tests', () => {8  let donor: IKeyringPair;9  let counselors: ICounselors;10  let sudoer: IKeyringPair;1112  const moreThanHalfCouncilThreshold = 3;1314  before(async function() {15    await usingPlaygrounds(async (helper, privateKey) => {16      requirePalletsOrSkip(this, helper, [Pallets.Council]);1718      donor = await privateKey({url: import.meta.url});19      sudoer = await privateKey('//Alice');20    });21  });2223  beforeEach(async () => {24    counselors = await initCouncil(donor, sudoer);25  });2627  afterEach(async () => {28    await clearCouncil(sudoer);29    await clearTechComm(sudoer);30  });3132  async function proposalFromMoreThanHalfCouncil(proposal: any) {33    return await usingPlaygrounds(async (helper) => {34      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);35      const proposeResult = await helper.council.collective.propose(36        counselors.filip,37        proposal,38        moreThanHalfCouncilThreshold,39      );4041      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);42      const proposalIndex = councilProposedEvent.proposalIndex;43      const proposalHash = councilProposedEvent.proposalHash;444546      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);47      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);48      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);4950      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);51    });52  }5354  async function proposalFromAllCouncil(proposal: any) {55    return await usingPlaygrounds(async (helper) => {56      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);57      const proposeResult = await helper.council.collective.propose(58        counselors.filip,59        proposal,60        moreThanHalfCouncilThreshold,61      );6263      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);64      const proposalIndex = councilProposedEvent.proposalIndex;65      const proposalHash = councilProposedEvent.proposalHash;666768      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);69      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);70      await helper.council.collective.vote(counselors.ildar, proposalHash, proposalIndex, true);71      await helper.council.collective.vote(counselors.irina, proposalHash, proposalIndex, true);72      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);7374      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);75    });76  }7778  itSub('>50% of Council can externally propose SuperMajorityAgainst', async ({helper}) => {79    const forceSetBalanceReceiver = helper.arrange.createEmptyAccount();80    const forceSetBalanceTestValue = 20n * 10n ** 25n;8182    const democracyProposal = await helper.constructApiCall('api.tx.balances.forceSetBalance', [83      forceSetBalanceReceiver.address, forceSetBalanceTestValue,84    ]);8586    const councilProposal = await helper.democracy.externalProposeDefaultCall(democracyProposal);8788    const proposeResult = await helper.council.collective.propose(89      counselors.filip,90      councilProposal,91      moreThanHalfCouncilThreshold,92    );9394    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);95    const proposalIndex = councilProposedEvent.proposalIndex;96    const proposalHash = councilProposedEvent.proposalHash;9798    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);99    await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);100    await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);101102    await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);103104    const democracyStartedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);105    const democracyReferendumIndex = democracyStartedEvent.referendumIndex;106    const democracyThreshold = democracyStartedEvent.threshold;107108    expect(democracyThreshold).to.be.equal('SuperMajorityAgainst');109110    await helper.democracy.vote(counselors.filip, democracyReferendumIndex, {111      Standard: {112        vote: {113          aye: true,114          conviction: 1,115        },116        balance: 10_000n,117      },118    });119120    await helper.democracy.vote(counselors.charu, democracyReferendumIndex, {121      Standard: {122        vote: {123          aye: false,124          conviction: 1,125        },126        balance: 50_000n,127      },128    });129130    const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);131    expect(passedReferendumEvent.referendumIndex).to.be.equal(democracyReferendumIndex);132133    await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);134    const receiverBalance = await helper.balance.getSubstrate(forceSetBalanceReceiver.address);135    expect(receiverBalance).to.be.equal(forceSetBalanceTestValue);136  });137138  itSub('Council prime member vote is the default', async ({helper}) => {139    const newTechCommMember = helper.arrange.createEmptyAccount();140    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);141    const proposeResult = await helper.council.collective.propose(142      counselors.filip,143      addMemberProposal,144      moreThanHalfCouncilThreshold,145    );146147    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);148    const proposalIndex = councilProposedEvent.proposalIndex;149    const proposalHash = councilProposedEvent.proposalHash;150151    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);152153    await helper.wait.newBlocks(councilMotionDuration);154    const closeResult = await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);155    const closeEvent = Event.Council.Closed.expect(closeResult);156    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as string[];157    expect(closeEvent.yes).to.be.equal(members.length);158  });159160  itSub('Superuser can add a member', async ({helper}) => {161    const newMember = helper.arrange.createEmptyAccount();162    await expect(helper.getSudo().council.membership.addMember(sudoer, newMember.address)).to.be.fulfilled;163164    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();165    expect(members).to.contains(newMember.address);166  });167168  itSub('Superuser can remove a member', async ({helper}) => {169    await expect(helper.getSudo().council.membership.removeMember(sudoer, counselors.alex.address)).to.be.fulfilled;170171    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();172    expect(members).to.not.contains(counselors.alex.address);173  });174175  itSub('>50% Council can add TechComm member', async ({helper}) => {176    const newTechCommMember = helper.arrange.createEmptyAccount();177    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);178179    await proposalFromMoreThanHalfCouncil(addMemberProposal);180181    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();182    expect(techCommMembers).to.contains(newTechCommMember.address);183  });184185  itSub('Council can remove TechComm member', async ({helper}) => {186    const techComm = await initTechComm(donor, sudoer);187    const removeMemberPrpoposal = helper.technicalCommittee.membership.removeMemberCall(techComm.andy.address);188    await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);189190    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();191    expect(techCommMembers).to.not.contains(techComm.andy.address);192  });193194  itSub.skip('Council member can add Fellowship member', async ({helper}) => {195    const newFellowshipMember = helper.arrange.createEmptyAccount();196    await expect(helper.council.collective.execute(197      counselors.alex,198      helper.fellowship.collective.addMemberCall(newFellowshipMember.address),199    )).to.be.fulfilled;200    const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();201    expect(fellowshipMembers).to.contains(newFellowshipMember.address);202  });203204  itSub('>50% Council can promote Fellowship member', async ({helper}) => {205    const fellowship = await initFellowship(donor, sudoer);206    const memberWithZeroRank = fellowship[0][0];207208    const proposal = helper.fellowship.collective.promoteCall(memberWithZeroRank.address);209    await proposalFromMoreThanHalfCouncil(proposal);210    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithZeroRank.address])).toJSON();211    expect(record).to.be.deep.equal({rank: 1});212213    await clearFellowship(sudoer);214  });215216  itSub('>50% Council can demote Fellowship member', async ({helper}) => {217    const fellowship = await initFellowship(donor, sudoer);218    const memberWithRankOne = fellowship[1][0];219220    const proposal = helper.fellowship.collective.demoteCall(memberWithRankOne.address);221    await proposalFromMoreThanHalfCouncil(proposal);222223    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithRankOne.address])).toJSON();224    expect(record).to.be.deep.equal({rank: 0});225226    await clearFellowship(sudoer);227  });228229  itSub('>50% Council can add\remove Fellowship member', async ({helper}) => {230    try {231      const newMember = helper.arrange.createEmptyAccount();232233      const proposalAdd = helper.fellowship.collective.addMemberCall(newMember.address);234      const proposalRemove = helper.fellowship.collective.removeMemberCall(newMember.address, fellowshipRankLimit);235      await expect(proposalFromMoreThanHalfCouncil(proposalAdd)).to.be.fulfilled;236      expect(await helper.fellowship.collective.getMembers()).to.be.deep.contain(newMember.address);237      await expect(proposalFromMoreThanHalfCouncil(proposalRemove)).to.be.fulfilled;238      expect(await helper.fellowship.collective.getMembers()).to.be.not.deep.contain(newMember.address);239    }240    finally {241      await clearFellowship(sudoer);242    }243  });244245  itSub('Council can blacklist Democracy proposals', async ({helper}) => {246    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);247    await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash, null))).to.be.fulfilled;248  });249250  itSub('Sudo can blacklist Democracy proposals', async ({helper}) => {251    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);252    await expect(helper.getSudo().democracy.blacklist(sudoer, preimageHash)).to.be.fulfilled;253  });254255  itSub('[Negative] Council cannot add Council member', async ({helper}) => {256    const newCouncilMember = helper.arrange.createEmptyAccount();257    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);258259    await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejected;260  });261262  itSub('[Negative] Council cannot remove Council member', async ({helper}) => {263    const removeMemberProposal = helper.council.membership.removeMemberCall(counselors.alex.address);264265    await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejected;266  });267268  itSub('[Negative] Council cannot submit regular democracy proposal', async ({helper}) => {269    const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);270271    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);272  });273274  itSub('[Negative] Council cannot externally propose SimpleMajority', async ({helper}) => {275    const councilProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));276277    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);278  });279280  itSub('[Negative] Council cannot externally propose SuperMajorityApprove', async ({helper}) => {281    const councilProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));282283    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);284  });285286  itSub('[Negative] Council member cannot add/remove a Council member', async ({helper}) => {287    const newCouncilMember = helper.arrange.createEmptyAccount();288    await expect(helper.council.collective.execute(289      counselors.alex,290      helper.council.membership.addMemberCall(newCouncilMember.address),291    )).to.be.rejectedWith('BadOrigin');292    await expect(helper.council.collective.execute(293      counselors.alex,294      helper.council.membership.removeMemberCall(counselors.charu.address),295    )).to.be.rejectedWith('BadOrigin');296  });297298  itSub('[Negative] Council cannot set/clear Council prime member', async ({helper}) => {299    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);300    const proposalForClear = await helper.council.membership.clearPrimeCall();301302    await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith(/BadOrigin/);303    await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith(/BadOrigin/);304305  });306307  itSub('[Negative] Council member cannot set/clear Council prime member', async ({helper}) => {308    await expect(helper.council.collective.execute(309      counselors.alex,310      helper.council.membership.setPrimeCall(counselors.charu.address),311    )).to.be.rejectedWith('BadOrigin');312    await expect(helper.council.collective.execute(313      counselors.alex,314      helper.council.membership.clearPrimeCall(),315    )).to.be.rejectedWith('BadOrigin');316  });317318  itSub('[Negative] Council member cannot add/remove a TechComm member', async ({helper}) => {319    const newTechCommMember = helper.arrange.createEmptyAccount();320    await expect(helper.council.collective.execute(321      counselors.alex,322      helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address),323    )).to.be.rejectedWith('BadOrigin');324    await expect(helper.council.collective.execute(325      counselors.alex,326      helper.technicalCommittee.membership.removeMemberCall(newTechCommMember.address),327    )).to.be.rejectedWith('BadOrigin');328  });329330  itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {331    const fellowship = await initFellowship(donor, sudoer);332    const memberWithRankOne = fellowship[1][0];333334    await expect(helper.council.collective.execute(335      counselors.alex,336      helper.fellowship.collective.promoteCall(memberWithRankOne.address),337    )).to.be.rejectedWith('BadOrigin');338    await expect(helper.council.collective.execute(339      counselors.alex,340      helper.fellowship.collective.demoteCall(memberWithRankOne.address),341    )).to.be.rejectedWith('BadOrigin');342    await clearFellowship(sudoer);343  });344345  itSub('[Negative] Council cannot fast-track Democracy proposals', async ({helper}) => {346    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);347    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);348349    await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))350      .to.be.rejectedWith(/BadOrigin/);351  });352353  itSub('[Negative] Council member cannot fast-track Democracy proposals', async ({helper}) => {354    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);355    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);356357    await expect(helper.council.collective.execute(358      counselors.alex,359      helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),360    )).to.be.rejectedWith('BadOrigin');361  });362363  itSub('[Negative] Council cannot cancel Democracy proposals', async ({helper}) => {364    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);365    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;366367    await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))368      .to.be.rejectedWith(/BadOrigin/);369  });370371  itSub('[Negative] Council member cannot cancel Democracy proposals', async ({helper}) => {372373    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);374    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;375376    await expect(helper.council.collective.execute(377      counselors.alex,378      helper.democracy.cancelProposalCall(proposalIndex),379    )).to.be.rejectedWith('BadOrigin');380  });381382  itSub('[Negative] Council cannot cancel ongoing Democracy referendums', async ({helper}) => {383    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));384    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);385    const referendumIndex = startedEvent.referendumIndex;386387    await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))388      .to.be.rejectedWith(/BadOrigin/);389  });390391  itSub('[Negative] Council member cannot cancel ongoing Democracy referendums', async ({helper}) => {392    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));393    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);394    const referendumIndex = startedEvent.referendumIndex;395396    await expect(helper.council.collective.execute(397      counselors.alex,398      helper.democracy.emergencyCancelCall(referendumIndex),399    )).to.be.rejectedWith('BadOrigin');400  });401402  itSub('[Negative] Council cannot cancel Fellowship referendums', async ({helper}) => {403    const fellowship = await initFellowship(donor, sudoer);404    const fellowshipProposer = fellowship[5][0];405    const proposal = dummyProposal(helper);406407    const submitResult = await helper.fellowship.referenda.submit(408      fellowshipProposer,409      fellowshipPropositionOrigin,410      proposal,411      defaultEnactmentMoment,412    );413414    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;415416    await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))417      .to.be.rejectedWith(/BadOrigin/);418  });419420  itSub('[Negative] Council member cannot cancel Fellowship referendums', async ({helper}) => {421    const fellowship = await initFellowship(donor, sudoer);422    const fellowshipProposer = fellowship[5][0];423    const proposal = dummyProposal(helper);424425    const submitResult = await helper.fellowship.referenda.submit(426      fellowshipProposer,427      fellowshipPropositionOrigin,428      proposal,429      defaultEnactmentMoment,430    );431    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;432    await expect(helper.council.collective.execute(433      counselors.alex,434      helper.fellowship.referenda.cancelCall(referendumIndex),435    )).to.be.rejectedWith('BadOrigin');436  });437438  itSub('[Negative] Council referendum cannot be closed until the voting threshold is met', async ({helper}) => {439    const councilSize = (await helper.callRpc('api.query.councilMembership.members')).toJSON().length as any as number;440    expect(councilSize).is.greaterThan(1);441    const proposeResult = await helper.council.collective.propose(442      counselors.filip,443      dummyProposalCall(helper),444      councilSize,445    );446447    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);448    const proposalIndex = councilProposedEvent.proposalIndex;449    const proposalHash = councilProposedEvent.proposalHash;450451452    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);453    await expect(helper.council.collective.close(counselors.filip, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');454  });455456});