@subwallet/extension-base 1.3.20-0 → 1.3.22-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.
Files changed (123) hide show
  1. package/background/KoniTypes.d.ts +8 -1
  2. package/cjs/defaults.js +1 -1
  3. package/cjs/koni/background/handlers/Extension.js +519 -90
  4. package/cjs/packageInfo.js +1 -1
  5. package/cjs/services/chain-service/constants.js +8 -3
  6. package/cjs/services/chain-service/handler/EvmApi.js +1 -3
  7. package/cjs/services/chain-service/handler/SubstrateChainHandler.js +3 -2
  8. package/cjs/services/chain-service/index.js +9 -0
  9. package/cjs/services/chain-service/utils/patch.js +1 -1
  10. package/cjs/services/earning-service/constants/chains.js +2 -1
  11. package/cjs/services/earning-service/handlers/liquid-staking/stella-swap.js +19 -8
  12. package/cjs/services/earning-service/handlers/native-staking/mythos.js +337 -0
  13. package/cjs/services/earning-service/handlers/special.js +16 -10
  14. package/cjs/services/earning-service/service.js +4 -0
  15. package/cjs/services/earning-service/utils/index.js +2 -0
  16. package/cjs/services/history-service/helpers/recoverHistoryStatus.js +14 -5
  17. package/cjs/services/history-service/index.js +15 -3
  18. package/cjs/services/inapp-notification-service/index.js +78 -0
  19. package/cjs/services/inapp-notification-service/interfaces.js +2 -0
  20. package/cjs/services/keyring-service/context/state.js +2 -1
  21. package/cjs/services/migration-service/scripts/databases/ClearMetadataDatabase.js +3 -23
  22. package/cjs/services/migration-service/scripts/databases/ClearMetadataForChains.js +40 -0
  23. package/cjs/services/migration-service/scripts/databases/ClearMetadataForMythos.js +15 -0
  24. package/cjs/services/migration-service/scripts/index.js +6 -2
  25. package/cjs/services/request-service/handler/EvmRequestHandler.js +10 -0
  26. package/cjs/services/request-service/handler/SubstrateRequestHandler.js +4 -3
  27. package/cjs/services/request-service/index.js +2 -2
  28. package/cjs/services/setting-service/constants.js +5 -2
  29. package/cjs/services/storage-service/DatabaseService.js +101 -2
  30. package/cjs/services/storage-service/databases/index.js +3 -0
  31. package/cjs/services/storage-service/db-stores/Metadata.js +3 -0
  32. package/cjs/services/storage-service/db-stores/Migration.js +6 -1
  33. package/cjs/services/storage-service/db-stores/ProcessTransaction.js +47 -0
  34. package/cjs/services/storage-service/db-stores/Transaction.js +2 -0
  35. package/cjs/services/storage-service/db-stores/index.js +8 -1
  36. package/cjs/services/swap-service/handler/asset-hub/handler.js +30 -11
  37. package/cjs/services/swap-service/handler/hydradx-handler.js +18 -10
  38. package/cjs/services/swap-service/index.js +3 -0
  39. package/cjs/services/swap-service/utils.js +1 -0
  40. package/cjs/services/transaction-service/index.js +218 -9
  41. package/cjs/types/index.js +11 -0
  42. package/cjs/types/setting.js +1 -0
  43. package/cjs/types/swap/index.js +4 -1
  44. package/cjs/types/transaction/index.js +11 -0
  45. package/cjs/types/transaction/process.js +28 -0
  46. package/cjs/types/yield/actions/join/submit.js +16 -1
  47. package/defaults.d.ts +1 -1
  48. package/defaults.js +1 -1
  49. package/koni/background/handlers/Extension.d.ts +5 -0
  50. package/koni/background/handlers/Extension.js +437 -12
  51. package/package.json +52 -22
  52. package/packageInfo.js +1 -1
  53. package/services/chain-service/constants.js +8 -3
  54. package/services/chain-service/handler/EvmApi.js +1 -3
  55. package/services/chain-service/handler/SubstrateChainHandler.js +3 -2
  56. package/services/chain-service/index.d.ts +1 -0
  57. package/services/chain-service/index.js +9 -0
  58. package/services/chain-service/utils/patch.js +1 -1
  59. package/services/earning-service/constants/chains.d.ts +1 -0
  60. package/services/earning-service/constants/chains.js +2 -1
  61. package/services/earning-service/handlers/liquid-staking/stella-swap.js +19 -8
  62. package/services/earning-service/handlers/native-staking/mythos.d.ts +35 -0
  63. package/services/earning-service/handlers/native-staking/mythos.js +329 -0
  64. package/services/earning-service/handlers/special.js +18 -12
  65. package/services/earning-service/service.js +4 -0
  66. package/services/earning-service/utils/index.js +2 -0
  67. package/services/history-service/helpers/recoverHistoryStatus.js +14 -5
  68. package/services/history-service/index.d.ts +6 -5
  69. package/services/history-service/index.js +16 -5
  70. package/services/inapp-notification-service/index.d.ts +2 -0
  71. package/services/inapp-notification-service/index.js +79 -1
  72. package/services/inapp-notification-service/interfaces.d.ts +8 -1
  73. package/services/inapp-notification-service/interfaces.js +2 -0
  74. package/services/keyring-service/context/state.d.ts +1 -1
  75. package/services/keyring-service/context/state.js +3 -2
  76. package/services/migration-service/scripts/databases/ClearMetadataDatabase.d.ts +3 -3
  77. package/services/migration-service/scripts/databases/ClearMetadataDatabase.js +3 -23
  78. package/services/migration-service/scripts/databases/ClearMetadataForChains.d.ts +5 -0
  79. package/services/migration-service/scripts/databases/ClearMetadataForChains.js +32 -0
  80. package/services/migration-service/scripts/databases/ClearMetadataForMythos.d.ts +4 -0
  81. package/services/migration-service/scripts/databases/ClearMetadataForMythos.js +7 -0
  82. package/services/migration-service/scripts/index.d.ts +1 -0
  83. package/services/migration-service/scripts/index.js +4 -1
  84. package/services/request-service/handler/EvmRequestHandler.js +10 -0
  85. package/services/request-service/handler/SubstrateRequestHandler.d.ts +1 -1
  86. package/services/request-service/handler/SubstrateRequestHandler.js +4 -3
  87. package/services/request-service/index.d.ts +1 -1
  88. package/services/request-service/index.js +2 -2
  89. package/services/setting-service/constants.d.ts +1 -0
  90. package/services/setting-service/constants.js +3 -1
  91. package/services/storage-service/DatabaseService.d.ts +13 -3
  92. package/services/storage-service/DatabaseService.js +103 -4
  93. package/services/storage-service/databases/index.d.ts +2 -1
  94. package/services/storage-service/databases/index.js +3 -0
  95. package/services/storage-service/db-stores/Metadata.d.ts +1 -0
  96. package/services/storage-service/db-stores/Metadata.js +3 -0
  97. package/services/storage-service/db-stores/Migration.d.ts +1 -0
  98. package/services/storage-service/db-stores/Migration.js +6 -1
  99. package/services/storage-service/db-stores/ProcessTransaction.d.ts +14 -0
  100. package/services/storage-service/db-stores/ProcessTransaction.js +39 -0
  101. package/services/storage-service/db-stores/Transaction.js +2 -0
  102. package/services/storage-service/db-stores/index.d.ts +1 -0
  103. package/services/storage-service/db-stores/index.js +2 -1
  104. package/services/swap-service/handler/asset-hub/handler.js +30 -11
  105. package/services/swap-service/handler/hydradx-handler.js +18 -10
  106. package/services/swap-service/index.js +3 -0
  107. package/services/swap-service/utils.js +1 -0
  108. package/services/transaction-service/index.d.ts +19 -1
  109. package/services/transaction-service/index.js +220 -11
  110. package/services/transaction-service/types.d.ts +13 -4
  111. package/types/index.d.ts +1 -0
  112. package/types/index.js +1 -0
  113. package/types/setting.d.ts +3 -0
  114. package/types/setting.js +1 -0
  115. package/types/swap/index.d.ts +3 -2
  116. package/types/swap/index.js +4 -1
  117. package/types/transaction/index.d.ts +1 -0
  118. package/types/transaction/index.js +1 -0
  119. package/types/transaction/process.d.ts +84 -0
  120. package/types/transaction/process.js +20 -0
  121. package/types/transaction/request.d.ts +3 -1
  122. package/types/yield/actions/join/submit.d.ts +18 -3
  123. package/types/yield/actions/join/submit.js +11 -1
@@ -0,0 +1,329 @@
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 { APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
+ import { getCommission } 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 BaseParaStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/native-staking/base-para';
9
+ import { BasicTxErrorType, EarningStatus, UnstakingStatus } from '@subwallet/extension-base/types';
10
+ import { balanceFormatter, formatNumber, reformatAddress } from '@subwallet/extension-base/utils';
11
+ export default class MythosNativeStakingPoolHandler extends BaseParaStakingPoolHandler {
12
+ availableMethod = {
13
+ join: true,
14
+ defaultUnstake: true,
15
+ fastUnstake: false,
16
+ cancelUnstake: false,
17
+ withdraw: true,
18
+ claimReward: true
19
+ };
20
+
21
+ /* Subscribe pool info */
22
+
23
+ async subscribePoolInfo(callback) {
24
+ let cancel = false;
25
+ const substrateApi = 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 substrateApi.isReady;
47
+ const unsub = await substrateApi.api.query.collatorStaking.currentSession(async _session => {
48
+ if (cancel) {
49
+ unsub();
50
+ return;
51
+ }
52
+ const currentSession = _session.toString();
53
+ const maxStakers = substrateApi.api.consts.collatorStaking.maxStakers.toString();
54
+ const unstakeDelay = substrateApi.api.consts.collatorStaking.stakeUnlockDelay.toString();
55
+ const maxStakedCandidates = substrateApi.api.consts.collatorStaking.maxStakedCandidates.toString();
56
+ const sessionTime = _STAKING_ERA_LENGTH_MAP[this.chain] || _STAKING_ERA_LENGTH_MAP.default; // in hours
57
+ const blockTime = _EXPECTED_BLOCK_TIME[this.chain];
58
+ const unstakingPeriod = parseInt(unstakeDelay) * blockTime / 60 / 60;
59
+ const _minStake = await substrateApi.api.query.collatorStaking.minStake();
60
+ const minStake = _minStake.toString();
61
+ const minStakeToHuman = formatNumber(minStake, nativeToken.decimals || 0, balanceFormatter);
62
+ const data = {
63
+ ...this.baseInfo,
64
+ type: this.type,
65
+ metadata: {
66
+ ...this.metadataInfo,
67
+ description: this.getDescription(minStakeToHuman)
68
+ },
69
+ statistic: {
70
+ assetEarning: [{
71
+ slug: this.nativeToken.slug
72
+ }],
73
+ maxCandidatePerFarmer: parseInt(maxStakedCandidates),
74
+ maxWithdrawalRequestPerFarmer: 3,
75
+ earningThreshold: {
76
+ join: minStake,
77
+ defaultUnstake: '0',
78
+ fastUnstake: '0'
79
+ },
80
+ era: parseInt(currentSession),
81
+ eraTime: sessionTime,
82
+ unstakingPeriod: unstakingPeriod,
83
+ totalApy: undefined
84
+ // tvl: totalStake.toString(),
85
+ // inflation
86
+ },
87
+
88
+ maxPoolMembers: parseInt(maxStakers)
89
+ };
90
+ callback(data);
91
+ });
92
+ return () => {
93
+ cancel = true;
94
+ unsub();
95
+ };
96
+ }
97
+
98
+ /* Subscribe pool info */
99
+
100
+ /* Subscribe pool position */
101
+
102
+ async subscribePoolPosition(useAddresses, resultCallback) {
103
+ let cancel = false;
104
+ const substrateApi = await this.substrateApi.isReady;
105
+ const defaultInfo = this.baseInfo;
106
+ const unsub = await substrateApi.api.query.collatorStaking.userStake.multi(useAddresses, async userStakes => {
107
+ if (cancel) {
108
+ unsub();
109
+ return;
110
+ }
111
+ if (userStakes) {
112
+ await Promise.all(userStakes.map(async (_userStake, i) => {
113
+ const userStake = _userStake.toPrimitive();
114
+ const owner = reformatAddress(useAddresses[i], 42);
115
+ if (userStake) {
116
+ const nominatorMetadata = await this.parseCollatorMetadata(this.chainInfo, useAddresses[i], substrateApi, userStake);
117
+ resultCallback({
118
+ ...defaultInfo,
119
+ ...nominatorMetadata,
120
+ address: owner,
121
+ type: this.type
122
+ });
123
+ } else {
124
+ resultCallback({
125
+ ...defaultInfo,
126
+ type: this.type,
127
+ address: owner,
128
+ balanceToken: this.nativeToken.slug,
129
+ totalStake: '0',
130
+ activeStake: '0',
131
+ unstakeBalance: '0',
132
+ status: EarningStatus.NOT_STAKING,
133
+ isBondedBefore: false,
134
+ nominations: [],
135
+ unstakings: []
136
+ });
137
+ }
138
+ }));
139
+ }
140
+ });
141
+ return () => {
142
+ cancel = true;
143
+ unsub();
144
+ };
145
+ }
146
+ async parseCollatorMetadata(chainInfo, stakerAddress, substrateApi, userStake) {
147
+ const nominationList = [];
148
+ const unstakingList = [];
149
+ let unstakingBalance = BigInt(0);
150
+ const {
151
+ candidates,
152
+ stake
153
+ } = userStake;
154
+ const [_minStake, _unstaking, _currentBlock, _currentTimestamp] = await Promise.all([substrateApi.api.query.collatorStaking.minStake(), substrateApi.api.query.collatorStaking.releaseQueues(stakerAddress), substrateApi.api.query.system.number(), substrateApi.api.query.timestamp.now()]);
155
+ const minStake = _minStake.toPrimitive();
156
+ const stakingStatus = candidates && !!candidates.length ? EarningStatus.EARNING_REWARD : EarningStatus.NOT_EARNING;
157
+ const isBondedBefore = candidates && !!candidates.length;
158
+ const unstakings = _unstaking.toPrimitive();
159
+ const currentBlock = _currentBlock.toPrimitive();
160
+ const currentTimestamp = _currentTimestamp.toPrimitive();
161
+ const blockDuration = _EXPECTED_BLOCK_TIME[chainInfo.slug];
162
+ if (candidates.length) {
163
+ await Promise.all(candidates.map(async collatorAddress => {
164
+ const _stakeInfo = await substrateApi.api.query.collatorStaking.candidateStake(collatorAddress, stakerAddress);
165
+ const stakeInfo = _stakeInfo.toPrimitive();
166
+ const activeStake = stakeInfo.stake.toString();
167
+ const earningStatus = BigInt(activeStake) > BigInt(0) && BigInt(activeStake) >= BigInt(minStake) ? EarningStatus.EARNING_REWARD : EarningStatus.NOT_EARNING;
168
+ nominationList.push({
169
+ status: earningStatus,
170
+ chain: chainInfo.slug,
171
+ validatorAddress: collatorAddress,
172
+ activeStake,
173
+ validatorMinStake: minStake,
174
+ hasUnstaking: !!unstakings.length
175
+ });
176
+ }));
177
+ }
178
+ if (unstakings.length) {
179
+ unstakings.forEach(unstaking => {
180
+ const releaseBlock = unstaking.block;
181
+ const unstakeAmount = unstaking.amount;
182
+ const isClaimable = currentBlock >= releaseBlock;
183
+ const targetTimestampMs = (releaseBlock - currentBlock) * blockDuration * 1000 + currentTimestamp;
184
+ unstakingBalance = unstakingBalance + BigInt(unstakeAmount);
185
+ unstakingList.push({
186
+ chain: chainInfo.slug,
187
+ status: isClaimable ? UnstakingStatus.CLAIMABLE : UnstakingStatus.UNLOCKING,
188
+ claimable: unstakeAmount,
189
+ targetTimestampMs
190
+ });
191
+ });
192
+ }
193
+ return {
194
+ status: stakingStatus,
195
+ balanceToken: this.nativeToken.slug,
196
+ totalStake: (BigInt(stake) + unstakingBalance).toString(),
197
+ activeStake: stake,
198
+ unstakeBalance: unstakingBalance.toString() || '0',
199
+ isBondedBefore: isBondedBefore,
200
+ nominations: nominationList,
201
+ unstakings: unstakingList
202
+ };
203
+ }
204
+
205
+ /* Subscribe pool position */
206
+
207
+ /* Get pool targets */
208
+
209
+ async getPoolTargets() {
210
+ const substrateApi = await this.substrateApi.isReady;
211
+ const [_allCollators, _minStake, _commission] = await Promise.all([substrateApi.api.query.collatorStaking.candidates.entries(), substrateApi.api.query.collatorStaking.minStake(), substrateApi.api.query.collatorStaking.collatorRewardPercentage()]);
212
+ const maxStakersPerCollator = substrateApi.api.consts.collatorStaking.maxStakers.toPrimitive();
213
+ return _allCollators.map(_collator => {
214
+ const _collatorAddress = _collator[0].toHuman();
215
+ const collatorAddress = _collatorAddress[0];
216
+ const collatorInfo = _collator[1].toPrimitive();
217
+ const bnTotalStake = BigInt(collatorInfo.stake);
218
+ const numOfStakers = parseInt(collatorInfo.stakers);
219
+ const isCrowded = numOfStakers >= maxStakersPerCollator;
220
+ return {
221
+ address: collatorAddress,
222
+ chain: this.chain,
223
+ totalStake: bnTotalStake.toString(),
224
+ ownStake: '0',
225
+ otherStake: bnTotalStake.toString(),
226
+ minBond: _minStake.toPrimitive(),
227
+ nominatorCount: numOfStakers,
228
+ commission: getCommission(_commission.toString()),
229
+ blocked: false,
230
+ isVerified: false,
231
+ isCrowded
232
+ };
233
+ });
234
+ }
235
+
236
+ /* Get pool targets */
237
+
238
+ /* Join pool action */
239
+
240
+ async createJoinExtrinsic(data, positionInfo) {
241
+ var _substrateApi$api$cal, _substrateApi$api$cal2;
242
+ const substrateApi = await this.substrateApi.isReady;
243
+ const {
244
+ address,
245
+ amount,
246
+ selectedValidators
247
+ } = data;
248
+ const selectedValidatorInfo = selectedValidators[0];
249
+ const _hasReward = await ((_substrateApi$api$cal = substrateApi.api.call) === null || _substrateApi$api$cal === void 0 ? void 0 : (_substrateApi$api$cal2 = _substrateApi$api$cal.collatorStakingApi) === null || _substrateApi$api$cal2 === void 0 ? void 0 : _substrateApi$api$cal2.shouldClaim(address));
250
+ const hasReward = _hasReward === null || _hasReward === void 0 ? void 0 : _hasReward.toPrimitive();
251
+ const extrinsicList = [];
252
+ if (positionInfo !== null && positionInfo !== void 0 && positionInfo.isBondedBefore && hasReward) {
253
+ extrinsicList.push(substrateApi.api.tx.collatorStaking.claimRewards());
254
+ }
255
+ extrinsicList.push(...[substrateApi.api.tx.collatorStaking.lock(amount), substrateApi.api.tx.collatorStaking.stake([{
256
+ candidate: selectedValidatorInfo.address,
257
+ stake: amount
258
+ }])]);
259
+ return [substrateApi.api.tx.utility.batchAll(extrinsicList), {
260
+ slug: this.nativeToken.slug,
261
+ amount: '0'
262
+ }];
263
+ }
264
+
265
+ /* Join pool action */
266
+
267
+ /* Leave pool action */
268
+
269
+ async handleYieldUnstake(amount, address, selectedTarget) {
270
+ var _substrateApi$api$cal3, _substrateApi$api$cal4;
271
+ const substrateApi = await this.substrateApi.isReady;
272
+ const _hasReward = await ((_substrateApi$api$cal3 = substrateApi.api.call) === null || _substrateApi$api$cal3 === void 0 ? void 0 : (_substrateApi$api$cal4 = _substrateApi$api$cal3.collatorStakingApi) === null || _substrateApi$api$cal4 === void 0 ? void 0 : _substrateApi$api$cal4.shouldClaim(address));
273
+ const hasReward = _hasReward === null || _hasReward === void 0 ? void 0 : _hasReward.toPrimitive();
274
+ const extrinsicList = [];
275
+ if (hasReward) {
276
+ extrinsicList.push(substrateApi.api.tx.collatorStaking.claimRewards());
277
+ }
278
+ extrinsicList.push(...[substrateApi.api.tx.collatorStaking.unstakeFrom(selectedTarget), substrateApi.api.tx.collatorStaking.unlock(null) // ignore amount to unlock all
279
+ ]);
280
+
281
+ return [ExtrinsicType.STAKING_UNBOND, substrateApi.api.tx.utility.batchAll(extrinsicList)];
282
+ }
283
+
284
+ /* Leave pool action */
285
+
286
+ /* Get pool reward */
287
+ async getPoolReward(useAddresses, callback) {
288
+ let cancel = false;
289
+ const substrateApi = this.substrateApi;
290
+ await substrateApi.isReady;
291
+ if (substrateApi.api.call.collatorStakingApi) {
292
+ await Promise.all(useAddresses.map(async address => {
293
+ if (!cancel) {
294
+ const _unclaimedReward = await substrateApi.api.call.collatorStakingApi.totalRewards(address);
295
+ const earningRewardItem = {
296
+ ...this.baseInfo,
297
+ address: address,
298
+ type: this.type,
299
+ unclaimedReward: (_unclaimedReward === null || _unclaimedReward === void 0 ? void 0 : _unclaimedReward.toString()) || '0',
300
+ state: APIItemState.READY
301
+ };
302
+ if (_unclaimedReward.toString() !== '0') {
303
+ await this.createClaimNotification(earningRewardItem, this.nativeToken);
304
+ }
305
+ callback(earningRewardItem);
306
+ }
307
+ }));
308
+ }
309
+ return () => {
310
+ cancel = false;
311
+ };
312
+ }
313
+ /* Get pool reward */
314
+
315
+ /* Other action */
316
+
317
+ async handleYieldCancelUnstake() {
318
+ return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED));
319
+ }
320
+ async handleYieldWithdraw(address, unstakingInfo) {
321
+ const substrateApi = await this.substrateApi.isReady;
322
+ return substrateApi.api.tx.collatorStaking.release();
323
+ }
324
+ async handleYieldClaimReward(address, bondReward) {
325
+ const substrateApi = await this.substrateApi.isReady;
326
+ return substrateApi.api.tx.collatorStaking.claimRewards();
327
+ }
328
+ /* Other action */
329
+ }
@@ -3,10 +3,10 @@
3
3
 
4
4
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
5
5
  import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
- import { ALL_ACCOUNT_KEY, XCM_FEE_RATIO } from '@subwallet/extension-base/constants';
6
+ import { ALL_ACCOUNT_KEY, XCM_FEE_RATIO, XCM_MIN_AMOUNT_RATIO } from '@subwallet/extension-base/constants';
7
7
  import { YIELD_POOL_STAT_REFRESH_INTERVAL } from '@subwallet/extension-base/koni/api/yield/helper/utils';
8
8
  import { createXcmExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
9
- import { _getAssetDecimals, _getAssetExistentialDeposit, _getAssetName, _getAssetSymbol, _getChainNativeTokenSlug } from '@subwallet/extension-base/services/chain-service/utils';
9
+ import { _getAssetDecimals, _getAssetExistentialDeposit, _getAssetName, _getAssetSymbol, _getChainNativeTokenSlug, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
10
10
  import { BasicTxErrorType, YieldStepType, YieldValidationStatus } from '@subwallet/extension-base/types';
11
11
  import { createPromiseHandler, formatNumber } from '@subwallet/extension-base/utils';
12
12
  import { getId } from '@subwallet/extension-base/utils/getId';
@@ -216,15 +216,6 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
216
216
  const altChainInfo = this.state.getChainInfo(altInputTokenInfo.originChain);
217
217
  const symbol = altInputTokenInfo.symbol;
218
218
  const networkName = altChainInfo.name;
219
- const step = {
220
- metadata: {
221
- sendingValue: bnAmount.toString(),
222
- originTokenInfo: altInputTokenInfo,
223
- destinationTokenInfo: inputTokenInfo
224
- },
225
- name: `Transfer ${symbol} from ${networkName}`,
226
- type: YieldStepType.XCM
227
- };
228
219
  const xcmOriginSubstrateApi = await this.state.getSubstrateApi(altInputTokenInfo.originChain).isReady;
229
220
  const id = getId();
230
221
  const feeInfo = await this.state.feeService.subscribeChainFee(id, altChainInfo.slug, 'substrate');
@@ -245,9 +236,24 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
245
236
 
246
237
  const fee = {
247
238
  slug: altInputTokenSlug,
248
- amount: Math.round(xcmFeeInfo.partialFee * 1.2).toString() // TODO
239
+ amount: Math.round(xcmFeeInfo.partialFee * XCM_MIN_AMOUNT_RATIO).toString() // TODO
249
240
  };
250
241
 
242
+ let bnTransferAmount = bnAmount.sub(bnInputTokenBalance);
243
+ if (_isNativeToken(altInputTokenInfo)) {
244
+ const bnXcmFee = new BN(fee.amount || 0); // xcm fee is paid in native token but swap token is not always native token
245
+
246
+ bnTransferAmount = bnTransferAmount.add(bnXcmFee);
247
+ }
248
+ const step = {
249
+ metadata: {
250
+ sendingValue: bnTransferAmount.toString(),
251
+ originTokenInfo: altInputTokenInfo,
252
+ destinationTokenInfo: inputTokenInfo
253
+ },
254
+ name: `Transfer ${symbol} from ${networkName}`,
255
+ type: YieldStepType.XCM
256
+ };
251
257
  return [step, fee];
252
258
  }
253
259
  }
@@ -8,6 +8,7 @@ import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
8
8
  import { _isChainEnabled, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils';
9
9
  import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants';
10
10
  import BaseLiquidStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/liquid-staking/base';
11
+ import MythosNativeStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/native-staking/mythos';
11
12
  import { BasicTxErrorType, YieldPoolType } from '@subwallet/extension-base/types';
12
13
  import { addLazy, categoryAddresses, createPromiseHandler, removeLazy } from '@subwallet/extension-base/utils';
13
14
  import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache';
@@ -68,6 +69,9 @@ export default class EarningService {
68
69
  if (_STAKING_CHAIN_GROUP.bittensor.includes(chain)) {
69
70
  handlers.push(new TaoNativeStakingPoolHandler(this.state, chain));
70
71
  }
72
+ if (_STAKING_CHAIN_GROUP.mythos.includes(chain)) {
73
+ handlers.push(new MythosNativeStakingPoolHandler(this.state, chain));
74
+ }
71
75
  if (_STAKING_CHAIN_GROUP.nominationPool.includes(chain)) {
72
76
  handlers.push(new NominationPoolHandler(this.state, chain));
73
77
  }
@@ -105,6 +105,8 @@ export function isActionFromValidator(stakingType, chain) {
105
105
  return true;
106
106
  } else if (_STAKING_CHAIN_GROUP.bittensor.includes(chain)) {
107
107
  return true;
108
+ } else if (_STAKING_CHAIN_GROUP.mythos.includes(chain)) {
109
+ return true;
108
110
  }
109
111
  return false;
110
112
  }
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { isSameAddress } from '@subwallet/extension-base/utils';
5
+ import { isHex } from '@polkadot/util';
5
6
  export let HistoryRecoverStatus;
6
7
  (function (HistoryRecoverStatus) {
7
8
  HistoryRecoverStatus["SUCCESS"] = "SUCCESS";
@@ -31,7 +32,7 @@ const substrateRecover = async (history, chainService) => {
31
32
  const _api = await substrateApi.isReady;
32
33
  const api = _api.api;
33
34
  if (!blockHash) {
34
- if (!nonce || !startBlock) {
35
+ if (nonce === undefined || startBlock === undefined) {
35
36
  console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
36
37
  return {
37
38
  status: HistoryRecoverStatus.LACK_INFO
@@ -41,7 +42,7 @@ const substrateRecover = async (history, chainService) => {
41
42
  for (let i = 1, found = false; i < BLOCK_LIMIT && !found && startBlock + i <= currentBlock; i++) {
42
43
  const blockHash = (await api.rpc.chain.getBlockHash(startBlock + i)).toHex();
43
44
  const block = await api.rpc.chain.getBlock(blockHash);
44
- const extrinsics = block.block.extrinsics;
45
+ const extrinsics = block.block.extrinsics.toArray();
45
46
  let index;
46
47
  for (const [idx, extrinsic] of Object.entries(extrinsics)) {
47
48
  if (extrinsic.signer && isSameAddress(from, extrinsic.signer.toString()) && nonce === extrinsic.nonce.toNumber()) {
@@ -142,16 +143,24 @@ const evmRecover = async (history, chainService) => {
142
143
  try {
143
144
  const evmApi = chainService.getEvmApi(chain);
144
145
  if (evmApi) {
145
- const _api = await evmApi.isReady;
146
+ const _api = await Promise.race([evmApi.isReady, new Promise((resolve, reject) => {
147
+ const createTimeout = callback => {
148
+ setTimeout(callback, 10000);
149
+ };
150
+ createTimeout(() => {
151
+ const api = chainService.getEvmApi(chain);
152
+ Promise.race([api.isReady, new Promise((resolve, reject) => createTimeout(() => reject(new Error('Timeout'))))]).then(resolve).catch(reject);
153
+ });
154
+ })]);
146
155
  const api = _api.api;
147
- if (extrinsicHash) {
156
+ if (extrinsicHash && isHex(extrinsicHash)) {
148
157
  const transactionReceipt = await api.eth.getTransactionReceipt(extrinsicHash);
149
158
  return {
150
159
  ...result,
151
160
  status: transactionReceipt.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED
152
161
  };
153
162
  } else {
154
- if (!nonce || !startBlock) {
163
+ if (nonce === undefined || startBlock === undefined) {
155
164
  console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
156
165
  return {
157
166
  ...result,
@@ -1,4 +1,4 @@
1
- import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
1
+ import { ExtrinsicType, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
2
2
  import { PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
3
3
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
4
4
  import { EventService } from '@subwallet/extension-base/services/event-service';
@@ -18,18 +18,18 @@ export declare class HistoryService implements StoppableServiceInterface, Persis
18
18
  private fetchPromise;
19
19
  private recoverInterval;
20
20
  private fetchAndLoadHistories;
21
- getHistories(): Promise<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>;
22
- getHistorySubject(): Promise<BehaviorSubject<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>>;
21
+ getHistories(): Promise<TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[]>;
22
+ getHistorySubject(): Promise<BehaviorSubject<TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[]>>;
23
23
  /**
24
24
  * @todo: Must improve performance of this function
25
25
  * */
26
26
  private fetchSubscanTransactionHistory;
27
27
  subscribeHistories(chain: string, proxyId: string, cb: (items: TransactionHistoryItem[]) => void): {
28
28
  unsubscribe: () => void;
29
- value: TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[];
29
+ value: TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[];
30
30
  };
31
31
  updateHistories(chain: string, extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
32
- updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
32
+ updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>, isRecover?: boolean): Promise<void>;
33
33
  insertHistories(historyItems: TransactionHistoryItem[]): Promise<void>;
34
34
  addHistoryItems(historyItems: TransactionHistoryItem[]): Promise<void>;
35
35
  removeHistoryByAddress(address: string): Promise<void>;
@@ -45,6 +45,7 @@ export declare class HistoryService implements StoppableServiceInterface, Persis
45
45
  promise: Promise<void>;
46
46
  };
47
47
  init(): Promise<void>;
48
+ restoreProcessTransaction(): Promise<void>;
48
49
  recoverProcessingHistory(): Promise<void>;
49
50
  start(): Promise<void>;
50
51
  waitForStarted(): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { ExtrinsicStatus } from '@subwallet/extension-base/background/KoniTypes';
4
+ import { ExtrinsicStatus, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
5
5
  import { CRON_RECOVER_HISTORY_INTERVAL } from '@subwallet/extension-base/constants';
6
6
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
7
7
  import { _isChainEvmCompatible, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils';
@@ -177,8 +177,8 @@ export class HistoryService {
177
177
  });
178
178
  await this.addHistoryItems(updatedRecords);
179
179
  }
180
- async updateHistoryByExtrinsicHash(extrinsicHash, updateData) {
181
- await this.dbService.updateHistoryByExtrinsicHash(extrinsicHash, updateData);
180
+ async updateHistoryByExtrinsicHash(extrinsicHash, updateData, isRecover = false) {
181
+ await this.dbService.updateHistoryByExtrinsicHash(extrinsicHash, updateData, isRecover);
182
182
  this.historySubject.next(await this.dbService.getHistories());
183
183
  }
184
184
 
@@ -253,11 +253,11 @@ export class HistoryService {
253
253
  case HistoryRecoverStatus.FAILED:
254
254
  case HistoryRecoverStatus.SUCCESS:
255
255
  updateData.status = recoverResult.status === HistoryRecoverStatus.SUCCESS ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL;
256
- this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
256
+ this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch(console.error);
257
257
  delete this.#needRecoveryHistories[currentExtrinsicHash];
258
258
  break;
259
259
  default:
260
- this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
260
+ this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch(console.error);
261
261
  delete this.#needRecoveryHistories[currentExtrinsicHash];
262
262
  }
263
263
  });
@@ -269,6 +269,7 @@ export class HistoryService {
269
269
  async init() {
270
270
  this.status = ServiceStatus.INITIALIZING;
271
271
  await this.eventService.waitCryptoReady;
272
+ this.restoreProcessTransaction().catch(console.error);
272
273
  await this.loadData();
273
274
  Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
274
275
  this.getHistories().catch(console.log);
@@ -279,11 +280,21 @@ export class HistoryService {
279
280
  }).catch(console.error);
280
281
  this.status = ServiceStatus.INITIALIZED;
281
282
  }
283
+ async restoreProcessTransaction() {
284
+ await this.dbService.restoreProcessTransaction();
285
+ }
282
286
  async recoverProcessingHistory() {
283
287
  const histories = await this.dbService.getHistories();
284
288
  this.#needRecoveryHistories = {};
285
289
  histories.filter(history => {
286
290
  return [ExtrinsicStatus.PROCESSING, ExtrinsicStatus.SUBMITTING].includes(history.status);
291
+ }).filter(history => {
292
+ if (history.type === ExtrinsicType.TRANSFER_XCM) {
293
+ const data = history.additionalInfo;
294
+ return data.originalChain === history.chain;
295
+ } else {
296
+ return true;
297
+ }
287
298
  }).forEach(history => {
288
299
  this.#needRecoveryHistories[history.extrinsicHash] = history;
289
300
  });
@@ -6,6 +6,7 @@ import { _BaseNotificationInfo, _NotificationInfo, NotificationActionType } from
6
6
  import { AvailBridgeTransaction, PolygonTransaction } from '@subwallet/extension-base/services/inapp-notification-service/utils';
7
7
  import { KeyringService } from '@subwallet/extension-base/services/keyring-service';
8
8
  import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
9
+ import { ProcessTransactionData } from '@subwallet/extension-base/types';
9
10
  import { GetNotificationParams, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
10
11
  export declare class InappNotificationService implements CronServiceInterface {
11
12
  private readonly dbService;
@@ -36,6 +37,7 @@ export declare class InappNotificationService implements CronServiceInterface {
36
37
  processWriteAvailBridgeClaim(address: string, transactions: AvailBridgeTransaction[], token: _ChainAsset): Promise<void>;
37
38
  createPolygonClaimableTransactions(): Promise<void>;
38
39
  processPolygonClaimNotification(address: string, transactions: PolygonTransaction[], token: _ChainAsset): Promise<void>;
40
+ createProcessNotification(process: ProcessTransactionData): Promise<void>;
39
41
  start(): Promise<void>;
40
42
  startCron(): Promise<void>;
41
43
  stop(): Promise<void>;