difftreelog
Check both unstakeAll and unstakePartial
in: master
2 files changed
tests/src/sub/appPromotion/appPromotion.test.tsdiffbeforeafterboth147 });147 });148 });148 });149149150 describe('unstake extrinsic', () => {150 describe('Unstaking', () => {151 [152 {method: 'unstakeAll' as const},153 {method: 'unstakePartial' as const},154 ].map(testCase => {151 itSub('should move tokens to "pendingUnstake" map and subtract it from totalStaked', async ({helper}) => {155 itSub(`[${testCase.method}] should move tokens to "pendingUnstake" and subtract it from totalStaked`, async ({helper}) => {152 const [staker, recepient] = [accounts.pop()!, accounts.pop()!];156 const [staker, recepient] = [accounts.pop()!, accounts.pop()!];153 const totalStakedBefore = await helper.staking.getTotalStaked();157 const totalStakedBefore = await helper.staking.getTotalStaked();158 const STAKE_AMOUNT = 900n * nominal;159154 await helper.staking.stake(staker, 900n * nominal);160 await helper.staking.stake(staker, STAKE_AMOUNT);161 testCase.method === 'unstakeAll'155 await helper.staking.unstakeAll(staker);162 ? await helper.staking.unstakeAll(staker)163 : await helper.staking.unstakePartial(staker, STAKE_AMOUNT);156164157 // Right after unstake tokens are still locked165 // Right after unstake tokens are still locked166 expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);158 expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'appstake', amount: 900n * nominal, reasons: 'All'}]);167 expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'appstake', amount: STAKE_AMOUNT, reasons: 'All'}]);159 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, miscFrozen: 900n * nominal, feeFrozen: 900n * nominal});168 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, miscFrozen: STAKE_AMOUNT, feeFrozen: STAKE_AMOUNT});160 // Staker can not transfer169 // Staker can not transfer161 await expect(helper.balance.transferToSubstrate(staker, recepient.address, 100n * nominal)).to.be.rejectedWith('balances.LiquidityRestrictions');170 await expect(helper.balance.transferToSubstrate(staker, recepient.address, 100n * nominal)).to.be.rejectedWith('balances.LiquidityRestrictions');162 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(900n * nominal);171 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(STAKE_AMOUNT);163 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);172 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);164 expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore);173 expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore);165 });174 });166175 });176177 [178 {method: 'unstakeAll' as const},179 {method: 'unstakePartial' as const},180 ].map(testCase => {167 itSub('should unlock balance after unlocking period ends and remove it from "pendingUnstake"', async ({helper}) => {181 itSub(`[${testCase.method}] should unlock balance after unlocking period ends and remove it from "pendingUnstake"`, async ({helper}) => {168 const staker = accounts.pop()!;182 const staker = accounts.pop()!;169 await helper.staking.stake(staker, 100n * nominal);183 await helper.staking.stake(staker, 100n * nominal);184 testCase.method === 'unstakeAll'170 await helper.staking.unstakeAll(staker);185 ? await helper.staking.unstakeAll(staker)186 : await helper.staking.unstakePartial(staker, 100n * nominal);171 const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});187 const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});172188173 // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n189 // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n178 // staker can transfer:194 // staker can transfer:179 await helper.balance.transferToSubstrate(staker, donor.address, 998n * nominal);195 await helper.balance.transferToSubstrate(staker, donor.address, 998n * nominal);180 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(1n);196 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(1n);181 });197 });182198 });199200 [201 {method: 'unstakeAll' as const},202 {method: 'unstakePartial' as const},203 ].map(testCase => {183 itSub('should successfully unstake multiple stakes', async ({helper}) => {204 itSub(`[${testCase.method}] should successfully unstake multiple stakes`, async ({helper}) => {184 const staker = accounts.pop()!;205 const staker = accounts.pop()!;185 await helper.staking.stake(staker, 100n * nominal);206 await helper.staking.stake(staker, 100n * nominal);186 await helper.staking.stake(staker, 200n * nominal);207 await helper.staking.stake(staker, 200n * nominal);197 expect(stakes[2].amount).to.equal(300n * nominal);218 expect(stakes[2].amount).to.equal(300n * nominal);198219199 // Can unstake multiple stakes220 // Can unstake multiple stakes221 testCase.method === 'unstakeAll'200 await helper.staking.unstakeAll(staker);222 ? await helper.staking.unstakeAll(staker)223 : await helper.staking.unstakePartial(staker, 600n * nominal);224201 pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});225 pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});202 totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});226 totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});210 await helper.wait.forParachainBlockNumber(pendingUnstake[0].block);234 await helper.wait.forParachainBlockNumber(pendingUnstake[0].block);211 expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, feeFrozen: 0n, miscFrozen: 0n});235 expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, feeFrozen: 0n, miscFrozen: 0n});212 expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);236 expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);213 });237 });214238 });239240 [241 {method: 'unstakeAll' as const},242 {method: 'unstakePartial' as const},243 ].map(testCase => {215 itSub('should not have any effects if no active stakes', async ({helper}) => {244 itSub(`[${testCase.method}] should not have any effects if no active stakes`, async ({helper}) => {216 const staker = accounts.pop()!;245 const staker = accounts.pop()!;217246218 // unstake has no effect if no stakes at all247 // unstake has no effect if no stakes at all248 testCase.method === 'unstakeAll'219 await helper.staking.unstakeAll(staker);249 ? await helper.staking.unstakeAll(staker)250 : await helper.staking.unstakePartial(staker, 100n * nominal);251220 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(0n);252 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(0n);221 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); // TODO bigint closeTo helper253 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); // TODO bigint closeTo helper225 // can't unstake if there are only pendingUnstakes257 // can't unstake if there are only pendingUnstakes226 await helper.staking.stake(staker, 100n * nominal);258 await helper.staking.stake(staker, 100n * nominal);259260 if (testCase.method === 'unstakeAll') {227 await helper.staking.unstakeAll(staker);261 await helper.staking.unstakeAll(staker);228 await helper.staking.unstakeAll(staker);262 await helper.staking.unstakeAll(staker);229263 } else {264 await helper.staking.unstakePartial(staker, 100n * nominal);265 await helper.staking.unstakePartial(staker, 100n * nominal);266 }267268 expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.eq(0);230 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);269 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);231 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);270 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);232 });271 });233272 });273274 [275 {method: 'unstakeAll' as const},276 {method: 'unstakePartial' as const},277 ].map(testCase => {234 itSub('should keep different unlocking block for each unlocking stake', async ({helper}) => {278 itSub(`[${testCase.method}] should create different pending-unlock for each unlocking stake`, async ({helper}) => {235 const staker = accounts.pop()!;279 const staker = accounts.pop()!;236 await helper.staking.stake(staker, 100n * nominal);280 await helper.staking.stake(staker, 100n * nominal);281 testCase.method === 'unstakeAll'237 await helper.staking.unstakeAll(staker);282 ? await helper.staking.unstakeAll(staker)283 : await helper.staking.unstakePartial(staker, 100n * nominal);238 await helper.staking.stake(staker, 120n * nominal);284 await helper.staking.stake(staker, 120n * nominal);285 testCase.method === 'unstakeAll'239 await helper.staking.unstakeAll(staker);286 ? await helper.staking.unstakeAll(staker)287 : await helper.staking.unstakePartial(staker, 120n * nominal);240288241 const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});289 const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});242 expect(unstakingPerBlock).has.length(2);290 expect(unstakingPerBlock).has.length(2);243 expect(unstakingPerBlock[0].amount).to.equal(100n * nominal);291 expect(unstakingPerBlock[0].amount).to.equal(100n * nominal);244 expect(unstakingPerBlock[1].amount).to.equal(120n * nominal);292 expect(unstakingPerBlock[1].amount).to.equal(120n * nominal);293 expect(await helper.staking.getStakesNumber({Substrate: staker.address})).to.equal(0);245 });294 });246295 });296297 [298 {method: 'unstakeAll' as const},299 {method: 'unstakePartial' as const},300 ].map(testCase => {247 itSub('should be possible for 3 accounts in one block', async ({helper}) => {301 itSub(`[${testCase.method}] should be possible for 3 accounts in one block`, async ({helper}) => {248 const stakers = [accounts.pop()!, accounts.pop()!, accounts.pop()!];302 const stakers = [accounts.pop()!, accounts.pop()!, accounts.pop()!];249303250 await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));304 await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));251 await Promise.all(stakers.map(staker => helper.staking.unstakeAll(staker)));305 await Promise.all(stakers.map(staker => {306 return testCase.method === 'unstakeAll'307 ? helper.staking.unstakeAll(staker)308 : helper.staking.unstakePartial(staker, 100n * nominal);309 }));252310253 await Promise.all(stakers.map(async (staker) => {311 await Promise.all(stakers.map(async (staker) => {254 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);312 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);255 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);313 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);256 }));314 }));257 });315 });316 });258317259 itSub('should not be possible for more than 3 accounts in one block', async ({helper}) => {318 itSub('should not be possible for more than 3 accounts in one block', async ({helper}) => {260 if (!await helper.arrange.isDevNode()) {319 if (!await helper.arrange.isDevNode()) {261 const stakers = await helper.arrange.createAccounts([200n,200n,200n,200n,200n,200n,200n,200n,200n,200n], donor);320 const stakers = await helper.arrange.createAccounts([200n,200n,200n,200n,200n,200n,200n,200n,200n,200n], donor);262321263 await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));322 await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));264 const unstakingResults = await Promise.allSettled(stakers.map(staker => helper.staking.unstakeAll(staker)));323 const unstakingResults = await Promise.allSettled(stakers.map((staker, i) => {324 return i % 2 === 0325 ? helper.staking.unstakeAll(staker)326 : helper.staking.unstakePartial(staker, 100n * nominal);327 }));265328266 const successfulUnstakes = unstakingResults.filter(result => result.status === 'fulfilled');329 const successfulUnstakes = unstakingResults.filter(result => result.status === 'fulfilled');267 expect(successfulUnstakes).to.have.length(3);330 expect(successfulUnstakes).to.have.length(3);tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -2689,6 +2689,16 @@
}
/**
+ * Get total number of active stakes
+ * @param address substrate address
+ * @returns {number}
+ */
+ async getStakesNumber(address: ICrossAccountId): Promise<number> {
+ if (address.Ethereum) throw Error('only substrate address');
+ return (await this.helper.callRpc('api.query.appPromotion.stakesPerAccount', [address.Substrate])).toNumber();
+ }
+
+ /**
* Get total staked amount for address
* @param address substrate or ethereum address
* @returns total staked amount