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

difftreelog

source

tests/src/governance/fellowship.test.ts14.3 KiBsourcehistory
1import {IKeyringPair} from '@polkadot/types/types';2import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util';3import {DevUniqueHelper, Event} from '../util/playgrounds/unique.dev';4import {ICounselors, initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, ITechComms, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, voteUnanimouslyInFellowship, democracyTrackMinRank, fellowshipPreparePeriod, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, democracyTrackId, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util';56describeGov('Governance: Fellowship tests', () => {7  let members: IKeyringPair[][];89  let rank1Proposer: IKeyringPair;1011  let sudoer: any;12  let donor: any;13  let counselors: ICounselors;14  let techcomms: ITechComms;1516  const submissionDeposit = 1000n;1718  async function testBadFellowshipProposal(19    helper: DevUniqueHelper,20    proposalCall: any,21  ) {22    const badProposal = {23      Inline: proposalCall.method.toHex(),24    };25    const submitResult = await helper.fellowship.referenda.submit(26      rank1Proposer,27      fellowshipPropositionOrigin,28      badProposal,29      defaultEnactmentMoment,30    );3132    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;33    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, referendumIndex);34    await helper.fellowship.referenda.placeDecisionDeposit(donor, referendumIndex);3536    const enactmentId = await helper.fellowship.referenda.enactmentEventId(referendumIndex);37    const dispatchedEvent = await helper.wait.expectEvent(38      fellowshipPreparePeriod + fellowshipConfirmPeriod + defaultEnactmentMoment.After,39      Event.Scheduler.Dispatched,40      (event: any) => event.id == enactmentId,41    );4243    expect(dispatchedEvent.result.isErr, 'Bad Fellowship must fail')44      .to.be.true;4546    expect(dispatchedEvent.result.asErr.isBadOrigin, 'Bad Fellowship must fail with BadOrigin')47      .to.be.true;48  }4950  before(async function() {51    await usingPlaygrounds(async (helper, privateKey) => {52      requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Fellowship, Pallets.TechnicalCommittee, Pallets.Council]);5354      sudoer = await privateKey('//Alice');55      donor = await privateKey({url: import.meta.url});56    });5758    counselors = await initCouncil(donor, sudoer);59    techcomms = await initTechComm(donor, sudoer);60    members = await initFellowship(donor, sudoer);6162    rank1Proposer = members[1][0];63  });6465  after(async () => {66    await clearFellowship(sudoer);67    await clearTechComm(sudoer);68    await clearCouncil(sudoer);69    await hardResetFellowshipReferenda(sudoer);70    await hardResetDemocracy(sudoer);71    await hardResetGovScheduler(sudoer);72  });7374  itSub('FellowshipProposition can submit regular Democracy proposals', async ({helper}) => {75    const democracyProposalCall = dummyProposalCall(helper);76    const fellowshipProposal = {77      Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),78    };7980    const submitResult = await helper.fellowship.referenda.submit(81      rank1Proposer,82      fellowshipPropositionOrigin,83      fellowshipProposal,84      defaultEnactmentMoment,85    );8687    const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;88    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, fellowshipReferendumIndex);89    await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);9091    const democracyProposed = await helper.wait.expectEvent(92      fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,93      Event.Democracy.Proposed,94    );9596    const democracyEnqueuedProposal = await helper.democracy.expectPublicProposal(democracyProposed.proposalIndex);97    expect(democracyEnqueuedProposal.inline, 'Fellowship proposal expected to be in the Democracy')98      .to.be.equal(democracyProposalCall.method.toHex());99100    await helper.wait.newBlocks(democracyVotingPeriod);101  });102103  itSub('Fellowship (rank-1 or greater) member can submit Fellowship proposals on the Democracy track', async ({helper}) => {104    for(let rank = 1; rank < fellowshipRankLimit; rank++) {105      const rankMembers = members[rank];106107      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {108        const member = rankMembers[memberIdx];109        const newDummyProposal = dummyProposal(helper);110111        const submitResult = await helper.fellowship.referenda.submit(112          member,113          fellowshipPropositionOrigin,114          newDummyProposal,115          defaultEnactmentMoment,116        );117118        const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;119        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);120        expect(referendumInfo.ongoing.track, `${memberIdx}-th member of rank #${rank}: proposal #${referendumIndex} is on invalid track`)121          .to.be.equal(democracyTrackId);122      }123    }124  });125126  itSub(`Fellowship (rank-${democracyTrackMinRank} or greater) members can vote on the Democracy track`, async ({helper}) => {127    const proposal = dummyProposal(helper);128129    const submitResult = await helper.fellowship.referenda.submit(130      rank1Proposer,131      fellowshipPropositionOrigin,132      proposal,133      defaultEnactmentMoment,134    );135136    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;137138    let expectedAyes = 0;139    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {140      const rankMembers = members[rank];141142      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {143        const member = rankMembers[memberIdx];144        await helper.fellowship.collective.vote(member, referendumIndex, true);145        expectedAyes += 1;146147        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);148        expect(referendumInfo.ongoing.tally.bareAyes, `Vote from ${memberIdx}-th member of rank #${rank} isn't accounted`)149          .to.be.equal(expectedAyes);150      }151    }152  });153154  itSub('Fellowship rank vote strength is correct', async ({helper}) => {155    const excessRankWeightTable = [156      1,157      3,158      6,159      10,160      15,161      21,162    ];163164    const proposal = dummyProposal(helper);165166    const submitResult = await helper.fellowship.referenda.submit(167      rank1Proposer,168      fellowshipPropositionOrigin,169      proposal,170      defaultEnactmentMoment,171    );172173    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;174175    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {176      const rankMembers = members[rank];177178      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {179        const member = rankMembers[memberIdx];180181        const referendumInfoBefore = await helper.fellowship.referenda.referendumInfo(referendumIndex);182        const ayesBefore = referendumInfoBefore.ongoing.tally.ayes;183184        await helper.fellowship.collective.vote(member, referendumIndex, true);185186        const referendumInfoAfter = await helper.fellowship.referenda.referendumInfo(referendumIndex);187        const ayesAfter = referendumInfoAfter.ongoing.tally.ayes;188189        const expectedVoteWeight = excessRankWeightTable[rank - democracyTrackMinRank];190        const voteWeight = ayesAfter - ayesBefore;191192        expect(voteWeight, `Vote weight of ${memberIdx}-th member of rank #${rank} is invalid`)193          .to.be.equal(expectedVoteWeight);194      }195    }196  });197198  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityAgainst', async ({helper}) => {199    await testBadFellowshipProposal(helper, helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper)));200  });201202  itSub('[Negative] FellowshipProposition cannot externally propose SimpleMajority', async ({helper}) => {203    await testBadFellowshipProposal(helper, helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper)));204  });205206  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityApprove', async ({helper}) => {207    await testBadFellowshipProposal(helper, helper.democracy.externalProposeCall(dummyProposalCall(helper)));208  });209210  itSub('[Negative] Fellowship (rank-0) member cannot submit Fellowship proposals on the Democracy track', async ({helper}) => {211    const rank0Proposer = members[0][0];212213    const proposal = dummyProposal(helper);214215    const submitResult = helper.fellowship.referenda.submit(216      rank0Proposer,217      fellowshipPropositionOrigin,218      proposal,219      defaultEnactmentMoment,220    );221222    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);223  });224225  itSub('[Negative] Fellowship (rank-1 or greater) member cannot submit if no deposit can be provided', async ({helper}) => {226    const poorMember = rank1Proposer;227228    const balanceBefore = await helper.balance.getSubstrate(poorMember.address);229    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, submissionDeposit - 1n);230231    const proposal = dummyProposal(helper);232233    const submitResult = helper.fellowship.referenda.submit(234      poorMember,235      fellowshipPropositionOrigin,236      proposal,237      defaultEnactmentMoment,238    );239240    await expect(submitResult).to.be.rejectedWith(/account balance too low/);241242    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, balanceBefore);243  });244245  itSub(`[Negative] Fellowship (rank-${democracyTrackMinRank - 1} or less) members cannot vote on the Democracy track`, async ({helper}) => {246    const proposal = dummyProposal(helper);247248    const submitResult = await helper.fellowship.referenda.submit(249      rank1Proposer,250      fellowshipPropositionOrigin,251      proposal,252      defaultEnactmentMoment,253    );254255    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;256257    for(let rank = 0; rank < democracyTrackMinRank; rank++) {258      for(const member of members[rank]) {259        const voteResult = helper.fellowship.collective.vote(member, referendumIndex, true);260        await expect(voteResult).to.be.rejectedWith(/RankTooLow/);261      }262    }263  });264265  itSub('[Negative] FellowshipProposition cannot add/remove a Council member', async ({helper}) => {266    const [councilNonMember] = await helper.arrange.createAccounts([10n], donor);267268    await testBadFellowshipProposal(helper, helper.council.membership.addMemberCall(councilNonMember.address));269    await testBadFellowshipProposal(helper, helper.council.membership.removeMemberCall(counselors.ildar.address));270  });271272  itSub('[Negative] FellowshipProposition cannot set/clear Council prime member', async ({helper}) => {273    await testBadFellowshipProposal(helper, helper.council.membership.setPrimeCall(counselors.ildar.address));274    await testBadFellowshipProposal(helper, helper.council.membership.clearPrimeCall());275  });276277  itSub('[Negative] FellowshipProposition cannot add/remove a TechComm member', async ({helper}) => {278    const [techCommNonMember] = await helper.arrange.createAccounts([10n], donor);279280    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.addMemberCall(techCommNonMember.address));281    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.removeMemberCall(techcomms.constantine.address));282  });283284  itSub('[Negative] FellowshipProposition cannot add/remove a Fellowship member', async ({helper}) => {285    const [fellowshipNonMember] = await helper.arrange.createAccounts([10n], donor);286287    await testBadFellowshipProposal(helper, helper.fellowship.collective.addMemberCall(fellowshipNonMember.address));288    await testBadFellowshipProposal(helper, helper.fellowship.collective.removeMemberCall(rank1Proposer.address, 1));289  });290291  itSub('[Negative] FellowshipProposition cannot promote/demote a Fellowship member', async ({helper}) => {292    await testBadFellowshipProposal(helper, helper.fellowship.collective.promoteCall(rank1Proposer.address));293    await testBadFellowshipProposal(helper, helper.fellowship.collective.demoteCall(rank1Proposer.address));294  });295296  itSub('[Negative] FellowshipProposition cannot fast-track Democracy proposals', async ({helper}) => {297    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);298299    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);300301    await testBadFellowshipProposal(helper, helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));302  });303304  itSub('[Negative] FellowshipProposition cannot cancel Democracy proposals', async ({helper}) => {305    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);306    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;307308    await testBadFellowshipProposal(helper, helper.democracy.cancelProposalCall(proposalIndex));309  });310311  itSub('[Negative] FellowshipProposition cannot cancel ongoing Democracy referendums', async ({helper}) => {312    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));313    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);314    const referendumIndex = startedEvent.referendumIndex;315316    await testBadFellowshipProposal(helper, helper.democracy.emergencyCancelCall(referendumIndex));317  });318319  itSub('[Negative] FellowshipProposition cannot blacklist Democracy proposals', async ({helper}) => {320    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);321322    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);323324    await testBadFellowshipProposal(helper, helper.democracy.blacklistCall(preimageHash, null));325  });326327  itSub('[Negative] FellowshipProposition cannot veto external proposals', async ({helper}) => {328    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);329330    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);331332    await testBadFellowshipProposal(helper, helper.democracy.vetoExternalCall(preimageHash));333  });334});