@subwallet/extension-base 1.0.7-0 → 1.0.7-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/background/KoniTypes.d.ts +7 -8
- package/cjs/constants/index.js +1 -1
- package/cjs/koni/api/staking/bonding/amplitude.js +83 -0
- package/cjs/koni/api/staking/bonding/astar.js +109 -5
- package/cjs/koni/api/staking/bonding/index.js +35 -0
- package/cjs/koni/api/staking/bonding/paraChain.js +97 -0
- package/cjs/koni/api/staking/bonding/relayChain.js +203 -15
- package/cjs/koni/api/staking/bonding/utils.js +7 -0
- package/cjs/koni/api/staking/index.js +11 -11
- package/cjs/koni/api/staking/paraChain.js +200 -130
- package/cjs/koni/api/staking/relayChain.js +66 -68
- package/cjs/koni/api/staking/subsquidStaking.js +6 -11
- package/cjs/koni/background/cron.js +0 -25
- package/cjs/koni/background/handlers/Extension.js +98 -74
- package/cjs/koni/background/handlers/State.js +17 -19
- package/cjs/koni/background/subscription.js +57 -12
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/constants.js +3 -1
- package/cjs/services/chain-service/utils.js +6 -1
- package/cjs/services/storage-service/DatabaseService.js +7 -3
- package/cjs/services/storage-service/db-stores/ChainStakingMetadata.js +5 -0
- package/cjs/services/storage-service/db-stores/NominatorMetadata.js +4 -4
- package/cjs/services/transaction-service/index.js +6 -1
- package/constants/index.d.ts +1 -1
- package/constants/index.js +1 -1
- package/koni/api/staking/bonding/amplitude.d.ts +4 -0
- package/koni/api/staking/bonding/amplitude.js +81 -0
- package/koni/api/staking/bonding/astar.d.ts +4 -0
- package/koni/api/staking/bonding/astar.js +107 -5
- package/koni/api/staking/bonding/index.d.ts +1 -0
- package/koni/api/staking/bonding/index.js +38 -4
- package/koni/api/staking/bonding/paraChain.d.ts +4 -0
- package/koni/api/staking/bonding/paraChain.js +95 -0
- package/koni/api/staking/bonding/relayChain.d.ts +5 -0
- package/koni/api/staking/bonding/relayChain.js +198 -14
- package/koni/api/staking/bonding/utils.d.ts +5 -0
- package/koni/api/staking/bonding/utils.js +6 -0
- package/koni/api/staking/index.d.ts +4 -4
- package/koni/api/staking/index.js +11 -11
- package/koni/api/staking/paraChain.d.ts +5 -5
- package/koni/api/staking/paraChain.js +201 -131
- package/koni/api/staking/relayChain.d.ts +4 -4
- package/koni/api/staking/relayChain.js +66 -67
- package/koni/api/staking/subsquidStaking.d.ts +1 -1
- package/koni/api/staking/subsquidStaking.js +6 -11
- package/koni/background/cron.js +1 -26
- package/koni/background/handlers/Extension.js +29 -7
- package/koni/background/handlers/State.d.ts +2 -2
- package/koni/background/handlers/State.js +17 -19
- package/koni/background/subscription.d.ts +2 -1
- package/koni/background/subscription.js +58 -13
- package/package.json +5 -5
- package/packageInfo.js +1 -1
- package/services/chain-service/constants.d.ts +1 -0
- package/services/chain-service/constants.js +3 -2
- package/services/chain-service/types.d.ts +8 -0
- package/services/chain-service/utils.js +6 -1
- package/services/storage-service/DatabaseService.d.ts +2 -2
- package/services/storage-service/DatabaseService.js +7 -3
- package/services/storage-service/db-stores/ChainStakingMetadata.d.ts +1 -0
- package/services/storage-service/db-stores/ChainStakingMetadata.js +3 -0
- package/services/storage-service/db-stores/NominatorMetadata.d.ts +2 -2
- package/services/storage-service/db-stores/NominatorMetadata.js +4 -4
- package/services/transaction-service/index.js +6 -1
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { StakingType } from '@subwallet/extension-base/background/KoniTypes';
|
|
5
|
-
import { getAmplitudeBondingExtrinsic, getAmplitudeClaimRewardExtrinsic, getAmplitudeCollatorsInfo, getAmplitudeNominatorMetadata, getAmplitudeStakingMetadata, getAmplitudeUnbondingExtrinsic, getAmplitudeWithdrawalExtrinsic } from '@subwallet/extension-base/koni/api/staking/bonding/amplitude';
|
|
6
|
-
import { getAstarBondingExtrinsic, getAstarClaimRewardExtrinsic, getAstarDappsInfo, getAstarNominatorMetadata, getAstarStakingMetadata, getAstarUnbondingExtrinsic, getAstarWithdrawalExtrinsic } from '@subwallet/extension-base/koni/api/staking/bonding/astar';
|
|
7
|
-
import { getParaBondingExtrinsic, getParaCancelWithdrawalExtrinsic, getParachainCollatorsInfo, getParaChainNominatorMetadata, getParaChainStakingMetadata, getParaUnbondingExtrinsic, getParaWithdrawalExtrinsic, validateParaChainBondingCondition, validateParaChainUnbondingCondition } from '@subwallet/extension-base/koni/api/staking/bonding/paraChain';
|
|
8
|
-
import { getPoolingClaimRewardExtrinsic, getPoolingWithdrawalExtrinsic, getRelayBondingExtrinsic, getRelayCancelWithdrawalExtrinsic, getRelayChainNominatorMetadata, getRelayChainStakingMetadata, getRelayPoolsInfo, getRelayUnbondingExtrinsic, getRelayValidatorsInfo, getRelayWithdrawalExtrinsic, validateRelayBondingCondition, validateRelayUnbondingCondition } from '@subwallet/extension-base/koni/api/staking/bonding/relayChain';
|
|
5
|
+
import { getAmplitudeBondingExtrinsic, getAmplitudeClaimRewardExtrinsic, getAmplitudeCollatorsInfo, getAmplitudeNominatorMetadata, getAmplitudeStakingMetadata, getAmplitudeUnbondingExtrinsic, getAmplitudeWithdrawalExtrinsic, subscribeAmplitudeStakingMetadata } from '@subwallet/extension-base/koni/api/staking/bonding/amplitude';
|
|
6
|
+
import { getAstarBondingExtrinsic, getAstarClaimRewardExtrinsic, getAstarDappsInfo, getAstarNominatorMetadata, getAstarStakingMetadata, getAstarUnbondingExtrinsic, getAstarWithdrawalExtrinsic, subscribeAstarStakingMetadata } from '@subwallet/extension-base/koni/api/staking/bonding/astar';
|
|
7
|
+
import { getParaBondingExtrinsic, getParaCancelWithdrawalExtrinsic, getParachainCollatorsInfo, getParaChainNominatorMetadata, getParaChainStakingMetadata, getParaUnbondingExtrinsic, getParaWithdrawalExtrinsic, subscribeParaChainStakingMetadata, validateParaChainBondingCondition, validateParaChainUnbondingCondition } from '@subwallet/extension-base/koni/api/staking/bonding/paraChain';
|
|
8
|
+
import { getPoolingClaimRewardExtrinsic, getPoolingWithdrawalExtrinsic, getRelayBondingExtrinsic, getRelayCancelWithdrawalExtrinsic, getRelayChainNominatorMetadata, getRelayChainStakingMetadata, getRelayPoolsInfo, getRelayUnbondingExtrinsic, getRelayValidatorsInfo, getRelayWithdrawalExtrinsic, subscribeRelayChainStakingMetadata, validateRelayBondingCondition, validateRelayUnbondingCondition } from '@subwallet/extension-base/koni/api/staking/bonding/relayChain';
|
|
9
9
|
import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
10
10
|
// all addresses must be converted to its chain format
|
|
11
11
|
|
|
@@ -100,4 +100,38 @@ export async function getCancelWithdrawalExtrinsic(substrateApi, chain, selected
|
|
|
100
100
|
return getParaCancelWithdrawalExtrinsic(substrateApi, selectedUnstaking);
|
|
101
101
|
}
|
|
102
102
|
return getRelayCancelWithdrawalExtrinsic(substrateApi, selectedUnstaking);
|
|
103
|
+
}
|
|
104
|
+
export function subscribeEssentialChainStakingMetadata(substrateApiMap, chainInfoMap, callback) {
|
|
105
|
+
const unsubList = [];
|
|
106
|
+
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
108
|
+
Object.values(chainInfoMap).forEach(async chainInfo => {
|
|
109
|
+
const substrateApi = await substrateApiMap[chainInfo.slug].isReady;
|
|
110
|
+
if (_STAKING_CHAIN_GROUP.astar.includes(chainInfo.slug)) {
|
|
111
|
+
const unsub = await subscribeAstarStakingMetadata(chainInfo.slug, substrateApi, callback);
|
|
112
|
+
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
unsubList.push(unsub);
|
|
115
|
+
} else if (_STAKING_CHAIN_GROUP.para.includes(chainInfo.slug)) {
|
|
116
|
+
const unsub = await subscribeParaChainStakingMetadata(chainInfo.slug, substrateApi, callback);
|
|
117
|
+
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
unsubList.push(unsub);
|
|
120
|
+
} else if (_STAKING_CHAIN_GROUP.amplitude.includes(chainInfo.slug)) {
|
|
121
|
+
const unsub = await subscribeAmplitudeStakingMetadata(chainInfo.slug, substrateApi, callback);
|
|
122
|
+
|
|
123
|
+
// @ts-ignore
|
|
124
|
+
unsubList.push(unsub);
|
|
125
|
+
} else if (_STAKING_CHAIN_GROUP.relay.includes(chainInfo.slug)) {
|
|
126
|
+
const unsub = await subscribeRelayChainStakingMetadata(chainInfo, substrateApi, callback);
|
|
127
|
+
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
unsubList.push(unsub);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return () => {
|
|
133
|
+
unsubList.forEach(unsub => {
|
|
134
|
+
unsub && unsub();
|
|
135
|
+
});
|
|
136
|
+
};
|
|
103
137
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
2
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
3
3
|
import { ChainStakingMetadata, NominatorMetadata, UnstakingInfo, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes';
|
|
4
|
+
import { PalletParachainStakingDelegator } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
4
5
|
import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
6
|
+
import { Codec } from '@polkadot/types/types';
|
|
5
7
|
export declare function validateParaChainUnbondingCondition(amount: string, nominatorMetadata: NominatorMetadata, chainStakingMetadata: ChainStakingMetadata, selectedCollator: string): TransactionError[];
|
|
6
8
|
export declare function validateParaChainBondingCondition(chainInfo: _ChainInfo, amount: string, selectedCollators: ValidatorInfo[], address: string, chainStakingMetadata: ChainStakingMetadata, nominatorMetadata?: NominatorMetadata): TransactionError[];
|
|
9
|
+
export declare function subscribeParaChainStakingMetadata(chain: string, substrateApi: _SubstrateApi, callback: (chain: string, rs: ChainStakingMetadata) => void): Promise<Codec>;
|
|
7
10
|
export declare function getParaChainStakingMetadata(chain: string, substrateApi: _SubstrateApi): Promise<ChainStakingMetadata>;
|
|
11
|
+
export declare function subscribeParaChainNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, delegatorState: PalletParachainStakingDelegator): Promise<NominatorMetadata>;
|
|
8
12
|
export declare function getParaChainNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi): Promise<NominatorMetadata | undefined>;
|
|
9
13
|
export declare function getParachainCollatorsInfo(chain: string, substrateApi: _SubstrateApi): Promise<ValidatorInfo[]>;
|
|
10
14
|
export declare function getParaBondingExtrinsic(chainInfo: _ChainInfo, substrateApi: _SubstrateApi, amount: string, selectedCollatorInfo: ValidatorInfo, nominatorMetadata?: NominatorMetadata): Promise<import("@polkadot/api-base/types").SubmittableExtrinsic<"promise", import("@polkadot/types/types").ISubmittableResult>>;
|
|
@@ -81,6 +81,26 @@ export function validateParaChainBondingCondition(chainInfo, amount, selectedCol
|
|
|
81
81
|
}
|
|
82
82
|
return errors;
|
|
83
83
|
}
|
|
84
|
+
export function subscribeParaChainStakingMetadata(chain, substrateApi, callback) {
|
|
85
|
+
return substrateApi.api.query.parachainStaking.round(_round => {
|
|
86
|
+
const roundObj = _round.toHuman();
|
|
87
|
+
const round = parseRawNumber(roundObj.current);
|
|
88
|
+
const maxDelegations = substrateApi.api.consts.parachainStaking.maxDelegationsPerDelegator.toString();
|
|
89
|
+
const unstakingDelay = substrateApi.api.consts.parachainStaking.delegationBondLessDelay.toString();
|
|
90
|
+
const unstakingPeriod = parseInt(unstakingDelay) * (_STAKING_ERA_LENGTH_MAP[chain] || _STAKING_ERA_LENGTH_MAP.default);
|
|
91
|
+
callback(chain, {
|
|
92
|
+
chain,
|
|
93
|
+
type: StakingType.NOMINATED,
|
|
94
|
+
era: round,
|
|
95
|
+
minStake: '0',
|
|
96
|
+
maxValidatorPerNominator: parseInt(maxDelegations),
|
|
97
|
+
maxWithdrawalRequestPerValidator: 1,
|
|
98
|
+
// by default
|
|
99
|
+
allowCancelUnstaking: true,
|
|
100
|
+
unstakingPeriod
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
84
104
|
export async function getParaChainStakingMetadata(chain, substrateApi) {
|
|
85
105
|
const chainApi = await substrateApi.isReady;
|
|
86
106
|
const _round = (await chainApi.api.query.parachainStaking.round()).toHuman();
|
|
@@ -119,6 +139,81 @@ export async function getParaChainStakingMetadata(chain, substrateApi) {
|
|
|
119
139
|
unstakingPeriod
|
|
120
140
|
};
|
|
121
141
|
}
|
|
142
|
+
export async function subscribeParaChainNominatorMetadata(chainInfo, address, substrateApi, delegatorState) {
|
|
143
|
+
const nominationList = [];
|
|
144
|
+
const unstakingMap = {};
|
|
145
|
+
let bnTotalActiveStake = BN_ZERO;
|
|
146
|
+
const _roundInfo = await substrateApi.api.query.parachainStaking.round();
|
|
147
|
+
const roundInfo = _roundInfo.toPrimitive();
|
|
148
|
+
const currentRound = roundInfo.current;
|
|
149
|
+
await Promise.all(delegatorState.delegations.map(async delegation => {
|
|
150
|
+
const [_delegationScheduledRequests, _identity, _collatorInfo] = await Promise.all([substrateApi.api.query.parachainStaking.delegationScheduledRequests(delegation.owner), substrateApi.api.query.identity.identityOf(delegation.owner), substrateApi.api.query.parachainStaking.candidateInfo(delegation.owner)]);
|
|
151
|
+
const collatorInfo = _collatorInfo.toPrimitive();
|
|
152
|
+
const minDelegation = collatorInfo === null || collatorInfo === void 0 ? void 0 : collatorInfo.lowestTopDelegationAmount.toString();
|
|
153
|
+
const identityInfo = _identity.toHuman();
|
|
154
|
+
const delegationScheduledRequests = _delegationScheduledRequests.toPrimitive();
|
|
155
|
+
const identity = parseIdentity(identityInfo);
|
|
156
|
+
let hasUnstaking = false;
|
|
157
|
+
let delegationStatus = StakingStatus.NOT_EARNING;
|
|
158
|
+
|
|
159
|
+
// parse unstaking info
|
|
160
|
+
if (delegationScheduledRequests) {
|
|
161
|
+
for (const scheduledRequest of delegationScheduledRequests) {
|
|
162
|
+
if (reformatAddress(scheduledRequest.delegator, 0) === reformatAddress(address, 0)) {
|
|
163
|
+
// add network prefix
|
|
164
|
+
const isClaimable = scheduledRequest.whenExecutable - currentRound <= 0;
|
|
165
|
+
const remainingEra = scheduledRequest.whenExecutable - (currentRound + 1);
|
|
166
|
+
const waitingTime = remainingEra * _STAKING_ERA_LENGTH_MAP[chainInfo.slug];
|
|
167
|
+
const claimable = Object.values(scheduledRequest.action)[0];
|
|
168
|
+
unstakingMap[delegation.owner] = {
|
|
169
|
+
chain: chainInfo.slug,
|
|
170
|
+
status: isClaimable ? UnstakingStatus.CLAIMABLE : UnstakingStatus.UNLOCKING,
|
|
171
|
+
validatorAddress: delegation.owner,
|
|
172
|
+
claimable: claimable.toString(),
|
|
173
|
+
waitingTime: waitingTime > 0 ? waitingTime : 0
|
|
174
|
+
};
|
|
175
|
+
hasUnstaking = true;
|
|
176
|
+
break; // only handle 1 scheduledRequest per collator
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const bnStake = new BN(delegation.amount);
|
|
182
|
+
const bnUnstakeBalance = unstakingMap[delegation.owner] ? new BN(unstakingMap[delegation.owner].claimable) : BN_ZERO;
|
|
183
|
+
const bnActiveStake = bnStake.sub(bnUnstakeBalance);
|
|
184
|
+
if (bnActiveStake.gt(BN_ZERO) && bnActiveStake.gte(new BN(minDelegation))) {
|
|
185
|
+
delegationStatus = StakingStatus.EARNING_REWARD;
|
|
186
|
+
}
|
|
187
|
+
bnTotalActiveStake = bnTotalActiveStake.add(bnActiveStake);
|
|
188
|
+
nominationList.push({
|
|
189
|
+
chain: chainInfo.slug,
|
|
190
|
+
status: delegationStatus,
|
|
191
|
+
validatorAddress: delegation.owner,
|
|
192
|
+
validatorIdentity: identity,
|
|
193
|
+
activeStake: bnActiveStake.toString(),
|
|
194
|
+
hasUnstaking,
|
|
195
|
+
validatorMinStake: collatorInfo.lowestTopDelegationAmount.toString()
|
|
196
|
+
});
|
|
197
|
+
}));
|
|
198
|
+
|
|
199
|
+
// await Promise.all(nominationList.map(async (nomination) => {
|
|
200
|
+
// const _collatorInfo = await substrateApi.api.query.parachainStaking.candidateInfo(nomination.validatorAddress);
|
|
201
|
+
// const collatorInfo = _collatorInfo.toPrimitive() as unknown as ParachainStakingCandidateMetadata;
|
|
202
|
+
//
|
|
203
|
+
// nomination.validatorMinStake = collatorInfo.lowestTopDelegationAmount.toString();
|
|
204
|
+
// }));
|
|
205
|
+
|
|
206
|
+
const stakingStatus = getStakingStatusByNominations(bnTotalActiveStake, nominationList);
|
|
207
|
+
return {
|
|
208
|
+
chain: chainInfo.slug,
|
|
209
|
+
type: StakingType.NOMINATED,
|
|
210
|
+
status: stakingStatus,
|
|
211
|
+
address: address,
|
|
212
|
+
activeStake: bnTotalActiveStake.toString(),
|
|
213
|
+
nominations: nominationList,
|
|
214
|
+
unstakings: Object.values(unstakingMap)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
122
217
|
export async function getParaChainNominatorMetadata(chainInfo, address, substrateApi) {
|
|
123
218
|
if (_isChainEvmCompatible(chainInfo) && !isEthereumAddress(address)) {
|
|
124
219
|
return;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
2
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
3
3
|
import { ChainStakingMetadata, NominationPoolInfo, NominatorMetadata, UnstakingInfo, ValidatorInfo } from '@subwallet/extension-base/background/KoniTypes';
|
|
4
|
+
import { PalletNominationPoolsPoolMember } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
4
5
|
import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
6
|
+
import { Codec } from '@polkadot/types/types';
|
|
5
7
|
export interface PalletStakingNominations {
|
|
6
8
|
targets: string[];
|
|
7
9
|
submittedIn: number;
|
|
@@ -21,8 +23,11 @@ export interface PalletStakingStakingLedger {
|
|
|
21
23
|
export declare function validateRelayUnbondingCondition(amount: string, chainStakingMetadata: ChainStakingMetadata, nominatorMetadata: NominatorMetadata): TransactionError[];
|
|
22
24
|
export declare function validatePoolBondingCondition(chainInfo: _ChainInfo, amount: string, selectedPool: NominationPoolInfo, address: string, chainStakingMetadata: ChainStakingMetadata, nominatorMetadata?: NominatorMetadata): TransactionError[];
|
|
23
25
|
export declare function validateRelayBondingCondition(chainInfo: _ChainInfo, amount: string, selectedValidators: ValidatorInfo[], address: string, chainStakingMetadata: ChainStakingMetadata, nominatorMetadata?: NominatorMetadata): TransactionError[];
|
|
26
|
+
export declare function subscribeRelayChainStakingMetadata(chainInfo: _ChainInfo, substrateApi: _SubstrateApi, callback: (chain: string, rs: ChainStakingMetadata) => void): Promise<Codec>;
|
|
24
27
|
export declare function getRelayChainStakingMetadata(chainInfo: _ChainInfo, substrateApi: _SubstrateApi): Promise<ChainStakingMetadata>;
|
|
28
|
+
export declare function subscribeRelayChainNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, ledger: PalletStakingStakingLedger): Promise<NominatorMetadata>;
|
|
25
29
|
export declare function getRelayChainNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi): Promise<NominatorMetadata | undefined>;
|
|
30
|
+
export declare function subscribeRelayChainPoolMemberMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, poolMemberInfo: PalletNominationPoolsPoolMember): Promise<NominatorMetadata>;
|
|
26
31
|
export declare function getRelayChainPoolMemberMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi): Promise<NominatorMetadata | undefined>;
|
|
27
32
|
export declare function getRelayValidatorsInfo(chain: string, substrateApi: _SubstrateApi, decimals: number, chainStakingMetadata: ChainStakingMetadata): Promise<ValidatorInfo[]>;
|
|
28
33
|
export declare function getRelayPoolsInfo(chain: string, substrateApi: _SubstrateApi): Promise<NominationPoolInfo[]>;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
5
5
|
import { StakingStatus, StakingTxErrorType, StakingType, UnstakingStatus } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
-
import { calculateAlephZeroValidatorReturn, calculateChainStakedReturn, calculateInflation, calculateValidatorStakedReturn, getCommission, parseIdentity, parsePoolStashAddress, transformPoolName } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
6
|
+
import { calculateAlephZeroValidatorReturn, calculateChainStakedReturn, calculateInflation, calculateTernoaValidatorReturn, calculateValidatorStakedReturn, getCommission, parseIdentity, parsePoolStashAddress, transformPoolName } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
7
7
|
import { _STAKING_CHAIN_GROUP, _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
8
8
|
import { _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils';
|
|
9
9
|
import { reformatAddress } from '@subwallet/extension-base/utils';
|
|
@@ -34,7 +34,7 @@ export function validatePoolBondingCondition(chainInfo, amount, selectedPool, ad
|
|
|
34
34
|
if (nominatorMetadata) {
|
|
35
35
|
const bnCurrentActiveStake = new BN(nominatorMetadata.activeStake);
|
|
36
36
|
bnTotalStake = bnTotalStake.add(bnCurrentActiveStake);
|
|
37
|
-
if (nominatorMetadata.unstakings.length > 0) {
|
|
37
|
+
if (nominatorMetadata.unstakings.length > 0 && bnCurrentActiveStake.isZero()) {
|
|
38
38
|
errors.push(new TransactionError(StakingTxErrorType.EXIST_UNSTAKING_REQUEST));
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -66,6 +66,35 @@ export function validateRelayBondingCondition(chainInfo, amount, selectedValidat
|
|
|
66
66
|
}
|
|
67
67
|
return errors;
|
|
68
68
|
}
|
|
69
|
+
export function subscribeRelayChainStakingMetadata(chainInfo, substrateApi, callback) {
|
|
70
|
+
return substrateApi.api.query.staking.currentEra(async _currentEra => {
|
|
71
|
+
var _substrateApi$api$que, _substrateApi$api$que2, _substrateApi$api$que3, _substrateApi$api$que4, _substrateApi$api$que5, _substrateApi$api$que6;
|
|
72
|
+
const currentEra = _currentEra.toString();
|
|
73
|
+
const maxNominations = substrateApi.api.consts.staking.maxNominations.toString();
|
|
74
|
+
const maxUnlockingChunks = substrateApi.api.consts.staking.maxUnlockingChunks.toString();
|
|
75
|
+
const unlockingEras = substrateApi.api.consts.staking.bondingDuration.toString();
|
|
76
|
+
const [_minNominatorBond, _minPoolJoin, _minimumActiveStake] = await Promise.all([substrateApi.api.query.staking.minNominatorBond(), (_substrateApi$api$que = substrateApi.api.query) === null || _substrateApi$api$que === void 0 ? void 0 : (_substrateApi$api$que2 = _substrateApi$api$que.nominationPools) === null || _substrateApi$api$que2 === void 0 ? void 0 : _substrateApi$api$que2.minJoinBond(), ((_substrateApi$api$que3 = substrateApi.api.query) === null || _substrateApi$api$que3 === void 0 ? void 0 : (_substrateApi$api$que4 = _substrateApi$api$que3.staking) === null || _substrateApi$api$que4 === void 0 ? void 0 : _substrateApi$api$que4.minimumActiveStake) && ((_substrateApi$api$que5 = substrateApi.api.query) === null || _substrateApi$api$que5 === void 0 ? void 0 : (_substrateApi$api$que6 = _substrateApi$api$que5.staking) === null || _substrateApi$api$que6 === void 0 ? void 0 : _substrateApi$api$que6.minimumActiveStake())]);
|
|
77
|
+
const minActiveStake = (_minimumActiveStake === null || _minimumActiveStake === void 0 ? void 0 : _minimumActiveStake.toString()) || '0';
|
|
78
|
+
const minNominatorBond = _minNominatorBond.toString();
|
|
79
|
+
const bnMinActiveStake = new BN(minActiveStake);
|
|
80
|
+
const bnMinNominatorBond = new BN(minNominatorBond);
|
|
81
|
+
const minStake = bnMinActiveStake.gt(bnMinNominatorBond) ? bnMinActiveStake : bnMinNominatorBond;
|
|
82
|
+
const minPoolJoin = (_minPoolJoin === null || _minPoolJoin === void 0 ? void 0 : _minPoolJoin.toString()) || undefined;
|
|
83
|
+
const unlockingPeriod = parseInt(unlockingEras) * (_STAKING_ERA_LENGTH_MAP[chainInfo.slug] || _STAKING_ERA_LENGTH_MAP.default); // in hours
|
|
84
|
+
|
|
85
|
+
callback(chainInfo.slug, {
|
|
86
|
+
chain: chainInfo.slug,
|
|
87
|
+
type: StakingType.NOMINATED,
|
|
88
|
+
era: parseInt(currentEra),
|
|
89
|
+
minStake: minStake.toString(),
|
|
90
|
+
maxValidatorPerNominator: parseInt(maxNominations),
|
|
91
|
+
maxWithdrawalRequestPerValidator: parseInt(maxUnlockingChunks),
|
|
92
|
+
allowCancelUnstaking: true,
|
|
93
|
+
unstakingPeriod: unlockingPeriod,
|
|
94
|
+
minJoinNominationPool: minPoolJoin
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
69
98
|
export async function getRelayChainStakingMetadata(chainInfo, substrateApi) {
|
|
70
99
|
var _chainApi$api$query$a, _chainApi$api$query, _chainApi$api$query$s, _chainApi$api$query2, _chainApi$api$query2$, _chainApi$api$query3, _chainApi$api$query3$;
|
|
71
100
|
const chain = chainInfo.slug;
|
|
@@ -77,16 +106,17 @@ export async function getRelayChainStakingMetadata(chainInfo, substrateApi) {
|
|
|
77
106
|
const unlockingEras = chainApi.api.consts.staking.bondingDuration.toString();
|
|
78
107
|
const [_totalEraStake, _totalIssuance, _auctionCounter, _minimumActiveStake, _minNominatorBond, _minPoolJoin, _eraStakers] = await Promise.all([chainApi.api.query.staking.erasTotalStake(parseInt(currentEra)), chainApi.api.query.balances.totalIssuance(), (_chainApi$api$query$a = chainApi.api.query.auctions) === null || _chainApi$api$query$a === void 0 ? void 0 : _chainApi$api$query$a.auctionCounter(), ((_chainApi$api$query = chainApi.api.query) === null || _chainApi$api$query === void 0 ? void 0 : (_chainApi$api$query$s = _chainApi$api$query.staking) === null || _chainApi$api$query$s === void 0 ? void 0 : _chainApi$api$query$s.minimumActiveStake) && ((_chainApi$api$query2 = chainApi.api.query) === null || _chainApi$api$query2 === void 0 ? void 0 : (_chainApi$api$query2$ = _chainApi$api$query2.staking) === null || _chainApi$api$query2$ === void 0 ? void 0 : _chainApi$api$query2$.minimumActiveStake()), chainApi.api.query.staking.minNominatorBond(), (_chainApi$api$query3 = chainApi.api.query) === null || _chainApi$api$query3 === void 0 ? void 0 : (_chainApi$api$query3$ = _chainApi$api$query3.nominationPools) === null || _chainApi$api$query3$ === void 0 ? void 0 : _chainApi$api$query3$.minJoinBond(), chainApi.api.query.staking.erasStakers.entries(parseInt(currentEra))]);
|
|
79
108
|
const eraStakers = _eraStakers;
|
|
109
|
+
let allCurrentNominators = [];
|
|
80
110
|
const nominatorList = [];
|
|
81
111
|
for (const item of eraStakers) {
|
|
82
112
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
|
|
83
113
|
const rawValidatorStat = item[1].toHuman();
|
|
84
114
|
const eraNominators = rawValidatorStat.others;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
115
|
+
allCurrentNominators = allCurrentNominators.concat(eraNominators);
|
|
116
|
+
}
|
|
117
|
+
for (const nominator of allCurrentNominators) {
|
|
118
|
+
if (!nominatorList.includes(nominator.who)) {
|
|
119
|
+
nominatorList.push(nominator.who);
|
|
90
120
|
}
|
|
91
121
|
}
|
|
92
122
|
const minActiveStake = (_minimumActiveStake === null || _minimumActiveStake === void 0 ? void 0 : _minimumActiveStake.toString()) || '0';
|
|
@@ -108,7 +138,7 @@ export async function getRelayChainStakingMetadata(chainInfo, substrateApi) {
|
|
|
108
138
|
chain,
|
|
109
139
|
type: StakingType.NOMINATED,
|
|
110
140
|
era: parseInt(currentEra),
|
|
111
|
-
expectedReturn,
|
|
141
|
+
expectedReturn: !_STAKING_CHAIN_GROUP.ternoa.includes(chain) ? expectedReturn : undefined,
|
|
112
142
|
// in %, annually
|
|
113
143
|
inflation,
|
|
114
144
|
minStake: minStake.toString(),
|
|
@@ -120,14 +150,98 @@ export async function getRelayChainStakingMetadata(chainInfo, substrateApi) {
|
|
|
120
150
|
nominatorCount: nominatorList.length
|
|
121
151
|
};
|
|
122
152
|
}
|
|
153
|
+
export async function subscribeRelayChainNominatorMetadata(chainInfo, address, substrateApi, ledger) {
|
|
154
|
+
var _chainApi$api$query4, _chainApi$api$query4$, _chainApi$api$query5, _chainApi$api$query5$, _chainApi$api$query6, _chainApi$api$query6$, _chainApi$api$query7, _chainApi$api$query7$, _chainApi$api$query8, _chainApi$api$query8$, _chainApi$api$query9, _chainApi$api$query9$;
|
|
155
|
+
const chain = chainInfo.slug;
|
|
156
|
+
const chainApi = await substrateApi.isReady;
|
|
157
|
+
const [_nominations, _currentEra, _bonded, _minimumActiveStake, _minNominatorBond] = await Promise.all([(_chainApi$api$query4 = chainApi.api.query) === null || _chainApi$api$query4 === void 0 ? void 0 : (_chainApi$api$query4$ = _chainApi$api$query4.staking) === null || _chainApi$api$query4$ === void 0 ? void 0 : _chainApi$api$query4$.nominators(address), (_chainApi$api$query5 = chainApi.api.query) === null || _chainApi$api$query5 === void 0 ? void 0 : (_chainApi$api$query5$ = _chainApi$api$query5.staking) === null || _chainApi$api$query5$ === void 0 ? void 0 : _chainApi$api$query5$.currentEra(), (_chainApi$api$query6 = chainApi.api.query) === null || _chainApi$api$query6 === void 0 ? void 0 : (_chainApi$api$query6$ = _chainApi$api$query6.staking) === null || _chainApi$api$query6$ === void 0 ? void 0 : _chainApi$api$query6$.bonded(address), ((_chainApi$api$query7 = chainApi.api.query) === null || _chainApi$api$query7 === void 0 ? void 0 : (_chainApi$api$query7$ = _chainApi$api$query7.staking) === null || _chainApi$api$query7$ === void 0 ? void 0 : _chainApi$api$query7$.minimumActiveStake) && ((_chainApi$api$query8 = chainApi.api.query) === null || _chainApi$api$query8 === void 0 ? void 0 : (_chainApi$api$query8$ = _chainApi$api$query8.staking) === null || _chainApi$api$query8$ === void 0 ? void 0 : _chainApi$api$query8$.minimumActiveStake()), (_chainApi$api$query9 = chainApi.api.query) === null || _chainApi$api$query9 === void 0 ? void 0 : (_chainApi$api$query9$ = _chainApi$api$query9.staking) === null || _chainApi$api$query9$ === void 0 ? void 0 : _chainApi$api$query9$.minNominatorBond()]);
|
|
158
|
+
const minActiveStake = (_minimumActiveStake === null || _minimumActiveStake === void 0 ? void 0 : _minimumActiveStake.toString()) || '0';
|
|
159
|
+
const minNominatorBond = _minNominatorBond.toString();
|
|
160
|
+
const bnMinActiveStake = new BN(minActiveStake);
|
|
161
|
+
const bnMinNominatorBond = new BN(minNominatorBond);
|
|
162
|
+
const minStake = bnMinActiveStake.gt(bnMinNominatorBond) ? bnMinActiveStake : bnMinNominatorBond;
|
|
163
|
+
const _maxNominatorRewardedPerValidator = chainApi.api.consts.staking.maxNominatorRewardedPerValidator.toString();
|
|
164
|
+
const maxNominatorRewardedPerValidator = parseInt(_maxNominatorRewardedPerValidator);
|
|
165
|
+
const nominations = _nominations.toPrimitive();
|
|
166
|
+
const currentEra = _currentEra.toString();
|
|
167
|
+
const bonded = _bonded.toHuman();
|
|
168
|
+
const activeStake = ledger.active.toString();
|
|
169
|
+
const nominationList = [];
|
|
170
|
+
const unstakingList = [];
|
|
171
|
+
if (nominations) {
|
|
172
|
+
const validatorList = nominations.targets;
|
|
173
|
+
await Promise.all(validatorList.map(async validatorAddress => {
|
|
174
|
+
let nominationStatus = StakingStatus.NOT_EARNING;
|
|
175
|
+
const [_identityInfo, _eraStaker] = await Promise.all([chainApi.api.query.identity.identityOf(validatorAddress), chainApi.api.query.staking.erasStakers(currentEra, validatorAddress)]);
|
|
176
|
+
const eraStaker = _eraStaker.toPrimitive();
|
|
177
|
+
const identityInfo = _identityInfo.toHuman();
|
|
178
|
+
const identity = parseIdentity(identityInfo);
|
|
179
|
+
const topNominators = eraStaker.others.map(nominator => {
|
|
180
|
+
return nominator.who;
|
|
181
|
+
});
|
|
182
|
+
if (!topNominators.includes(reformatAddress(address, _getChainSubstrateAddressPrefix(chainInfo)))) {
|
|
183
|
+
// if nominator has target but not in nominator list
|
|
184
|
+
nominationStatus = StakingStatus.WAITING;
|
|
185
|
+
} else if (topNominators.slice(0, maxNominatorRewardedPerValidator).includes(reformatAddress(address, _getChainSubstrateAddressPrefix(chainInfo)))) {
|
|
186
|
+
// if address in top nominators
|
|
187
|
+
nominationStatus = StakingStatus.EARNING_REWARD;
|
|
188
|
+
}
|
|
189
|
+
nominationList.push({
|
|
190
|
+
chain,
|
|
191
|
+
validatorAddress,
|
|
192
|
+
status: nominationStatus,
|
|
193
|
+
validatorIdentity: identity,
|
|
194
|
+
activeStake: '0' // relaychain allocates stake accordingly
|
|
195
|
+
});
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let stakingStatus = StakingStatus.NOT_EARNING;
|
|
200
|
+
const bnActiveStake = new BN(activeStake);
|
|
201
|
+
let waitingNominationCount = 0;
|
|
202
|
+
if (bnActiveStake.gte(minStake)) {
|
|
203
|
+
for (const nomination of nominationList) {
|
|
204
|
+
if (nomination.status === StakingStatus.EARNING_REWARD) {
|
|
205
|
+
// only need 1 earning nomination to count
|
|
206
|
+
stakingStatus = StakingStatus.EARNING_REWARD;
|
|
207
|
+
} else if (nomination.status === StakingStatus.WAITING) {
|
|
208
|
+
waitingNominationCount += 1;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (waitingNominationCount === nominationList.length) {
|
|
212
|
+
stakingStatus = StakingStatus.WAITING;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
ledger.unlocking.forEach(unlockingChunk => {
|
|
216
|
+
const isClaimable = unlockingChunk.era - parseInt(currentEra) <= 0;
|
|
217
|
+
const remainingEra = unlockingChunk.era - (parseInt(currentEra) + 1);
|
|
218
|
+
const waitingTime = remainingEra * _STAKING_ERA_LENGTH_MAP[chain];
|
|
219
|
+
unstakingList.push({
|
|
220
|
+
chain,
|
|
221
|
+
status: isClaimable ? UnstakingStatus.CLAIMABLE : UnstakingStatus.UNLOCKING,
|
|
222
|
+
claimable: unlockingChunk.value.toString(),
|
|
223
|
+
waitingTime: waitingTime > 0 ? waitingTime : 0
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
return {
|
|
227
|
+
chain,
|
|
228
|
+
type: StakingType.NOMINATED,
|
|
229
|
+
status: stakingStatus,
|
|
230
|
+
address: address,
|
|
231
|
+
activeStake,
|
|
232
|
+
nominations: nominationList,
|
|
233
|
+
unstakings: unstakingList,
|
|
234
|
+
isBondedBefore: bonded !== null
|
|
235
|
+
};
|
|
236
|
+
}
|
|
123
237
|
export async function getRelayChainNominatorMetadata(chainInfo, address, substrateApi) {
|
|
124
|
-
var _chainApi$api$
|
|
238
|
+
var _chainApi$api$query10, _chainApi$api$query11, _chainApi$api$query12, _chainApi$api$query13, _chainApi$api$query14, _chainApi$api$query15, _chainApi$api$query16, _chainApi$api$query17, _chainApi$api$query18, _chainApi$api$query19, _chainApi$api$query20, _chainApi$api$query21, _chainApi$api$query22, _chainApi$api$query23;
|
|
125
239
|
if (isEthereumAddress(address)) {
|
|
126
240
|
return;
|
|
127
241
|
}
|
|
128
242
|
const chain = chainInfo.slug;
|
|
129
243
|
const chainApi = await substrateApi.isReady;
|
|
130
|
-
const [_ledger, _nominations, _currentEra, _bonded, _minimumActiveStake, _minNominatorBond] = await Promise.all([(_chainApi$api$
|
|
244
|
+
const [_ledger, _nominations, _currentEra, _bonded, _minimumActiveStake, _minNominatorBond] = await Promise.all([(_chainApi$api$query10 = chainApi.api.query) === null || _chainApi$api$query10 === void 0 ? void 0 : (_chainApi$api$query11 = _chainApi$api$query10.staking) === null || _chainApi$api$query11 === void 0 ? void 0 : _chainApi$api$query11.ledger(address), (_chainApi$api$query12 = chainApi.api.query) === null || _chainApi$api$query12 === void 0 ? void 0 : (_chainApi$api$query13 = _chainApi$api$query12.staking) === null || _chainApi$api$query13 === void 0 ? void 0 : _chainApi$api$query13.nominators(address), (_chainApi$api$query14 = chainApi.api.query) === null || _chainApi$api$query14 === void 0 ? void 0 : (_chainApi$api$query15 = _chainApi$api$query14.staking) === null || _chainApi$api$query15 === void 0 ? void 0 : _chainApi$api$query15.currentEra(), (_chainApi$api$query16 = chainApi.api.query) === null || _chainApi$api$query16 === void 0 ? void 0 : (_chainApi$api$query17 = _chainApi$api$query16.staking) === null || _chainApi$api$query17 === void 0 ? void 0 : _chainApi$api$query17.bonded(address), ((_chainApi$api$query18 = chainApi.api.query) === null || _chainApi$api$query18 === void 0 ? void 0 : (_chainApi$api$query19 = _chainApi$api$query18.staking) === null || _chainApi$api$query19 === void 0 ? void 0 : _chainApi$api$query19.minimumActiveStake) && ((_chainApi$api$query20 = chainApi.api.query) === null || _chainApi$api$query20 === void 0 ? void 0 : (_chainApi$api$query21 = _chainApi$api$query20.staking) === null || _chainApi$api$query21 === void 0 ? void 0 : _chainApi$api$query21.minimumActiveStake()), (_chainApi$api$query22 = chainApi.api.query) === null || _chainApi$api$query22 === void 0 ? void 0 : (_chainApi$api$query23 = _chainApi$api$query22.staking) === null || _chainApi$api$query23 === void 0 ? void 0 : _chainApi$api$query23.minNominatorBond()]);
|
|
131
245
|
const minActiveStake = (_minimumActiveStake === null || _minimumActiveStake === void 0 ? void 0 : _minimumActiveStake.toString()) || '0';
|
|
132
246
|
const minNominatorBond = _minNominatorBond.toString();
|
|
133
247
|
const bnMinActiveStake = new BN(minActiveStake);
|
|
@@ -219,6 +333,67 @@ export async function getRelayChainNominatorMetadata(chainInfo, address, substra
|
|
|
219
333
|
isBondedBefore: bonded !== null
|
|
220
334
|
};
|
|
221
335
|
}
|
|
336
|
+
export async function subscribeRelayChainPoolMemberMetadata(chainInfo, address, substrateApi, poolMemberInfo) {
|
|
337
|
+
const _maxNominatorRewardedPerValidator = substrateApi.api.consts.staking.maxNominatorRewardedPerValidator.toString();
|
|
338
|
+
const maxNominatorRewardedPerValidator = parseInt(_maxNominatorRewardedPerValidator);
|
|
339
|
+
const poolsPalletId = substrateApi.api.consts.nominationPools.palletId.toString();
|
|
340
|
+
const poolStashAccount = parsePoolStashAddress(substrateApi.api, 0, poolMemberInfo.poolId, poolsPalletId);
|
|
341
|
+
const [_nominations, _poolMetadata, _currentEra] = await Promise.all([substrateApi.api.query.staking.nominators(poolStashAccount), substrateApi.api.query.nominationPools.metadata(poolMemberInfo.poolId), substrateApi.api.query.staking.currentEra()]);
|
|
342
|
+
const poolMetadata = _poolMetadata.toPrimitive();
|
|
343
|
+
const currentEra = _currentEra.toString();
|
|
344
|
+
const nominations = _nominations.toJSON();
|
|
345
|
+
let stakingStatus = StakingStatus.NOT_EARNING;
|
|
346
|
+
const poolName = transformPoolName(poolMetadata.isUtf8 ? poolMetadata.toUtf8() : poolMetadata.toString());
|
|
347
|
+
if (nominations) {
|
|
348
|
+
const validatorList = nominations.targets;
|
|
349
|
+
await Promise.all(validatorList.map(async validatorAddress => {
|
|
350
|
+
const _eraStaker = await substrateApi.api.query.staking.erasStakers(currentEra, validatorAddress);
|
|
351
|
+
const eraStaker = _eraStaker.toPrimitive();
|
|
352
|
+
const topNominators = eraStaker.others.map(nominator => {
|
|
353
|
+
return nominator.who;
|
|
354
|
+
}).slice(0, maxNominatorRewardedPerValidator);
|
|
355
|
+
if (topNominators.includes(reformatAddress(poolStashAccount, _getChainSubstrateAddressPrefix(chainInfo)))) {
|
|
356
|
+
// if address in top nominators
|
|
357
|
+
stakingStatus = StakingStatus.EARNING_REWARD;
|
|
358
|
+
}
|
|
359
|
+
}));
|
|
360
|
+
}
|
|
361
|
+
const joinedPoolInfo = {
|
|
362
|
+
activeStake: poolMemberInfo.points.toString(),
|
|
363
|
+
chain: chainInfo.slug,
|
|
364
|
+
status: stakingStatus,
|
|
365
|
+
validatorIdentity: poolName,
|
|
366
|
+
validatorAddress: poolMemberInfo.poolId.toString(),
|
|
367
|
+
// use poolId
|
|
368
|
+
hasUnstaking: poolMemberInfo.unbondingEras && Object.keys(poolMemberInfo.unbondingEras).length > 0
|
|
369
|
+
};
|
|
370
|
+
const unstakings = [];
|
|
371
|
+
Object.entries(poolMemberInfo.unbondingEras).forEach(([unlockingEra, amount]) => {
|
|
372
|
+
const isClaimable = parseInt(unlockingEra) - parseInt(currentEra) <= 0;
|
|
373
|
+
const remainingEra = parseInt(unlockingEra) - (parseInt(currentEra) + 1);
|
|
374
|
+
const waitingTime = remainingEra * _STAKING_ERA_LENGTH_MAP[chainInfo.slug];
|
|
375
|
+
unstakings.push({
|
|
376
|
+
chain: chainInfo.slug,
|
|
377
|
+
status: isClaimable ? UnstakingStatus.CLAIMABLE : UnstakingStatus.UNLOCKING,
|
|
378
|
+
claimable: amount.toString(),
|
|
379
|
+
waitingTime: waitingTime > 0 ? waitingTime : 0
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
const bnActiveStake = new BN(poolMemberInfo.points.toString());
|
|
383
|
+
if (!bnActiveStake.gt(BN_ZERO)) {
|
|
384
|
+
stakingStatus = StakingStatus.NOT_EARNING;
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
chain: chainInfo.slug,
|
|
388
|
+
type: StakingType.POOLED,
|
|
389
|
+
address,
|
|
390
|
+
status: stakingStatus,
|
|
391
|
+
activeStake: poolMemberInfo.points.toString(),
|
|
392
|
+
nominations: [joinedPoolInfo],
|
|
393
|
+
// can only join 1 pool at a time
|
|
394
|
+
unstakings
|
|
395
|
+
};
|
|
396
|
+
}
|
|
222
397
|
export async function getRelayChainPoolMemberMetadata(chainInfo, address, substrateApi) {
|
|
223
398
|
const chainApi = await substrateApi.isReady;
|
|
224
399
|
const [_poolMemberInfo, _currentEra] = await Promise.all([chainApi.api.query.nominationPools.poolMembers(address), chainApi.api.query.staking.currentEra()]);
|
|
@@ -302,7 +477,8 @@ export async function getRelayValidatorsInfo(chain, substrateApi, decimals, chai
|
|
|
302
477
|
const currentEra = _era.toString();
|
|
303
478
|
const allValidators = [];
|
|
304
479
|
const validatorInfoList = [];
|
|
305
|
-
const [_totalEraStake, _eraStakers, _minBond] = await Promise.all([chainApi.api.query.staking.erasTotalStake(parseInt(currentEra)), chainApi.api.query.staking.erasStakers.entries(parseInt(currentEra)), chainApi.api.query.staking.minNominatorBond()]);
|
|
480
|
+
const [_totalEraStake, _eraStakers, _minBond, _stakingRewards] = await Promise.all([chainApi.api.query.staking.erasTotalStake(parseInt(currentEra)), chainApi.api.query.staking.erasStakers.entries(parseInt(currentEra)), chainApi.api.query.staking.minNominatorBond(), chainApi.api.query.stakingRewards && chainApi.api.query.stakingRewards.data()]);
|
|
481
|
+
const stakingRewards = _stakingRewards === null || _stakingRewards === void 0 ? void 0 : _stakingRewards.toPrimitive();
|
|
306
482
|
const maxNominatorRewarded = chainApi.api.consts.staking.maxNominatorRewardedPerValidator.toString();
|
|
307
483
|
const bnTotalEraStake = new BN(_totalEraStake.toString());
|
|
308
484
|
const eraStakers = _eraStakers;
|
|
@@ -345,9 +521,9 @@ export async function getRelayValidatorsInfo(chain, substrateApi, decimals, chai
|
|
|
345
521
|
}
|
|
346
522
|
const extraInfoMap = {};
|
|
347
523
|
await Promise.all(allValidators.map(async address => {
|
|
348
|
-
var _chainApi$api$
|
|
524
|
+
var _chainApi$api$query24, _chainApi$api$query25, _identityInfo$judgeme;
|
|
349
525
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
350
|
-
const [_commissionInfo, _identityInfo] = await Promise.all([chainApi.api.query.staking.validators(address), (_chainApi$api$
|
|
526
|
+
const [_commissionInfo, _identityInfo] = await Promise.all([chainApi.api.query.staking.validators(address), (_chainApi$api$query24 = chainApi.api.query) === null || _chainApi$api$query24 === void 0 ? void 0 : (_chainApi$api$query25 = _chainApi$api$query24.identity) === null || _chainApi$api$query25 === void 0 ? void 0 : _chainApi$api$query25.identityOf(address)]);
|
|
351
527
|
const commissionInfo = _commissionInfo.toHuman();
|
|
352
528
|
const identityInfo = _identityInfo ? _identityInfo.toHuman() : null;
|
|
353
529
|
let identity;
|
|
@@ -365,7 +541,15 @@ export async function getRelayValidatorsInfo(chain, substrateApi, decimals, chai
|
|
|
365
541
|
for (const validator of validatorInfoList) {
|
|
366
542
|
const commission = extraInfoMap[validator.address].commission;
|
|
367
543
|
const bnValidatorStake = totalStakeMap[validator.address].div(bnDecimals);
|
|
368
|
-
|
|
544
|
+
if (_STAKING_CHAIN_GROUP.aleph.includes(chain)) {
|
|
545
|
+
validator.expectedReturn = calculateAlephZeroValidatorReturn(chainStakingMetadata.expectedReturn, getCommission(commission));
|
|
546
|
+
} else if (_STAKING_CHAIN_GROUP.ternoa.includes(chain)) {
|
|
547
|
+
const rewardPerValidator = new BN(stakingRewards.sessionExtraRewardPayout).divn(allValidators.length).div(bnDecimals);
|
|
548
|
+
const validatorStake = totalStakeMap[validator.address].div(bnDecimals).toNumber();
|
|
549
|
+
validator.expectedReturn = calculateTernoaValidatorReturn(rewardPerValidator.toNumber(), validatorStake, getCommission(commission));
|
|
550
|
+
} else {
|
|
551
|
+
validator.expectedReturn = calculateValidatorStakedReturn(chainStakingMetadata.expectedReturn, bnValidatorStake, bnAvgStake, getCommission(commission));
|
|
552
|
+
}
|
|
369
553
|
validator.commission = parseFloat(commission.split('%')[0]);
|
|
370
554
|
validator.blocked = extraInfoMap[validator.address].blocked;
|
|
371
555
|
validator.identity = extraInfoMap[validator.address].identity;
|
|
@@ -102,6 +102,10 @@ export interface Unlocking {
|
|
|
102
102
|
remainingEras: BN;
|
|
103
103
|
value: BN;
|
|
104
104
|
}
|
|
105
|
+
export interface TernoaStakingRewardsStakingRewardsData {
|
|
106
|
+
sessionEraPayout: string;
|
|
107
|
+
sessionExtraRewardPayout: string;
|
|
108
|
+
}
|
|
105
109
|
export declare function parsePoolStashAddress(api: ApiPromise, index: number, poolId: number, poolsPalletId: string): string;
|
|
106
110
|
export declare function transformPoolName(input: string): string;
|
|
107
111
|
export declare function parseIdentity(identityInfo: PalletIdentityRegistration | null): string | undefined;
|
|
@@ -111,6 +115,7 @@ export declare function calcInflationRewardCurve(minInflation: number, stakedFra
|
|
|
111
115
|
export declare function calculateInflation(totalEraStake: BN, totalIssuance: BN, numAuctions: number, networkKey: string): number;
|
|
112
116
|
export declare function calculateChainStakedReturn(inflation: number, totalEraStake: BN, totalIssuance: BN, networkKey: string): number;
|
|
113
117
|
export declare function calculateAlephZeroValidatorReturn(chainStakedReturn: number, commission: number): number;
|
|
118
|
+
export declare function calculateTernoaValidatorReturn(rewardPerValidator: number, validatorStake: number, commission: number): number;
|
|
114
119
|
export declare function calculateValidatorStakedReturn(chainStakedReturn: number, totalValidatorStake: BN, avgStake: BN, commission: number): number;
|
|
115
120
|
export declare function getCommission(commissionString: string): number;
|
|
116
121
|
export interface InflationConfig {
|
|
@@ -86,6 +86,12 @@ export function calculateChainStakedReturn(inflation, totalEraStake, totalIssuan
|
|
|
86
86
|
export function calculateAlephZeroValidatorReturn(chainStakedReturn, commission) {
|
|
87
87
|
return chainStakedReturn * (100 - commission) / 100;
|
|
88
88
|
}
|
|
89
|
+
export function calculateTernoaValidatorReturn(rewardPerValidator, validatorStake, commission) {
|
|
90
|
+
const percentRewardForNominators = (100 - commission) / 100;
|
|
91
|
+
const rewardForNominators = rewardPerValidator * percentRewardForNominators;
|
|
92
|
+
const stakeRatio = rewardForNominators / validatorStake;
|
|
93
|
+
return stakeRatio * 365 * 100;
|
|
94
|
+
}
|
|
89
95
|
export function calculateValidatorStakedReturn(chainStakedReturn, totalValidatorStake, avgStake, commission) {
|
|
90
96
|
const bnAdjusted = avgStake.mul(BN_HUNDRED).div(totalValidatorStake);
|
|
91
97
|
const adjusted = bnAdjusted.toNumber() * chainStakedReturn;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
|
-
import { StakingItem, StakingRewardItem } from '@subwallet/extension-base/background/KoniTypes';
|
|
2
|
+
import { NominatorMetadata, StakingItem, StakingRewardItem } from '@subwallet/extension-base/background/KoniTypes';
|
|
3
3
|
import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
4
|
-
export declare function stakingOnChainApi(addresses: string[], substrateApiMap: Record<string, _SubstrateApi>,
|
|
5
|
-
export declare function getNominationStakingRewardData(addresses: string[], chainInfoMap: Record<string, _ChainInfo
|
|
6
|
-
export declare function getPoolingStakingRewardData(addresses: string[], networkMap: Record<string, _ChainInfo>, dotSamaApiMap: Record<string, _SubstrateApi
|
|
4
|
+
export declare function stakingOnChainApi(addresses: string[], substrateApiMap: Record<string, _SubstrateApi>, chainInfoMap: Record<string, _ChainInfo>, stakingCallback: (networkKey: string, rs: StakingItem) => void, nominatorStateCallback: (nominatorMetadata: NominatorMetadata) => void): () => void;
|
|
5
|
+
export declare function getNominationStakingRewardData(addresses: string[], chainInfoMap: Record<string, _ChainInfo>, callback: (rewardItem: StakingRewardItem) => void): Promise<void>;
|
|
6
|
+
export declare function getPoolingStakingRewardData(addresses: string[], networkMap: Record<string, _ChainInfo>, dotSamaApiMap: Record<string, _SubstrateApi>, callback: (rs: StakingRewardItem) => void): Promise<void>;
|
|
@@ -7,7 +7,7 @@ import { getAllSubsquidStaking } from '@subwallet/extension-base/koni/api/stakin
|
|
|
7
7
|
import { _PURE_EVM_CHAINS, _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
8
8
|
import { _isChainEvmCompatible, _isChainSupportSubstrateStaking, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
9
9
|
import { categoryAddresses } from '@subwallet/extension-base/utils';
|
|
10
|
-
export function stakingOnChainApi(addresses, substrateApiMap,
|
|
10
|
+
export function stakingOnChainApi(addresses, substrateApiMap, chainInfoMap, stakingCallback, nominatorStateCallback) {
|
|
11
11
|
const filteredApiMap = [];
|
|
12
12
|
const [substrateAddresses, evmAddresses] = categoryAddresses(addresses);
|
|
13
13
|
Object.entries(chainInfoMap).forEach(([networkKey, chainInfo]) => {
|
|
@@ -28,20 +28,20 @@ export function stakingOnChainApi(addresses, substrateApiMap, callback, chainInf
|
|
|
28
28
|
const parentApi = await apiPromise.isReady;
|
|
29
29
|
const useAddresses = _isChainEvmCompatible(chainInfoMap[chain]) ? evmAddresses : substrateAddresses;
|
|
30
30
|
if (_STAKING_CHAIN_GROUP.amplitude.includes(chain)) {
|
|
31
|
-
const unsub = await getAmplitudeStakingOnChain(parentApi, useAddresses, chainInfoMap, chain,
|
|
31
|
+
const unsub = await getAmplitudeStakingOnChain(parentApi, useAddresses, chainInfoMap, chain, stakingCallback, nominatorStateCallback);
|
|
32
32
|
unsubList.push(unsub);
|
|
33
33
|
} else if (_STAKING_CHAIN_GROUP.astar.includes(chain)) {
|
|
34
|
-
const unsub = await getAstarStakingOnChain(parentApi, useAddresses, chainInfoMap, chain,
|
|
34
|
+
const unsub = await getAstarStakingOnChain(parentApi, useAddresses, chainInfoMap, chain, stakingCallback, nominatorStateCallback);
|
|
35
35
|
unsubList.push(unsub);
|
|
36
36
|
} else if (_STAKING_CHAIN_GROUP.para.includes(chain)) {
|
|
37
|
-
const unsub = await getParaStakingOnChain(parentApi, useAddresses, chainInfoMap, chain,
|
|
37
|
+
const unsub = await getParaStakingOnChain(parentApi, useAddresses, chainInfoMap, chain, stakingCallback, nominatorStateCallback);
|
|
38
38
|
unsubList.push(unsub);
|
|
39
39
|
} else if (_STAKING_CHAIN_GROUP.relay.includes(chain)) {
|
|
40
|
-
const unsub = await getRelayStakingOnChain(parentApi, useAddresses, chainInfoMap, chain,
|
|
40
|
+
const unsub = await getRelayStakingOnChain(parentApi, useAddresses, chainInfoMap, chain, stakingCallback, nominatorStateCallback);
|
|
41
41
|
unsubList.push(unsub);
|
|
42
42
|
}
|
|
43
43
|
if (_STAKING_CHAIN_GROUP.nominationPool.includes(chain)) {
|
|
44
|
-
const unsub = await getRelayPoolingOnChain(parentApi, useAddresses, chainInfoMap, chain,
|
|
44
|
+
const unsub = await getRelayPoolingOnChain(parentApi, useAddresses, chainInfoMap, chain, stakingCallback, nominatorStateCallback);
|
|
45
45
|
unsubList.push(unsub);
|
|
46
46
|
}
|
|
47
47
|
});
|
|
@@ -51,11 +51,11 @@ export function stakingOnChainApi(addresses, substrateApiMap, callback, chainInf
|
|
|
51
51
|
});
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
export async function getNominationStakingRewardData(addresses, chainInfoMap) {
|
|
54
|
+
export async function getNominationStakingRewardData(addresses, chainInfoMap, callback) {
|
|
55
55
|
// might retrieve from other sources
|
|
56
|
-
|
|
56
|
+
await getAllSubsquidStaking(addresses, chainInfoMap, callback);
|
|
57
57
|
}
|
|
58
|
-
export async function getPoolingStakingRewardData(addresses, networkMap, dotSamaApiMap) {
|
|
58
|
+
export async function getPoolingStakingRewardData(addresses, networkMap, dotSamaApiMap, callback) {
|
|
59
59
|
const activeNetworks = [];
|
|
60
60
|
Object.entries(networkMap).forEach(([key, chainInfo]) => {
|
|
61
61
|
if (_isChainSupportSubstrateStaking(chainInfo) && _isSubstrateRelayChain(chainInfo)) {
|
|
@@ -63,7 +63,7 @@ export async function getPoolingStakingRewardData(addresses, networkMap, dotSama
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
if (activeNetworks.length === 0) {
|
|
66
|
-
return
|
|
66
|
+
return;
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
await getNominationPoolReward(addresses, networkMap, dotSamaApiMap, callback);
|
|
69
69
|
}
|