瀏覽代碼

Merge pull request #1027 from gleb-urvanov/feature/manage-lead-proposals

Network tests: refactoring
Mokhtar Naamani 4 年之前
父節點
當前提交
422881b36f

+ 12 - 6
tests/network-tests/src/nicaea/dto/fillOpeningParameters.ts

@@ -32,28 +32,34 @@ export class FillOpeningParameters {
     return this.workingGroup;
   }
 
-  public setAmountPerPayout(value: BN) {
+  public setAmountPerPayout(value: BN): FillOpeningParameters {
     this.amountPerPayout = value;
+    return this;
   }
 
-  public setNextPaymentAtBlock(value: BN) {
+  public setNextPaymentAtBlock(value: BN): FillOpeningParameters {
     this.nextPaymentAtBlock = value;
+    return this;
   }
 
-  public setPayoutInterval(value: BN) {
+  public setPayoutInterval(value: BN): FillOpeningParameters {
     this.payoutInterval = value;
+    return this;
   }
 
-  public setOpeningId(value: BN) {
+  public setOpeningId(value: BN): FillOpeningParameters {
     this.openingId = value;
+    return this;
   }
 
-  public setSuccessfulApplicationId(value: BN) {
+  public setSuccessfulApplicationId(value: BN): FillOpeningParameters {
     this.successfulApplicationId = value;
+    return this;
   }
 
-  public setWorkingGroup(value: string) {
+  public setWorkingGroup(value: string): FillOpeningParameters {
     this.workingGroup = value;
+    return this;
   }
 
   constructor() {

+ 49 - 20
tests/network-tests/src/nicaea/dto/workingGroupOpening.ts

@@ -102,84 +102,104 @@ export class WorkingGroupOpening {
     return this.openingType;
   }
 
-  public setActivateAtBlock(value: BN | undefined) {
+  public setActivateAtBlock(value: BN | undefined): WorkingGroupOpening {
     this.activateAtBlock = value;
+    return this;
   }
 
-  public setMaxActiveApplicants(value: BN) {
+  public setMaxActiveApplicants(value: BN): WorkingGroupOpening {
     this.maxActiveApplicants = value;
+    return this;
   }
 
-  public setMaxReviewPeriodLength(value: BN) {
+  public setMaxReviewPeriodLength(value: BN): WorkingGroupOpening {
     this.maxReviewPeriodLength = value;
+    return this;
   }
 
-  public setApplicationStakingPolicyAmount(value: BN) {
+  public setApplicationStakingPolicyAmount(value: BN): WorkingGroupOpening {
     this.applicationStakingPolicyAmount = value;
+    return this;
   }
 
-  public setApplicationCrowdedOutUnstakingPeriodLength(value: BN) {
+  public setApplicationCrowdedOutUnstakingPeriodLength(value: BN): WorkingGroupOpening {
     this.applicationCrowdedOutUnstakingPeriodLength = value;
+    return this;
   }
 
-  public setApplicationExpiredUnstakingPeriodLength(value: BN) {
+  public setApplicationExpiredUnstakingPeriodLength(value: BN): WorkingGroupOpening {
     this.applicationExpiredUnstakingPeriodLength = value;
+    return this;
   }
 
-  public setRoleStakingPolicyAmount(value: BN) {
+  public setRoleStakingPolicyAmount(value: BN): WorkingGroupOpening {
     this.roleStakingPolicyAmount = value;
+    return this;
   }
 
-  public setRoleCrowdedOutUnstakingPeriodLength(value: BN) {
+  public setRoleCrowdedOutUnstakingPeriodLength(value: BN): WorkingGroupOpening {
     this.roleCrowdedOutUnstakingPeriodLength = value;
+    return this;
   }
 
-  public setRoleExpiredUnstakingPeriodLength(value: BN) {
+  public setRoleExpiredUnstakingPeriodLength(value: BN): WorkingGroupOpening {
     this.roleExpiredUnstakingPeriodLength = value;
+    return this;
   }
 
-  public setSlashableMaxCount(value: BN) {
+  public setSlashableMaxCount(value: BN): WorkingGroupOpening {
     this.slashableMaxCount = value;
+    return this;
   }
 
-  public setSlashableMaxPercentPtsPerTime(value: BN) {
+  public setSlashableMaxPercentPtsPerTime(value: BN): WorkingGroupOpening {
     this.slashableMaxPercentPtsPerTime = value;
+    return this;
   }
 
-  public setSuccessfulApplicantApplicationStakeUnstakingPeriod(value: BN) {
+  public setSuccessfulApplicantApplicationStakeUnstakingPeriod(value: BN): WorkingGroupOpening {
     this.successfulApplicantApplicationStakeUnstakingPeriod = value;
+    return this;
   }
 
-  public setFailedApplicantApplicationStakeUnstakingPeriod(value: BN) {
+  public setFailedApplicantApplicationStakeUnstakingPeriod(value: BN): WorkingGroupOpening {
     this.failedApplicantApplicationStakeUnstakingPeriod = value;
+    return this;
   }
 
-  public setFailedApplicantRoleStakeUnstakingPeriod(value: BN) {
+  public setFailedApplicantRoleStakeUnstakingPeriod(value: BN): WorkingGroupOpening {
     this.failedApplicantRoleStakeUnstakingPeriod = value;
+    return this;
   }
 
-  public setTerminateApplicationStakeUnstakingPeriod(value: BN) {
+  public setTerminateApplicationStakeUnstakingPeriod(value: BN): WorkingGroupOpening {
     this.terminateApplicationStakeUnstakingPeriod = value;
+    return this;
   }
 
-  public setTerminateRoleStakeUnstakingPeriod(value: BN) {
+  public setTerminateRoleStakeUnstakingPeriod(value: BN): WorkingGroupOpening {
     this.terminateRoleStakeUnstakingPeriod = value;
+    return this;
   }
 
-  public setExitRoleApplicationStakeUnstakingPeriod(value: BN) {
+  public setExitRoleApplicationStakeUnstakingPeriod(value: BN): WorkingGroupOpening {
     this.exitRoleApplicationStakeUnstakingPeriod = value;
+    return this;
   }
 
-  public setExitRoleStakeUnstakingPeriod(value: BN) {
+  public setExitRoleStakeUnstakingPeriod(value: BN): WorkingGroupOpening {
     this.exitRoleStakeUnstakingPeriod = value;
+    return this;
   }
 
-  public setText(value: string) {
+  public setText(value: string): WorkingGroupOpening {
     this.text = value;
+    return this;
   }
 
-  public setOpeningType(value: string) {
+  public setOpeningType(value: string): WorkingGroupOpening {
     this.openingType = value;
+    return this;
   }
 
   constructor() {
@@ -223,4 +243,13 @@ export class WorkingGroupOpening {
       exit_role_stake_unstaking_period: this.exitRoleStakeUnstakingPeriod,
     };
   }
+
+  public getAddOpeningParameters(workingGroup: string) {
+    return {
+      activate_at: this.getActivateAt(),
+      commitment: this.getCommitment(),
+      human_readable_text: this.getText(),
+      working_group: workingGroup,
+    }
+  }
 }

+ 26 - 26
tests/network-tests/src/nicaea/tests/proposals/impl/proposalsModule.ts

@@ -23,25 +23,25 @@ export async function createWorkingGroupLeaderOpening(
   await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
 
   // Opening construction
-  const opening = new WorkingGroupOpening();
-  opening.setMaxActiveApplicants(new BN(m1KeyPairs.length));
-  opening.setMaxReviewPeriodLength(new BN(32));
-  opening.setApplicationStakingPolicyAmount(new BN(applicationStake));
-  opening.setApplicationCrowdedOutUnstakingPeriodLength(new BN(1));
-  opening.setApplicationExpiredUnstakingPeriodLength(new BN(1));
-  opening.setRoleStakingPolicyAmount(new BN(roleStake));
-  opening.setRoleCrowdedOutUnstakingPeriodLength(new BN(1));
-  opening.setRoleExpiredUnstakingPeriodLength(new BN(1));
-  opening.setSlashableMaxCount(new BN(1));
-  opening.setSlashableMaxPercentPtsPerTime(new BN(100));
-  opening.setSuccessfulApplicantApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setFailedApplicantApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setFailedApplicantRoleStakeUnstakingPeriod(new BN(1));
-  opening.setTerminateApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setTerminateRoleStakeUnstakingPeriod(new BN(1));
-  opening.setExitRoleApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setExitRoleStakeUnstakingPeriod(new BN(1));
-  opening.setText(uuid().substring(0, 8));
+  const opening = new WorkingGroupOpening()
+    .setMaxActiveApplicants(new BN(m1KeyPairs.length))
+    .setMaxReviewPeriodLength(new BN(32))
+    .setApplicationStakingPolicyAmount(new BN(applicationStake))
+    .setApplicationCrowdedOutUnstakingPeriodLength(new BN(1))
+    .setApplicationExpiredUnstakingPeriodLength(new BN(1))
+    .setRoleStakingPolicyAmount(new BN(roleStake))
+    .setRoleCrowdedOutUnstakingPeriodLength(new BN(1))
+    .setRoleExpiredUnstakingPeriodLength(new BN(1))
+    .setSlashableMaxCount(new BN(1))
+    .setSlashableMaxPercentPtsPerTime(new BN(100))
+    .setSuccessfulApplicantApplicationStakeUnstakingPeriod(new BN(1))
+    .setFailedApplicantApplicationStakeUnstakingPeriod(new BN(1))
+    .setFailedApplicantRoleStakeUnstakingPeriod(new BN(1))
+    .setTerminateApplicationStakeUnstakingPeriod(new BN(1))
+    .setTerminateRoleStakeUnstakingPeriod(new BN(1))
+    .setExitRoleApplicationStakeUnstakingPeriod(new BN(1))
+    .setExitRoleStakeUnstakingPeriod(new BN(1))
+    .setText(uuid().substring(0, 8));
 
   // Proposal creation
   const proposalPromise = apiWrapper.expectProposalCreated();
@@ -113,13 +113,13 @@ export async function fillLeaderOpeningProposal(
     await apiWrapper.getActiveApplicationsIdsByRoleAccount(applicantRoleAccountAddress, workingGroup)
   )[0];
   const now = await apiWrapper.getBestBlock();
-  const fillOpeningParameters: FillOpeningParameters = new FillOpeningParameters();
-  fillOpeningParameters.setAmountPerPayout(payoutAmount);
-  fillOpeningParameters.setNextPaymentAtBlock(now.add(firstRewardInterval));
-  fillOpeningParameters.setPayoutInterval(rewardInterval);
-  fillOpeningParameters.setOpeningId(openingId);
-  fillOpeningParameters.setSuccessfulApplicationId(applicationId);
-  fillOpeningParameters.setWorkingGroup(workingGroupString);
+  const fillOpeningParameters: FillOpeningParameters = new FillOpeningParameters()
+    .setAmountPerPayout(payoutAmount)
+    .setNextPaymentAtBlock(now.add(firstRewardInterval))
+    .setPayoutInterval(rewardInterval)
+    .setOpeningId(openingId)
+    .setSuccessfulApplicationId(applicationId)
+    .setWorkingGroup(workingGroupString);
 
   const proposalPromise = apiWrapper.expectProposalCreated();
   await apiWrapper.proposeFillLeaderOpening(

+ 1 - 1
tests/network-tests/src/nicaea/tests/proposals/impl/workingGroupMintCapacityProposal.ts

@@ -19,7 +19,7 @@ export function workingGroupMintCapacityProposalTest(
   tap.test('Mint capacity proposal test', async () => {
     // Setup
     sudo = keyring.addFromUri(sudoUri);
-    const description: string = 'spending proposal which is used for API network testing';
+    const description: string = 'Mint capacity proposal which is used for API network testing';
     const runtimeVoteFee: BN = apiWrapper.estimateVoteForProposalFee();
     const initialMintingCapacity: BN = await apiWrapper.getContentWorkingGroupMintCapacity();
 

+ 49 - 43
tests/network-tests/src/nicaea/tests/workingGroup/impl/workingGroupModule.ts

@@ -24,30 +24,30 @@ export async function addWorkerOpening(
   expectFailure: boolean
 ): Promise<BN> {
   // Worker opening construction
-  const opening = new WorkingGroupOpening();
   const activateAtBlock: BN | undefined = activationDelay.eqn(0)
     ? undefined
     : (await apiWrapper.getBestBlock()).add(activationDelay);
-  opening.setActivateAtBlock(activateAtBlock);
-  opening.setMaxActiveApplicants(new BN(membersKeyPairs.length));
-  opening.setMaxReviewPeriodLength(new BN(32));
-  opening.setApplicationStakingPolicyAmount(new BN(applicationStake));
-  opening.setApplicationCrowdedOutUnstakingPeriodLength(new BN(1));
-  opening.setApplicationExpiredUnstakingPeriodLength(new BN(1));
-  opening.setRoleStakingPolicyAmount(new BN(roleStake));
-  opening.setRoleCrowdedOutUnstakingPeriodLength(new BN(1));
-  opening.setRoleExpiredUnstakingPeriodLength(new BN(1));
-  opening.setSlashableMaxCount(new BN(1));
-  opening.setSlashableMaxPercentPtsPerTime(new BN(100));
-  opening.setSuccessfulApplicantApplicationStakeUnstakingPeriod(unstakingPeriod);
-  opening.setFailedApplicantApplicationStakeUnstakingPeriod(unstakingPeriod);
-  opening.setFailedApplicantRoleStakeUnstakingPeriod(unstakingPeriod);
-  opening.setTerminateApplicationStakeUnstakingPeriod(unstakingPeriod);
-  opening.setTerminateRoleStakeUnstakingPeriod(unstakingPeriod);
-  opening.setExitRoleApplicationStakeUnstakingPeriod(unstakingPeriod);
-  opening.setExitRoleStakeUnstakingPeriod(unstakingPeriod);
-  opening.setText(uuid().substring(0, 8));
-  opening.setOpeningType('Worker');
+  const opening = new WorkingGroupOpening()
+    .setActivateAtBlock(activateAtBlock)
+    .setMaxActiveApplicants(new BN(membersKeyPairs.length))
+    .setMaxReviewPeriodLength(new BN(32))
+    .setApplicationStakingPolicyAmount(new BN(applicationStake))
+    .setApplicationCrowdedOutUnstakingPeriodLength(new BN(1))
+    .setApplicationExpiredUnstakingPeriodLength(new BN(1))
+    .setRoleStakingPolicyAmount(new BN(roleStake))
+    .setRoleCrowdedOutUnstakingPeriodLength(new BN(1))
+    .setRoleExpiredUnstakingPeriodLength(new BN(1))
+    .setSlashableMaxCount(new BN(1))
+    .setSlashableMaxPercentPtsPerTime(new BN(100))
+    .setSuccessfulApplicantApplicationStakeUnstakingPeriod(unstakingPeriod)
+    .setFailedApplicantApplicationStakeUnstakingPeriod(unstakingPeriod)
+    .setFailedApplicantRoleStakeUnstakingPeriod(unstakingPeriod)
+    .setTerminateApplicationStakeUnstakingPeriod(unstakingPeriod)
+    .setTerminateRoleStakeUnstakingPeriod(unstakingPeriod)
+    .setExitRoleApplicationStakeUnstakingPeriod(unstakingPeriod)
+    .setExitRoleStakeUnstakingPeriod(unstakingPeriod)
+    .setText(uuid().substring(0, 8))
+    .setOpeningType('Worker');
 
   // Fee estimation and transfer
   const addOpeningFee: BN = apiWrapper.estimateAddOpeningFee(opening, module);
@@ -76,27 +76,27 @@ export async function addLeaderOpening(
   const activateAtBlock: BN | undefined = activationDelay.eqn(0)
     ? undefined
     : (await apiWrapper.getBestBlock()).add(activationDelay);
-  const opening = new WorkingGroupOpening();
-  opening.setActivateAtBlock(activateAtBlock);
-  opening.setMaxActiveApplicants(new BN(membersKeyPairs.length));
-  opening.setMaxReviewPeriodLength(new BN(32));
-  opening.setApplicationStakingPolicyAmount(new BN(applicationStake));
-  opening.setApplicationCrowdedOutUnstakingPeriodLength(new BN(1));
-  opening.setApplicationExpiredUnstakingPeriodLength(new BN(1));
-  opening.setRoleStakingPolicyAmount(new BN(roleStake));
-  opening.setRoleCrowdedOutUnstakingPeriodLength(new BN(1));
-  opening.setRoleExpiredUnstakingPeriodLength(new BN(1));
-  opening.setSlashableMaxCount(new BN(1));
-  opening.setSlashableMaxPercentPtsPerTime(new BN(100));
-  opening.setSuccessfulApplicantApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setFailedApplicantApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setFailedApplicantRoleStakeUnstakingPeriod(new BN(1));
-  opening.setTerminateApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setTerminateRoleStakeUnstakingPeriod(new BN(1));
-  opening.setExitRoleApplicationStakeUnstakingPeriod(new BN(1));
-  opening.setExitRoleStakeUnstakingPeriod(new BN(1));
-  opening.setText(uuid().substring(0, 8));
-  opening.setOpeningType('leader');
+  const opening = new WorkingGroupOpening()
+    .setActivateAtBlock(activateAtBlock)
+    .setMaxActiveApplicants(new BN(membersKeyPairs.length))
+    .setMaxReviewPeriodLength(new BN(32))
+    .setApplicationStakingPolicyAmount(new BN(applicationStake))
+    .setApplicationCrowdedOutUnstakingPeriodLength(new BN(1))
+    .setApplicationExpiredUnstakingPeriodLength(new BN(1))
+    .setRoleStakingPolicyAmount(new BN(roleStake))
+    .setRoleCrowdedOutUnstakingPeriodLength(new BN(1))
+    .setRoleExpiredUnstakingPeriodLength(new BN(1))
+    .setSlashableMaxCount(new BN(1))
+    .setSlashableMaxPercentPtsPerTime(new BN(100))
+    .setSuccessfulApplicantApplicationStakeUnstakingPeriod(new BN(1))
+    .setFailedApplicantApplicationStakeUnstakingPeriod(new BN(1))
+    .setFailedApplicantRoleStakeUnstakingPeriod(new BN(1))
+    .setTerminateApplicationStakeUnstakingPeriod(new BN(1))
+    .setTerminateRoleStakeUnstakingPeriod(new BN(1))
+    .setExitRoleApplicationStakeUnstakingPeriod(new BN(1))
+    .setExitRoleStakeUnstakingPeriod(new BN(1))
+    .setText(uuid().substring(0, 8))
+    .setOpeningType('leader');
 
   const addOpeningPromise: Promise<BN> = apiWrapper.expectOpeningAdded();
   await apiWrapper.sudoAddOpening(sudo, opening, module);
@@ -286,6 +286,12 @@ export async function fillLeaderOpening(
       `Role account ids does not match, leader account: ${worker.role_account_id}, application account ${application.role_account_id}`
     );
   });
+  const leadWorkerId: BN = (await apiWrapper.getLeadWorkerId(module))!;
+  const openingLeaderAccount: string = (await apiWrapper.getWorkerById(leadWorkerId, module)).role_account_id.toString();
+  assert(
+    openingLeaderAccount === membersKeyPairs[0].address, 
+    `Unexpected leader account ${openingLeaderAccount}, expected ${membersKeyPairs[0].address}`
+    );
 }
 
 export async function increaseStake(
@@ -519,7 +525,7 @@ export async function expectLeaderSet(
   const leaderApplicationId = (await apiWrapper.getApplicationsIdsByRoleAccount(leaderAddress, module))[0];
   const application: Application = await apiWrapper.getApplicationById(leaderApplicationId, module);
   assert(
-    worker.role_account_id.toString() === application.role_account_id.toString(),
+    worker.role_account_id.eq(application.role_account_id),
     `Role account ids does not match, leader account: ${worker.role_account_id}, application account ${application.role_account_id}`
   );
   return leadWorkerId;

+ 36 - 28
tests/network-tests/src/nicaea/utils/apiWrapper.ts

@@ -11,7 +11,7 @@ import { RoleParameters } from '@nicaea/types/roles';
 import { Seat } from '@nicaea/types/council';
 import { Balance, EventRecord, AccountId, BlockNumber, BalanceOf } from '@polkadot/types/interfaces';
 import BN from 'bn.js';
-import { SubmittableExtrinsic } from '@polkadot/api/types';
+import { SubmittableExtrinsic, UnsubscribePromise } from '@polkadot/api/types';
 import { Sender } from './sender';
 import { Utils } from './utils';
 import { Stake, StakedState } from '@nicaea/types/stake';
@@ -47,7 +47,8 @@ export class ApiWrapper {
       case WorkingGroups.storageWorkingGroup:
         return 'Storage';
       default:
-        return 'Undefined';
+        throw new Error(`Invalid working group string representation: ${workingGroup}`);
+        ;
     }
   }
 
@@ -335,7 +336,7 @@ export class ApiWrapper {
         {
           activate_at: 'CurrentBlock',
           commitment: {
-            application_rationing_policy: { max_active_applicants: '32' },
+            application_rationing_policy: { max_active_applicants: 32 },
             max_review_period_length: 32,
             application_staking_policy: {
               amount: 0,
@@ -384,13 +385,13 @@ export class ApiWrapper {
   }
 
   public estimateProposeFillLeaderOpeningFee(): BN {
-    const fillOpeningParameters: FillOpeningParameters = new FillOpeningParameters();
-    fillOpeningParameters.setAmountPerPayout(new BN(1));
-    fillOpeningParameters.setNextPaymentAtBlock(new BN(99999));
-    fillOpeningParameters.setPayoutInterval(new BN(99999));
-    fillOpeningParameters.setOpeningId(new BN(0));
-    fillOpeningParameters.setSuccessfulApplicationId(new BN(0));
-    fillOpeningParameters.setWorkingGroup('Storage');
+    const fillOpeningParameters: FillOpeningParameters = new FillOpeningParameters()
+      .setAmountPerPayout(new BN(1))
+      .setNextPaymentAtBlock(new BN(99999))
+      .setPayoutInterval(new BN(99999))
+      .setOpeningId(new BN(0))
+      .setSuccessfulApplicationId(new BN(0))
+      .setWorkingGroup('Storage');
 
     return this.estimateTxFee(
       this.api.tx.proposalsCodex.createFillWorkingGroupLeaderOpeningProposal(
@@ -808,9 +809,10 @@ export class ApiWrapper {
 
   public expectProposalCreated(): Promise<BN> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'ProposalCreated') {
+            unsubscribe();
             resolve(new BN(record.event.data[1].toString()));
           }
         });
@@ -820,9 +822,10 @@ export class ApiWrapper {
 
   public expectRuntimeUpgraded(): Promise<void> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method.toString() === 'RuntimeUpdated') {
+            unsubscribe();
             resolve();
           }
         });
@@ -832,13 +835,14 @@ export class ApiWrapper {
 
   public expectProposalFinalized(): Promise<void> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (
             record.event.method &&
             record.event.method.toString() === 'ProposalStatusUpdated' &&
             record.event.data[1].toString().includes('Executed')
           ) {
+            unsubscribe();
             resolve();
           }
         });
@@ -848,9 +852,10 @@ export class ApiWrapper {
 
   public expectOpeningFilled(): Promise<ApplicationIdToWorkerIdMap> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'OpeningFilled') {
+            unsubscribe();
             resolve((record.event.data[1] as unknown) as ApplicationIdToWorkerIdMap);
           }
         });
@@ -860,9 +865,10 @@ export class ApiWrapper {
 
   public expectOpeningAdded(): Promise<BN> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'OpeningAdded') {
+            unsubscribe();
             resolve((record.event.data as unknown) as BN);
           }
         });
@@ -872,9 +878,10 @@ export class ApiWrapper {
 
   public expectLeaderSet(): Promise<BN> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'LeaderSet') {
+            unsubscribe();
             resolve((record.event.data as unknown) as BN);
           }
         });
@@ -884,9 +891,10 @@ export class ApiWrapper {
 
   public expectLeaderTerminated(): Promise<void> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'TerminatedLeader') {
+            unsubscribe();
             resolve();
           }
         });
@@ -896,9 +904,10 @@ export class ApiWrapper {
 
   public expectWorkerRewardAmountUpdated(): Promise<void> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'WorkerRewardAmountUpdated') {
+            unsubscribe();
             resolve();
           }
         });
@@ -908,9 +917,10 @@ export class ApiWrapper {
 
   public expectWorkerStakeDecreased(): Promise<void> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'StakeDecreased') {
+            unsubscribe();
             resolve();
           }
         });
@@ -920,9 +930,10 @@ export class ApiWrapper {
 
   public expectWorkerStakeSlashed(): Promise<void> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'StakeSlashed') {
+            unsubscribe();
             resolve();
           }
         });
@@ -932,9 +943,10 @@ export class ApiWrapper {
 
   public expectApplicationReviewBegan(): Promise<BN> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'BeganApplicationReview') {
+            unsubscribe();
             resolve((record.event.data as unknown) as BN);
           }
         });
@@ -944,9 +956,10 @@ export class ApiWrapper {
 
   public expectMintCapacityChanged(): Promise<BN> {
     return new Promise(async resolve => {
-      await this.api.query.system.events<Vec<EventRecord>>(events => {
+      const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
           if (record.event.method && record.event.method.toString() === 'MintCapacityChanged') {
+            unsubscribe();
             resolve((record.event.data[1] as unknown) as BN);
           }
         });
@@ -1040,12 +1053,7 @@ export class ApiWrapper {
         title,
         description,
         proposalStake,
-        {
-          activate_at: opening.getActivateAt(),
-          commitment: opening.getCommitment(),
-          human_readable_text: opening.getText(),
-          working_group: workingGroup,
-        }
+        opening.getAddOpeningParameters(workingGroup)
       ),
       account,
       false