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 proposalFromMoreThanHalfFinCouncil(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 proposalFromAllFinCouncil(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(proposalFromAllFinCouncil(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(proposalFromAllFinCouncil(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(proposalFromAllFinCouncil(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 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(proposalFromAllFinCouncil(helper.democracy.vetoExternalCall(preimageHash)))164 .rejectedWith('BadOrigin');165 });166167 itSub('[Negative] FinCouncil member can\'t veto Democracy proposals', async ({helper}) => {168 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);169 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);170171 await expect(helper.finCouncil.collective.execute(172 finCounselors.andy,173 helper.democracy.vetoExternalCall(preimageHash),174 )).rejectedWith('BadOrigin');175 });176177 itSub('[Negative] FinCouncil cannot blacklist Democracy proposals', async ({helper}) => {178 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);179 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);180181 await expect(proposalFromAllFinCouncil(helper.democracy.blacklistCall(preimageHash))).to.be.rejectedWith('BadOrigin');182 });183184 itSub('[Negative] FinCouncil member cannot blacklist Democracy proposals', async ({helper}) => {185 const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);186 await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);187188 await expect(helper.finCouncil.collective.execute(189 finCounselors.andy,190 helper.democracy.blacklistCall(preimageHash),191 )).to.be.rejectedWith('BadOrigin');192 });193194 itSub('[Negative] FinCouncil can\'t cancel Fellowship referendums', async ({helper}) => {195 const fellowship = await initFellowship(donor, sudoer);196 const fellowshipProposer = fellowship[5][0];197 const proposal = dummyProposal(helper);198199 const submitResult = await helper.fellowship.referenda.submit(200 fellowshipProposer,201 fellowshipPropositionOrigin,202 proposal,203 defaultEnactmentMoment,204 );205 const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;206 await expect(proposalFromAllFinCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))207 .rejectedWith('BadOrigin');208 });209210 itSub('[Negative] FinCouncil member cannot cancel Fellowship referendums', async ({helper}) => {211 const fellowship = await initFellowship(donor, sudoer);212 const fellowshipProposer = fellowship[5][0];213 const proposal = dummyProposal(helper);214215 const submitResult = await helper.fellowship.referenda.submit(216 fellowshipProposer,217 fellowshipPropositionOrigin,218 proposal,219 defaultEnactmentMoment,220 );221222 const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;223224 await expect(helper.finCouncil.collective.execute(225 finCounselors.andy,226 helper.fellowship.referenda.cancelCall(referendumIndex),227 )).to.be.rejectedWith('BadOrigin');228 });229230 itSub('[Negative] FinCouncil member can\'t add a Fellowship member', async ({helper}) => {231 const newFellowshipMember = helper.arrange.createEmptyAccount();232 await expect(helper.finCouncil.collective.execute(233 finCounselors.andy,234 helper.fellowship.collective.addMemberCall(newFellowshipMember.address),235 )).to.be.rejectedWith('BadOrigin');236 });237238 itSub('[Negative] FinCouncil cannot submit regular democracy proposal', async ({helper}) => {239 const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);240241 await expect(proposalFromAllFinCouncil(councilProposal)).to.be.rejectedWith('BadOrigin');242 });243244 itSub('[Negative] FinCouncil cannot externally propose SuperMajorityAgainst', async ({helper}) => {245 const commiteeProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));246247 await expect(proposalFromAllFinCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');248 });249250 itSub('[Negative] FinCouncil member cannot submit regular democracy proposal', async ({helper}) => {251 const memberProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);252253 await expect(helper.finCouncil.collective.execute(254 finCounselors.andy,255 memberProposal,256 )).to.be.rejectedWith('BadOrigin');257 });258259 itSub('[Negative] FinCouncil cannot externally propose SimpleMajority', async ({helper}) => {260 const commiteeProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));261262 await expect(proposalFromAllFinCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');263 });264265 itSub('[Negative] FinCouncil cannot externally propose SuperMajorityApprove', async ({helper}) => {266 const commiteeProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));267268 await expect(proposalFromAllFinCouncil(commiteeProposal)).to.be.rejectedWith('BadOrigin');269 });270271 itSub('[Negative] FinCouncil member cannot externally propose SuperMajorityAgainst', async ({helper}) => {272 const memberProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));273274 await expect(helper.finCouncil.collective.execute(275 finCounselors.andy,276 memberProposal,277 )).to.be.rejectedWith('BadOrigin');278 });279280 itSub('[Negative] FinCouncil member cannot externally propose SimpleMajority', async ({helper}) => {281 const memberProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));282283 await expect(helper.finCouncil.collective.execute(284 finCounselors.andy,285 memberProposal,286 )).to.be.rejectedWith('BadOrigin');287 });288289 itSub('[Negative] FinCouncil member cannot externally propose SuperMajorityApprove', async ({helper}) => {290 const memberProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));291292 await expect(helper.finCouncil.collective.execute(293 finCounselors.andy,294 memberProposal,295 )).to.be.rejectedWith('BadOrigin');296 });297298 itSub('[Negative] FinCouncil cannot add/remove a Council member', async ({helper}) => {299 const newCouncilMember = helper.arrange.createEmptyAccount();300 const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);301 const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);302303 await expect(proposalFromAllFinCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');304 await expect(proposalFromAllFinCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');305 });306307 itSub('[Negative] FinCouncil member cannot add/remove a Council member', async ({helper}) => {308 const newCouncilMember = helper.arrange.createEmptyAccount();309 const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);310 const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);311312 await expect(helper.finCouncil.collective.execute(313 finCounselors.andy,314 addMemberProposal,315 )).to.be.rejectedWith('BadOrigin');316 await expect(helper.finCouncil.collective.execute(317 finCounselors.andy,318 removeMemberProposal,319 )).to.be.rejectedWith('BadOrigin');320 });321322 itSub('[Negative] FinCouncil cannot add/remove a FinCouncil member', async ({helper}) => {323 const newCouncilMember = helper.arrange.createEmptyAccount();324 const addMemberProposal = helper.finCouncil.membership.addMemberCall(newCouncilMember.address);325 const removeMemberProposal = helper.finCouncil.membership.removeMemberCall(finCounselors.ildar.address);326327 await expect(proposalFromAllFinCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');328 await expect(proposalFromAllFinCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');329 });330331 itSub('[Negative] FinCouncil cannot add/remove a FinCouncil prime member', async ({helper}) => {332 const setPrimeCall = helper.finCouncil.membership.setPrimeCall(finCounselors.andy.address);333 const clearPrimeCall = helper.finCouncil.membership.clearPrimeCall();334335 await expect(proposalFromAllFinCouncil(setPrimeCall)).to.be.rejectedWith('BadOrigin');336 await expect(proposalFromAllFinCouncil(clearPrimeCall)).to.be.rejectedWith('BadOrigin');337 });338339 itSub('[Negative] FinCouncil member cannot add/remove a FinCouncil prime member', async ({helper}) => {340 await expect(helper.finCouncil.collective.execute(341 finCounselors.andy,342 helper.finCouncil.membership.setPrimeCall(finCounselors.andy.address),343 )).to.be.rejectedWith('BadOrigin');344345 await expect(helper.finCouncil.collective.execute(346 finCounselors.andy,347 helper.finCouncil.membership.clearPrimeCall(),348 )).to.be.rejectedWith('BadOrigin');349 });350351 itSub('[Negative] FinCouncil member cannot add/remove a FinCouncil member', async ({helper}) => {352 const newCouncilMember = helper.arrange.createEmptyAccount();353 const addMemberProposal = helper.finCouncil.membership.addMemberCall(newCouncilMember.address);354 const removeMemberProposal = helper.finCouncil.membership.removeMemberCall(finCounselors.ildar.address);355356 await expect(helper.finCouncil.collective.execute(357 finCounselors.andy,358 addMemberProposal,359 )).to.be.rejectedWith('BadOrigin');360 await expect(helper.finCouncil.collective.execute(361 finCounselors.andy,362 removeMemberProposal,363 )).to.be.rejectedWith('BadOrigin');364 });365366 itSub('[Negative] FinCouncil cannot set/clear Council prime member', async ({helper}) => {367 const counselors = await initCouncil(donor, sudoer);368 const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);369 const proposalForClear = await helper.council.membership.clearPrimeCall();370371 await expect(proposalFromAllFinCouncil(proposalForSet)).to.be.rejectedWith('BadOrigin');372 await expect(proposalFromAllFinCouncil(proposalForClear)).to.be.rejectedWith('BadOrigin');373 await clearCouncil(sudoer);374 });375376 itSub('[Negative] FinCouncil member cannot set/clear Council prime member', async ({helper}) => {377 const counselors = await initCouncil(donor, sudoer);378 const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);379 const proposalForClear = await helper.council.membership.clearPrimeCall();380381 await expect(helper.finCouncil.collective.execute(382 finCounselors.andy,383 proposalForSet,384 )).to.be.rejectedWith('BadOrigin');385 await expect(helper.finCouncil.collective.execute(386 finCounselors.andy,387 proposalForClear,388 )).to.be.rejectedWith('BadOrigin');389 await clearCouncil(sudoer);390 });391392 itSub('[Negative] FinCouncil cannot add/remove a TechComm member', async ({helper}) => {393 const newCommMember = helper.arrange.createEmptyAccount();394 const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newCommMember.address);395 const removeMemberProposal = helper.technicalCommittee.membership.removeMemberCall(newCommMember.address);396397 await expect(proposalFromAllFinCouncil(addMemberProposal)).to.be.rejectedWith('BadOrigin');398 await expect(proposalFromAllFinCouncil(removeMemberProposal)).to.be.rejectedWith('BadOrigin');399 });400401 itSub('[Negative] FinCouncil member cannot add/remove a TechComm member', async ({helper}) => {402 const newCommMember = helper.arrange.createEmptyAccount();403 const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newCommMember.address);404 const removeMemberProposal = helper.technicalCommittee.membership.removeMemberCall(newCommMember.address);405406 await expect(helper.finCouncil.collective.execute(407 finCounselors.andy,408 addMemberProposal,409 )).to.be.rejectedWith('BadOrigin');410 await expect(helper.finCouncil.collective.execute(411 finCounselors.andy,412 removeMemberProposal,413 )).to.be.rejectedWith('BadOrigin');414 });415416 itSub('[Negative] FinCouncil cannot remove a Fellowship member', async ({helper}) => {417 const fellowship = await initFellowship(donor, sudoer);418419 await expect(proposalFromAllFinCouncil(helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5))).to.be.rejectedWith('BadOrigin');420 await clearFellowship(sudoer);421 });422423 itSub('[Negative] FinCouncil member cannot remove a Fellowship member', async ({helper}) => {424 const fellowship = await initFellowship(donor, sudoer);425426 await expect(helper.finCouncil.collective.execute(427 finCounselors.andy,428 helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5),429 )).to.be.rejectedWith('BadOrigin');430 await clearFellowship(sudoer);431 });432433434});