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

difftreelog

Tests/fin council (#1070)

Max Andreev2024-06-05parent: #c9b1f9a.patch.diff
in: master

7 files changed

modifiedjs-packages/.vscode/settings.jsondiffbeforeafterboth
--- a/js-packages/.vscode/settings.json
+++ b/js-packages/.vscode/settings.json
@@ -5,6 +5,8 @@
 	},
 	"mochaExplorer.files": "tests/**/*.test.ts",
 	"mochaExplorer.require": "ts-node/register",
+  "mochaExplorer.esmLoader": true,
+  "mochaExplorer.nodeArgv": ["--loader", "ts-node/esm"],
 	"eslint.format.enable": true,
 	"[javascript]": {
 		"editor.defaultFormatter": "dbaeumer.vscode-eslint"
modifiedjs-packages/test-utils/index.tsdiffbeforeafterboth
--- a/js-packages/test-utils/index.ts
+++ b/js-packages/test-utils/index.ts
@@ -214,6 +214,23 @@
     }));
   };
 
+  static FinCouncil = class extends EventSection('financialCouncil') {
+    static Proposed = this.Method('Proposed', data => ({
+      account: eventHumanData(data, 0),
+      proposalIndex: eventJsonData<number>(data, 1),
+      proposalHash: eventHumanData(data, 2),
+      threshold: eventJsonData<number>(data, 3),
+    }));
+    static Closed = this.Method('Closed', data => ({
+      proposalHash: eventHumanData(data, 0),
+      yes: eventJsonData<number>(data, 1),
+      no: eventJsonData<number>(data, 2),
+    }));
+    static Executed = this.Method('Executed', data => ({
+      proposalHash: eventHumanData(data, 0),
+    }));
+  };
+
   static TechnicalCommittee = class extends EventSection('technicalCommittee') {
     static Proposed = this.Method('Proposed', data => ({
       account: eventHumanData(data, 0),
@@ -475,6 +492,7 @@
   scheduler: SchedulerGroup;
   collatorSelection: CollatorSelectionGroup;
   council: ICollectiveGroup;
+  finCouncil: ICollectiveGroup;
   technicalCommittee: ICollectiveGroup;
   fellowship: IFellowshipGroup;
   democracy: DemocracyGroup;
@@ -498,6 +516,10 @@
       collective: new CollectiveGroup(this, 'council'),
       membership: new CollectiveMembershipGroup(this, 'councilMembership'),
     };
+    this.finCouncil = {
+      collective: new CollectiveGroup(this, 'financialCouncil'),
+      membership: new CollectiveMembershipGroup(this, 'financialCouncilMembership'),
+    };
     this.technicalCommittee = {
       collective: new CollectiveGroup(this, 'technicalCommittee'),
       membership: new CollectiveMembershipGroup(this, 'technicalCommitteeMembership'),
modifiedjs-packages/test-utils/util.tsdiffbeforeafterboth
--- a/js-packages/test-utils/util.ts
+++ b/js-packages/test-utils/util.ts
@@ -117,6 +117,7 @@
   Identity = 'identity',
   Democracy = 'democracy',
   Council = 'council',
+  FinancialCouncil = 'financialcouncil',
   //CouncilMembership = 'councilmembership',
   TechnicalCommittee = 'technicalcommittee',
   Fellowship = 'fellowshipcollective',
modifiedjs-packages/tests/sub/governance/council.test.tsdiffbeforeafterboth
--- a/js-packages/tests/sub/governance/council.test.ts
+++ b/js-packages/tests/sub/governance/council.test.ts
@@ -2,7 +2,7 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '@unique/test-utils/util.js';
 import {Event} from '@unique/test-utils';
-import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util.js';
+import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin, initFinCouncil} from './util.js';
 import type {ICounselors} from './util.js';
 
 describeGov('Governance: Council tests', () => {
@@ -192,6 +192,25 @@
     expect(techCommMembers).to.not.contains(techComm.andy.address);
   });
 
+  itSub('Council can remove FinCouncil member', async ({helper}) => {
+    const finCouncil = await initFinCouncil(donor, sudoer);
+    const removeMemberPrpoposal = helper.finCouncil.membership.removeMemberCall(finCouncil.andy.address);
+    await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);
+
+    const finCouncilMembers = await helper.finCouncil.membership.getMembers();
+    expect(finCouncilMembers).to.not.contains(finCouncil.andy.address);
+  });
+
+  itSub('Council can add FinCouncil member', async ({helper}) => {
+    await initFinCouncil(donor, sudoer);
+    const newFinCouncilMember = helper.arrange.createEmptyAccount();
+    const addMemberPrpoposal = helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address);
+    await proposalFromMoreThanHalfCouncil(addMemberPrpoposal);
+
+    const finCouncilMembers = await helper.finCouncil.membership.getMembers();
+    expect(finCouncilMembers).to.contains(newFinCouncilMember.address);
+  });
+
   itSub.skip('Council member can add Fellowship member', async ({helper}) => {
     const newFellowshipMember = helper.arrange.createEmptyAccount();
     await expect(helper.council.collective.execute(
@@ -328,6 +347,22 @@
     )).to.be.rejectedWith('BadOrigin');
   });
 
+  itSub('[Negative] Council member can\'t add FinCouncil member', async ({helper}) => {
+    const newFinCouncilMember = helper.arrange.createEmptyAccount();
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address),
+    )).rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council member can\'t remove FinCouncil member', async ({helper}) => {
+    const finCouncil = await initFinCouncil(donor, sudoer);
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.finCouncil.membership.removeMemberCall(finCouncil.ildar.address),
+    )).rejectedWith('BadOrigin');
+  });
+
   itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {
     const fellowship = await initFellowship(donor, sudoer);
     const memberWithRankOne = fellowship[1][0];
addedjs-packages/tests/sub/governance/financialCouncil.test.tsdiffbeforeafterboth

no content

modifiedjs-packages/tests/sub/governance/technicalCommittee.test.tsdiffbeforeafterboth
--- a/js-packages/tests/sub/governance/technicalCommittee.test.ts
+++ b/js-packages/tests/sub/governance/technicalCommittee.test.ts
@@ -130,6 +130,50 @@
     await clearFellowship(sudoer);
   });
 
+  itSub('[Negative] TechComm can\'t add FinCouncil member', async ({helper}) => {
+    const newFinCouncilMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address);
+    await proposalFromAllCommittee(addMemberProposal);
+
+    const finCouncilMembers = await helper.finCouncil.membership.getMembers();
+    expect(finCouncilMembers).to.contains(newFinCouncilMember.address);
+  });
+
+
+  itSub('[Negative] TechComm member can\'t add FinCouncil member', async ({helper}) => {
+    const newFinCouncilMember = helper.arrange.createEmptyAccount();
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.greg,
+      helper.finCouncil.membership.addMemberCall(newFinCouncilMember.address),
+    )).rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot register foreign asset', async ({helper}) => {
+    const location = {
+      parents: 1,
+      interior: {X3: [
+        {
+          Parachain: 1000,
+        },
+        {
+          PalletInstance: 50,
+        },
+        {
+          GeneralIndex: 1985,
+        },
+      ]},
+    };
+    const assetId = {Concrete: location};
+
+    const foreignAssetProposal = helper.constructApiCall(
+      'api.tx.foreignAssets.forceRegisterForeignAsset',
+      [{V3: assetId}, helper.util.str2vec('New Asset2'), 'NEW', {Fungible: 10}],
+    );
+
+    await expect(helper.technicalCommittee.collective.execute(techcomms.andy, foreignAssetProposal))
+      .to.be.rejectedWith('BadOrigin');
+  });
+
   itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {
     const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
 
modifiedjs-packages/tests/sub/governance/util.tsdiffbeforeafterboth
--- a/js-packages/tests/sub/governance/util.ts
+++ b/js-packages/tests/sub/governance/util.ts
@@ -29,12 +29,62 @@
   filip: IKeyringPair;
   irina: IKeyringPair;
 }
+
+export interface IFinCounselors {
+  greg: IKeyringPair;
+  ildar: IKeyringPair;
+  andy: IKeyringPair;
+}
+
 export interface ITechComms {
     greg: IKeyringPair;
     andy: IKeyringPair;
     constantine: IKeyringPair;
 }
 
+export function initFinCouncil(donor: IKeyringPair, superuser: IKeyringPair): Promise<IFinCounselors> {
+  return usingPlaygrounds(async (helper) => {
+    const [greg, ildar, andy] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n], donor);
+    const sudo = helper.getSudo();
+    {
+      const members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON() as [];
+      if(members.length != 0) {
+        await clearFinCouncil(superuser);
+      }
+    }
+    const expectedMembers = [greg, ildar, andy];
+    for(const member of expectedMembers) {
+      await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.addMember', [member.address]);
+    }
+    await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.setPrime', [greg.address]);
+    {
+      const members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
+      expect(members).to.containSubset(expectedMembers.map((x: IKeyringPair) => x.address));
+      expect(members.length).to.be.equal(expectedMembers.length);
+    }
+
+    return {
+      greg,
+      ildar,
+      andy,
+    };
+  });
+}
+
+export async function clearFinCouncil(superuser: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    let members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
+    if(members.length) {
+      const sudo = helper.getSudo();
+      for(const address of members) {
+        await sudo.executeExtrinsic(superuser, 'api.tx.financialCouncilMembership.removeMember', [address]);
+      }
+      members = (await helper.callRpc('api.query.financialCouncilMembership.members')).toJSON();
+    }
+    expect(members).to.be.deep.equal([]);
+  });
+}
+
 export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {
   let counselors: IKeyringPair[] = [];