@subwallet/extension-base 1.3.45-1 → 1.3.47-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/background/KoniTypes.d.ts +5 -0
- package/background/KoniTypes.js +5 -0
- package/background/types.d.ts +2 -0
- package/cjs/background/KoniTypes.js +7 -1
- package/cjs/core/logic-validation/request.js +55 -28
- package/cjs/core/utils.js +22 -0
- package/cjs/koni/api/nft/ordinal_nft/index.js +3 -2
- package/cjs/koni/background/handlers/Extension.js +84 -61
- package/cjs/koni/background/handlers/State.js +3 -0
- package/cjs/koni/background/handlers/Tabs.js +11 -3
- package/cjs/packageInfo.js +1 -1
- package/cjs/page/evm/index.js +64 -105
- package/cjs/page/index.js +5 -3
- package/cjs/page/substrate/Accounts.js +2 -1
- package/cjs/services/balance-service/helpers/subscribe/index.js +3 -76
- package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +8 -14
- package/cjs/services/buy-service/index.js +2 -0
- package/cjs/services/chain-service/index.js +3 -0
- package/cjs/services/chain-service/utils/index.js +34 -1
- package/cjs/services/chain-service/utils/patch.js +1 -1
- package/cjs/services/earning-service/constants/chains.js +2 -1
- package/cjs/services/earning-service/handlers/native-staking/amplitude.js +32 -0
- package/cjs/services/earning-service/handlers/native-staking/astar.js +18 -0
- package/cjs/services/earning-service/handlers/native-staking/base.js +40 -29
- package/cjs/services/earning-service/handlers/native-staking/dtao.js +5 -0
- package/cjs/services/earning-service/handlers/native-staking/mythos.js +28 -0
- package/cjs/services/earning-service/handlers/native-staking/para-chain.js +17 -0
- package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +25 -2
- package/cjs/services/earning-service/handlers/native-staking/tao.js +5 -0
- package/cjs/services/earning-service/handlers/nomination-pool/index.js +6 -3
- package/cjs/services/earning-service/service.js +65 -22
- package/cjs/services/history-service/index.js +12 -7
- package/cjs/services/keyring-service/context/handlers/Json.js +2 -1
- package/cjs/services/keyring-service/context/handlers/Ledger.js +7 -2
- package/cjs/services/request-service/handler/AuthRequestHandler.js +30 -6
- package/cjs/services/subscan-service/index.js +35 -104
- package/cjs/services/transaction-service/utils.js +10 -1
- package/cjs/strategy/api-request-strategy/index.js +1 -0
- package/cjs/strategy/api-request-strategy/utils/index.js +2 -2
- package/cjs/strategy/api-request-strategy-v2/index.js +138 -0
- package/cjs/strategy/api-request-strategy-v2/types.js +1 -0
- package/cjs/types/account/info/keyring.js +1 -0
- package/cjs/utils/account/analyze.js +5 -2
- package/cjs/utils/account/common.js +93 -2
- package/cjs/utils/account/transform.js +10 -0
- package/cjs/utils/asset.js +9 -2
- package/cjs/utils/gear/combine.js +4 -3
- package/cjs/utils/gear/vft.js +104 -135
- package/cjs/utils/staticData/index.js +7 -2
- package/core/logic-validation/request.js +31 -4
- package/core/types.d.ts +3 -2
- package/core/utils.js +24 -2
- package/koni/api/nft/ordinal_nft/index.js +3 -2
- package/koni/background/handlers/Extension.js +31 -8
- package/koni/background/handlers/State.js +4 -1
- package/koni/background/handlers/Tabs.js +11 -4
- package/package.json +21 -9
- package/packageInfo.js +1 -1
- package/page/evm/index.d.ts +9 -18
- package/page/evm/index.js +62 -101
- package/page/index.js +5 -3
- package/page/substrate/Accounts.js +2 -1
- package/services/balance-service/helpers/subscribe/index.d.ts +1 -11
- package/services/balance-service/helpers/subscribe/index.js +3 -74
- package/services/balance-service/helpers/subscribe/substrate/index.js +8 -14
- package/services/buy-service/index.js +2 -0
- package/services/chain-service/index.d.ts +1 -0
- package/services/chain-service/index.js +3 -0
- package/services/chain-service/utils/index.d.ts +10 -2
- package/services/chain-service/utils/index.js +29 -2
- package/services/chain-service/utils/patch.js +1 -1
- package/services/earning-service/constants/chains.d.ts +1 -0
- package/services/earning-service/constants/chains.js +2 -1
- package/services/earning-service/handlers/native-staking/amplitude.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/amplitude.js +32 -0
- package/services/earning-service/handlers/native-staking/astar.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/astar.js +18 -0
- package/services/earning-service/handlers/native-staking/base.d.ts +2 -0
- package/services/earning-service/handlers/native-staking/base.js +40 -29
- package/services/earning-service/handlers/native-staking/dtao.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/dtao.js +5 -0
- package/services/earning-service/handlers/native-staking/mythos.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/mythos.js +28 -0
- package/services/earning-service/handlers/native-staking/para-chain.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/para-chain.js +17 -0
- package/services/earning-service/handlers/native-staking/relay-chain.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/relay-chain.js +25 -2
- package/services/earning-service/handlers/native-staking/tao.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/tao.js +5 -0
- package/services/earning-service/handlers/nomination-pool/index.d.ts +1 -0
- package/services/earning-service/handlers/nomination-pool/index.js +6 -3
- package/services/earning-service/service.d.ts +3 -0
- package/services/earning-service/service.js +68 -25
- package/services/history-service/index.js +12 -7
- package/services/keyring-service/context/handlers/Json.js +2 -1
- package/services/keyring-service/context/handlers/Ledger.js +7 -2
- package/services/request-service/handler/AuthRequestHandler.d.ts +1 -0
- package/services/request-service/handler/AuthRequestHandler.js +30 -6
- package/services/request-service/types.d.ts +1 -0
- package/services/subscan-service/index.d.ts +13 -27
- package/services/subscan-service/index.js +26 -95
- package/services/transaction-service/utils.js +11 -2
- package/strategy/api-request-strategy/context/base.d.ts +2 -6
- package/strategy/api-request-strategy/index.js +1 -0
- package/strategy/api-request-strategy/types.d.ts +4 -2
- package/strategy/api-request-strategy/utils/index.js +2 -2
- package/strategy/api-request-strategy-v2/index.d.ts +22 -0
- package/strategy/api-request-strategy-v2/index.js +128 -0
- package/strategy/api-request-strategy-v2/types.d.ts +11 -0
- package/strategy/api-request-strategy-v2/types.js +1 -0
- package/types/account/action/subscribe.d.ts +3 -0
- package/types/account/info/keyring.d.ts +3 -0
- package/types/account/info/keyring.js +1 -0
- package/types/balance/transfer.d.ts +1 -0
- package/types/buy.d.ts +1 -1
- package/utils/account/analyze.js +5 -2
- package/utils/account/common.d.ts +13 -1
- package/utils/account/common.js +91 -2
- package/utils/account/transform.js +10 -0
- package/utils/asset.d.ts +2 -1
- package/utils/asset.js +7 -1
- package/utils/gear/combine.d.ts +2 -1
- package/utils/gear/combine.js +4 -4
- package/utils/gear/vft.d.ts +20 -9
- package/utils/gear/vft.js +104 -135
- package/utils/staticData/assetHubStaking.json +1 -0
- package/utils/staticData/index.d.ts +4 -1
- package/utils/staticData/index.js +5 -1
|
@@ -4,34 +4,15 @@
|
|
|
4
4
|
import { SWError } from '@subwallet/extension-base/background/errors/SWError';
|
|
5
5
|
import { BASE_FETCH_ORDINAL_EVENT_DATA } from '@subwallet/extension-base/koni/api/nft/ordinal_nft/constants';
|
|
6
6
|
import { SUBSCAN_API_CHAIN_MAP } from '@subwallet/extension-base/services/subscan-service/subscan-chain-map';
|
|
7
|
+
import { BaseApiRequestContext } from '@subwallet/extension-base/strategy/api-request-strategy/context/base';
|
|
8
|
+
import { BaseApiRequestStrategyV2 } from '@subwallet/extension-base/strategy/api-request-strategy-v2';
|
|
7
9
|
import { wait } from '@subwallet/extension-base/utils';
|
|
8
10
|
const QUERY_ROW = 100;
|
|
9
|
-
export class SubscanService {
|
|
10
|
-
callRate = 2; // limit per interval check
|
|
11
|
-
limitRate = 2; // max rate per interval check
|
|
12
|
-
intervalCheck = 1000; // interval check in ms
|
|
13
|
-
maxRetry = 9; // interval check in ms
|
|
14
|
-
rollbackRateTime = 30 * 1000; // rollback rate time in ms
|
|
15
|
-
timeoutRollbackRate = undefined;
|
|
16
|
-
requestMap = {};
|
|
17
|
-
nextId = 0;
|
|
18
|
-
isRunning = false;
|
|
19
|
-
getId() {
|
|
20
|
-
return this.nextId++;
|
|
21
|
-
}
|
|
11
|
+
export class SubscanService extends BaseApiRequestStrategyV2 {
|
|
22
12
|
constructor(subscanChainMap, options) {
|
|
13
|
+
const context = new BaseApiRequestContext(options);
|
|
14
|
+
super(context);
|
|
23
15
|
this.subscanChainMap = subscanChainMap;
|
|
24
|
-
this.callRate = (options === null || options === void 0 ? void 0 : options.limitRate) || this.callRate;
|
|
25
|
-
this.limitRate = (options === null || options === void 0 ? void 0 : options.limitRate) || this.limitRate;
|
|
26
|
-
this.intervalCheck = (options === null || options === void 0 ? void 0 : options.intervalCheck) || this.intervalCheck;
|
|
27
|
-
this.maxRetry = (options === null || options === void 0 ? void 0 : options.maxRetry) || this.maxRetry;
|
|
28
|
-
}
|
|
29
|
-
reduceLimitRate() {
|
|
30
|
-
clearTimeout(this.timeoutRollbackRate);
|
|
31
|
-
this.callRate = Math.ceil(this.limitRate / 2);
|
|
32
|
-
this.timeoutRollbackRate = setTimeout(() => {
|
|
33
|
-
this.callRate = this.limitRate;
|
|
34
|
-
}, this.rollbackRateTime);
|
|
35
16
|
}
|
|
36
17
|
getApiUrl(chain, path) {
|
|
37
18
|
const subscanChain = this.subscanChainMap[chain];
|
|
@@ -49,61 +30,9 @@ export class SubscanService {
|
|
|
49
30
|
body: JSON.stringify(body)
|
|
50
31
|
});
|
|
51
32
|
}
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
return
|
|
55
|
-
this.requestMap[newId] = {
|
|
56
|
-
id: newId,
|
|
57
|
-
status: 'pending',
|
|
58
|
-
retry: -1,
|
|
59
|
-
ordinal,
|
|
60
|
-
run,
|
|
61
|
-
resolve,
|
|
62
|
-
reject
|
|
63
|
-
};
|
|
64
|
-
if (!this.isRunning) {
|
|
65
|
-
this.process();
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
process() {
|
|
70
|
-
this.isRunning = true;
|
|
71
|
-
const maxRetry = this.maxRetry;
|
|
72
|
-
const interval = setInterval(() => {
|
|
73
|
-
const remainingRequests = Object.values(this.requestMap);
|
|
74
|
-
if (remainingRequests.length === 0) {
|
|
75
|
-
this.isRunning = false;
|
|
76
|
-
clearInterval(interval);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Get first this.limit requests base on id
|
|
81
|
-
const requests = remainingRequests.filter(request => request.status !== 'running').sort((a, b) => a.id - b.id).sort((a, b) => a.ordinal - b.ordinal).slice(0, this.callRate);
|
|
82
|
-
|
|
83
|
-
// Start requests
|
|
84
|
-
requests.forEach(request => {
|
|
85
|
-
request.status = 'running';
|
|
86
|
-
request.run().then(rs => {
|
|
87
|
-
request.resolve(rs);
|
|
88
|
-
}).catch(e => {
|
|
89
|
-
const error = JSON.parse(e.message);
|
|
90
|
-
|
|
91
|
-
// Limit rate
|
|
92
|
-
if (error.code === 20008) {
|
|
93
|
-
if (request.retry < maxRetry) {
|
|
94
|
-
request.status = 'pending';
|
|
95
|
-
request.retry++;
|
|
96
|
-
this.reduceLimitRate();
|
|
97
|
-
} else {
|
|
98
|
-
// Reject request
|
|
99
|
-
request.reject(new SWError('MAX_RETRY', String(e)));
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
request.reject(new SWError('UNKNOWN', String(e)));
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
}, this.intervalCheck);
|
|
33
|
+
isRateLimited(e) {
|
|
34
|
+
const error = JSON.parse(e.message);
|
|
35
|
+
return error.code === 20008;
|
|
107
36
|
}
|
|
108
37
|
checkSupportedSubscanChain(chain) {
|
|
109
38
|
return !!this.subscanChainMap[chain];
|
|
@@ -114,6 +43,7 @@ export class SubscanService {
|
|
|
114
43
|
|
|
115
44
|
// Implement Subscan API
|
|
116
45
|
getMultiChainBalance(address) {
|
|
46
|
+
const hashKey = this.createKeyHash(['multi_chain_balance', address]);
|
|
117
47
|
return this.addRequest(async () => {
|
|
118
48
|
const rs = await this.postRequest(this.getApiUrl('polkadot', 'api/scan/multiChain/account'), {
|
|
119
49
|
address
|
|
@@ -123,7 +53,7 @@ export class SubscanService {
|
|
|
123
53
|
}
|
|
124
54
|
const jsonData = await rs.json();
|
|
125
55
|
return jsonData.data;
|
|
126
|
-
}, 1);
|
|
56
|
+
}, 1, undefined, hashKey);
|
|
127
57
|
}
|
|
128
58
|
getCrowdloanContributions(relayChain, address, page = 0) {
|
|
129
59
|
return this.addRequest(async () => {
|
|
@@ -140,7 +70,7 @@ export class SubscanService {
|
|
|
140
70
|
return jsonData.data;
|
|
141
71
|
}, 2);
|
|
142
72
|
}
|
|
143
|
-
getExtrinsicsList(chain, address, page = 0, blockRange) {
|
|
73
|
+
getExtrinsicsList(groupId, chain, address, page = 0, blockRange) {
|
|
144
74
|
const _blockRange = (() => {
|
|
145
75
|
if (!blockRange || !blockRange.to) {
|
|
146
76
|
return null;
|
|
@@ -159,9 +89,9 @@ export class SubscanService {
|
|
|
159
89
|
}
|
|
160
90
|
const jsonData = await rs.json();
|
|
161
91
|
return jsonData.data;
|
|
162
|
-
}, 0);
|
|
92
|
+
}, 0, groupId);
|
|
163
93
|
}
|
|
164
|
-
async fetchAllPossibleExtrinsicItems(chain, address, cbAfterEachRequest, limit = {
|
|
94
|
+
async fetchAllPossibleExtrinsicItems(groupId, chain, address, cbAfterEachRequest, limit = {
|
|
165
95
|
page: 10,
|
|
166
96
|
record: 1000
|
|
167
97
|
}) {
|
|
@@ -173,7 +103,7 @@ export class SubscanService {
|
|
|
173
103
|
};
|
|
174
104
|
const resultMap = {};
|
|
175
105
|
const _getExtrinsicItems = async page => {
|
|
176
|
-
const res = await this.getExtrinsicsList(chain, address, page, blockRange);
|
|
106
|
+
const res = await this.getExtrinsicsList(groupId, chain, address, page, blockRange);
|
|
177
107
|
if (!res || !res.count || !res.extrinsics || !res.extrinsics.length) {
|
|
178
108
|
return;
|
|
179
109
|
}
|
|
@@ -182,7 +112,7 @@ export class SubscanService {
|
|
|
182
112
|
}
|
|
183
113
|
const extrinsics = res.extrinsics;
|
|
184
114
|
const extrinsicIndexes = extrinsics.map(item => item.extrinsic_index);
|
|
185
|
-
const extrinsicParams = await this.getExtrinsicParams(chain, extrinsicIndexes, 0);
|
|
115
|
+
const extrinsicParams = await this.getExtrinsicParams(groupId, chain, extrinsicIndexes, 0);
|
|
186
116
|
for (const data of extrinsicParams) {
|
|
187
117
|
const {
|
|
188
118
|
extrinsic_index: extrinsicIndex,
|
|
@@ -214,7 +144,7 @@ export class SubscanService {
|
|
|
214
144
|
await _getExtrinsicItems(0);
|
|
215
145
|
return Object.values(resultMap);
|
|
216
146
|
}
|
|
217
|
-
getTransfersList(chain, address, page = 0, direction, blockRange) {
|
|
147
|
+
getTransfersList(groupId, chain, address, page = 0, direction, blockRange) {
|
|
218
148
|
return this.addRequest(async () => {
|
|
219
149
|
const rs = await this.postRequest(this.getApiUrl(chain, 'api/v2/scan/transfers'), {
|
|
220
150
|
page,
|
|
@@ -229,9 +159,9 @@ export class SubscanService {
|
|
|
229
159
|
}
|
|
230
160
|
const jsonData = await rs.json();
|
|
231
161
|
return jsonData.data;
|
|
232
|
-
}, 0);
|
|
162
|
+
}, 0, groupId);
|
|
233
163
|
}
|
|
234
|
-
async fetchAllPossibleTransferItems(chain, address, direction, cbAfterEachRequest, limit = {
|
|
164
|
+
async fetchAllPossibleTransferItems(groupId, chain, address, direction, cbAfterEachRequest, limit = {
|
|
235
165
|
page: 10,
|
|
236
166
|
record: 1000
|
|
237
167
|
}) {
|
|
@@ -243,7 +173,7 @@ export class SubscanService {
|
|
|
243
173
|
};
|
|
244
174
|
const resultMap = {};
|
|
245
175
|
const _getTransferItems = async page => {
|
|
246
|
-
const res = await this.getTransfersList(chain, address, page, direction, blockRange);
|
|
176
|
+
const res = await this.getTransfersList(groupId, chain, address, page, direction, blockRange);
|
|
247
177
|
if (!res || !res.count || !res.transfers || !res.transfers.length) {
|
|
248
178
|
return;
|
|
249
179
|
}
|
|
@@ -273,7 +203,8 @@ export class SubscanService {
|
|
|
273
203
|
await _getTransferItems(0);
|
|
274
204
|
return resultMap;
|
|
275
205
|
}
|
|
276
|
-
getRewardHistoryList(chain, address, page = 0) {
|
|
206
|
+
getRewardHistoryList(groupId, chain, address, page = 0) {
|
|
207
|
+
const hashKey = this.createKeyHash([chain, 'reward_slash', address, page]);
|
|
277
208
|
return this.addRequest(async () => {
|
|
278
209
|
const rs = await this.postRequest(this.getApiUrl(chain, 'api/scan/account/reward_slash'), {
|
|
279
210
|
page,
|
|
@@ -293,9 +224,9 @@ export class SubscanService {
|
|
|
293
224
|
};
|
|
294
225
|
}
|
|
295
226
|
return jsonData.data;
|
|
296
|
-
}, 2);
|
|
227
|
+
}, 2, groupId, hashKey);
|
|
297
228
|
}
|
|
298
|
-
getAccountRemarkEvents(chain, address) {
|
|
229
|
+
getAccountRemarkEvents(groupId, chain, address) {
|
|
299
230
|
return this.addRequest(async () => {
|
|
300
231
|
const rs = await this.postRequest(this.getApiUrl(chain, 'api/v2/scan/events'), {
|
|
301
232
|
...BASE_FETCH_ORDINAL_EVENT_DATA,
|
|
@@ -306,9 +237,9 @@ export class SubscanService {
|
|
|
306
237
|
}
|
|
307
238
|
const jsonData = await rs.json();
|
|
308
239
|
return jsonData.data.events;
|
|
309
|
-
}, 3);
|
|
240
|
+
}, 3, groupId);
|
|
310
241
|
}
|
|
311
|
-
getExtrinsicParams(chain, extrinsicIndexes, ordinal = 3) {
|
|
242
|
+
getExtrinsicParams(groupId, chain, extrinsicIndexes, ordinal = 3) {
|
|
312
243
|
return this.addRequest(async () => {
|
|
313
244
|
const rs = await this.postRequest(this.getApiUrl(chain, 'api/scan/extrinsic/params'), {
|
|
314
245
|
extrinsic_index: extrinsicIndexes
|
|
@@ -318,7 +249,7 @@ export class SubscanService {
|
|
|
318
249
|
}
|
|
319
250
|
const jsonData = await rs.json();
|
|
320
251
|
return jsonData.data;
|
|
321
|
-
}, ordinal);
|
|
252
|
+
}, ordinal, groupId);
|
|
322
253
|
}
|
|
323
254
|
|
|
324
255
|
// Singleton
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright 2019-2022 @subwallet/extension-base authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import { _getBlockExplorerFromChain, _isChainTestNet, _isPureBitcoinChain, _isPureCardanoChain, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
4
|
+
import { _getBlockExplorerFromChain, _isChainTestNet, _isPureBitcoinChain, _isPureCardanoChain, _isPureEvmChain, _isPureTonChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
5
5
|
import { CHAIN_FLIP_MAINNET_EXPLORER, CHAIN_FLIP_TESTNET_EXPLORER, SIMPLE_SWAP_EXPLORER } from '@subwallet/extension-base/services/swap-service/utils';
|
|
6
6
|
import { hexAddPrefix, isHex, u8aToHex } from '@polkadot/util';
|
|
7
7
|
import { decodeAddress } from '@polkadot/util-crypto';
|
|
@@ -37,13 +37,19 @@ function getBlockExplorerAccountRoute(explorerLink) {
|
|
|
37
37
|
if (explorerLink.includes('taostats.io')) {
|
|
38
38
|
return 'account';
|
|
39
39
|
}
|
|
40
|
+
if (explorerLink.includes('tonviewer.com')) {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
if (explorerLink.includes('devnet-explorer.mosaicchain.io')) {
|
|
44
|
+
return 'accounts';
|
|
45
|
+
}
|
|
40
46
|
return 'address';
|
|
41
47
|
}
|
|
42
48
|
function getBlockExplorerTxRoute(chainInfo) {
|
|
43
49
|
if (_isPureEvmChain(chainInfo) || _isPureBitcoinChain(chainInfo)) {
|
|
44
50
|
return 'tx';
|
|
45
51
|
}
|
|
46
|
-
if (_isPureCardanoChain(chainInfo)) {
|
|
52
|
+
if (_isPureCardanoChain(chainInfo) || _isPureTonChain(chainInfo)) {
|
|
47
53
|
return 'transaction';
|
|
48
54
|
}
|
|
49
55
|
if (['aventus', 'deeper_network'].includes(chainInfo.slug)) {
|
|
@@ -52,6 +58,9 @@ function getBlockExplorerTxRoute(chainInfo) {
|
|
|
52
58
|
if (['gen6_public'].includes(chainInfo.slug)) {
|
|
53
59
|
return '#/extrinsics';
|
|
54
60
|
}
|
|
61
|
+
if (['mosaicTest'].includes(chainInfo.slug)) {
|
|
62
|
+
return 'transactions';
|
|
63
|
+
}
|
|
55
64
|
const explorerLink = _getBlockExplorerFromChain(chainInfo);
|
|
56
65
|
if (explorerLink && explorerLink.includes('statescan.io')) {
|
|
57
66
|
return '#/extrinsics';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiRequestContext } from '@subwallet/extension-base/strategy/api-request-strategy/types';
|
|
1
|
+
import { ApiRequestContext, ApiRequestContextProps } from '@subwallet/extension-base/strategy/api-request-strategy/types';
|
|
2
2
|
export declare class BaseApiRequestContext implements ApiRequestContext {
|
|
3
3
|
callRate: number;
|
|
4
4
|
limitRate: number;
|
|
@@ -6,10 +6,6 @@ export declare class BaseApiRequestContext implements ApiRequestContext {
|
|
|
6
6
|
maxRetry: number;
|
|
7
7
|
private rollbackRateTime;
|
|
8
8
|
private timeoutRollbackRate;
|
|
9
|
-
constructor(options?:
|
|
10
|
-
limitRate?: number;
|
|
11
|
-
intervalCheck?: number;
|
|
12
|
-
maxRetry?: number;
|
|
13
|
-
});
|
|
9
|
+
constructor(options?: Partial<ApiRequestContextProps>);
|
|
14
10
|
reduceLimitRate(): void;
|
|
15
11
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
callRate: number;
|
|
1
|
+
export interface ApiRequestContextProps {
|
|
3
2
|
limitRate: number;
|
|
4
3
|
intervalCheck: number;
|
|
5
4
|
maxRetry: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ApiRequestContext extends ApiRequestContextProps {
|
|
7
|
+
callRate: number;
|
|
6
8
|
reduceLimitRate: () => void;
|
|
7
9
|
}
|
|
8
10
|
export interface ApiRequestStrategy {
|
|
@@ -12,8 +12,8 @@ export const postRequest = (url, body, headers, jsonBody = true) => {
|
|
|
12
12
|
});
|
|
13
13
|
};
|
|
14
14
|
export const getRequest = (url, params, headers) => {
|
|
15
|
-
const
|
|
16
|
-
const _url = `${url}?${
|
|
15
|
+
const q = new URLSearchParams(params);
|
|
16
|
+
const _url = `${url}?${q.toString()}`;
|
|
17
17
|
return fetch(_url, {
|
|
18
18
|
method: 'GET',
|
|
19
19
|
headers: headers || {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ApiRequestContext } from '../api-request-strategy/types';
|
|
2
|
+
import { ApiRequestStrategyV2, ApiRequestV2 } from './types';
|
|
3
|
+
export declare abstract class BaseApiRequestStrategyV2 implements ApiRequestStrategyV2 {
|
|
4
|
+
private nextId;
|
|
5
|
+
private groupId;
|
|
6
|
+
private isRunning;
|
|
7
|
+
private requestMap;
|
|
8
|
+
private context;
|
|
9
|
+
private processInterval;
|
|
10
|
+
private canceledGroupIds;
|
|
11
|
+
private cacheMap;
|
|
12
|
+
private getId;
|
|
13
|
+
protected constructor(context: ApiRequestContext);
|
|
14
|
+
getGroupId(): number;
|
|
15
|
+
createKeyHash(keys: Array<string | number>): string;
|
|
16
|
+
addRequest<T>(run: ApiRequestV2<T>['run'], ordinal: number, _groupId?: number, keyHash?: string): Promise<T>;
|
|
17
|
+
abstract isRateLimited(error: Error): boolean;
|
|
18
|
+
private process;
|
|
19
|
+
stop(): void;
|
|
20
|
+
cancelGroupRequest(groupId: number): void;
|
|
21
|
+
setContext(context: ApiRequestContext): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { SWError } from '@subwallet/extension-base/background/errors/SWError';
|
|
5
|
+
import { BASE_MINUTE_INTERVAL } from '@subwallet/extension-base/constants';
|
|
6
|
+
import { Md5 } from 'ts-md5';
|
|
7
|
+
export class BaseApiRequestStrategyV2 {
|
|
8
|
+
nextId = 0;
|
|
9
|
+
groupId = 0;
|
|
10
|
+
isRunning = false;
|
|
11
|
+
requestMap = {};
|
|
12
|
+
processInterval = undefined;
|
|
13
|
+
canceledGroupIds = new Set();
|
|
14
|
+
cacheMap = new Map();
|
|
15
|
+
getId() {
|
|
16
|
+
return this.nextId++;
|
|
17
|
+
}
|
|
18
|
+
constructor(context) {
|
|
19
|
+
this.context = context;
|
|
20
|
+
}
|
|
21
|
+
getGroupId() {
|
|
22
|
+
return this.groupId++;
|
|
23
|
+
}
|
|
24
|
+
createKeyHash(keys) {
|
|
25
|
+
return Md5.hashStr(JSON.stringify([this.constructor.name, ...keys]));
|
|
26
|
+
}
|
|
27
|
+
addRequest(run, ordinal, _groupId, keyHash) {
|
|
28
|
+
const newId = this.getId();
|
|
29
|
+
const groupId = _groupId !== null && _groupId !== void 0 ? _groupId : this.getGroupId();
|
|
30
|
+
if (this.canceledGroupIds.has(groupId)) {
|
|
31
|
+
return Promise.reject(new SWError('CANCELED', 'Request has been canceled'));
|
|
32
|
+
}
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
this.requestMap[newId] = {
|
|
35
|
+
cacheKey: keyHash,
|
|
36
|
+
groupId,
|
|
37
|
+
id: newId,
|
|
38
|
+
ordinal,
|
|
39
|
+
reject,
|
|
40
|
+
resolve,
|
|
41
|
+
retry: -1,
|
|
42
|
+
run,
|
|
43
|
+
status: 'pending'
|
|
44
|
+
};
|
|
45
|
+
if (!this.isRunning) {
|
|
46
|
+
this.process();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
process() {
|
|
51
|
+
this.stop();
|
|
52
|
+
this.isRunning = true;
|
|
53
|
+
const maxRetry = this.context.maxRetry;
|
|
54
|
+
const interval = setInterval(() => {
|
|
55
|
+
const remainingRequests = Object.values(this.requestMap);
|
|
56
|
+
if (remainingRequests.length === 0) {
|
|
57
|
+
this.isRunning = false;
|
|
58
|
+
clearInterval(interval);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.log('[ApiRequestStrategyV2] Processing requests...', remainingRequests.map(r => r.groupId));
|
|
62
|
+
|
|
63
|
+
// Get first this.limit requests base on id
|
|
64
|
+
const requests = remainingRequests.filter(request => request.status !== 'running').sort((a, b) => a.id - b.id).sort((a, b) => a.ordinal - b.ordinal).slice(0, this.context.callRate);
|
|
65
|
+
|
|
66
|
+
// Start requests
|
|
67
|
+
requests.forEach(request => {
|
|
68
|
+
request.status = 'running';
|
|
69
|
+
if (request.cacheKey) {
|
|
70
|
+
if (this.cacheMap.has(request.cacheKey)) {
|
|
71
|
+
const resp = this.cacheMap.get(request.cacheKey);
|
|
72
|
+
request.resolve(resp);
|
|
73
|
+
console.log('[ApiRequestStrategyV2] Cache hit for request', request.id, 'with cache key', request.cacheKey);
|
|
74
|
+
delete this.requestMap[request.id];
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
request.run().then(rs => {
|
|
79
|
+
request.resolve(rs);
|
|
80
|
+
if (request.cacheKey) {
|
|
81
|
+
this.cacheMap.set(request.cacheKey, rs);
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
if (request.cacheKey) {
|
|
84
|
+
this.cacheMap.delete(request.cacheKey);
|
|
85
|
+
}
|
|
86
|
+
}, BASE_MINUTE_INTERVAL);
|
|
87
|
+
}
|
|
88
|
+
delete this.requestMap[request.id];
|
|
89
|
+
}).catch(e => {
|
|
90
|
+
const isRateLimited = this.isRateLimited(e);
|
|
91
|
+
|
|
92
|
+
// Limit rate
|
|
93
|
+
if (isRateLimited) {
|
|
94
|
+
if (request.retry < maxRetry) {
|
|
95
|
+
request.status = 'pending';
|
|
96
|
+
request.retry++;
|
|
97
|
+
this.context.reduceLimitRate();
|
|
98
|
+
} else {
|
|
99
|
+
// Reject request
|
|
100
|
+
request.reject(new SWError('MAX_RETRY', String(e)));
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
request.reject(new SWError('UNKNOWN', String(e)));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}, this.context.intervalCheck);
|
|
108
|
+
this.processInterval = interval;
|
|
109
|
+
}
|
|
110
|
+
stop() {
|
|
111
|
+
clearInterval(this.processInterval);
|
|
112
|
+
this.processInterval = undefined;
|
|
113
|
+
}
|
|
114
|
+
cancelGroupRequest(groupId) {
|
|
115
|
+
Object.values(this.requestMap).forEach(request => {
|
|
116
|
+
if (request.groupId === groupId) {
|
|
117
|
+
request.reject(new SWError('CANCELED', 'Request has been canceled'));
|
|
118
|
+
}
|
|
119
|
+
this.canceledGroupIds.add(groupId);
|
|
120
|
+
});
|
|
121
|
+
this.requestMap = Object.fromEntries(Object.entries(this.requestMap).filter(([_, request]) => request.groupId !== groupId));
|
|
122
|
+
}
|
|
123
|
+
setContext(context) {
|
|
124
|
+
this.stop();
|
|
125
|
+
this.context = context;
|
|
126
|
+
this.process();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ApiRequest, ApiRequestContext } from '../api-request-strategy/types';
|
|
2
|
+
export interface ApiRequestStrategyV2 {
|
|
3
|
+
addRequest: <T>(run: ApiRequestV2<T>['run'], groupId: number, ordinal: number) => Promise<T>;
|
|
4
|
+
setContext: (context: ApiRequestContext) => void;
|
|
5
|
+
stop: (groupId?: number) => void;
|
|
6
|
+
cancelGroupRequest: (groupId: number) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface ApiRequestV2<T> extends ApiRequest<T> {
|
|
9
|
+
groupId: number;
|
|
10
|
+
cacheKey?: string;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -54,6 +54,8 @@ export interface AccountLedgerData {
|
|
|
54
54
|
availableGenesisHashes?: string[];
|
|
55
55
|
/** Is Ledger recovery chain */
|
|
56
56
|
isLedgerRecovery?: boolean;
|
|
57
|
+
/** Is Ledger substrate ECDSA scheme signature */
|
|
58
|
+
isSubstrateECDSA?: boolean;
|
|
57
59
|
}
|
|
58
60
|
/**
|
|
59
61
|
* @interface AccountInjectData
|
|
@@ -103,6 +105,7 @@ export declare enum AccountSignMode {
|
|
|
103
105
|
QR = "qr",
|
|
104
106
|
LEGACY_LEDGER = "legacy-ledger",
|
|
105
107
|
GENERIC_LEDGER = "generic-ledger",
|
|
108
|
+
ECDSA_SUBSTRATE_LEDGER = "ecdsa-substrate-ledger",
|
|
106
109
|
READ_ONLY = "readonly",
|
|
107
110
|
ALL_ACCOUNT = "all",
|
|
108
111
|
INJECTED = "injected",
|
|
@@ -54,6 +54,7 @@ export let AccountSignMode;
|
|
|
54
54
|
AccountSignMode["QR"] = "qr";
|
|
55
55
|
AccountSignMode["LEGACY_LEDGER"] = "legacy-ledger";
|
|
56
56
|
AccountSignMode["GENERIC_LEDGER"] = "generic-ledger";
|
|
57
|
+
AccountSignMode["ECDSA_SUBSTRATE_LEDGER"] = "ecdsa-substrate-ledger";
|
|
57
58
|
AccountSignMode["READ_ONLY"] = "readonly";
|
|
58
59
|
AccountSignMode["ALL_ACCOUNT"] = "all";
|
|
59
60
|
AccountSignMode["INJECTED"] = "injected";
|
|
@@ -31,6 +31,7 @@ export interface RequestSubmitTransfer extends BaseRequestSign, TransactionFee {
|
|
|
31
31
|
transferAll: boolean;
|
|
32
32
|
value: string;
|
|
33
33
|
transferBounceable?: boolean;
|
|
34
|
+
isSubstrateECDSATransaction?: boolean;
|
|
34
35
|
}
|
|
35
36
|
export interface RequestSubmitSignPsbtTransfer extends BaseRequestSign {
|
|
36
37
|
id: string;
|
package/types/buy.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface BuyService {
|
|
|
4
4
|
symbol: string;
|
|
5
5
|
}
|
|
6
6
|
export declare type SupportService = 'transak' | 'banxa' | 'coinbase' | 'moonpay' | 'onramper' | 'meld';
|
|
7
|
-
export declare type OnrampAccountSupportType = 'ETHEREUM' | 'SUBSTRATE' | 'TON' | 'CARDANO';
|
|
7
|
+
export declare type OnrampAccountSupportType = 'ETHEREUM' | 'SUBSTRATE' | 'TON' | 'CARDANO' | 'BITCOIN';
|
|
8
8
|
export interface BuyTokenInfo {
|
|
9
9
|
network: string;
|
|
10
10
|
symbol: string;
|
package/utils/account/analyze.js
CHANGED
|
@@ -58,7 +58,7 @@ export const _analyzeAddress = async (data, accountProxies, contacts, chainInfo,
|
|
|
58
58
|
for (const accountProxy of accountProxies) {
|
|
59
59
|
const _name = accountProxy.name.trim().toLowerCase();
|
|
60
60
|
const nameCondition = isNameValid(_data, _name);
|
|
61
|
-
const filterAccounts = accountProxy.accounts.filter(account => _isChainInfoCompatibleWithAccountInfo(chainInfo, account
|
|
61
|
+
const filterAccounts = accountProxy.accounts.filter(account => _isChainInfoCompatibleWithAccountInfo(chainInfo, account));
|
|
62
62
|
for (const account of filterAccounts) {
|
|
63
63
|
const addressCondition = isStrValidWithAddress(_data, account, chainInfo);
|
|
64
64
|
const condition = nameCondition !== 'invalid' ? nameCondition : addressCondition;
|
|
@@ -86,7 +86,10 @@ export const _analyzeAddress = async (data, accountProxies, contacts, chainInfo,
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
const filterContacts = contacts.filter(contact => _isChainInfoCompatibleWithAccountInfo(chainInfo,
|
|
89
|
+
const filterContacts = contacts.filter(contact => _isChainInfoCompatibleWithAccountInfo(chainInfo, {
|
|
90
|
+
chainType: contact.chainType,
|
|
91
|
+
type: getKeypairTypeByAddress(contact.address)
|
|
92
|
+
}));
|
|
90
93
|
|
|
91
94
|
// Filter address book addresses
|
|
92
95
|
for (const contact of filterContacts) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
2
|
import { ChainType } from '@subwallet/extension-base/background/KoniTypes';
|
|
3
|
-
import { AccountChainType } from '@subwallet/extension-base/types';
|
|
3
|
+
import { AccountChainType, AccountJson } from '@subwallet/extension-base/types';
|
|
4
4
|
import { KeypairType } from '@subwallet/keyring/types';
|
|
5
5
|
export declare function isAccountAll(address?: string): boolean;
|
|
6
6
|
export declare function reformatAddress(address: string, networkPrefix?: number, isEthereum?: boolean, ignoreError?: boolean): string;
|
|
@@ -17,4 +17,16 @@ export declare function getAddressesByChainTypeMap(addresses: string[], chainInf
|
|
|
17
17
|
export declare function quickFormatAddressToCompare(address?: string): string | undefined;
|
|
18
18
|
/** @deprecated */
|
|
19
19
|
export declare const modifyAccountName: (type: KeypairType, name: string, modify: boolean) => string;
|
|
20
|
+
/**
|
|
21
|
+
* @function getAccountJsonByAddress
|
|
22
|
+
* @desc Get account info by address
|
|
23
|
+
* <p>
|
|
24
|
+
* Note: Use on the background only
|
|
25
|
+
* </p>
|
|
26
|
+
* @param {string} address - Address
|
|
27
|
+
* @returns {AccountJson|null} - Account info or null if not found
|
|
28
|
+
*/
|
|
29
|
+
export declare const getAccountJsonByAddress: (address: string) => AccountJson | null;
|
|
30
|
+
/** Filter addresses to subscribe by chain info */
|
|
31
|
+
export declare const filterAddressByChainInfo: (addresses: string[], chainInfo: _ChainInfo) => [string[], string[]];
|
|
20
32
|
export {};
|