difftreelog
Fix helpers, refactor tests, and add tests TODOs
in: master
2 files changed
tests/src/app-promotion.test.tsdiffbeforeafterboth24import chai from 'chai';24import chai from 'chai';25import chaiAsPromised from 'chai-as-promised';25import chaiAsPromised from 'chai-as-promised';26import {usingPlaygrounds} from './util/playgrounds';26import {usingPlaygrounds} from './util/playgrounds';27import {default as waitNewBlocks} from './substrate/wait-new-blocks';282729import {encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto';28import {encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto';30import {stringToU8a} from '@polkadot/util';29import {stringToU8a} from '@polkadot/util';56 const totalStakedBefore = await helper.staking.getTotalStaked();55 const totalStakedBefore = await helper.staking.getTotalStaked();57 const [staker] = await helper.arrange.creteAccounts([10n], alice);56 const [staker] = await helper.arrange.creteAccounts([10n], alice);58 57 58 // Minimum stake amount is 1:59 await expect(helper.staking.stake(staker, nominal - 1n)).to.be.eventually.rejected; // minimum stake amount is 159 await expect(helper.staking.stake(staker, nominal - 1n)).to.be.eventually.rejected;60 await expect(helper.staking.stake(staker, nominal)).to.be.eventually.fulfilled;60 await helper.staking.stake(staker, nominal);61 expect(await helper.staking.getTotalStakingLocked({Substrate: staker.address})).to.be.equal(nominal);61 expect(await helper.staking.getTotalStakingLocked({Substrate: staker.address})).to.be.equal(nominal);626263 // TODO add helpers to assert bigints. Check balance close to 1063 // TODO add helpers to assert bigints. Check balance close to 1066 // it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo? 66 // it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo? 67 expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + nominal); // total tokens amount staked in app-promotion increased 67 expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + nominal); // total tokens amount staked in app-promotion increased 686869 await expect(helper.staking.stake(staker, 2n * nominal)).to.be.eventually.fulfilled;69 await helper.staking.stake(staker, 2n * nominal);70 expect(await helper.staking.getTotalStakingLocked({Substrate: staker.address})).to.be.equal(3n * nominal);70 expect(await helper.staking.getTotalStakingLocked({Substrate: staker.address})).to.be.equal(3n * nominal);71 71 72 const stakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});72 const stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map((x) => x[1]);73 expect(stakedPerBlock.map((x) => x[1])).to.be.deep.equal([nominal, 2n * nominal]);73 expect(stakedPerBlock).to.be.deep.equal([nominal, 2n * nominal]);74 });74 });75 });75 });76 76 77 it('will throws if stake amount is more than total free balance', async () => {77 it('will throws if stake amount is more than total free balance', async () => {78 await usingPlaygrounds(async helper => { 78 await usingPlaygrounds(async helper => { 79 const [staker] = await helper.arrange.creteAccounts([10n], alice);79 const [staker] = await helper.arrange.creteAccounts([10n], alice);808081 // Can't stake full balance because Alice needs to pay some fee81 await expect(helper.staking.stake(staker, 10n * nominal)).to.be.eventually.rejected; // because Alice needs some fee82 await expect(helper.staking.stake(staker, 10n * nominal)).to.be.eventually.rejected;82 await expect(helper.staking.stake(staker, 7n * nominal)).to.be.eventually.fulfilled;83 await helper.staking.stake(staker, 7n * nominal);8485 // Can't stake 4 tkn because Alice has ~3 free tkn, and 7 locked83 await expect(helper.staking.stake(staker, 4n * nominal)).to.be.eventually.rejected; // because Alice has ~300 free QTZ and 700 locked86 await expect(helper.staking.stake(staker, 4n * nominal)).to.be.eventually.rejected; 84 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(7n * nominal);87 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(7n * nominal);85 });88 });86 });89 });97 });100 });98 });101 });99 // TODO it('Staker stakes 5 times in one block with nonce');102 // TODO it('Staker stakes 5 times in one block with nonce');100 // TODO it('Staked balance appears as locked in the balance pallet')103 // TODO it('Staked balance appears as locked in the balance pallet');104 // TODO it('Alice stakes huge amount of tokens');105 // TODO it('Can stake from ethereum account')101});106});102107103describe('unstake balance extrinsic', () => { 108describe('unstake balance extrinsic', () => { 104 it('will change balance state to "reserved", add it to "pendingUnstake" map, and subtract it from totalStaked', async () => {109 it('will change balance state to "reserved", add it to "pendingUnstake" map, and subtract it from totalStaked', async () => {105 await usingPlaygrounds(async helper => {110 await usingPlaygrounds(async helper => {106 const totalStakedBefore = await helper.staking.getTotalStaked();111 const totalStakedBefore = await helper.staking.getTotalStaked();107 const [staker] = await helper.arrange.creteAccounts([10n], alice);112 const [staker] = await helper.arrange.creteAccounts([10n], alice);108 await expect(helper.staking.stake(staker, 5n * nominal)).to.be.eventually.fulfilled;113 await helper.staking.stake(staker, 5n * nominal);109 await expect(helper.staking.unstake(staker, 3n * nominal)).to.be.eventually.fulfilled;114 await helper.staking.unstake(staker, 3n * nominal);110115111 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(3n * nominal);116 expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(3n * nominal);112 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(2n * nominal);117 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(2n * nominal);113 expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 2n * nominal);118 expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 2n * nominal);114 });119 });115 });120 });121116 it('will remove from the "staked" map starting from the oldest entry', async () => {122 it('will remove from the "staked" map starting from the oldest entry', async () => {117 // arrange: Alice balance = 1000118 // arrange: Alice stakes 100119 // arrange: Alice stakes 200120 // arrange: Alice stakes 300121122 // assert Alice stake is [100, 200, 300]123124125 // act: Alice calls appPromotion.unstake(30)126 // assert: query appPromotion.staked(Alice) to equal [70, 200, 300] /// Can unstake part of stake127 // assert: query appPromotion.pendingUnstake(Alice) to equal [30]128129 // act: Alice calls appPromotion.unstake(170)130 // assert: query appPromotion.staked(Alice) to equal [100, 300] /// Can unstake one stake totally and one more partialy131 // assert: query appPromotion.pendingUnstake(Alice) to equal [30, 170]132133 // act: Alice calls appPromotion.unstake(400)134 // assert: query appPromotion.staked(Alice) to equal [100, 300] /// Can totally unstake 2 stakes in one tx135 // assert: query appPromotion.pendingUnstake(Alice) to equal [30, 170, 400]136 await usingPlaygrounds(async helper => {123 await usingPlaygrounds(async helper => {137 const totalStakedBefore = (await helper.api!.rpc.unique.totalStaked()).toBigInt();124 const [staker] = await helper.arrange.creteAccounts([100n], alice);138 const staker = await createUser();125 await helper.staking.stake(staker, 10n * nominal);139 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(1n * nominal))).to.be.eventually.fulfilled;126 await helper.staking.stake(staker, 20n * nominal);140 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(2n * nominal))).to.be.eventually.fulfilled;127 await helper.staking.stake(staker, 30n * nominal);128129 // staked: [10, 20, 30]; unstaked: 0130 let pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});141 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(3n * nominal))).to.be.eventually.fulfilled;131 let unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);142 let stakedPerBlock = (await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker))).map(([_, amount]) => amount.toBigInt());132 let stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);133 expect(pendingUnstake).to.be.deep.equal(0n);134 expect(unstakedPerBlock).to.be.deep.equal([]);143 expect(stakedPerBlock).to.be.deep.equal([nominal, 2n * nominal, 3n * nominal]);135 expect(stakedPerBlock).to.be.deep.equal([10n * nominal, 20n * nominal, 30n * nominal]);136 137 // Can unstake the part of a stake144 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.unstake(3n * nominal / 10n))).to.be.eventually.fulfilled;138 await helper.staking.unstake(staker, 5n * nominal);139 pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});145 expect((await helper.api!.rpc.unique.pendingUnstake(normalizeAccountId(staker.address))).toBigInt()).to.be.equal(3n * nominal / 10n);140 unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);146 stakedPerBlock = (await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker))).map(([_, amount]) => amount.toBigInt());141 stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);147 142 expect(pendingUnstake).to.be.equal(5n * nominal);148 expect(stakedPerBlock).to.be.deep.equal([7n * nominal / 10n, 2n * nominal, 3n * nominal]);143 expect(stakedPerBlock).to.be.deep.equal([5n * nominal, 20n * nominal, 30n * nominal]);149 144 expect(unstakedPerBlock).to.be.deep.equal([5n * nominal]);145146 // Can unstake one stake totally and one more partially147 await helper.staking.unstake(staker, 10n * nominal);148 pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});150 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.unstake(17n * nominal / 10n))).to.be.eventually.fulfilled;149 unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);151 stakedPerBlock = (await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker))).map(([_, amount]) => amount.toBigInt());150 stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);151 expect(pendingUnstake).to.be.equal(15n * nominal);152 expect(stakedPerBlock).to.be.deep.equal([nominal, 3n * nominal]);152 expect(stakedPerBlock).to.be.deep.equal([15n * nominal, 30n * nominal]);153 const unstakedPerBlock = (await helper.api!.rpc.unique.pendingUnstakePerBlock(normalizeAccountId(staker))).map(([_, amount]) => amount.toBigInt());154 155 expect(unstakedPerBlock).to.be.deep.equal([3n * nominal / 10n, 17n * nominal / 10n]);153 expect(unstakedPerBlock).to.deep.equal([5n * nominal, 10n * nominal]);156 154155 // Can totally unstake 2 stakes in one tx157 await waitNewBlocks(helper.api!, 1);156 await helper.staking.unstake(staker, 45n * nominal);157 pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});158 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.unstake(4n * nominal))).to.be.eventually.fulfilled;158 unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);159 expect((await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker))).map(([_, amount]) => amount.toBigInt())).to.be.deep.equal([]);159 stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);160 expect(pendingUnstake).to.be.equal(60n * nominal);161 expect(stakedPerBlock).to.deep.equal([]);160 expect((await helper.api!.rpc.unique.pendingUnstakePerBlock(normalizeAccountId(staker))).map(([_, amount]) => amount.toBigInt())).to.be.deep.equal([3n * nominal / 10n, 17n * nominal / 10n, 4n * nominal]);162 expect(unstakedPerBlock).to.deep.equal([5n * nominal, 10n * nominal, 45n * nominal]);161 });163 });162 164165 // TODO it('try to hack unstaking with nonce')163 });166 });164});167});165tests/src/util/playgrounds/unique.tsdiffbeforeafterboth2030 }2030 }203120312032 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2032 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2033 return (await this.helper.callRpc('api.rpc.unique.pendingUnstake')).toBigInt();2033 return (await this.helper.callRpc('api.rpc.unique.pendingUnstake', [address])).toBigInt();2034 }2034 }2035 2036 async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<bigint[][]> {2037 return (await this.helper.callRpc('api.rpc.unique.pendingUnstakePerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);2038 }2035}2039}203620402037export class UniqueHelper extends ChainHelperBase {2041export class UniqueHelper extends ChainHelperBase {