difftreelog
Return (un)staking info in more convinient view
in: master
- Refactor getTotalStakedPerBlock getPendingUnstakePerBlock methods. - Add docs
3 files changed
tests/src/app-promotion.test.tsdiffbeforeafterboth81 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 });8789159 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});163165164 // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n166 // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n165 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);168170180 await helper.staking.stake(staker, 300n * nominal);182 await helper.staking.stake(staker, 300n * nominal);181183182 // staked: [100, 200, 300]; unstaked: 0184 // staked: [100, 200, 300]; unstaked: 0183 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 stakes191 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);199202200 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 });235238236 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 });242245668 await helper.staking.stake(staker, 100n * nominal);671 await helper.staking.stake(staker, 100n * nominal);669672670 // Wait for rewards and pay673 // Wait for rewards and pay671 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));674677675 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);692695693 // 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));696699697 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));700 await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));698701699 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 });703707707711708 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);712716713 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);717721718 const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);722 const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);719723726 // staker unstakes before rewards has been payed730 // staker unstakes before rewards has been payed727 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 rewards745 749 746 await helper.staking.stake(staker, 100n * nominal);750 await helper.staking.stake(staker, 100n * nominal);747751748 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 });761765tests/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';
tests/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;
}
}