1import type {IKeyringPair} from '@polkadot/types/types';2import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '@unique/test-utils/util.js';3import {Event} from '@unique/test-utils';4import {democracyFastTrackVotingPeriod, IFinCounselors, clearTechComm, dummyProposalCall, initFinCouncil, clearFinCouncil, democracyLaunchPeriod, initFellowship, dummyProposal, fellowshipPropositionOrigin, defaultEnactmentMoment, initCouncil, clearCouncil, clearFellowship} from './util.js';567describeGov('Governance: Financial Council tests', () => {8 let donor: IKeyringPair;9 let finCounselors: IFinCounselors;10 let sudoer: IKeyringPair;1112 const moreThanHalfCouncilThreshold = 2;1314 before(async function() {15 await usingPlaygrounds(async (helper, privateKey) => {16 requirePalletsOrSkip(this, helper, [Pallets.FinancialCouncil]);17 sudoer = await privateKey('//Alice');18 donor = await privateKey({url: import.meta.url});19 });20 });2122 beforeEach(async () => {23 finCounselors = await initFinCouncil(donor, sudoer);24 });2526 afterEach(async () => {27 await clearFinCouncil(sudoer);28 await clearTechComm(sudoer);29 });3031 async function proposalFromMoreThanHalfCouncil(proposal: any) {32 return await usingPlaygrounds(async (helper) => {33 expect((await helper.finCouncil.membership.getMembers()).length).to.be.equal(3);34 const proposeResult = await helper.finCouncil.collective.propose(35 finCounselors.ildar,36 proposal,37 moreThanHalfCouncilThreshold,38 );3940 const councilProposedEvent = Event.FinCouncil.Proposed.expect(proposeResult);41 const proposalIndex = councilProposedEvent.proposalIndex;42 const proposalHash = councilProposedEvent.proposalHash;4344 await helper.finCouncil.collective.vote(finCounselors.greg, proposalHash, proposalIndex, true);45 await helper.finCouncil.collective.vote(finCounselors.ildar, proposalHash, proposalIndex, true);4647 return await helper.finCouncil.collective.close(finCounselors.ildar, proposalHash, proposalIndex);48 });49 }5051 async function proposalFromAllCouncil(proposal: any) {52 return await usingPlaygrounds(async (helper) => {53 expect((await helper.finCouncil.membership.getMembers()).length).to.be.equal(3);54 const proposeResult = await helper.finCouncil.collective.propose(55 finCounselors.ildar,56 proposal,57 moreThanHalfCouncilThreshold,58 );5960 const councilProposedEvent = Event.FinCouncil.Proposed.expect(proposeResult);61 const proposalIndex = councilProposedEvent.proposalIndex;62 const proposalHash = councilProposedEvent.proposalHash;6364 await helper.finCouncil.collective.vote(finCounselors.greg, proposalHash, proposalIndex, true);65 await helper.finCouncil.collective.vote(finCounselors.ildar, proposalHash, proposalIndex, true);66 await helper.finCouncil.collective.vote(finCounselors.andy, proposalHash, proposalIndex, true);6768 return await helper.finCouncil.collective.close(finCounselors.andy, proposalHash, proposalIndex);69 });70 }7172 itSub('FinCouncil member can register foreign asset', async ({helper}) => {73 const location = {74 parents: 1,75 interior: {X3: [76 {77 Parachain: 1000,78 },79 {80 PalletInstance: 50,81 },82 {83 GeneralIndex: 1984,84 },85 ]},86 };87 const assetId = {Concrete: location};8889 const registerForeignAssetCall = helper.constructApiCall(90 'api.tx.foreignAssets.forceRegisterForeignAsset',91 [{V3: assetId}, helper.util.str2vec('New Asset'), 'NEW', {Fungible: 10}],92 );9394 await helper.finCouncil.collective.execute(finCounselors.andy, registerForeignAssetCall);9596 const asset = await helper.foreignAssets.foreignCollectionId(location);97 expect(asset).not.null;98 });99100 itSub('[Negative] FinCouncil can\'t fast-track Democracy proposals', async ({helper}) => {101 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);102 await helper.wait.parachainBlockMultiplesOf(35n);103104 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);105106 await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))107 .rejectedWith('BadOrigin');108 });109110 itSub('[Negative] FinCouncil member cannot fast-track Democracy proposals', async ({helper}) => {111 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);112 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);113114 await expect(helper.finCouncil.collective.execute(115 finCounselors.andy,116 helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),117 )).to.be.rejectedWith('BadOrigin');118 });119120 itSub('[Negative] FinCouncil can\'t cancel Democracy proposals', async ({helper}) => {121 const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);122 const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;123124 await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))125 .rejectedWith('BadOrigin');126 });127128 itSub('[Negative] FinCouncil member cannot cancel Democracy proposals', async ({helper}) => {129 const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);130 const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;131132 await expect(helper.finCouncil.collective.execute(133 finCounselors.andy,134 helper.democracy.cancelProposalCall(proposalIndex),135 ))136 .to.be.rejectedWith('BadOrigin');137 });138139 itSub('[Negative] FinCouncil can\'t cancel ongoing Democracy referendums', async ({helper}) => {140 await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));141 const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);142 const referendumIndex = startedEvent.referendumIndex;143144 await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))145 .rejectedWith('BadOrigin');146 });147148 itSub('[Negative] FinCouncil member cannot cancel ongoing Democracy referendums', async ({helper}) => {149 await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));150 const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);151 const referendumIndex = startedEvent.referendumIndex;152153 await expect(helper.finCouncil.collective.execute(154 finCounselors.andy,155 helper.democracy.emergencyCancelCall(referendumIndex),156 )).to.be.rejectedWith('BadOrigin');157 });158159 itSub('[Negative] FinCouncil member can\'t veto Democracy proposals', async ({helper}) => {160 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);161 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);162163 await expect(helper.finCouncil.collective.execute(164 finCounselors.andy,165 helper.democracy.vetoExternalCall(preimageHash),166 )).rejectedWith('BadOrigin');167 });168169 itSub('[Negative] FinCouncil cannot blacklist Democracy proposals', async ({helper}) => {170 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);171 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);172173 await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash))).to.be.rejectedWith('BadOrigin');174 });175176 itSub('[Negative] FinCouncil member cannot blacklist Democracy proposals', async ({helper}) => {177 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);178 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);179180 await expect(helper.finCouncil.collective.execute(181 finCounselors.andy,182 helper.democracy.blacklistCall(preimageHash),183 )).to.be.rejectedWith('BadOrigin');184 });185186 itSub('[Negative] FinCouncil can\' cancel Fellowship referendums', async ({helper}) => {187 const fellowship = await initFellowship(donor, sudoer);188 const fellowshipProposer = fellowship[5][0];189 const proposal = dummyProposal(helper);190191 const submitResult = await helper.fellowship.referenda.submit(192 fellowshipProposer,193 fellowshipPropositionOrigin,194 proposal,195 defaultEnactmentMoment,196 );197 const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;198 await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))199 .rejectedWith('BadOrigin');200 });201202 itSub('[Negative] TechComm member cannot cancel Fellowship referendums', async ({helper}) => {203 const fellowship = await initFellowship(donor, sudoer);204 const fellowshipProposer = fellowship[5][0];205 const proposal = dummyProposal(helper);206207 const submitResult = await helper.fellowship.referenda.submit(208 fellowshipProposer,209 fellowshipPropositionOrigin,210 proposal,211 defaultEnactmentMoment,212 );213214 const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;215216 await expect(helper.finCouncil.collective.execute(217 finCounselors.andy,218 helper.fellowship.referenda.cancelCall(referendumIndex),219 )).to.be.rejectedWith('BadOrigin');220 });221222 itSub('[Negative] FinCouncil member can\' add a Fellowship member', async ({helper}) => {223 const newFellowshipMember = helper.arrange.createEmptyAccount();224 await expect(helper.finCouncil.collective.execute(225 finCounselors.andy,226 helper.fellowship.collective.addMemberCall(newFellowshipMember.address),227 )).to.be.rejectedWith('BadOrigin');228 });229230 itSub('[Negative] FinCouncil cannot submit regular democracy proposal', async ({helper}) => {231 const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);232233 await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith('BadOrigin');234 });235236 itSub('[Negative] FinCouncil cannot externally propose SuperMajorityAgainst', async ({helper}) => {237 const commiteeProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));238239 await expect(proposalFromAllCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');240 });241242 itSub('[Negative] FinCouncil member cannot submit regular democracy proposal', async ({helper}) => {243 const memberProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);244245 await expect(helper.finCouncil.collective.execute(246 finCounselors.andy,247 memberProposal,248 )).to.be.rejectedWith('BadOrigin');249 });250251 itSub('[Negative] FinCouncil cannot externally propose SimpleMajority', async ({helper}) => {252 const commiteeProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));253254 await expect(proposalFromAllCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');255 });256257 itSub('[Negative] FinCouncil cannot externally propose SuperMajorityApprove', async ({helper}) => {258 const commiteeProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));259260 await expect(proposalFromAllCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');261 });262263 itSub('[Negative] FinCouncil member cannot externally propose SuperMajorityAgainst', async ({helper}) => {264 const memberProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));265266 await expect(helper.finCouncil.collective.execute(267 finCounselors.andy,268 memberProposal,269 )).to.be.rejectedWith('BadOrigin');270 });271272 itSub('[Negative] FinCouncil member cannot externally propose SimpleMajority', async ({helper}) => {273 const memberProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));274275 await expect(helper.finCouncil.collective.execute(276 finCounselors.andy,277 memberProposal,278 )).to.be.rejectedWith('BadOrigin');279 });280281 itSub('[Negative] FinCouncil member cannot externally propose SuperMajorityApprove', async ({helper}) => {282 const memberProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));283284 await expect(helper.finCouncil.collective.execute(285 finCounselors.andy,286 memberProposal,287 )).to.be.rejectedWith('BadOrigin');288 });289290 itSub('[Negative] FinCouncil cannot add/remove a Council member', async ({helper}) => {291 const newCouncilMember = helper.arrange.createEmptyAccount();292 const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);293 const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);294295 await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');296 await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');297 });298299 itSub('[Negative] FinCouncil member cannot add/remove a Council member', async ({helper}) => {300 const newCouncilMember = helper.arrange.createEmptyAccount();301 const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);302 const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);303304 await expect(helper.finCouncil.collective.execute(305 finCounselors.andy,306 addMemberProposal,307 )).to.be.rejectedWith('BadOrigin');308 await expect(helper.finCouncil.collective.execute(309 finCounselors.andy,310 removeMemberProposal,311 )).to.be.rejectedWith('BadOrigin');312 });313314 itSub('[Negative] FinCouncil cannot add/remove a FinCouncil member', async ({helper}) => {315 const newCouncilMember = helper.arrange.createEmptyAccount();316 const addMemberProposal = helper.finCouncil.membership.addMemberCall(newCouncilMember.address);317 const removeMemberProposal = helper.finCouncil.membership.removeMemberCall(finCounselors.ildar.address);318319 await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');320 await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');321 });322323 itSub('[Negative] FinCouncil member cannot add/remove a FinCouncil member', async ({helper}) => {324 const newCouncilMember = helper.arrange.createEmptyAccount();325 const addMemberProposal = helper.finCouncil.membership.addMemberCall(newCouncilMember.address);326 const removeMemberProposal = helper.finCouncil.membership.removeMemberCall(finCounselors.ildar.address);327328 await expect(helper.finCouncil.collective.execute(329 finCounselors.andy,330 addMemberProposal,331 )).to.be.rejectedWith('BadOrigin');332 await expect(helper.finCouncil.collective.execute(333 finCounselors.andy,334 removeMemberProposal,335 )).to.be.rejectedWith('BadOrigin');336 });337338 itSub('[Negative] FinCouncil cannot set/clear Council prime member', async ({helper}) => {339 const counselors = await initCouncil(donor, sudoer);340 const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);341 const proposalForClear = await helper.council.membership.clearPrimeCall();342343 await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith('BadOrigin');344 await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith('BadOrigin');345 await clearCouncil(sudoer);346 });347348 itSub('[Negative] FinCouncil member cannot set/clear Council prime member', async ({helper}) => {349 const counselors = await initCouncil(donor, sudoer);350 const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);351 const proposalForClear = await helper.council.membership.clearPrimeCall();352353 await expect(helper.finCouncil.collective.execute(354 finCounselors.andy,355 proposalForSet,356 )).to.be.rejectedWith('BadOrigin');357 await expect(helper.finCouncil.collective.execute(358 finCounselors.andy,359 proposalForClear,360 )).to.be.rejectedWith('BadOrigin');361 await clearCouncil(sudoer);362 });363364 itSub('[Negative] FinCouncil cannot add/remove a TechComm member', async ({helper}) => {365 const newCommMember = helper.arrange.createEmptyAccount();366 const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);367 const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);368369 await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');370 await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');371 });372373 itSub('[Negative] FinCouncil member cannot add/remove a TechComm member', async ({helper}) => {374 const newCommMember = helper.arrange.createEmptyAccount();375 const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);376 const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);377378 await expect(helper.finCouncil.collective.execute(379 finCounselors.andy,380 addMemberProposal,381 )).to.be.rejectedWith('BadOrigin');382 await expect(helper.finCouncil.collective.execute(383 finCounselors.andy,384 removeMemberProposal,385 )).to.be.rejectedWith('BadOrigin');386 });387388 itSub('[Negative] FinCouncil cannot remove a Fellowship member', async ({helper}) => {389 const fellowship = await initFellowship(donor, sudoer);390391 await expect(proposalFromAllCouncil(helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5))).to.be.rejectedWith('BadOrigin');392 await clearFellowship(sudoer);393 });394395 itSub('[Negative] FinCouncil member cannot remove a Fellowship member', async ({helper}) => {396 const fellowship = await initFellowship(donor, sudoer);397398 await expect(helper.finCouncil.collective.execute(399 finCounselors.andy,400 helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5),401 )).to.be.rejectedWith('BadOrigin');402 await clearFellowship(sudoer);403 });404405406});