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

difftreelog

source

js-packages/tests/sub/governance/fellowship.test.ts14.3 KiBsourcehistory
1import type {IKeyringPair} from '@polkadot/types/types';2import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '@unique/test-utils/util.js';3import {DevUniqueHelper, Event} from '@unique/test-utils';4import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, voteUnanimouslyInFellowship, democracyTrackMinRank, fellowshipPreparePeriod, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, democracyTrackId, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';5import type {ICounselors, ITechComms} from './util.js';67describeGov('Governance: Fellowship tests', () => {8  let members: IKeyringPair[][];910  let rank1Proposer: IKeyringPair;1112  let sudoer: any;13  let donor: any;14  let counselors: ICounselors;15  let techcomms: ITechComms;1617  const submissionDeposit = 1000n;1819  async function testBadFellowshipProposal(20    helper: DevUniqueHelper,21    proposalCall: any,22  ) {23    const badProposal = {24      Inline: proposalCall.method.toHex(),25    };26    const submitResult = await helper.fellowship.referenda.submit(27      rank1Proposer,28      fellowshipPropositionOrigin,29      badProposal,30      defaultEnactmentMoment,31    );3233    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;34    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, referendumIndex);35    await helper.fellowship.referenda.placeDecisionDeposit(donor, referendumIndex);3637    const enactmentId = await helper.fellowship.referenda.enactmentEventId(referendumIndex);38    const dispatchedEvent = await helper.wait.expectEvent(39      fellowshipPreparePeriod + fellowshipConfirmPeriod + defaultEnactmentMoment.After,40      Event.Scheduler.Dispatched,41      (event: any) => event.id == enactmentId,42    );4344    expect(dispatchedEvent.result.isErr, 'Bad Fellowship must fail')45      .to.be.true;4647    expect(dispatchedEvent.result.asErr.isBadOrigin, 'Bad Fellowship must fail with BadOrigin')48      .to.be.true;49  }5051  before(async function() {52    await usingPlaygrounds(async (helper, privateKey) => {53      requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Fellowship, Pallets.TechnicalCommittee, Pallets.Council]);5455      sudoer = await privateKey('//Alice');56      donor = await privateKey({url: import.meta.url});57    });5859    counselors = await initCouncil(donor, sudoer);60    techcomms = await initTechComm(donor, sudoer);61    members = await initFellowship(donor, sudoer);6263    rank1Proposer = members[1][0];64  });6566  after(async () => {67    await clearFellowship(sudoer);68    await clearTechComm(sudoer);69    await clearCouncil(sudoer);70    await hardResetFellowshipReferenda(sudoer);71    await hardResetDemocracy(sudoer);72    await hardResetGovScheduler(sudoer);73  });7475  itSub('FellowshipProposition can submit regular Democracy proposals', async ({helper}) => {76    const democracyProposalCall = dummyProposalCall(helper);77    const fellowshipProposal = {78      Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),79    };8081    const submitResult = await helper.fellowship.referenda.submit(82      rank1Proposer,83      fellowshipPropositionOrigin,84      fellowshipProposal,85      defaultEnactmentMoment,86    );8788    const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;89    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, fellowshipReferendumIndex);90    await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);9192    const democracyProposed = await helper.wait.expectEvent(93      fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,94      Event.Democracy.Proposed,95    );9697    const democracyEnqueuedProposal = await helper.democracy.expectPublicProposal(democracyProposed.proposalIndex);98    expect(democracyEnqueuedProposal.inline, 'Fellowship proposal expected to be in the Democracy')99      .to.be.equal(democracyProposalCall.method.toHex());100101    await helper.wait.newBlocks(democracyVotingPeriod);102  });103104  itSub('Fellowship (rank-1 or greater) member can submit Fellowship proposals on the Democracy track', async ({helper}) => {105    for(let rank = 1; rank < fellowshipRankLimit; rank++) {106      const rankMembers = members[rank];107108      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {109        const member = rankMembers[memberIdx];110        const newDummyProposal = dummyProposal(helper);111112        const submitResult = await helper.fellowship.referenda.submit(113          member,114          fellowshipPropositionOrigin,115          newDummyProposal,116          defaultEnactmentMoment,117        );118119        const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;120        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);121        expect(referendumInfo.ongoing.track, `${memberIdx}-th member of rank #${rank}: proposal #${referendumIndex} is on invalid track`)122          .to.be.equal(democracyTrackId);123      }124    }125  });126127  itSub(`Fellowship (rank-${democracyTrackMinRank} or greater) members can vote on the Democracy track`, async ({helper}) => {128    const proposal = dummyProposal(helper);129130    const submitResult = await helper.fellowship.referenda.submit(131      rank1Proposer,132      fellowshipPropositionOrigin,133      proposal,134      defaultEnactmentMoment,135    );136137    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;138139    let expectedAyes = 0;140    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {141      const rankMembers = members[rank];142143      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {144        const member = rankMembers[memberIdx];145        await helper.fellowship.collective.vote(member, referendumIndex, true);146        expectedAyes += 1;147148        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);149        expect(referendumInfo.ongoing.tally.bareAyes, `Vote from ${memberIdx}-th member of rank #${rank} isn't accounted`)150          .to.be.equal(expectedAyes);151      }152    }153  });154155  itSub('Fellowship rank vote strength is correct', async ({helper}) => {156    const excessRankWeightTable = [157      1,158      3,159      6,160      10,161      15,162      21,163    ];164165    const proposal = dummyProposal(helper);166167    const submitResult = await helper.fellowship.referenda.submit(168      rank1Proposer,169      fellowshipPropositionOrigin,170      proposal,171      defaultEnactmentMoment,172    );173174    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;175176    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {177      const rankMembers = members[rank];178179      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {180        const member = rankMembers[memberIdx];181182        const referendumInfoBefore = await helper.fellowship.referenda.referendumInfo(referendumIndex);183        const ayesBefore = referendumInfoBefore.ongoing.tally.ayes;184185        await helper.fellowship.collective.vote(member, referendumIndex, true);186187        const referendumInfoAfter = await helper.fellowship.referenda.referendumInfo(referendumIndex);188        const ayesAfter = referendumInfoAfter.ongoing.tally.ayes;189190        const expectedVoteWeight = excessRankWeightTable[rank - democracyTrackMinRank];191        const voteWeight = ayesAfter - ayesBefore;192193        expect(voteWeight, `Vote weight of ${memberIdx}-th member of rank #${rank} is invalid`)194          .to.be.equal(expectedVoteWeight);195      }196    }197  });198199  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityAgainst', async ({helper}) => {200    await testBadFellowshipProposal(helper, helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper)));201  });202203  itSub('[Negative] FellowshipProposition cannot externally propose SimpleMajority', async ({helper}) => {204    await testBadFellowshipProposal(helper, helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper)));205  });206207  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityApprove', async ({helper}) => {208    await testBadFellowshipProposal(helper, helper.democracy.externalProposeCall(dummyProposalCall(helper)));209  });210211  itSub('[Negative] Fellowship (rank-0) member cannot submit Fellowship proposals on the Democracy track', async ({helper}) => {212    const rank0Proposer = members[0][0];213214    const proposal = dummyProposal(helper);215216    const submitResult = helper.fellowship.referenda.submit(217      rank0Proposer,218      fellowshipPropositionOrigin,219      proposal,220      defaultEnactmentMoment,221    );222223    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);224  });225226  itSub('[Negative] Fellowship (rank-1 or greater) member cannot submit if no deposit can be provided', async ({helper}) => {227    const poorMember = rank1Proposer;228229    const balanceBefore = await helper.balance.getSubstrate(poorMember.address);230    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, submissionDeposit - 1n);231232    const proposal = dummyProposal(helper);233234    const submitResult = helper.fellowship.referenda.submit(235      poorMember,236      fellowshipPropositionOrigin,237      proposal,238      defaultEnactmentMoment,239    );240241    await expect(submitResult).to.be.rejectedWith(/account balance too low/);242243    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, balanceBefore);244  });245246  itSub(`[Negative] Fellowship (rank-${democracyTrackMinRank - 1} or less) members cannot vote on the Democracy track`, async ({helper}) => {247    const proposal = dummyProposal(helper);248249    const submitResult = await helper.fellowship.referenda.submit(250      rank1Proposer,251      fellowshipPropositionOrigin,252      proposal,253      defaultEnactmentMoment,254    );255256    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;257258    for(let rank = 0; rank < democracyTrackMinRank; rank++) {259      for(const member of members[rank]) {260        const voteResult = helper.fellowship.collective.vote(member, referendumIndex, true);261        await expect(voteResult).to.be.rejectedWith(/RankTooLow/);262      }263    }264  });265266  itSub('[Negative] FellowshipProposition cannot add/remove a Council member', async ({helper}) => {267    const [councilNonMember] = await helper.arrange.createAccounts([10n], donor);268269    await testBadFellowshipProposal(helper, helper.council.membership.addMemberCall(councilNonMember.address));270    await testBadFellowshipProposal(helper, helper.council.membership.removeMemberCall(counselors.ildar.address));271  });272273  itSub('[Negative] FellowshipProposition cannot set/clear Council prime member', async ({helper}) => {274    await testBadFellowshipProposal(helper, helper.council.membership.setPrimeCall(counselors.ildar.address));275    await testBadFellowshipProposal(helper, helper.council.membership.clearPrimeCall());276  });277278  itSub('[Negative] FellowshipProposition cannot add/remove a TechComm member', async ({helper}) => {279    const [techCommNonMember] = await helper.arrange.createAccounts([10n], donor);280281    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.addMemberCall(techCommNonMember.address));282    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.removeMemberCall(techcomms.constantine.address));283  });284285  itSub('[Negative] FellowshipProposition cannot add/remove a Fellowship member', async ({helper}) => {286    const [fellowshipNonMember] = await helper.arrange.createAccounts([10n], donor);287288    await testBadFellowshipProposal(helper, helper.fellowship.collective.addMemberCall(fellowshipNonMember.address));289    await testBadFellowshipProposal(helper, helper.fellowship.collective.removeMemberCall(rank1Proposer.address, 1));290  });291292  itSub('[Negative] FellowshipProposition cannot promote/demote a Fellowship member', async ({helper}) => {293    await testBadFellowshipProposal(helper, helper.fellowship.collective.promoteCall(rank1Proposer.address));294    await testBadFellowshipProposal(helper, helper.fellowship.collective.demoteCall(rank1Proposer.address));295  });296297  itSub('[Negative] FellowshipProposition cannot fast-track Democracy proposals', async ({helper}) => {298    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);299300    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);301302    await testBadFellowshipProposal(helper, helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));303  });304305  itSub('[Negative] FellowshipProposition cannot cancel Democracy proposals', async ({helper}) => {306    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);307    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;308309    await testBadFellowshipProposal(helper, helper.democracy.cancelProposalCall(proposalIndex));310  });311312  itSub('[Negative] FellowshipProposition cannot cancel ongoing Democracy referendums', async ({helper}) => {313    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));314    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);315    const referendumIndex = startedEvent.referendumIndex;316317    await testBadFellowshipProposal(helper, helper.democracy.emergencyCancelCall(referendumIndex));318  });319320  itSub('[Negative] FellowshipProposition cannot blacklist Democracy proposals', async ({helper}) => {321    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);322323    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);324325    await testBadFellowshipProposal(helper, helper.democracy.blacklistCall(preimageHash, null));326  });327328  itSub('[Negative] FellowshipProposition cannot veto external proposals', async ({helper}) => {329    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);330331    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);332333    await testBadFellowshipProposal(helper, helper.democracy.vetoExternalCall(preimageHash));334  });335});