@subwallet/extension-base 1.3.56-0 → 1.3.57-0
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/cjs/koni/api/staking/bonding/utils.js +2 -0
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/constants.js +7 -2
- package/cjs/services/earning-service/constants/chains.js +1 -0
- package/cjs/services/earning-service/handlers/native-staking/energy.js +394 -0
- package/cjs/services/earning-service/handlers/native-staking/index.js +8 -1
- package/cjs/services/earning-service/service.js +3 -0
- package/cjs/services/earning-service/utils/index.js +2 -0
- package/koni/api/staking/bonding/utils.js +2 -0
- package/package.json +10 -5
- package/packageInfo.js +1 -1
- package/services/chain-service/constants.js +8 -2
- package/services/earning-service/constants/chains.d.ts +1 -0
- package/services/earning-service/constants/chains.js +1 -0
- package/services/earning-service/handlers/native-staking/energy.d.ts +30 -0
- package/services/earning-service/handlers/native-staking/energy.js +386 -0
- package/services/earning-service/handlers/native-staking/index.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/index.js +2 -1
- package/services/earning-service/service.js +4 -1
- package/services/earning-service/utils/index.js +2 -0
|
@@ -249,6 +249,8 @@ function getYieldAvailableActionsByType(yieldPoolInfo) {
|
|
|
249
249
|
const chain = yieldPoolInfo.chain;
|
|
250
250
|
if (_constants2._STAKING_CHAIN_GROUP.para.includes(chain)) {
|
|
251
251
|
return [YieldAction.STAKE, YieldAction.UNSTAKE, YieldAction.WITHDRAW, YieldAction.CANCEL_UNSTAKE];
|
|
252
|
+
} else if (_constants2._STAKING_CHAIN_GROUP.energy.includes(chain)) {
|
|
253
|
+
return [YieldAction.STAKE, YieldAction.UNSTAKE, YieldAction.WITHDRAW, YieldAction.CANCEL_UNSTAKE];
|
|
252
254
|
} else if (_constants2._STAKING_CHAIN_GROUP.astar.includes(chain)) {
|
|
253
255
|
return [YieldAction.STAKE, YieldAction.CLAIM_REWARD, YieldAction.UNSTAKE, YieldAction.WITHDRAW];
|
|
254
256
|
} else if (_constants2._STAKING_CHAIN_GROUP.amplitude.includes(chain)) {
|
package/cjs/packageInfo.js
CHANGED
|
@@ -120,7 +120,10 @@ const _STAKING_ERA_LENGTH_MAP = {
|
|
|
120
120
|
analog_timechain: 12,
|
|
121
121
|
muse_testnet: 25 * 6 / 60 / 60,
|
|
122
122
|
// 25 blocks per session
|
|
123
|
-
mythos: 24
|
|
123
|
+
mythos: 24,
|
|
124
|
+
energy_web_x_testnet: 22 * 12 / 3600,
|
|
125
|
+
// 22 blocks per era, 1 block per 12s
|
|
126
|
+
energy_web_x: 7200 * 12 / 3600 // 24 hours, 7200 blocks per era, 1 block per 12s
|
|
124
127
|
};
|
|
125
128
|
exports._STAKING_ERA_LENGTH_MAP = _STAKING_ERA_LENGTH_MAP;
|
|
126
129
|
const _EXPECTED_BLOCK_TIME = {
|
|
@@ -156,7 +159,9 @@ const _EXPECTED_BLOCK_TIME = {
|
|
|
156
159
|
avail_mainnet: 20,
|
|
157
160
|
dentnet: 3,
|
|
158
161
|
muse_testnet: 6,
|
|
159
|
-
mythos: 6
|
|
162
|
+
mythos: 6,
|
|
163
|
+
energy_web_x_testnet: 12,
|
|
164
|
+
energy_web_x: 12
|
|
160
165
|
};
|
|
161
166
|
exports._EXPECTED_BLOCK_TIME = _EXPECTED_BLOCK_TIME;
|
|
162
167
|
const _PARACHAIN_INFLATION_DISTRIBUTION = {
|
|
@@ -24,6 +24,7 @@ const _STAKING_CHAIN_GROUP = {
|
|
|
24
24
|
krest_network: ['krest_network'],
|
|
25
25
|
manta: ['manta_network'],
|
|
26
26
|
bittensor: ['bittensor', 'bittensor_testnet'],
|
|
27
|
+
energy: ['energy_web_x_testnet', 'energy_web_x'],
|
|
27
28
|
mythos: ['mythos', 'muse_testnet']
|
|
28
29
|
};
|
|
29
30
|
exports._STAKING_CHAIN_GROUP = _STAKING_CHAIN_GROUP;
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _TransactionError = require("@subwallet/extension-base/background/errors/TransactionError");
|
|
9
|
+
var _KoniTypes = require("@subwallet/extension-base/background/KoniTypes");
|
|
10
|
+
var _utils = require("@subwallet/extension-base/koni/api/staking/bonding/utils");
|
|
11
|
+
var _constants = require("@subwallet/extension-base/services/chain-service/constants");
|
|
12
|
+
var _utils2 = require("@subwallet/extension-base/services/earning-service/utils");
|
|
13
|
+
var _types = require("@subwallet/extension-base/types");
|
|
14
|
+
var _utils3 = require("@subwallet/extension-base/utils");
|
|
15
|
+
var _util = require("@polkadot/util");
|
|
16
|
+
var _basePara = _interopRequireDefault(require("./base-para"));
|
|
17
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
18
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
19
|
+
|
|
20
|
+
class EnergyNativeStakingPoolHandler extends _basePara.default {
|
|
21
|
+
/* Subscribe pool info */
|
|
22
|
+
|
|
23
|
+
async subscribePoolInfo(callback) {
|
|
24
|
+
let cancel = false;
|
|
25
|
+
const chainApi = this.substrateApi;
|
|
26
|
+
const nativeToken = this.nativeToken;
|
|
27
|
+
const defaultCallback = async () => {
|
|
28
|
+
const data = {
|
|
29
|
+
...this.baseInfo,
|
|
30
|
+
type: this.type,
|
|
31
|
+
metadata: {
|
|
32
|
+
...this.metadataInfo,
|
|
33
|
+
description: this.getDescription()
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const poolInfo = await this.getPoolInfo();
|
|
37
|
+
!poolInfo && callback(data);
|
|
38
|
+
};
|
|
39
|
+
if (!this.isActive) {
|
|
40
|
+
await defaultCallback();
|
|
41
|
+
return () => {
|
|
42
|
+
cancel = true;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
await defaultCallback();
|
|
46
|
+
await chainApi.isReady;
|
|
47
|
+
const unsub = await chainApi.api.query.parachainStaking.era(async _era => {
|
|
48
|
+
var _chainApi$api$consts, _chainApi$api$consts$, _chainApi$api$consts$2, _chainApi$api$consts$3, _chainApi$api$query$p;
|
|
49
|
+
if (cancel) {
|
|
50
|
+
unsub();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const eraObj = _era.toHuman();
|
|
54
|
+
const era = (0, _utils3.parseRawNumber)(eraObj.current);
|
|
55
|
+
const maxNominations = (_chainApi$api$consts = chainApi.api.consts) === null || _chainApi$api$consts === void 0 ? void 0 : (_chainApi$api$consts$ = _chainApi$api$consts.parachainStaking) === null || _chainApi$api$consts$ === void 0 ? void 0 : (_chainApi$api$consts$2 = _chainApi$api$consts$.maxNominationsPerNominator) === null || _chainApi$api$consts$2 === void 0 ? void 0 : _chainApi$api$consts$2.toString();
|
|
56
|
+
const maxTopNominatorsPerCollator = (_chainApi$api$consts$3 = chainApi.api.consts.parachainStaking.maxTopNominationsPerCandidate) === null || _chainApi$api$consts$3 === void 0 ? void 0 : _chainApi$api$consts$3.toPrimitive();
|
|
57
|
+
const [_totalStake, unstakingDelay] = await Promise.all([(_chainApi$api$query$p = chainApi.api.query.parachainStaking) === null || _chainApi$api$query$p === void 0 ? void 0 : _chainApi$api$query$p.staked(era), chainApi.api.query.parachainStaking.delay()]);
|
|
58
|
+
const totalStake = _totalStake ? new _util.BN(_totalStake.toString()) : _util.BN_ZERO;
|
|
59
|
+
const eraTime = _constants._STAKING_ERA_LENGTH_MAP[this.chain] || _constants._STAKING_ERA_LENGTH_MAP.default; // in hours
|
|
60
|
+
const unstakingPeriod = parseInt(unstakingDelay.toString()) * eraTime;
|
|
61
|
+
const minStake = '0';
|
|
62
|
+
const minToHuman = (0, _utils3.formatNumber)(minStake.toString(), nativeToken.decimals || 0, _utils3.balanceFormatter);
|
|
63
|
+
const data = {
|
|
64
|
+
...this.baseInfo,
|
|
65
|
+
type: this.type,
|
|
66
|
+
metadata: {
|
|
67
|
+
...this.metadataInfo,
|
|
68
|
+
description: this.getDescription(minToHuman)
|
|
69
|
+
},
|
|
70
|
+
statistic: {
|
|
71
|
+
assetEarning: [{
|
|
72
|
+
slug: this.nativeToken.slug
|
|
73
|
+
}],
|
|
74
|
+
maxCandidatePerFarmer: parseInt(maxNominations),
|
|
75
|
+
maxWithdrawalRequestPerFarmer: 1,
|
|
76
|
+
// by default
|
|
77
|
+
earningThreshold: {
|
|
78
|
+
join: minStake.toString(),
|
|
79
|
+
defaultUnstake: '0',
|
|
80
|
+
fastUnstake: '0'
|
|
81
|
+
},
|
|
82
|
+
farmerCount: 0,
|
|
83
|
+
// TODO recheck
|
|
84
|
+
era,
|
|
85
|
+
eraTime,
|
|
86
|
+
totalApy: undefined,
|
|
87
|
+
// not have
|
|
88
|
+
tvl: totalStake.toString(),
|
|
89
|
+
unstakingPeriod: unstakingPeriod
|
|
90
|
+
},
|
|
91
|
+
maxPoolMembers: maxTopNominatorsPerCollator
|
|
92
|
+
};
|
|
93
|
+
callback(data);
|
|
94
|
+
});
|
|
95
|
+
return () => {
|
|
96
|
+
cancel = true;
|
|
97
|
+
unsub();
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Subscribe pool info */
|
|
102
|
+
|
|
103
|
+
/* Subscribe pool position */
|
|
104
|
+
|
|
105
|
+
async parseNominatorMetadata(chainInfo, address, substrateApi, nominatorState) {
|
|
106
|
+
const nominationList = [];
|
|
107
|
+
const unstakingMap = {};
|
|
108
|
+
const substrateIdentityApi = this.substrateIdentityApi;
|
|
109
|
+
let bnTotalActiveStake = _util.BN_ZERO;
|
|
110
|
+
let bnTotalStake = _util.BN_ZERO;
|
|
111
|
+
let bnTotalUnstaking = _util.BN_ZERO;
|
|
112
|
+
const _eraInfo = await substrateApi.api.query.parachainStaking.era();
|
|
113
|
+
const roundInfo = _eraInfo.toPrimitive();
|
|
114
|
+
const currentRound = roundInfo.current;
|
|
115
|
+
await Promise.all(nominatorState.nominations.map(async nomination => {
|
|
116
|
+
const [_nominationScheduledRequests, [identity], _collatorInfo, _currentBlock, _currentTimestamp] = await Promise.all([substrateApi.api.query.parachainStaking.nominationScheduledRequests(nomination.owner), (0, _utils2.parseIdentity)(substrateIdentityApi, nomination.owner), substrateApi.api.query.parachainStaking.candidateInfo(nomination.owner), substrateApi.api.query.system.number(), substrateApi.api.query.timestamp.now()]);
|
|
117
|
+
const currentBlock = _currentBlock.toPrimitive();
|
|
118
|
+
const currentTimestamp = _currentTimestamp.toPrimitive();
|
|
119
|
+
const collatorInfo = _collatorInfo.toPrimitive();
|
|
120
|
+
const minNomination = collatorInfo === null || collatorInfo === void 0 ? void 0 : collatorInfo.lowestTopNominationAmount.toString();
|
|
121
|
+
const nominationScheduledRequests = _nominationScheduledRequests.toPrimitive();
|
|
122
|
+
let hasUnstaking = false;
|
|
123
|
+
let nominationStatus = _types.EarningStatus.NOT_EARNING;
|
|
124
|
+
|
|
125
|
+
// parse unstaking info
|
|
126
|
+
if (nominationScheduledRequests) {
|
|
127
|
+
for (const scheduledRequest of nominationScheduledRequests) {
|
|
128
|
+
if ((0, _utils3.reformatAddress)(scheduledRequest.nominator, 0) === (0, _utils3.reformatAddress)(address, 0)) {
|
|
129
|
+
// add network prefix
|
|
130
|
+
const isClaimable = scheduledRequest.whenExecutable - parseInt(currentRound) <= 0;
|
|
131
|
+
const remainingEra = scheduledRequest.whenExecutable - parseInt(currentRound);
|
|
132
|
+
const waitingTime = remainingEra * _constants._STAKING_ERA_LENGTH_MAP[chainInfo.slug];
|
|
133
|
+
const claimable = Object.values(scheduledRequest.action)[0];
|
|
134
|
+
|
|
135
|
+
// noted: target timestamp in parachainStaking easily volatile if block time volatile
|
|
136
|
+
const targetBlock = remainingEra * parseInt(roundInfo.length) + parseInt(roundInfo.first);
|
|
137
|
+
const remainingBlock = targetBlock - currentBlock;
|
|
138
|
+
const targetTimestampMs = remainingBlock * _constants._EXPECTED_BLOCK_TIME[chainInfo.slug] * 1000 + currentTimestamp;
|
|
139
|
+
unstakingMap[nomination.owner] = {
|
|
140
|
+
chain: chainInfo.slug,
|
|
141
|
+
status: isClaimable ? _types.UnstakingStatus.CLAIMABLE : _types.UnstakingStatus.UNLOCKING,
|
|
142
|
+
validatorAddress: nomination.owner,
|
|
143
|
+
claimable: claimable.toString(),
|
|
144
|
+
waitingTime,
|
|
145
|
+
targetTimestampMs: targetTimestampMs
|
|
146
|
+
};
|
|
147
|
+
hasUnstaking = true;
|
|
148
|
+
break; // only handle 1 scheduledRequest per collator
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const bnStake = new _util.BN(nomination.amount);
|
|
154
|
+
const bnUnstakeBalance = unstakingMap[nomination.owner] ? new _util.BN(unstakingMap[nomination.owner].claimable) : _util.BN_ZERO;
|
|
155
|
+
const bnActiveStake = bnStake.sub(bnUnstakeBalance);
|
|
156
|
+
if (bnActiveStake.gt(_util.BN_ZERO) && bnActiveStake.gte(new _util.BN(minNomination))) {
|
|
157
|
+
nominationStatus = _types.EarningStatus.EARNING_REWARD;
|
|
158
|
+
}
|
|
159
|
+
bnTotalActiveStake = bnTotalActiveStake.add(bnActiveStake);
|
|
160
|
+
bnTotalStake = bnTotalStake.add(bnStake);
|
|
161
|
+
bnTotalUnstaking = bnTotalUnstaking.add(bnUnstakeBalance);
|
|
162
|
+
nominationList.push({
|
|
163
|
+
chain: chainInfo.slug,
|
|
164
|
+
status: nominationStatus,
|
|
165
|
+
validatorAddress: nomination.owner,
|
|
166
|
+
validatorIdentity: identity,
|
|
167
|
+
activeStake: bnActiveStake.toString(),
|
|
168
|
+
hasUnstaking,
|
|
169
|
+
validatorMinStake: collatorInfo.lowestTopNominationAmount.toString()
|
|
170
|
+
});
|
|
171
|
+
}));
|
|
172
|
+
const stakingStatus = (0, _utils.getEarningStatusByNominations)(bnTotalActiveStake, nominationList);
|
|
173
|
+
const totalStake = bnTotalStake.toString();
|
|
174
|
+
const activeStake = bnTotalActiveStake.toString();
|
|
175
|
+
const unstakingBalance = bnTotalUnstaking.toString();
|
|
176
|
+
const tokenInfo = this.state.chainService.getAssetBySlug(this.nativeToken.slug);
|
|
177
|
+
await this.createWithdrawNotifications(Object.values(unstakingMap), tokenInfo, address);
|
|
178
|
+
return {
|
|
179
|
+
status: stakingStatus,
|
|
180
|
+
totalStake,
|
|
181
|
+
balanceToken: this.nativeToken.slug,
|
|
182
|
+
activeStake: activeStake,
|
|
183
|
+
unstakeBalance: unstakingBalance,
|
|
184
|
+
isBondedBefore: !!nominationList.length,
|
|
185
|
+
nominations: nominationList,
|
|
186
|
+
unstakings: Object.values(unstakingMap)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async subscribePoolPosition(useAddresses, resultCallback) {
|
|
190
|
+
let cancel = false;
|
|
191
|
+
const substrateApi = this.substrateApi;
|
|
192
|
+
const defaultInfo = this.baseInfo;
|
|
193
|
+
const chainInfo = this.chainInfo;
|
|
194
|
+
await substrateApi.isReady;
|
|
195
|
+
const unsub = await substrateApi.api.query.parachainStaking.nominatorState.multi(useAddresses, async ledgers => {
|
|
196
|
+
if (cancel) {
|
|
197
|
+
unsub();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (ledgers) {
|
|
201
|
+
await Promise.all(ledgers.map(async (_nominatorState, i) => {
|
|
202
|
+
const nominatorState = _nominatorState.toPrimitive();
|
|
203
|
+
const owner = (0, _utils3.reformatAddress)(useAddresses[i], 42);
|
|
204
|
+
if (nominatorState) {
|
|
205
|
+
const nominatorMetadata = await this.parseNominatorMetadata(chainInfo, owner, substrateApi, nominatorState);
|
|
206
|
+
resultCallback({
|
|
207
|
+
...defaultInfo,
|
|
208
|
+
...nominatorMetadata,
|
|
209
|
+
address: owner,
|
|
210
|
+
type: this.type
|
|
211
|
+
});
|
|
212
|
+
} else {
|
|
213
|
+
resultCallback({
|
|
214
|
+
...defaultInfo,
|
|
215
|
+
type: this.type,
|
|
216
|
+
address: owner,
|
|
217
|
+
balanceToken: this.nativeToken.slug,
|
|
218
|
+
totalStake: '0',
|
|
219
|
+
activeStake: '0',
|
|
220
|
+
unstakeBalance: '0',
|
|
221
|
+
status: _types.EarningStatus.NOT_STAKING,
|
|
222
|
+
isBondedBefore: false,
|
|
223
|
+
nominations: [],
|
|
224
|
+
unstakings: []
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
return () => {
|
|
231
|
+
cancel = true;
|
|
232
|
+
unsub();
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async checkAccountHaveStake(useAddresses) {
|
|
236
|
+
var _substrateApi$api$que, _substrateApi$api$que2, _substrateApi$api$que3;
|
|
237
|
+
const result = [];
|
|
238
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
239
|
+
const ledgers = await ((_substrateApi$api$que = substrateApi.api.query.parachainStaking) === null || _substrateApi$api$que === void 0 ? void 0 : (_substrateApi$api$que2 = _substrateApi$api$que.nominatorState) === null || _substrateApi$api$que2 === void 0 ? void 0 : (_substrateApi$api$que3 = _substrateApi$api$que2.multi) === null || _substrateApi$api$que3 === void 0 ? void 0 : _substrateApi$api$que3.call(_substrateApi$api$que2, useAddresses));
|
|
240
|
+
if (!ledgers) {
|
|
241
|
+
return [];
|
|
242
|
+
}
|
|
243
|
+
for (let i = 0; i < useAddresses.length; i++) {
|
|
244
|
+
const owner = useAddresses[i];
|
|
245
|
+
const nominatorState = ledgers[i].toPrimitive();
|
|
246
|
+
if (nominatorState && nominatorState.total > 0) {
|
|
247
|
+
result.push(owner);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Subscribe pool position */
|
|
254
|
+
|
|
255
|
+
/* Get pool targets */
|
|
256
|
+
async getPoolTargets() {
|
|
257
|
+
const apiProps = await this.substrateApi.isReady;
|
|
258
|
+
const substrateIdentityApi = this.substrateIdentityApi;
|
|
259
|
+
const allCollators = [];
|
|
260
|
+
const [_allCollators, _selectedCandidates] = await Promise.all([apiProps.api.query.parachainStaking.candidateInfo.entries(),
|
|
261
|
+
// use it when energy support collatorCommission
|
|
262
|
+
// apiProps.api.query.parachainStaking.collatorCommission(),
|
|
263
|
+
apiProps.api.query.parachainStaking.selectedCandidates()]);
|
|
264
|
+
const maxNominationPerCollator = apiProps.api.consts.parachainStaking.maxTopNominationsPerCandidate.toString();
|
|
265
|
+
const selectedCollators = _selectedCandidates.toPrimitive();
|
|
266
|
+
for (const collator of _allCollators) {
|
|
267
|
+
const _collatorAddress = collator[0].toHuman();
|
|
268
|
+
const collatorAddress = _collatorAddress[0];
|
|
269
|
+
const collatorInfo = collator[1].toPrimitive();
|
|
270
|
+
const bnTotalStake = new _util.BN(collatorInfo.totalCounted);
|
|
271
|
+
const bnOwnStake = new _util.BN(collatorInfo.bond);
|
|
272
|
+
const bnOtherStake = bnTotalStake.sub(bnOwnStake);
|
|
273
|
+
const bnMinBond = new _util.BN(collatorInfo.lowestTopNominationAmount);
|
|
274
|
+
const maxNominatorRewarded = parseInt(maxNominationPerCollator);
|
|
275
|
+
if (selectedCollators.includes(collatorAddress)) {
|
|
276
|
+
allCollators.push({
|
|
277
|
+
commission: 0,
|
|
278
|
+
expectedReturn: 0,
|
|
279
|
+
address: collatorAddress,
|
|
280
|
+
totalStake: bnTotalStake.toString(),
|
|
281
|
+
ownStake: bnOwnStake.toString(),
|
|
282
|
+
otherStake: bnOtherStake.toString(),
|
|
283
|
+
nominatorCount: collatorInfo.nominationCount,
|
|
284
|
+
blocked: false,
|
|
285
|
+
isVerified: false,
|
|
286
|
+
minBond: bnMinBond.toString(),
|
|
287
|
+
chain: this.chain,
|
|
288
|
+
isCrowded: collatorInfo.nominationCount >= maxNominatorRewarded
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const extraInfoMap = {};
|
|
293
|
+
await Promise.all(allCollators.map(async collator => {
|
|
294
|
+
const [_info, [identity, isReasonable]] = await Promise.all([apiProps.api.query.parachainStaking.candidateInfo(collator.address), (0, _utils2.parseIdentity)(substrateIdentityApi, collator.address)]);
|
|
295
|
+
const rawInfo = _info.toHuman();
|
|
296
|
+
const active = (rawInfo === null || rawInfo === void 0 ? void 0 : rawInfo.status) === 'Active';
|
|
297
|
+
extraInfoMap[collator.address] = {
|
|
298
|
+
identity,
|
|
299
|
+
isVerified: isReasonable,
|
|
300
|
+
active
|
|
301
|
+
};
|
|
302
|
+
}));
|
|
303
|
+
for (const validator of allCollators) {
|
|
304
|
+
validator.blocked = !extraInfoMap[validator.address].active;
|
|
305
|
+
validator.identity = extraInfoMap[validator.address].identity;
|
|
306
|
+
validator.isVerified = extraInfoMap[validator.address].isVerified;
|
|
307
|
+
}
|
|
308
|
+
return allCollators;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* Get pool targets */
|
|
312
|
+
|
|
313
|
+
/* Join pool action */
|
|
314
|
+
|
|
315
|
+
async createJoinExtrinsic(data, positionInfo) {
|
|
316
|
+
const {
|
|
317
|
+
amount,
|
|
318
|
+
selectedValidators
|
|
319
|
+
} = data;
|
|
320
|
+
const apiPromise = await this.substrateApi.isReady;
|
|
321
|
+
const binaryAmount = new _util.BN(amount);
|
|
322
|
+
const selectedCollatorInfo = selectedValidators[0];
|
|
323
|
+
const {
|
|
324
|
+
address: selectedCollatorAddress,
|
|
325
|
+
nominatorCount: selectedCollatorNominatorCount
|
|
326
|
+
} = selectedCollatorInfo;
|
|
327
|
+
const compoundResult = extrinsic => {
|
|
328
|
+
return Promise.resolve([extrinsic, {
|
|
329
|
+
slug: this.nativeToken.slug,
|
|
330
|
+
amount: '0'
|
|
331
|
+
}]);
|
|
332
|
+
};
|
|
333
|
+
if (!positionInfo) {
|
|
334
|
+
const extrinsic = apiPromise.api.tx.parachainStaking.nominate(selectedCollatorAddress, binaryAmount, new _util.BN(selectedCollatorNominatorCount), 0);
|
|
335
|
+
return compoundResult(extrinsic);
|
|
336
|
+
}
|
|
337
|
+
const {
|
|
338
|
+
bondedValidators,
|
|
339
|
+
nominationCount
|
|
340
|
+
} = (0, _utils.getBondedValidators)(positionInfo.nominations);
|
|
341
|
+
const parsedSelectedCollatorAddress = (0, _utils3.reformatAddress)(selectedCollatorInfo.address, 0);
|
|
342
|
+
if (!bondedValidators.includes(parsedSelectedCollatorAddress)) {
|
|
343
|
+
const extrinsic = apiPromise.api.tx.parachainStaking.nominate(selectedCollatorAddress, binaryAmount, new _util.BN(selectedCollatorNominatorCount), nominationCount);
|
|
344
|
+
return compoundResult(extrinsic);
|
|
345
|
+
} else {
|
|
346
|
+
const extrinsic = apiPromise.api.tx.parachainStaking.bondExtra(selectedCollatorAddress, binaryAmount);
|
|
347
|
+
return compoundResult(extrinsic);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* Join pool action */
|
|
352
|
+
|
|
353
|
+
/* Leave pool action */
|
|
354
|
+
|
|
355
|
+
async handleYieldUnstake(amount, address, selectedTarget) {
|
|
356
|
+
const apiPromise = await this.substrateApi.isReady;
|
|
357
|
+
const binaryAmount = new _util.BN(amount);
|
|
358
|
+
const poolPosition = await this.getPoolPosition(address);
|
|
359
|
+
if (!selectedTarget || !poolPosition) {
|
|
360
|
+
return Promise.reject(new _TransactionError.TransactionError(_types.BasicTxErrorType.INVALID_PARAMS));
|
|
361
|
+
}
|
|
362
|
+
const unstakeAll = (0, _utils.isUnstakeAll)(selectedTarget, poolPosition.nominations, amount);
|
|
363
|
+
let extrinsic;
|
|
364
|
+
if (!unstakeAll) {
|
|
365
|
+
extrinsic = apiPromise.api.tx.parachainStaking.scheduleNominatorUnbond(selectedTarget, binaryAmount);
|
|
366
|
+
} else {
|
|
367
|
+
extrinsic = apiPromise.api.tx.parachainStaking.scheduleRevokeNomination(selectedTarget);
|
|
368
|
+
}
|
|
369
|
+
return [_KoniTypes.ExtrinsicType.STAKING_UNBOND, extrinsic];
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* Leave pool action */
|
|
373
|
+
|
|
374
|
+
/* Other action */
|
|
375
|
+
|
|
376
|
+
async handleYieldCancelUnstake(params) {
|
|
377
|
+
const {
|
|
378
|
+
selectedUnstaking
|
|
379
|
+
} = params;
|
|
380
|
+
const chainApi = await this.substrateApi.isReady;
|
|
381
|
+
return chainApi.api.tx.parachainStaking.cancelNominationRequest(selectedUnstaking.validatorAddress);
|
|
382
|
+
}
|
|
383
|
+
async handleYieldWithdraw(address, unstakingInfo) {
|
|
384
|
+
const collatorAddress = unstakingInfo.validatorAddress;
|
|
385
|
+
if (!collatorAddress) {
|
|
386
|
+
return Promise.reject(new _TransactionError.TransactionError(_types.BasicTxErrorType.INVALID_PARAMS));
|
|
387
|
+
}
|
|
388
|
+
const chainApi = await this.substrateApi.isReady;
|
|
389
|
+
return chainApi.api.tx.parachainStaking.executeNominationRequest(address, collatorAddress);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* Other actions */
|
|
393
|
+
}
|
|
394
|
+
exports.default = EnergyNativeStakingPoolHandler;
|
|
@@ -16,6 +16,12 @@ Object.defineProperty(exports, "AstarNativeStakingPoolHandler", {
|
|
|
16
16
|
return _astar.default;
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
|
+
Object.defineProperty(exports, "EnergyNativeStakingPoolHandler", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () {
|
|
22
|
+
return _energy.default;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
19
25
|
Object.defineProperty(exports, "ParaNativeStakingPoolHandler", {
|
|
20
26
|
enumerable: true,
|
|
21
27
|
get: function () {
|
|
@@ -45,4 +51,5 @@ var _astar = _interopRequireDefault(require("./astar"));
|
|
|
45
51
|
var _relayChain = _interopRequireDefault(require("./relay-chain"));
|
|
46
52
|
var _paraChain = _interopRequireDefault(require("./para-chain"));
|
|
47
53
|
var _tao = _interopRequireDefault(require("./tao"));
|
|
48
|
-
var _dtao = _interopRequireDefault(require("./dtao"));
|
|
54
|
+
var _dtao = _interopRequireDefault(require("./dtao"));
|
|
55
|
+
var _energy = _interopRequireDefault(require("./energy"));
|
|
@@ -100,6 +100,9 @@ class EarningService {
|
|
|
100
100
|
if (_constants2._STAKING_CHAIN_GROUP.mythos.includes(chain)) {
|
|
101
101
|
handlers.push(new _mythos.default(this.state, chain));
|
|
102
102
|
}
|
|
103
|
+
if (_constants2._STAKING_CHAIN_GROUP.energy.includes(chain)) {
|
|
104
|
+
handlers.push(new _handlers.EnergyNativeStakingPoolHandler(this.state, chain));
|
|
105
|
+
}
|
|
103
106
|
if (_constants2._STAKING_CHAIN_GROUP.nominationPool.includes(chain)) {
|
|
104
107
|
const ahChain = ahMapChain[chain];
|
|
105
108
|
if (ahChain) {
|
|
@@ -120,6 +120,8 @@ function isActionFromValidator(stakingType, chain) {
|
|
|
120
120
|
return true;
|
|
121
121
|
} else if (_constants._STAKING_CHAIN_GROUP.mythos.includes(chain)) {
|
|
122
122
|
return true;
|
|
123
|
+
} else if (_constants._STAKING_CHAIN_GROUP.energy.includes(chain)) {
|
|
124
|
+
return true;
|
|
123
125
|
}
|
|
124
126
|
return false;
|
|
125
127
|
}
|
|
@@ -206,6 +206,8 @@ export function getYieldAvailableActionsByType(yieldPoolInfo) {
|
|
|
206
206
|
const chain = yieldPoolInfo.chain;
|
|
207
207
|
if (_STAKING_CHAIN_GROUP.para.includes(chain)) {
|
|
208
208
|
return [YieldAction.STAKE, YieldAction.UNSTAKE, YieldAction.WITHDRAW, YieldAction.CANCEL_UNSTAKE];
|
|
209
|
+
} else if (_STAKING_CHAIN_GROUP.energy.includes(chain)) {
|
|
210
|
+
return [YieldAction.STAKE, YieldAction.UNSTAKE, YieldAction.WITHDRAW, YieldAction.CANCEL_UNSTAKE];
|
|
209
211
|
} else if (_STAKING_CHAIN_GROUP.astar.includes(chain)) {
|
|
210
212
|
return [YieldAction.STAKE, YieldAction.CLAIM_REWARD, YieldAction.UNSTAKE, YieldAction.WITHDRAW];
|
|
211
213
|
} else if (_STAKING_CHAIN_GROUP.amplitude.includes(chain)) {
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"./cjs/detectPackage.js"
|
|
18
18
|
],
|
|
19
19
|
"type": "module",
|
|
20
|
-
"version": "1.3.
|
|
20
|
+
"version": "1.3.57-0",
|
|
21
21
|
"main": "./cjs/index.js",
|
|
22
22
|
"module": "./index.js",
|
|
23
23
|
"types": "./index.d.ts",
|
|
@@ -1171,6 +1171,11 @@
|
|
|
1171
1171
|
"require": "./cjs/services/earning-service/handlers/native-staking/dtao.js",
|
|
1172
1172
|
"default": "./services/earning-service/handlers/native-staking/dtao.js"
|
|
1173
1173
|
},
|
|
1174
|
+
"./services/earning-service/handlers/native-staking/energy": {
|
|
1175
|
+
"types": "./services/earning-service/handlers/native-staking/energy.d.ts",
|
|
1176
|
+
"require": "./cjs/services/earning-service/handlers/native-staking/energy.js",
|
|
1177
|
+
"default": "./services/earning-service/handlers/native-staking/energy.js"
|
|
1178
|
+
},
|
|
1174
1179
|
"./services/earning-service/handlers/native-staking/mythos": {
|
|
1175
1180
|
"types": "./services/earning-service/handlers/native-staking/mythos.d.ts",
|
|
1176
1181
|
"require": "./cjs/services/earning-service/handlers/native-staking/mythos.js",
|
|
@@ -2874,10 +2879,10 @@
|
|
|
2874
2879
|
"@substrate/connect": "^0.8.9",
|
|
2875
2880
|
"@subwallet-monorepos/subwallet-services-sdk": "^0.1.8",
|
|
2876
2881
|
"@subwallet/chain-list": "0.2.114",
|
|
2877
|
-
"@subwallet/extension-base": "^1.3.
|
|
2878
|
-
"@subwallet/extension-chains": "^1.3.
|
|
2879
|
-
"@subwallet/extension-dapp": "^1.3.
|
|
2880
|
-
"@subwallet/extension-inject": "^1.3.
|
|
2882
|
+
"@subwallet/extension-base": "^1.3.57-0",
|
|
2883
|
+
"@subwallet/extension-chains": "^1.3.57-0",
|
|
2884
|
+
"@subwallet/extension-dapp": "^1.3.57-0",
|
|
2885
|
+
"@subwallet/extension-inject": "^1.3.57-0",
|
|
2881
2886
|
"@subwallet/keyring": "^0.1.13",
|
|
2882
2887
|
"@subwallet/ui-keyring": "^0.1.13",
|
|
2883
2888
|
"@ton/core": "^0.56.3",
|
package/packageInfo.js
CHANGED
|
@@ -7,5 +7,5 @@ export const packageInfo = {
|
|
|
7
7
|
name: '@subwallet/extension-base',
|
|
8
8
|
path: (import.meta && import.meta.url) ? new URL(import.meta.url).pathname.substring(0, new URL(import.meta.url).pathname.lastIndexOf('/') + 1) : 'auto',
|
|
9
9
|
type: 'esm',
|
|
10
|
-
version: '1.3.
|
|
10
|
+
version: '1.3.57-0'
|
|
11
11
|
};
|
|
@@ -107,8 +107,12 @@ export const _STAKING_ERA_LENGTH_MAP = {
|
|
|
107
107
|
analog_timechain: 12,
|
|
108
108
|
muse_testnet: 25 * 6 / 60 / 60,
|
|
109
109
|
// 25 blocks per session
|
|
110
|
-
mythos: 24
|
|
110
|
+
mythos: 24,
|
|
111
|
+
energy_web_x_testnet: 22 * 12 / 3600,
|
|
112
|
+
// 22 blocks per era, 1 block per 12s
|
|
113
|
+
energy_web_x: 7200 * 12 / 3600 // 24 hours, 7200 blocks per era, 1 block per 12s
|
|
111
114
|
};
|
|
115
|
+
|
|
112
116
|
export const _EXPECTED_BLOCK_TIME = {
|
|
113
117
|
// in seconds
|
|
114
118
|
alephTest: 1,
|
|
@@ -142,7 +146,9 @@ export const _EXPECTED_BLOCK_TIME = {
|
|
|
142
146
|
avail_mainnet: 20,
|
|
143
147
|
dentnet: 3,
|
|
144
148
|
muse_testnet: 6,
|
|
145
|
-
mythos: 6
|
|
149
|
+
mythos: 6,
|
|
150
|
+
energy_web_x_testnet: 12,
|
|
151
|
+
energy_web_x: 12
|
|
146
152
|
};
|
|
147
153
|
export const _PARACHAIN_INFLATION_DISTRIBUTION = {
|
|
148
154
|
moonbeam: {
|
|
@@ -18,6 +18,7 @@ export const _STAKING_CHAIN_GROUP = {
|
|
|
18
18
|
krest_network: ['krest_network'],
|
|
19
19
|
manta: ['manta_network'],
|
|
20
20
|
bittensor: ['bittensor', 'bittensor_testnet'],
|
|
21
|
+
energy: ['energy_web_x_testnet', 'energy_web_x'],
|
|
21
22
|
mythos: ['mythos', 'muse_testnet']
|
|
22
23
|
};
|
|
23
24
|
export const TON_CHAINS = ['ton', 'ton_testnet'];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
|
+
import { ExtrinsicType, UnstakingInfo } from '@subwallet/extension-base/background/KoniTypes';
|
|
3
|
+
import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
4
|
+
import { BaseYieldPositionInfo, PalletParachainStakingDelegationInfo, PalletParachainStakingRequestType, StakeCancelWithdrawalParams, SubmitJoinNativeStaking, TransactionData, ValidatorInfo, YieldPoolInfo, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types';
|
|
5
|
+
import BaseParaNativeStakingPoolHandler from './base-para';
|
|
6
|
+
declare type PalletEnergyStakingNominationInfo = PalletParachainStakingDelegationInfo;
|
|
7
|
+
interface PalletEnergyStakingNominator {
|
|
8
|
+
id: string;
|
|
9
|
+
nominations: PalletEnergyStakingNominationInfo[];
|
|
10
|
+
total: number;
|
|
11
|
+
lessTotal: number;
|
|
12
|
+
status: number;
|
|
13
|
+
}
|
|
14
|
+
export interface PalletEnergyStakingNominationRequestsScheduledRequest {
|
|
15
|
+
nominator: string;
|
|
16
|
+
whenExecutable: number;
|
|
17
|
+
action: Record<PalletParachainStakingRequestType, number>;
|
|
18
|
+
}
|
|
19
|
+
export default class EnergyNativeStakingPoolHandler extends BaseParaNativeStakingPoolHandler {
|
|
20
|
+
subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
|
|
21
|
+
parseNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, nominatorState: PalletEnergyStakingNominator): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
|
|
22
|
+
subscribePoolPosition(useAddresses: string[], resultCallback: (rs: YieldPositionInfo) => void): Promise<VoidFunction>;
|
|
23
|
+
checkAccountHaveStake(useAddresses: string[]): Promise<string[]>;
|
|
24
|
+
getPoolTargets(): Promise<ValidatorInfo[]>;
|
|
25
|
+
createJoinExtrinsic(data: SubmitJoinNativeStaking, positionInfo?: YieldPositionInfo): Promise<[TransactionData, YieldTokenBaseInfo]>;
|
|
26
|
+
handleYieldUnstake(amount: string, address: string, selectedTarget?: string): Promise<[ExtrinsicType, TransactionData]>;
|
|
27
|
+
handleYieldCancelUnstake(params: StakeCancelWithdrawalParams): Promise<TransactionData>;
|
|
28
|
+
handleYieldWithdraw(address: string, unstakingInfo: UnstakingInfo): Promise<TransactionData>;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
5
|
+
import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
+
import { getBondedValidators, getEarningStatusByNominations, isUnstakeAll } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
7
|
+
import { _EXPECTED_BLOCK_TIME, _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
8
|
+
import { parseIdentity } from '@subwallet/extension-base/services/earning-service/utils';
|
|
9
|
+
import { BasicTxErrorType, EarningStatus, UnstakingStatus } from '@subwallet/extension-base/types';
|
|
10
|
+
import { balanceFormatter, formatNumber, parseRawNumber, reformatAddress } from '@subwallet/extension-base/utils';
|
|
11
|
+
import { BN, BN_ZERO } from '@polkadot/util';
|
|
12
|
+
import BaseParaNativeStakingPoolHandler from "./base-para.js";
|
|
13
|
+
export default class EnergyNativeStakingPoolHandler extends BaseParaNativeStakingPoolHandler {
|
|
14
|
+
/* Subscribe pool info */
|
|
15
|
+
|
|
16
|
+
async subscribePoolInfo(callback) {
|
|
17
|
+
let cancel = false;
|
|
18
|
+
const chainApi = this.substrateApi;
|
|
19
|
+
const nativeToken = this.nativeToken;
|
|
20
|
+
const defaultCallback = async () => {
|
|
21
|
+
const data = {
|
|
22
|
+
...this.baseInfo,
|
|
23
|
+
type: this.type,
|
|
24
|
+
metadata: {
|
|
25
|
+
...this.metadataInfo,
|
|
26
|
+
description: this.getDescription()
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const poolInfo = await this.getPoolInfo();
|
|
30
|
+
!poolInfo && callback(data);
|
|
31
|
+
};
|
|
32
|
+
if (!this.isActive) {
|
|
33
|
+
await defaultCallback();
|
|
34
|
+
return () => {
|
|
35
|
+
cancel = true;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
await defaultCallback();
|
|
39
|
+
await chainApi.isReady;
|
|
40
|
+
const unsub = await chainApi.api.query.parachainStaking.era(async _era => {
|
|
41
|
+
var _chainApi$api$consts, _chainApi$api$consts$, _chainApi$api$consts$2, _chainApi$api$consts$3, _chainApi$api$query$p;
|
|
42
|
+
if (cancel) {
|
|
43
|
+
unsub();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const eraObj = _era.toHuman();
|
|
47
|
+
const era = parseRawNumber(eraObj.current);
|
|
48
|
+
const maxNominations = (_chainApi$api$consts = chainApi.api.consts) === null || _chainApi$api$consts === void 0 ? void 0 : (_chainApi$api$consts$ = _chainApi$api$consts.parachainStaking) === null || _chainApi$api$consts$ === void 0 ? void 0 : (_chainApi$api$consts$2 = _chainApi$api$consts$.maxNominationsPerNominator) === null || _chainApi$api$consts$2 === void 0 ? void 0 : _chainApi$api$consts$2.toString();
|
|
49
|
+
const maxTopNominatorsPerCollator = (_chainApi$api$consts$3 = chainApi.api.consts.parachainStaking.maxTopNominationsPerCandidate) === null || _chainApi$api$consts$3 === void 0 ? void 0 : _chainApi$api$consts$3.toPrimitive();
|
|
50
|
+
const [_totalStake, unstakingDelay] = await Promise.all([(_chainApi$api$query$p = chainApi.api.query.parachainStaking) === null || _chainApi$api$query$p === void 0 ? void 0 : _chainApi$api$query$p.staked(era), chainApi.api.query.parachainStaking.delay()]);
|
|
51
|
+
const totalStake = _totalStake ? new BN(_totalStake.toString()) : BN_ZERO;
|
|
52
|
+
const eraTime = _STAKING_ERA_LENGTH_MAP[this.chain] || _STAKING_ERA_LENGTH_MAP.default; // in hours
|
|
53
|
+
const unstakingPeriod = parseInt(unstakingDelay.toString()) * eraTime;
|
|
54
|
+
const minStake = '0';
|
|
55
|
+
const minToHuman = formatNumber(minStake.toString(), nativeToken.decimals || 0, balanceFormatter);
|
|
56
|
+
const data = {
|
|
57
|
+
...this.baseInfo,
|
|
58
|
+
type: this.type,
|
|
59
|
+
metadata: {
|
|
60
|
+
...this.metadataInfo,
|
|
61
|
+
description: this.getDescription(minToHuman)
|
|
62
|
+
},
|
|
63
|
+
statistic: {
|
|
64
|
+
assetEarning: [{
|
|
65
|
+
slug: this.nativeToken.slug
|
|
66
|
+
}],
|
|
67
|
+
maxCandidatePerFarmer: parseInt(maxNominations),
|
|
68
|
+
maxWithdrawalRequestPerFarmer: 1,
|
|
69
|
+
// by default
|
|
70
|
+
earningThreshold: {
|
|
71
|
+
join: minStake.toString(),
|
|
72
|
+
defaultUnstake: '0',
|
|
73
|
+
fastUnstake: '0'
|
|
74
|
+
},
|
|
75
|
+
farmerCount: 0,
|
|
76
|
+
// TODO recheck
|
|
77
|
+
era,
|
|
78
|
+
eraTime,
|
|
79
|
+
totalApy: undefined,
|
|
80
|
+
// not have
|
|
81
|
+
tvl: totalStake.toString(),
|
|
82
|
+
unstakingPeriod: unstakingPeriod
|
|
83
|
+
},
|
|
84
|
+
maxPoolMembers: maxTopNominatorsPerCollator
|
|
85
|
+
};
|
|
86
|
+
callback(data);
|
|
87
|
+
});
|
|
88
|
+
return () => {
|
|
89
|
+
cancel = true;
|
|
90
|
+
unsub();
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Subscribe pool info */
|
|
95
|
+
|
|
96
|
+
/* Subscribe pool position */
|
|
97
|
+
|
|
98
|
+
async parseNominatorMetadata(chainInfo, address, substrateApi, nominatorState) {
|
|
99
|
+
const nominationList = [];
|
|
100
|
+
const unstakingMap = {};
|
|
101
|
+
const substrateIdentityApi = this.substrateIdentityApi;
|
|
102
|
+
let bnTotalActiveStake = BN_ZERO;
|
|
103
|
+
let bnTotalStake = BN_ZERO;
|
|
104
|
+
let bnTotalUnstaking = BN_ZERO;
|
|
105
|
+
const _eraInfo = await substrateApi.api.query.parachainStaking.era();
|
|
106
|
+
const roundInfo = _eraInfo.toPrimitive();
|
|
107
|
+
const currentRound = roundInfo.current;
|
|
108
|
+
await Promise.all(nominatorState.nominations.map(async nomination => {
|
|
109
|
+
const [_nominationScheduledRequests, [identity], _collatorInfo, _currentBlock, _currentTimestamp] = await Promise.all([substrateApi.api.query.parachainStaking.nominationScheduledRequests(nomination.owner), parseIdentity(substrateIdentityApi, nomination.owner), substrateApi.api.query.parachainStaking.candidateInfo(nomination.owner), substrateApi.api.query.system.number(), substrateApi.api.query.timestamp.now()]);
|
|
110
|
+
const currentBlock = _currentBlock.toPrimitive();
|
|
111
|
+
const currentTimestamp = _currentTimestamp.toPrimitive();
|
|
112
|
+
const collatorInfo = _collatorInfo.toPrimitive();
|
|
113
|
+
const minNomination = collatorInfo === null || collatorInfo === void 0 ? void 0 : collatorInfo.lowestTopNominationAmount.toString();
|
|
114
|
+
const nominationScheduledRequests = _nominationScheduledRequests.toPrimitive();
|
|
115
|
+
let hasUnstaking = false;
|
|
116
|
+
let nominationStatus = EarningStatus.NOT_EARNING;
|
|
117
|
+
|
|
118
|
+
// parse unstaking info
|
|
119
|
+
if (nominationScheduledRequests) {
|
|
120
|
+
for (const scheduledRequest of nominationScheduledRequests) {
|
|
121
|
+
if (reformatAddress(scheduledRequest.nominator, 0) === reformatAddress(address, 0)) {
|
|
122
|
+
// add network prefix
|
|
123
|
+
const isClaimable = scheduledRequest.whenExecutable - parseInt(currentRound) <= 0;
|
|
124
|
+
const remainingEra = scheduledRequest.whenExecutable - parseInt(currentRound);
|
|
125
|
+
const waitingTime = remainingEra * _STAKING_ERA_LENGTH_MAP[chainInfo.slug];
|
|
126
|
+
const claimable = Object.values(scheduledRequest.action)[0];
|
|
127
|
+
|
|
128
|
+
// noted: target timestamp in parachainStaking easily volatile if block time volatile
|
|
129
|
+
const targetBlock = remainingEra * parseInt(roundInfo.length) + parseInt(roundInfo.first);
|
|
130
|
+
const remainingBlock = targetBlock - currentBlock;
|
|
131
|
+
const targetTimestampMs = remainingBlock * _EXPECTED_BLOCK_TIME[chainInfo.slug] * 1000 + currentTimestamp;
|
|
132
|
+
unstakingMap[nomination.owner] = {
|
|
133
|
+
chain: chainInfo.slug,
|
|
134
|
+
status: isClaimable ? UnstakingStatus.CLAIMABLE : UnstakingStatus.UNLOCKING,
|
|
135
|
+
validatorAddress: nomination.owner,
|
|
136
|
+
claimable: claimable.toString(),
|
|
137
|
+
waitingTime,
|
|
138
|
+
targetTimestampMs: targetTimestampMs
|
|
139
|
+
};
|
|
140
|
+
hasUnstaking = true;
|
|
141
|
+
break; // only handle 1 scheduledRequest per collator
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const bnStake = new BN(nomination.amount);
|
|
147
|
+
const bnUnstakeBalance = unstakingMap[nomination.owner] ? new BN(unstakingMap[nomination.owner].claimable) : BN_ZERO;
|
|
148
|
+
const bnActiveStake = bnStake.sub(bnUnstakeBalance);
|
|
149
|
+
if (bnActiveStake.gt(BN_ZERO) && bnActiveStake.gte(new BN(minNomination))) {
|
|
150
|
+
nominationStatus = EarningStatus.EARNING_REWARD;
|
|
151
|
+
}
|
|
152
|
+
bnTotalActiveStake = bnTotalActiveStake.add(bnActiveStake);
|
|
153
|
+
bnTotalStake = bnTotalStake.add(bnStake);
|
|
154
|
+
bnTotalUnstaking = bnTotalUnstaking.add(bnUnstakeBalance);
|
|
155
|
+
nominationList.push({
|
|
156
|
+
chain: chainInfo.slug,
|
|
157
|
+
status: nominationStatus,
|
|
158
|
+
validatorAddress: nomination.owner,
|
|
159
|
+
validatorIdentity: identity,
|
|
160
|
+
activeStake: bnActiveStake.toString(),
|
|
161
|
+
hasUnstaking,
|
|
162
|
+
validatorMinStake: collatorInfo.lowestTopNominationAmount.toString()
|
|
163
|
+
});
|
|
164
|
+
}));
|
|
165
|
+
const stakingStatus = getEarningStatusByNominations(bnTotalActiveStake, nominationList);
|
|
166
|
+
const totalStake = bnTotalStake.toString();
|
|
167
|
+
const activeStake = bnTotalActiveStake.toString();
|
|
168
|
+
const unstakingBalance = bnTotalUnstaking.toString();
|
|
169
|
+
const tokenInfo = this.state.chainService.getAssetBySlug(this.nativeToken.slug);
|
|
170
|
+
await this.createWithdrawNotifications(Object.values(unstakingMap), tokenInfo, address);
|
|
171
|
+
return {
|
|
172
|
+
status: stakingStatus,
|
|
173
|
+
totalStake,
|
|
174
|
+
balanceToken: this.nativeToken.slug,
|
|
175
|
+
activeStake: activeStake,
|
|
176
|
+
unstakeBalance: unstakingBalance,
|
|
177
|
+
isBondedBefore: !!nominationList.length,
|
|
178
|
+
nominations: nominationList,
|
|
179
|
+
unstakings: Object.values(unstakingMap)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async subscribePoolPosition(useAddresses, resultCallback) {
|
|
183
|
+
let cancel = false;
|
|
184
|
+
const substrateApi = this.substrateApi;
|
|
185
|
+
const defaultInfo = this.baseInfo;
|
|
186
|
+
const chainInfo = this.chainInfo;
|
|
187
|
+
await substrateApi.isReady;
|
|
188
|
+
const unsub = await substrateApi.api.query.parachainStaking.nominatorState.multi(useAddresses, async ledgers => {
|
|
189
|
+
if (cancel) {
|
|
190
|
+
unsub();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (ledgers) {
|
|
194
|
+
await Promise.all(ledgers.map(async (_nominatorState, i) => {
|
|
195
|
+
const nominatorState = _nominatorState.toPrimitive();
|
|
196
|
+
const owner = reformatAddress(useAddresses[i], 42);
|
|
197
|
+
if (nominatorState) {
|
|
198
|
+
const nominatorMetadata = await this.parseNominatorMetadata(chainInfo, owner, substrateApi, nominatorState);
|
|
199
|
+
resultCallback({
|
|
200
|
+
...defaultInfo,
|
|
201
|
+
...nominatorMetadata,
|
|
202
|
+
address: owner,
|
|
203
|
+
type: this.type
|
|
204
|
+
});
|
|
205
|
+
} else {
|
|
206
|
+
resultCallback({
|
|
207
|
+
...defaultInfo,
|
|
208
|
+
type: this.type,
|
|
209
|
+
address: owner,
|
|
210
|
+
balanceToken: this.nativeToken.slug,
|
|
211
|
+
totalStake: '0',
|
|
212
|
+
activeStake: '0',
|
|
213
|
+
unstakeBalance: '0',
|
|
214
|
+
status: EarningStatus.NOT_STAKING,
|
|
215
|
+
isBondedBefore: false,
|
|
216
|
+
nominations: [],
|
|
217
|
+
unstakings: []
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return () => {
|
|
224
|
+
cancel = true;
|
|
225
|
+
unsub();
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
async checkAccountHaveStake(useAddresses) {
|
|
229
|
+
var _substrateApi$api$que, _substrateApi$api$que2, _substrateApi$api$que3;
|
|
230
|
+
const result = [];
|
|
231
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
232
|
+
const ledgers = await ((_substrateApi$api$que = substrateApi.api.query.parachainStaking) === null || _substrateApi$api$que === void 0 ? void 0 : (_substrateApi$api$que2 = _substrateApi$api$que.nominatorState) === null || _substrateApi$api$que2 === void 0 ? void 0 : (_substrateApi$api$que3 = _substrateApi$api$que2.multi) === null || _substrateApi$api$que3 === void 0 ? void 0 : _substrateApi$api$que3.call(_substrateApi$api$que2, useAddresses));
|
|
233
|
+
if (!ledgers) {
|
|
234
|
+
return [];
|
|
235
|
+
}
|
|
236
|
+
for (let i = 0; i < useAddresses.length; i++) {
|
|
237
|
+
const owner = useAddresses[i];
|
|
238
|
+
const nominatorState = ledgers[i].toPrimitive();
|
|
239
|
+
if (nominatorState && nominatorState.total > 0) {
|
|
240
|
+
result.push(owner);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* Subscribe pool position */
|
|
247
|
+
|
|
248
|
+
/* Get pool targets */
|
|
249
|
+
async getPoolTargets() {
|
|
250
|
+
const apiProps = await this.substrateApi.isReady;
|
|
251
|
+
const substrateIdentityApi = this.substrateIdentityApi;
|
|
252
|
+
const allCollators = [];
|
|
253
|
+
const [_allCollators, _selectedCandidates] = await Promise.all([apiProps.api.query.parachainStaking.candidateInfo.entries(),
|
|
254
|
+
// use it when energy support collatorCommission
|
|
255
|
+
// apiProps.api.query.parachainStaking.collatorCommission(),
|
|
256
|
+
apiProps.api.query.parachainStaking.selectedCandidates()]);
|
|
257
|
+
const maxNominationPerCollator = apiProps.api.consts.parachainStaking.maxTopNominationsPerCandidate.toString();
|
|
258
|
+
const selectedCollators = _selectedCandidates.toPrimitive();
|
|
259
|
+
for (const collator of _allCollators) {
|
|
260
|
+
const _collatorAddress = collator[0].toHuman();
|
|
261
|
+
const collatorAddress = _collatorAddress[0];
|
|
262
|
+
const collatorInfo = collator[1].toPrimitive();
|
|
263
|
+
const bnTotalStake = new BN(collatorInfo.totalCounted);
|
|
264
|
+
const bnOwnStake = new BN(collatorInfo.bond);
|
|
265
|
+
const bnOtherStake = bnTotalStake.sub(bnOwnStake);
|
|
266
|
+
const bnMinBond = new BN(collatorInfo.lowestTopNominationAmount);
|
|
267
|
+
const maxNominatorRewarded = parseInt(maxNominationPerCollator);
|
|
268
|
+
if (selectedCollators.includes(collatorAddress)) {
|
|
269
|
+
allCollators.push({
|
|
270
|
+
commission: 0,
|
|
271
|
+
expectedReturn: 0,
|
|
272
|
+
address: collatorAddress,
|
|
273
|
+
totalStake: bnTotalStake.toString(),
|
|
274
|
+
ownStake: bnOwnStake.toString(),
|
|
275
|
+
otherStake: bnOtherStake.toString(),
|
|
276
|
+
nominatorCount: collatorInfo.nominationCount,
|
|
277
|
+
blocked: false,
|
|
278
|
+
isVerified: false,
|
|
279
|
+
minBond: bnMinBond.toString(),
|
|
280
|
+
chain: this.chain,
|
|
281
|
+
isCrowded: collatorInfo.nominationCount >= maxNominatorRewarded
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const extraInfoMap = {};
|
|
286
|
+
await Promise.all(allCollators.map(async collator => {
|
|
287
|
+
const [_info, [identity, isReasonable]] = await Promise.all([apiProps.api.query.parachainStaking.candidateInfo(collator.address), parseIdentity(substrateIdentityApi, collator.address)]);
|
|
288
|
+
const rawInfo = _info.toHuman();
|
|
289
|
+
const active = (rawInfo === null || rawInfo === void 0 ? void 0 : rawInfo.status) === 'Active';
|
|
290
|
+
extraInfoMap[collator.address] = {
|
|
291
|
+
identity,
|
|
292
|
+
isVerified: isReasonable,
|
|
293
|
+
active
|
|
294
|
+
};
|
|
295
|
+
}));
|
|
296
|
+
for (const validator of allCollators) {
|
|
297
|
+
validator.blocked = !extraInfoMap[validator.address].active;
|
|
298
|
+
validator.identity = extraInfoMap[validator.address].identity;
|
|
299
|
+
validator.isVerified = extraInfoMap[validator.address].isVerified;
|
|
300
|
+
}
|
|
301
|
+
return allCollators;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/* Get pool targets */
|
|
305
|
+
|
|
306
|
+
/* Join pool action */
|
|
307
|
+
|
|
308
|
+
async createJoinExtrinsic(data, positionInfo) {
|
|
309
|
+
const {
|
|
310
|
+
amount,
|
|
311
|
+
selectedValidators
|
|
312
|
+
} = data;
|
|
313
|
+
const apiPromise = await this.substrateApi.isReady;
|
|
314
|
+
const binaryAmount = new BN(amount);
|
|
315
|
+
const selectedCollatorInfo = selectedValidators[0];
|
|
316
|
+
const {
|
|
317
|
+
address: selectedCollatorAddress,
|
|
318
|
+
nominatorCount: selectedCollatorNominatorCount
|
|
319
|
+
} = selectedCollatorInfo;
|
|
320
|
+
const compoundResult = extrinsic => {
|
|
321
|
+
return Promise.resolve([extrinsic, {
|
|
322
|
+
slug: this.nativeToken.slug,
|
|
323
|
+
amount: '0'
|
|
324
|
+
}]);
|
|
325
|
+
};
|
|
326
|
+
if (!positionInfo) {
|
|
327
|
+
const extrinsic = apiPromise.api.tx.parachainStaking.nominate(selectedCollatorAddress, binaryAmount, new BN(selectedCollatorNominatorCount), 0);
|
|
328
|
+
return compoundResult(extrinsic);
|
|
329
|
+
}
|
|
330
|
+
const {
|
|
331
|
+
bondedValidators,
|
|
332
|
+
nominationCount
|
|
333
|
+
} = getBondedValidators(positionInfo.nominations);
|
|
334
|
+
const parsedSelectedCollatorAddress = reformatAddress(selectedCollatorInfo.address, 0);
|
|
335
|
+
if (!bondedValidators.includes(parsedSelectedCollatorAddress)) {
|
|
336
|
+
const extrinsic = apiPromise.api.tx.parachainStaking.nominate(selectedCollatorAddress, binaryAmount, new BN(selectedCollatorNominatorCount), nominationCount);
|
|
337
|
+
return compoundResult(extrinsic);
|
|
338
|
+
} else {
|
|
339
|
+
const extrinsic = apiPromise.api.tx.parachainStaking.bondExtra(selectedCollatorAddress, binaryAmount);
|
|
340
|
+
return compoundResult(extrinsic);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Join pool action */
|
|
345
|
+
|
|
346
|
+
/* Leave pool action */
|
|
347
|
+
|
|
348
|
+
async handleYieldUnstake(amount, address, selectedTarget) {
|
|
349
|
+
const apiPromise = await this.substrateApi.isReady;
|
|
350
|
+
const binaryAmount = new BN(amount);
|
|
351
|
+
const poolPosition = await this.getPoolPosition(address);
|
|
352
|
+
if (!selectedTarget || !poolPosition) {
|
|
353
|
+
return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS));
|
|
354
|
+
}
|
|
355
|
+
const unstakeAll = isUnstakeAll(selectedTarget, poolPosition.nominations, amount);
|
|
356
|
+
let extrinsic;
|
|
357
|
+
if (!unstakeAll) {
|
|
358
|
+
extrinsic = apiPromise.api.tx.parachainStaking.scheduleNominatorUnbond(selectedTarget, binaryAmount);
|
|
359
|
+
} else {
|
|
360
|
+
extrinsic = apiPromise.api.tx.parachainStaking.scheduleRevokeNomination(selectedTarget);
|
|
361
|
+
}
|
|
362
|
+
return [ExtrinsicType.STAKING_UNBOND, extrinsic];
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* Leave pool action */
|
|
366
|
+
|
|
367
|
+
/* Other action */
|
|
368
|
+
|
|
369
|
+
async handleYieldCancelUnstake(params) {
|
|
370
|
+
const {
|
|
371
|
+
selectedUnstaking
|
|
372
|
+
} = params;
|
|
373
|
+
const chainApi = await this.substrateApi.isReady;
|
|
374
|
+
return chainApi.api.tx.parachainStaking.cancelNominationRequest(selectedUnstaking.validatorAddress);
|
|
375
|
+
}
|
|
376
|
+
async handleYieldWithdraw(address, unstakingInfo) {
|
|
377
|
+
const collatorAddress = unstakingInfo.validatorAddress;
|
|
378
|
+
if (!collatorAddress) {
|
|
379
|
+
return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS));
|
|
380
|
+
}
|
|
381
|
+
const chainApi = await this.substrateApi.isReady;
|
|
382
|
+
return chainApi.api.tx.parachainStaking.executeNominationRequest(address, collatorAddress);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/* Other actions */
|
|
386
|
+
}
|
|
@@ -4,3 +4,4 @@ export { default as RelayNativeStakingPoolHandler } from './relay-chain';
|
|
|
4
4
|
export { default as ParaNativeStakingPoolHandler } from './para-chain';
|
|
5
5
|
export { default as TaoNativeStakingPoolHandler } from './tao';
|
|
6
6
|
export { default as SubnetTaoStakingPoolHandler } from './dtao';
|
|
7
|
+
export { default as EnergyNativeStakingPoolHandler } from './energy';
|
|
@@ -6,4 +6,5 @@ export { default as AstarNativeStakingPoolHandler } from "./astar.js";
|
|
|
6
6
|
export { default as RelayNativeStakingPoolHandler } from "./relay-chain.js";
|
|
7
7
|
export { default as ParaNativeStakingPoolHandler } from "./para-chain.js";
|
|
8
8
|
export { default as TaoNativeStakingPoolHandler } from "./tao.js";
|
|
9
|
-
export { default as SubnetTaoStakingPoolHandler } from "./dtao.js";
|
|
9
|
+
export { default as SubnetTaoStakingPoolHandler } from "./dtao.js";
|
|
10
|
+
export { default as EnergyNativeStakingPoolHandler } from "./energy.js";
|
|
@@ -13,7 +13,7 @@ import { BasicTxErrorType, YieldPoolType } from '@subwallet/extension-base/types
|
|
|
13
13
|
import { addLazy, createPromiseHandler, filterAddressByChainInfo, removeLazy } from '@subwallet/extension-base/utils';
|
|
14
14
|
import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache';
|
|
15
15
|
import { BehaviorSubject, combineLatest } from 'rxjs';
|
|
16
|
-
import { AcalaLiquidStakingPoolHandler, AmplitudeNativeStakingPoolHandler, AstarNativeStakingPoolHandler, BifrostLiquidStakingPoolHandler, BifrostMantaLiquidStakingPoolHandler, InterlayLendingPoolHandler, NominationPoolHandler, ParallelLiquidStakingPoolHandler, ParaNativeStakingPoolHandler, RelayNativeStakingPoolHandler, StellaSwapLiquidStakingPoolHandler, SubnetTaoStakingPoolHandler, TaoNativeStakingPoolHandler } from "./handlers/index.js";
|
|
16
|
+
import { AcalaLiquidStakingPoolHandler, AmplitudeNativeStakingPoolHandler, AstarNativeStakingPoolHandler, BifrostLiquidStakingPoolHandler, BifrostMantaLiquidStakingPoolHandler, EnergyNativeStakingPoolHandler, InterlayLendingPoolHandler, NominationPoolHandler, ParallelLiquidStakingPoolHandler, ParaNativeStakingPoolHandler, RelayNativeStakingPoolHandler, StellaSwapLiquidStakingPoolHandler, SubnetTaoStakingPoolHandler, TaoNativeStakingPoolHandler } from "./handlers/index.js";
|
|
17
17
|
export const fetchPoolsData = async () => {
|
|
18
18
|
const fetchData = await fetchStaticCache('earning/yield-pools.json', {
|
|
19
19
|
data: {}
|
|
@@ -92,6 +92,9 @@ export default class EarningService {
|
|
|
92
92
|
if (_STAKING_CHAIN_GROUP.mythos.includes(chain)) {
|
|
93
93
|
handlers.push(new MythosNativeStakingPoolHandler(this.state, chain));
|
|
94
94
|
}
|
|
95
|
+
if (_STAKING_CHAIN_GROUP.energy.includes(chain)) {
|
|
96
|
+
handlers.push(new EnergyNativeStakingPoolHandler(this.state, chain));
|
|
97
|
+
}
|
|
95
98
|
if (_STAKING_CHAIN_GROUP.nominationPool.includes(chain)) {
|
|
96
99
|
const ahChain = ahMapChain[chain];
|
|
97
100
|
if (ahChain) {
|
|
@@ -107,6 +107,8 @@ export function isActionFromValidator(stakingType, chain) {
|
|
|
107
107
|
return true;
|
|
108
108
|
} else if (_STAKING_CHAIN_GROUP.mythos.includes(chain)) {
|
|
109
109
|
return true;
|
|
110
|
+
} else if (_STAKING_CHAIN_GROUP.energy.includes(chain)) {
|
|
111
|
+
return true;
|
|
110
112
|
}
|
|
111
113
|
return false;
|
|
112
114
|
}
|