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
147 feeFrozen: bigint147 feeFrozen: bigint
148}148}
149
150export interface IStakingInfo {
151 block: bigint,
152 amount: bigint,
153}
149154
150export type TSubstrateAccount = string;155export type TSubstrateAccount = string;
151export type TEthereumAccount = string;156export type TEthereumAccount = string;
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
9import {ApiInterfaceEvents} from '@polkadot/api/types';9import {ApiInterfaceEvents} from '@polkadot/api/types';
10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
11import {IKeyringPair} from '@polkadot/types/types';11import {IKeyringPair} from '@polkadot/types/types';
12import {IApiListeners, IBlock, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';12import {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';
1313
14export const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {14export const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
15 const address = {} as ICrossAccountId;15 const address = {} as ICrossAccountId;
2029 return 1;2029 return 1;
2030 }2030 }
20312031
2032 /**
2033 * Get total staked amount for address
2034 * @param address substrate or ethereum address
2035 * @returns total staked amount
2036 */
2032 async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2037 async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {
2033 if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2038 if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();
2034 return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2039 return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();
2035 }2040 }
20362041
2042 /**
2043 * Get total staked per block
2044 * @param address substrate or ethereum address
2045 * @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
2046 */
2037 async getTotalStakedPerBlock(address: ICrossAccountId): Promise<bigint[][]> {2047 async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
2048 const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);
2038 return (await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);2049 return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {
2050 return {
2051 block: block.toBigInt(),
2052 amount: amount.toBigInt(),
2053 };
2054 });
2039 }2055 }
20402056
2057 /**
2058 * Get total pending unstake amount for address
2059 * @param address substrate or ethereum address
2060 * @returns total pending unstake amount
2061 */
2041 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2062 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {
2042 return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2063 return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();
2043 }2064 }
20442065
2066 /**
2067 * Get pending unstake amount per block for address
2068 * @param address substrate or ethereum address
2069 * @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
2070 */
2045 async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<bigint[][]> {2071 async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {
2072 const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);
2046 return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);2073 const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {
2074 return {
2075 block: block.toBigInt(),
2076 amount: amount.toBigInt(),
2077 };
2078 });
2079 return result;
2047 }2080 }
2048}2081}
20492082