git.delta.rocks / unique-network / refs/commits / 160555a5ac1e

difftreelog

Fix helpers, refactor tests, and add tests TODOs

Max Andreev2022-08-27parent: #0095393.patch.diff
in: master

2 files changed

modifiedtests/src/app-promotion.test.tsdiffbeforeafterboth
24import 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';
2827
29import {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);
6262
63 // TODO add helpers to assert bigints. Check balance close to 1063 // TODO add helpers to assert bigints. Check balance close to 10
66 // 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
6868
69 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);
8080
81 // Can't stake full balance because Alice needs to pay some fee
81 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);
84
85 // Can't stake 4 tkn because Alice has ~3 free tkn, and 7 locked
83 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});
102107
103describe('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);
110115
111 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 });
121
116 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 = 1000
118 // arrange: Alice stakes 100
119 // arrange: Alice stakes 200
120 // arrange: Alice stakes 300
121
122 // assert Alice stake is [100, 200, 300]
123
124
125 // act: Alice calls appPromotion.unstake(30)
126 // assert: query appPromotion.staked(Alice) to equal [70, 200, 300] /// Can unstake part of stake
127 // assert: query appPromotion.pendingUnstake(Alice) to equal [30]
128
129 // act: Alice calls appPromotion.unstake(170)
130 // assert: query appPromotion.staked(Alice) to equal [100, 300] /// Can unstake one stake totally and one more partialy
131 // assert: query appPromotion.pendingUnstake(Alice) to equal [30, 170]
132
133 // act: Alice calls appPromotion.unstake(400)
134 // assert: query appPromotion.staked(Alice) to equal [100, 300] /// Can totally unstake 2 stakes in one tx
135 // 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);
128
129 // staked: [10, 20, 30]; unstaked: 0
130 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 stake
144 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]);
145
146 // Can unstake one stake totally and one more partially
147 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 154
155 // Can totally unstake 2 stakes in one tx
157 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 164
165 // TODO it('try to hack unstaking with nonce')
163 });166 });
164});167});
165
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -2030,7 +2030,11 @@
   }
 
   async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {
-    return (await this.helper.callRpc('api.rpc.unique.pendingUnstake')).toBigInt();
+    return (await this.helper.callRpc('api.rpc.unique.pendingUnstake', [address])).toBigInt();
+  }
+  
+  async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<bigint[][]> {
+    return (await this.helper.callRpc('api.rpc.unique.pendingUnstakePerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);
   }
 }