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

difftreelog

Return (un)staking info in more convinient view

Max Andreev2022-09-14parent: #85b56f6.patch.diff
in: master
- Refactor getTotalStakedPerBlock getPendingUnstakePerBlock methods.
- Add docs

3 files changed

modifiedtests/src/app-promotion.test.tsdiffbeforeafterboth
81 81
82 await helper.staking.stake(staker, 200n * nominal);82 await helper.staking.stake(staker, 200n * nominal);
83 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(300n * nominal);83 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(300n * nominal);
84 expect((await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map((x) => x[1])).to.be.deep.equal([100n * nominal, 200n * nominal]);84 const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
85 expect(totalStakedPerBlock[0].amount).to.equal(100n * nominal);
86 expect(totalStakedPerBlock[1].amount).to.equal(200n * nominal);
85 });87 });
86 });88 });
8789
159 const staker = accounts.pop()!;161 const staker = accounts.pop()!;
160 await helper.staking.stake(staker, 100n * nominal);162 await helper.staking.stake(staker, 100n * nominal);
161 await helper.staking.unstake(staker);163 await helper.staking.unstake(staker);
162 const unstakedInBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}))[0][0];164 const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
163165
164 // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n166 // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n
165 await helper.wait.forParachainBlockNumber(unstakedInBlock);167 await helper.wait.forParachainBlockNumber(pendingUnstake.block);
166 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, miscFrozen: 0n, feeFrozen: 0n});168 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, miscFrozen: 0n, feeFrozen: 0n});
167 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);169 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
168170
180 await helper.staking.stake(staker, 300n * nominal);182 await helper.staking.stake(staker, 300n * nominal);
181183
182 // staked: [100, 200, 300]; unstaked: 0184 // staked: [100, 200, 300]; unstaked: 0
183 let pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});185 let totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
184 let unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);186 let pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
185 let stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);187 let stakes = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
186 expect(pendingUnstake).to.be.deep.equal(0n);188 expect(totalPendingUnstake).to.be.deep.equal(0n);
187 expect(unstakedPerBlock).to.be.deep.equal([]);189 expect(pendingUnstake).to.be.deep.equal([]);
188 expect(stakedPerBlock).to.be.deep.equal([100n * nominal, 200n * nominal, 300n * nominal]);190 expect(stakes[0].amount).to.equal(100n * nominal);
189 191 expect(stakes[1].amount).to.equal(200n * nominal);
192 expect(stakes[2].amount).to.equal(300n * nominal);
193
190 // Can unstake multiple stakes194 // Can unstake multiple stakes
191 await helper.staking.unstake(staker);195 await helper.staking.unstake(staker);
192 const unstakingBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}))[0][0];196 pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
193 pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});197 totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
194 unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);
195 stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);198 stakes = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
196 expect(pendingUnstake).to.be.equal(600n * nominal);199 expect(totalPendingUnstake).to.be.equal(600n * nominal);
197 expect(stakedPerBlock).to.be.deep.equal([]);200 expect(stakes).to.be.deep.equal([]);
198 expect(unstakedPerBlock).to.be.deep.equal([600n * nominal]);201 expect(pendingUnstake[0].amount).to.equal(600n * nominal);
199202
200 expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 600n * nominal, feeFrozen: 0n, miscFrozen: 0n});203 expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 600n * nominal, feeFrozen: 0n, miscFrozen: 0n});
201 await helper.wait.forParachainBlockNumber(unstakingBlock);204 await helper.wait.forParachainBlockNumber(pendingUnstake[0].block);
202 expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, feeFrozen: 0n, miscFrozen: 0n});205 expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, feeFrozen: 0n, miscFrozen: 0n});
203 expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);206 expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
204 });207 });
235238
236 const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});239 const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
237 expect(unstakingPerBlock).has.length(2);240 expect(unstakingPerBlock).has.length(2);
238 expect(unstakingPerBlock[0][1]).to.equal(100n * nominal);241 expect(unstakingPerBlock[0].amount).to.equal(100n * nominal);
239 expect(unstakingPerBlock[1][1]).to.equal(120n * nominal);242 expect(unstakingPerBlock[1].amount).to.equal(120n * nominal);
240 });243 });
241 });244 });
242245
668 await helper.staking.stake(staker, 100n * nominal);671 await helper.staking.stake(staker, 100n * nominal);
669672
670 // Wait for rewards and pay673 // Wait for rewards and pay
671 const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[0][0];674 const [stakedInBlock] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
672 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock));675 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock.block));
673 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));676 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
674677
675 const totalStakedAfter = await helper.staking.getTotalStaked();678 const totalStakedAfter = await helper.staking.getTotalStaked();
691 await helper.staking.stake(staker, 200n * nominal);694 await helper.staking.stake(staker, 200n * nominal);
692695
693 // wait rewards are available:696 // wait rewards are available:
694 const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[1][0];697 const [_, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
695 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock));698 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block));
696699
697 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));700 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
698701
699 const totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);702 const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
700 expect(totalStakedPerBlock).to.be.deep.equal([calculateIncome(100n * nominal, 10n), calculateIncome(200n * nominal, 10n)]);703 expect(totalStakedPerBlock[0].amount).to.equal(calculateIncome(100n * nominal, 10n));
704 expect(totalStakedPerBlock[1].amount).to.equal(calculateIncome(200n * nominal, 10n));
701 });705 });
702 });706 });
703707
707711
708 await helper.staking.stake(staker, 100n * nominal);712 await helper.staking.stake(staker, 100n * nominal);
709 // wait for two rewards are available:713 // wait for two rewards are available:
710 const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[0][0];714 let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
711 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock) + LOCKING_PERIOD);715 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
712716
713 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));717 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
714 const stakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});718 [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
715 const frozenBalanceShouldBe = calculateIncome(100n * nominal, 10n, 2);719 const frozenBalanceShouldBe = calculateIncome(100n * nominal, 10n, 2);
716 expect(stakedPerBlock[0][1]).to.be.equal(frozenBalanceShouldBe);720 expect(stake.amount).to.be.equal(frozenBalanceShouldBe);
717721
718 const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);722 const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);
719723
726 // staker unstakes before rewards has been payed730 // staker unstakes before rewards has been payed
727 const staker = accounts.pop()!;731 const staker = accounts.pop()!;
728 await helper.staking.stake(staker, 100n * nominal);732 await helper.staking.stake(staker, 100n * nominal);
729 const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[0][0];733 const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
730 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock) + LOCKING_PERIOD);734 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
731 await helper.staking.unstake(staker);735 await helper.staking.unstake(staker);
732 736
733 // so he did not receive any rewards737 // so he did not receive any rewards
745 749
746 await helper.staking.stake(staker, 100n * nominal);750 await helper.staking.stake(staker, 100n * nominal);
747751
748 const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[0][0];752 let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
749 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock));753 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block));
750 754
751 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));755 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
752 let totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);756 [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
753 expect(totalStakedPerBlock).to.deep.equal([calculateIncome(100n * nominal, 10n)]);757 expect(stake.amount).to.equal(calculateIncome(100n * nominal, 10n));
754 758
755 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock) + LOCKING_PERIOD);759 await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
756 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));760 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
757 totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);761 [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
758 expect(totalStakedPerBlock).to.deep.equal([calculateIncome(100n * nominal, 10n, 2)]); 762 expect(stake.amount).to.equal(calculateIncome(100n * nominal, 10n, 2));
759 });763 });
760 });764 });
761765
modifiedtests/src/util/playgrounds/types.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/types.ts
+++ b/tests/src/util/playgrounds/types.ts
@@ -147,6 +147,11 @@
   feeFrozen: bigint
 }
 
+export interface IStakingInfo {
+  block: bigint,
+  amount: bigint,
+}
+
 export type TSubstrateAccount = string;
 export type TEthereumAccount = string;
 export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -9,7 +9,7 @@
 import {ApiInterfaceEvents} from '@polkadot/api/types';
 import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
 import {IKeyringPair} from '@polkadot/types/types';
-import {IApiListeners, IBlock, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
+import {IApiListeners, IBlock, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
 
 export const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
   const address = {} as ICrossAccountId;
@@ -2029,21 +2029,54 @@
     return 1;
   }
 
+  /**
+   * Get total staked amount for address
+   * @param address substrate or ethereum address
+   * @returns total staked amount
+   */
   async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {
     if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();
     return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();
   }
 
-  async getTotalStakedPerBlock(address: ICrossAccountId): Promise<bigint[][]> {
-    return (await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);
+  /**
+   * Get total staked per block
+   * @param address substrate or ethereum address
+   * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block
+   */
+  async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
+    const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);
+    return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {
+      return { 
+        block: block.toBigInt(),
+        amount: amount.toBigInt(),
+      };
+    });
   }
 
+  /**
+   * Get total pending unstake amount for address
+   * @param address substrate or ethereum address
+   * @returns total pending unstake amount
+   */
   async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {
     return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();
   }
 
-  async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<bigint[][]> {
-    return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);
+  /**
+   * Get pending unstake amount per block for address
+   * @param address substrate or ethereum address
+   * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block
+   */
+  async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
+    const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);
+    const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {
+      return {
+        block: block.toBigInt(),
+        amount: amount.toBigInt(),
+      };
+    });
+    return result;
   }
 }