@subwallet/extension-base 1.1.21-3 → 1.1.23-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 +10 -1
- package/cjs/koni/api/dotsama/balance.js +51 -1
- package/cjs/koni/api/dotsama/crowdloan.js +29 -3
- package/cjs/koni/api/dotsama/transfer.js +10 -3
- package/cjs/koni/api/staking/bonding/astar.js +9 -5
- package/cjs/koni/api/staking/bonding/relayChain.js +2 -2
- package/cjs/koni/api/xcm/index.js +6 -1
- package/cjs/koni/api/xcm/polkadotXcm.js +1 -3
- package/cjs/koni/api/xcm/xTokens.js +1 -1
- package/cjs/koni/background/handlers/Extension.js +117 -99
- package/cjs/koni/background/handlers/State.js +12 -6
- package/cjs/koni/background/subscription.js +1 -1
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/constants.js +8 -4
- package/cjs/services/chain-service/handler/SubstrateApi.js +9 -0
- package/cjs/services/chain-service/handler/chain-spec/goldberg.js +123 -0
- package/cjs/services/chain-service/index.js +18 -0
- package/cjs/services/history-service/helpers/subscan-extrinsic-parser-helper.js +53 -0
- package/cjs/services/history-service/index.js +78 -21
- package/cjs/services/history-service/subscan-history.js +107 -0
- package/cjs/services/subscan-service/index.js +109 -4
- package/cjs/services/subscan-service/subscan-chain-map.js +82 -8
- package/cjs/utils/index.js +10 -1
- package/koni/api/dotsama/balance.js +51 -1
- package/koni/api/dotsama/crowdloan.d.ts +2 -2
- package/koni/api/dotsama/crowdloan.js +29 -2
- package/koni/api/dotsama/transfer.js +10 -3
- package/koni/api/staking/bonding/astar.js +9 -5
- package/koni/api/staking/bonding/relayChain.js +2 -2
- package/koni/api/xcm/index.js +6 -1
- package/koni/api/xcm/polkadotXcm.js +2 -4
- package/koni/api/xcm/xTokens.js +1 -1
- package/koni/background/handlers/Extension.d.ts +1 -0
- package/koni/background/handlers/Extension.js +20 -3
- package/koni/background/handlers/State.d.ts +1 -0
- package/koni/background/handlers/State.js +13 -7
- package/koni/background/subscription.js +1 -1
- package/package.json +21 -6
- package/packageInfo.js +1 -1
- package/services/chain-service/constants.d.ts +3 -0
- package/services/chain-service/constants.js +8 -5
- package/services/chain-service/handler/SubstrateApi.js +8 -0
- package/services/chain-service/handler/chain-spec/goldberg.d.ts +115 -0
- package/services/chain-service/handler/chain-spec/goldberg.js +116 -0
- package/services/chain-service/index.d.ts +1 -0
- package/services/chain-service/index.js +18 -0
- package/services/history-service/helpers/subscan-extrinsic-parser-helper.d.ts +6 -0
- package/services/history-service/helpers/subscan-extrinsic-parser-helper.js +44 -0
- package/services/history-service/index.d.ts +10 -6
- package/services/history-service/index.js +79 -22
- package/services/history-service/subscan-history.d.ts +5 -0
- package/services/history-service/subscan-history.js +100 -0
- package/services/subscan-service/index.d.ts +10 -2
- package/services/subscan-service/index.js +105 -4
- package/services/subscan-service/subscan-chain-map.d.ts +9 -3
- package/services/subscan-service/subscan-chain-map.js +78 -5
- package/services/subscan-service/types.d.ts +146 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +7 -0
|
@@ -2,24 +2,32 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { ExtrinsicStatus } from '@subwallet/extension-base/background/KoniTypes';
|
|
5
|
-
import { CRON_RECOVER_HISTORY_INTERVAL
|
|
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 { historyRecover, HistoryRecoverStatus } from '@subwallet/extension-base/services/history-service/helpers/recoverHistoryStatus';
|
|
8
|
+
import { getExtrinsicParserKey } from '@subwallet/extension-base/services/history-service/helpers/subscan-extrinsic-parser-helper';
|
|
9
|
+
import { parseSubscanExtrinsicData, parseSubscanTransferData } from '@subwallet/extension-base/services/history-service/subscan-history';
|
|
10
|
+
import { reformatAddress } from '@subwallet/extension-base/utils';
|
|
8
11
|
import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
|
|
9
12
|
import { keyring } from '@subwallet/ui-keyring';
|
|
10
13
|
import { BehaviorSubject } from 'rxjs';
|
|
14
|
+
function filterHistoryItemByAddressAndChain(chain, address) {
|
|
15
|
+
return item => {
|
|
16
|
+
return item.chain === chain && item.address === address;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
11
19
|
export class HistoryService {
|
|
12
20
|
historySubject = new BehaviorSubject([]);
|
|
13
21
|
#needRecoveryHistories = {};
|
|
14
|
-
constructor(dbService, chainService, eventService, keyringService) {
|
|
22
|
+
constructor(dbService, chainService, eventService, keyringService, subscanService) {
|
|
15
23
|
this.dbService = dbService;
|
|
16
24
|
this.chainService = chainService;
|
|
17
25
|
this.eventService = eventService;
|
|
18
26
|
this.keyringService = keyringService;
|
|
27
|
+
this.subscanService = subscanService;
|
|
19
28
|
this.init().catch(console.error);
|
|
20
29
|
}
|
|
21
30
|
fetchPromise = null;
|
|
22
|
-
interval = undefined;
|
|
23
31
|
recoverInterval = undefined;
|
|
24
32
|
async fetchAndLoadHistories(addresses) {
|
|
25
33
|
if (!addresses || addresses.length === 0) {
|
|
@@ -60,6 +68,74 @@ export class HistoryService {
|
|
|
60
68
|
await this.getHistories();
|
|
61
69
|
return this.historySubject;
|
|
62
70
|
}
|
|
71
|
+
fetchSubscanTransactionHistory(chain, address) {
|
|
72
|
+
if (!this.subscanService.checkSupportedSubscanChain(chain)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const chainInfo = this.chainService.getChainInfoByKey(chain);
|
|
76
|
+
const excludeExtrinsicParserKeys = ['balances.transfer_all'];
|
|
77
|
+
|
|
78
|
+
// Note: fetchAllPossibleExtrinsicItems and fetchAllPossibleTransferItems-receive can run parallelly
|
|
79
|
+
// Hover, fetchAllPossibleTransferItems-sent must run after fetchAllPossibleExtrinsicItems,
|
|
80
|
+
// to avoid "duplicate Extrinsic Hash between items" problem
|
|
81
|
+
|
|
82
|
+
this.subscanService.fetchAllPossibleExtrinsicItems(chain, address, extrinsicItems => {
|
|
83
|
+
const result = [];
|
|
84
|
+
extrinsicItems.forEach(x => {
|
|
85
|
+
const item = parseSubscanExtrinsicData(address, x, chainInfo);
|
|
86
|
+
if (item) {
|
|
87
|
+
result.push(item);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
this.addHistoryItems(result).catch(e => {
|
|
91
|
+
console.log('addHistoryItems in fetchAllPossibleExtrinsicItems error', e);
|
|
92
|
+
});
|
|
93
|
+
}).then(extrinsicItems => {
|
|
94
|
+
const excludeTransferExtrinsicHash = [];
|
|
95
|
+
extrinsicItems.forEach(x => {
|
|
96
|
+
if (!excludeExtrinsicParserKeys.includes(getExtrinsicParserKey(x))) {
|
|
97
|
+
excludeTransferExtrinsicHash.push(x.extrinsic_hash);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
this.subscanService.fetchAllPossibleTransferItems(chain, address, 'sent', transferItems => {
|
|
101
|
+
const result = [];
|
|
102
|
+
transferItems.forEach(t => {
|
|
103
|
+
if (!excludeTransferExtrinsicHash.includes(t.hash)) {
|
|
104
|
+
result.push(parseSubscanTransferData(address, t, chainInfo));
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
this.addHistoryItems(result).catch(e => {
|
|
108
|
+
console.log('addHistoryItems in fetchAllPossibleTransferItems-sent error', e);
|
|
109
|
+
});
|
|
110
|
+
}).catch(e => {
|
|
111
|
+
console.log('fetchAllPossibleTransferItems-sent error', e);
|
|
112
|
+
});
|
|
113
|
+
}).catch(e => {
|
|
114
|
+
console.log('fetchAllPossibleExtrinsicItems error', e);
|
|
115
|
+
});
|
|
116
|
+
this.subscanService.fetchAllPossibleTransferItems(chain, address, 'received', transferItems => {
|
|
117
|
+
const result = [];
|
|
118
|
+
transferItems.forEach(t => {
|
|
119
|
+
result.push(parseSubscanTransferData(address, t, chainInfo));
|
|
120
|
+
});
|
|
121
|
+
this.addHistoryItems(result).catch(e => {
|
|
122
|
+
console.log('addHistoryItems in fetchAllPossibleTransferItems-receive error', e);
|
|
123
|
+
});
|
|
124
|
+
}).catch(e => {
|
|
125
|
+
console.log('fetchAllPossibleTransferItems-receive error', e);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
subscribeHistories(chain, address, cb) {
|
|
129
|
+
const _address = reformatAddress(address);
|
|
130
|
+
const subscription = this.historySubject.subscribe(items => {
|
|
131
|
+
cb(items.filter(filterHistoryItemByAddressAndChain(chain, _address)));
|
|
132
|
+
});
|
|
133
|
+
this.fetchSubscanTransactionHistory(chain, _address);
|
|
134
|
+
return {
|
|
135
|
+
unsubscribe: subscription.unsubscribe,
|
|
136
|
+
value: this.historySubject.getValue().filter(filterHistoryItemByAddressAndChain(chain, _address))
|
|
137
|
+
};
|
|
138
|
+
}
|
|
63
139
|
async updateHistories(chain, extrinsicHash, updateData) {
|
|
64
140
|
const existedRecords = await this.dbService.getHistories({
|
|
65
141
|
chain,
|
|
@@ -110,17 +186,6 @@ export class HistoryService {
|
|
|
110
186
|
async persistData() {
|
|
111
187
|
await this.dbService.upsertHistory(this.historySubject.value);
|
|
112
188
|
}
|
|
113
|
-
async startCron() {
|
|
114
|
-
await this.getHistories();
|
|
115
|
-
this.interval = setInterval(() => {
|
|
116
|
-
this.getHistories().catch(console.error);
|
|
117
|
-
}, CRON_REFRESH_HISTORY_INTERVAL);
|
|
118
|
-
}
|
|
119
|
-
stopCron() {
|
|
120
|
-
clearTimeout(this.interval);
|
|
121
|
-
this.fetchPromise = null;
|
|
122
|
-
return Promise.resolve();
|
|
123
|
-
}
|
|
124
189
|
async startRecoverHistories() {
|
|
125
190
|
await this.recoverHistories();
|
|
126
191
|
this.recoverInterval = setInterval(() => {
|
|
@@ -175,12 +240,6 @@ export class HistoryService {
|
|
|
175
240
|
Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
|
|
176
241
|
this.getHistories().catch(console.log);
|
|
177
242
|
this.recoverProcessingHistory().catch(console.error);
|
|
178
|
-
this.eventService.on('account.add', () => {
|
|
179
|
-
(async () => {
|
|
180
|
-
await this.stopCron();
|
|
181
|
-
await this.startCron();
|
|
182
|
-
})().catch(console.error);
|
|
183
|
-
});
|
|
184
243
|
this.eventService.on('account.remove', address => {
|
|
185
244
|
this.removeHistoryByAddress(address).catch(console.error);
|
|
186
245
|
});
|
|
@@ -209,7 +268,6 @@ export class HistoryService {
|
|
|
209
268
|
await Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]);
|
|
210
269
|
this.startPromiseHandler = createPromiseHandler();
|
|
211
270
|
this.status = ServiceStatus.STARTING;
|
|
212
|
-
await this.startCron();
|
|
213
271
|
this.status = ServiceStatus.STARTED;
|
|
214
272
|
this.startPromiseHandler.resolve();
|
|
215
273
|
} catch (e) {
|
|
@@ -225,7 +283,6 @@ export class HistoryService {
|
|
|
225
283
|
this.stopPromiseHandler = createPromiseHandler();
|
|
226
284
|
this.status = ServiceStatus.STOPPING;
|
|
227
285
|
await this.persistData();
|
|
228
|
-
await this.stopCron();
|
|
229
286
|
await this.stopRecoverHistories();
|
|
230
287
|
this.stopPromiseHandler.resolve();
|
|
231
288
|
this.status = ServiceStatus.STOPPED;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
|
+
import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
|
|
3
|
+
import { ExtrinsicItem, TransferItem } from '@subwallet/extension-base/services/subscan-service/types';
|
|
4
|
+
export declare function parseSubscanExtrinsicData(address: string, extrinsicItem: ExtrinsicItem, chainInfo: _ChainInfo): TransactionHistoryItem | null;
|
|
5
|
+
export declare function parseSubscanTransferData(address: string, transferItem: TransferItem, chainInfo: _ChainInfo): TransactionHistoryItem;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { ChainType, ExtrinsicStatus, ExtrinsicType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
|
|
5
|
+
import { getExtrinsicParserKey, subscanExtrinsicParserMap, supportedExtrinsicParser } from '@subwallet/extension-base/services/history-service/helpers/subscan-extrinsic-parser-helper';
|
|
6
|
+
import { decodeAddress, encodeAddress, isEthereumAddress } from '@polkadot/util-crypto';
|
|
7
|
+
function autoFormatAddress(address) {
|
|
8
|
+
try {
|
|
9
|
+
if (isEthereumAddress(address)) {
|
|
10
|
+
return address;
|
|
11
|
+
} else {
|
|
12
|
+
const decoded = decodeAddress(address);
|
|
13
|
+
return encodeAddress(decoded, 42);
|
|
14
|
+
}
|
|
15
|
+
} catch (e) {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function parseSubscanExtrinsicData(address, extrinsicItem, chainInfo) {
|
|
20
|
+
var _chainInfo$substrateI, _chainInfo$evmInfo, _chainInfo$substrateI2, _chainInfo$evmInfo2;
|
|
21
|
+
const extrinsicParserKey = getExtrinsicParserKey(extrinsicItem);
|
|
22
|
+
if (!supportedExtrinsicParser.includes(extrinsicParserKey)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const chainType = chainInfo.substrateInfo ? ChainType.SUBSTRATE : ChainType.EVM;
|
|
26
|
+
const nativeDecimals = ((_chainInfo$substrateI = chainInfo.substrateInfo) === null || _chainInfo$substrateI === void 0 ? void 0 : _chainInfo$substrateI.decimals) || ((_chainInfo$evmInfo = chainInfo.evmInfo) === null || _chainInfo$evmInfo === void 0 ? void 0 : _chainInfo$evmInfo.decimals) || 18;
|
|
27
|
+
const nativeSymbol = ((_chainInfo$substrateI2 = chainInfo.substrateInfo) === null || _chainInfo$substrateI2 === void 0 ? void 0 : _chainInfo$substrateI2.symbol) || ((_chainInfo$evmInfo2 = chainInfo.evmInfo) === null || _chainInfo$evmInfo2 === void 0 ? void 0 : _chainInfo$evmInfo2.symbol) || '';
|
|
28
|
+
const initData = {
|
|
29
|
+
address,
|
|
30
|
+
origin: 'subscan',
|
|
31
|
+
time: extrinsicItem.block_timestamp * 1000,
|
|
32
|
+
chainType,
|
|
33
|
+
from: address,
|
|
34
|
+
signature: extrinsicItem.signature,
|
|
35
|
+
fromName: undefined,
|
|
36
|
+
direction: TransactionDirection.SEND,
|
|
37
|
+
blockNumber: extrinsicItem.block_num,
|
|
38
|
+
blockHash: '',
|
|
39
|
+
chain: chainInfo.slug,
|
|
40
|
+
type: ExtrinsicType.UNKNOWN,
|
|
41
|
+
to: '',
|
|
42
|
+
toName: undefined,
|
|
43
|
+
extrinsicHash: extrinsicItem.extrinsic_hash,
|
|
44
|
+
amount: {
|
|
45
|
+
value: '0',
|
|
46
|
+
decimals: nativeDecimals,
|
|
47
|
+
symbol: nativeSymbol
|
|
48
|
+
},
|
|
49
|
+
data: extrinsicItem.params,
|
|
50
|
+
fee: {
|
|
51
|
+
value: extrinsicItem.fee,
|
|
52
|
+
decimals: nativeDecimals,
|
|
53
|
+
symbol: nativeSymbol
|
|
54
|
+
},
|
|
55
|
+
status: extrinsicItem.success ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL,
|
|
56
|
+
nonce: extrinsicItem.nonce
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
return subscanExtrinsicParserMap[extrinsicParserKey](initData);
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.log('parseSubscanExtrinsicData error:', e, initData);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function parseSubscanTransferData(address, transferItem, chainInfo) {
|
|
66
|
+
var _chainInfo$substrateI3, _chainInfo$evmInfo3, _chainInfo$substrateI4, _chainInfo$evmInfo4;
|
|
67
|
+
const chainType = chainInfo.substrateInfo ? ChainType.SUBSTRATE : ChainType.EVM;
|
|
68
|
+
const nativeDecimals = ((_chainInfo$substrateI3 = chainInfo.substrateInfo) === null || _chainInfo$substrateI3 === void 0 ? void 0 : _chainInfo$substrateI3.decimals) || ((_chainInfo$evmInfo3 = chainInfo.evmInfo) === null || _chainInfo$evmInfo3 === void 0 ? void 0 : _chainInfo$evmInfo3.decimals) || 18;
|
|
69
|
+
const nativeSymbol = ((_chainInfo$substrateI4 = chainInfo.substrateInfo) === null || _chainInfo$substrateI4 === void 0 ? void 0 : _chainInfo$substrateI4.symbol) || ((_chainInfo$evmInfo4 = chainInfo.evmInfo) === null || _chainInfo$evmInfo4 === void 0 ? void 0 : _chainInfo$evmInfo4.symbol) || '';
|
|
70
|
+
const from = autoFormatAddress(transferItem.from);
|
|
71
|
+
const to = autoFormatAddress(transferItem.to);
|
|
72
|
+
return {
|
|
73
|
+
address,
|
|
74
|
+
origin: 'subscan',
|
|
75
|
+
time: transferItem.block_timestamp * 1000,
|
|
76
|
+
chainType,
|
|
77
|
+
from,
|
|
78
|
+
fromName: transferItem.from_account_display.display,
|
|
79
|
+
direction: address === from ? TransactionDirection.SEND : TransactionDirection.RECEIVED,
|
|
80
|
+
blockNumber: transferItem.block_num,
|
|
81
|
+
blockHash: '',
|
|
82
|
+
chain: chainInfo.slug,
|
|
83
|
+
type: ExtrinsicType.TRANSFER_BALANCE,
|
|
84
|
+
to,
|
|
85
|
+
toName: transferItem.to_account_display.display,
|
|
86
|
+
extrinsicHash: transferItem.hash,
|
|
87
|
+
amount: {
|
|
88
|
+
value: transferItem.amount,
|
|
89
|
+
decimals: 0,
|
|
90
|
+
symbol: transferItem.asset_symbol
|
|
91
|
+
},
|
|
92
|
+
fee: {
|
|
93
|
+
value: transferItem.fee,
|
|
94
|
+
decimals: nativeDecimals,
|
|
95
|
+
symbol: nativeSymbol
|
|
96
|
+
},
|
|
97
|
+
status: transferItem.success ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL,
|
|
98
|
+
nonce: transferItem.nonce
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { IMultiChainBalance } from '@subwallet/extension-base/services/subscan-service/types';
|
|
1
|
+
import { CrowdloanContributionsResponse, ExtrinsicItem, ExtrinsicsListResponse, IMultiChainBalance, TransferItem, TransfersListResponse } from '@subwallet/extension-base/services/subscan-service/types';
|
|
2
2
|
export declare class SubscanService {
|
|
3
|
+
private subscanChainMap;
|
|
3
4
|
private limitRate;
|
|
4
5
|
private intervalCheck;
|
|
5
6
|
private maxRetry;
|
|
@@ -7,7 +8,7 @@ export declare class SubscanService {
|
|
|
7
8
|
private nextId;
|
|
8
9
|
private isRunning;
|
|
9
10
|
private getId;
|
|
10
|
-
constructor(options?: {
|
|
11
|
+
constructor(subscanChainMap: Record<string, string>, options?: {
|
|
11
12
|
limitRate?: number;
|
|
12
13
|
intervalCheck?: number;
|
|
13
14
|
maxRetry?: number;
|
|
@@ -16,5 +17,12 @@ export declare class SubscanService {
|
|
|
16
17
|
private postRequest;
|
|
17
18
|
private addRequest;
|
|
18
19
|
private process;
|
|
20
|
+
checkSupportedSubscanChain(chain: string): boolean;
|
|
21
|
+
setSubscanChainMap(subscanChainMap: Record<string, string>): void;
|
|
19
22
|
getMultiChainBalance(address: string): Promise<IMultiChainBalance[]>;
|
|
23
|
+
getCrowdloanContributions(relayChain: string, address: string, page?: number): Promise<CrowdloanContributionsResponse>;
|
|
24
|
+
getExtrinsicsList(chain: string, address: string, page?: number): Promise<ExtrinsicsListResponse>;
|
|
25
|
+
fetchAllPossibleExtrinsicItems(chain: string, address: string, cbAfterEachRequest?: (items: ExtrinsicItem[]) => void): Promise<ExtrinsicItem[]>;
|
|
26
|
+
getTransfersList(chain: string, address: string, page?: number, direction?: 'sent' | 'received'): Promise<TransfersListResponse>;
|
|
27
|
+
fetchAllPossibleTransferItems(chain: string, address: string, direction?: 'sent' | 'received', cbAfterEachRequest?: (items: TransferItem[]) => void): Promise<TransferItem[]>;
|
|
20
28
|
}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { SWError } from '@subwallet/extension-base/background/errors/SWError';
|
|
5
|
-
import
|
|
5
|
+
import { wait } from '@subwallet/extension-base/utils';
|
|
6
6
|
import fetch from 'cross-fetch';
|
|
7
|
+
const QUERY_ROW = 100;
|
|
7
8
|
export class SubscanService {
|
|
8
9
|
limitRate = 2; // limit per interval check
|
|
9
10
|
intervalCheck = 1000; // interval check in ms
|
|
@@ -14,17 +15,18 @@ export class SubscanService {
|
|
|
14
15
|
getId() {
|
|
15
16
|
return this.nextId++;
|
|
16
17
|
}
|
|
17
|
-
constructor(options) {
|
|
18
|
+
constructor(subscanChainMap, options) {
|
|
19
|
+
this.subscanChainMap = subscanChainMap;
|
|
18
20
|
this.limitRate = (options === null || options === void 0 ? void 0 : options.limitRate) || this.limitRate;
|
|
19
21
|
this.intervalCheck = (options === null || options === void 0 ? void 0 : options.intervalCheck) || this.intervalCheck;
|
|
20
22
|
this.maxRetry = (options === null || options === void 0 ? void 0 : options.maxRetry) || this.maxRetry;
|
|
21
23
|
}
|
|
22
24
|
getApiUrl(chain, path) {
|
|
23
|
-
const subscanChain =
|
|
25
|
+
const subscanChain = this.subscanChainMap[chain];
|
|
24
26
|
if (!subscanChain) {
|
|
25
27
|
throw new SWError('NOT_SUPPORTED', 'Chain is not supported');
|
|
26
28
|
}
|
|
27
|
-
return `https://${
|
|
29
|
+
return `https://${subscanChain}.api.subscan.io/${path}`;
|
|
28
30
|
}
|
|
29
31
|
postRequest(url, body) {
|
|
30
32
|
return fetch(url, {
|
|
@@ -82,6 +84,12 @@ export class SubscanService {
|
|
|
82
84
|
});
|
|
83
85
|
}, this.intervalCheck);
|
|
84
86
|
}
|
|
87
|
+
checkSupportedSubscanChain(chain) {
|
|
88
|
+
return !!this.subscanChainMap[chain];
|
|
89
|
+
}
|
|
90
|
+
setSubscanChainMap(subscanChainMap) {
|
|
91
|
+
this.subscanChainMap = subscanChainMap;
|
|
92
|
+
}
|
|
85
93
|
|
|
86
94
|
// Implement Subscan API
|
|
87
95
|
getMultiChainBalance(address) {
|
|
@@ -96,4 +104,97 @@ export class SubscanService {
|
|
|
96
104
|
return jsonData.data;
|
|
97
105
|
});
|
|
98
106
|
}
|
|
107
|
+
getCrowdloanContributions(relayChain, address, page = 0) {
|
|
108
|
+
return this.addRequest(async () => {
|
|
109
|
+
const rs = await this.postRequest(this.getApiUrl(relayChain, 'api/scan/account/contributions'), {
|
|
110
|
+
include_total: true,
|
|
111
|
+
page,
|
|
112
|
+
row: QUERY_ROW,
|
|
113
|
+
who: address
|
|
114
|
+
});
|
|
115
|
+
if (rs.status !== 200) {
|
|
116
|
+
throw new SWError('SubscanService.getCrowdloanContributions', await rs.text());
|
|
117
|
+
}
|
|
118
|
+
const jsonData = await rs.json();
|
|
119
|
+
return jsonData.data;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
getExtrinsicsList(chain, address, page = 0) {
|
|
123
|
+
return this.addRequest(async () => {
|
|
124
|
+
const rs = await this.postRequest(this.getApiUrl(chain, 'api/scan/extrinsics'), {
|
|
125
|
+
page,
|
|
126
|
+
row: QUERY_ROW,
|
|
127
|
+
address
|
|
128
|
+
});
|
|
129
|
+
if (rs.status !== 200) {
|
|
130
|
+
throw new SWError('SubscanService.getExtrinsicsList', await rs.text());
|
|
131
|
+
}
|
|
132
|
+
const jsonData = await rs.json();
|
|
133
|
+
return jsonData.data;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async fetchAllPossibleExtrinsicItems(chain, address, cbAfterEachRequest) {
|
|
137
|
+
let count = 0;
|
|
138
|
+
const resultMap = {};
|
|
139
|
+
const _getExtrinsicItems = async page => {
|
|
140
|
+
const res = await this.getExtrinsicsList(chain, address, page);
|
|
141
|
+
if (!res || !res.count || !res.extrinsics || !res.extrinsics.length) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (res.count > count) {
|
|
145
|
+
count = res.count;
|
|
146
|
+
}
|
|
147
|
+
cbAfterEachRequest === null || cbAfterEachRequest === void 0 ? void 0 : cbAfterEachRequest(res.extrinsics);
|
|
148
|
+
res.extrinsics.forEach(item => {
|
|
149
|
+
resultMap[item.extrinsic_hash] = item;
|
|
150
|
+
});
|
|
151
|
+
if (Object.values(resultMap).length < count) {
|
|
152
|
+
await wait(100);
|
|
153
|
+
await _getExtrinsicItems(++page);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
await _getExtrinsicItems(0);
|
|
157
|
+
return Object.values(resultMap);
|
|
158
|
+
}
|
|
159
|
+
getTransfersList(chain, address, page = 0, direction) {
|
|
160
|
+
const requestBody = {
|
|
161
|
+
page,
|
|
162
|
+
row: QUERY_ROW,
|
|
163
|
+
address
|
|
164
|
+
};
|
|
165
|
+
if (direction) {
|
|
166
|
+
requestBody.direction = direction;
|
|
167
|
+
}
|
|
168
|
+
return this.addRequest(async () => {
|
|
169
|
+
const rs = await this.postRequest(this.getApiUrl(chain, 'api/v2/scan/transfers'), requestBody);
|
|
170
|
+
if (rs.status !== 200) {
|
|
171
|
+
throw new SWError('SubscanService.getTransfersList', await rs.text());
|
|
172
|
+
}
|
|
173
|
+
const jsonData = await rs.json();
|
|
174
|
+
return jsonData.data;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async fetchAllPossibleTransferItems(chain, address, direction, cbAfterEachRequest) {
|
|
178
|
+
let count = 0;
|
|
179
|
+
const resultMap = {};
|
|
180
|
+
const _getTransferItems = async page => {
|
|
181
|
+
const res = await this.getTransfersList(chain, address, page, direction);
|
|
182
|
+
if (!res || !res.count || !res.transfers || !res.transfers.length) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (res.count > count) {
|
|
186
|
+
count = res.count;
|
|
187
|
+
}
|
|
188
|
+
cbAfterEachRequest === null || cbAfterEachRequest === void 0 ? void 0 : cbAfterEachRequest(res.transfers);
|
|
189
|
+
res.transfers.forEach(item => {
|
|
190
|
+
resultMap[item.hash] = item;
|
|
191
|
+
});
|
|
192
|
+
if (Object.values(resultMap).length < count) {
|
|
193
|
+
await wait(100);
|
|
194
|
+
await _getTransferItems(++page);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
await _getTransferItems(0);
|
|
198
|
+
return Object.values(resultMap);
|
|
199
|
+
}
|
|
99
200
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Only use this for initiating SubscanService or unit test
|
|
3
|
+
*/
|
|
4
|
+
export declare const SUBSCAN_API_CHAIN_MAP: Record<string, string>;
|
|
5
|
+
/**
|
|
6
|
+
* Map for token self-activation feature
|
|
7
|
+
*/
|
|
8
|
+
export declare const SUBSCAN_BALANCE_CHAIN_MAP: Record<string, string>;
|
|
9
|
+
export declare const SUBSCAN_BALANCE_CHAIN_MAP_REVERSE: {
|
|
3
10
|
[k: string]: string;
|
|
4
11
|
};
|
|
5
|
-
export default SUBSCAN_CHAIN_MAP;
|
|
@@ -1,7 +1,76 @@
|
|
|
1
1
|
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Only use this for initiating SubscanService or unit test
|
|
6
|
+
*/
|
|
7
|
+
export const SUBSCAN_API_CHAIN_MAP = {
|
|
8
|
+
polkadot: 'polkadot',
|
|
9
|
+
kusama: 'kusama',
|
|
10
|
+
moonbeam: 'moonbeam',
|
|
11
|
+
pioneer: 'pioneer',
|
|
12
|
+
aleph: 'alephzero',
|
|
13
|
+
astar: 'astar',
|
|
14
|
+
statemint: 'assethub-polkadot',
|
|
15
|
+
acala: 'acala',
|
|
16
|
+
shiden: 'shiden',
|
|
17
|
+
shibuya: 'shibuya',
|
|
18
|
+
westend: 'westend',
|
|
19
|
+
rococo: 'rococo',
|
|
20
|
+
moonbase: 'moonbase',
|
|
21
|
+
moonriver: 'moonriver',
|
|
22
|
+
turing: 'turing',
|
|
23
|
+
bifrost: 'bifrost-kusama',
|
|
24
|
+
bifrost_dot: 'bifrost',
|
|
25
|
+
calamari: 'calamari',
|
|
26
|
+
parallel: 'parallel',
|
|
27
|
+
clover: 'clv',
|
|
28
|
+
hydradx_main: 'hydradx',
|
|
29
|
+
centrifuge: 'centrifuge',
|
|
30
|
+
interlay: 'interlay',
|
|
31
|
+
nodle: 'nodle',
|
|
32
|
+
darwinia2: 'darwinia',
|
|
33
|
+
polkadex: 'polkadex-parachain',
|
|
34
|
+
composableFinance: 'composable',
|
|
35
|
+
phala: 'phala',
|
|
36
|
+
crust: 'crust-parachain',
|
|
37
|
+
statemine: 'assethub-kusama',
|
|
38
|
+
karura: 'karura',
|
|
39
|
+
khala: 'khala',
|
|
40
|
+
kilt: 'spiritnet',
|
|
41
|
+
basilisk: 'basilisk',
|
|
42
|
+
altair: 'altair',
|
|
43
|
+
heiko: 'parallel-heiko',
|
|
44
|
+
kintsugi: 'kintsugi',
|
|
45
|
+
picasso: 'picasso',
|
|
46
|
+
unique_network: 'unique',
|
|
47
|
+
zeitgeist: 'zeitgeist',
|
|
48
|
+
sakura: 'sakura',
|
|
49
|
+
shadow: 'shadow',
|
|
50
|
+
robonomics: 'robonomics',
|
|
51
|
+
integritee: 'integritee',
|
|
52
|
+
crabParachain: 'crab',
|
|
53
|
+
acala_testnet: 'acala-testnet',
|
|
54
|
+
mangatax_para: 'mangatax',
|
|
55
|
+
origintrail: 'origintrail',
|
|
56
|
+
subspace_gemini_3g: 'subspace',
|
|
57
|
+
bajun: 'bajun',
|
|
58
|
+
tanganika: 'datahighway',
|
|
59
|
+
kilt_peregrine: 'kilt-testnet',
|
|
60
|
+
dockPosMainnet: 'dock',
|
|
61
|
+
polymesh: 'polymesh',
|
|
62
|
+
sora_substrate: 'sora',
|
|
63
|
+
joystream: 'joystream',
|
|
64
|
+
vara_network: 'vara',
|
|
65
|
+
krest_network: 'krest',
|
|
66
|
+
crust_mainnet: 'crust',
|
|
67
|
+
manta_network: 'manta'
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Map for token self-activation feature
|
|
72
|
+
*/
|
|
73
|
+
export const SUBSCAN_BALANCE_CHAIN_MAP = {
|
|
5
74
|
polkadot: 'polkadot',
|
|
6
75
|
kusama: 'kusama',
|
|
7
76
|
moonbeam: 'moonbeam',
|
|
@@ -21,7 +90,7 @@ const SUBSCAN_CHAIN_MAP = {
|
|
|
21
90
|
clover: 'clover',
|
|
22
91
|
hydradx_main: 'hydradx',
|
|
23
92
|
edgeware: 'edgeware',
|
|
24
|
-
centrifuge: 'centrifuge',
|
|
93
|
+
centrifuge: 'centrifuge-parachain',
|
|
25
94
|
interlay: 'interlay',
|
|
26
95
|
nodle: 'nodle',
|
|
27
96
|
darwinia: 'darwinia',
|
|
@@ -57,7 +126,11 @@ const SUBSCAN_CHAIN_MAP = {
|
|
|
57
126
|
bajun: 'bajun',
|
|
58
127
|
snow: 'snow',
|
|
59
128
|
kilt_peregrine: 'kilt-testnet',
|
|
60
|
-
polymesh: 'polymesh'
|
|
129
|
+
polymesh: 'polymesh',
|
|
130
|
+
bifrost_dot: 'bifrost-p',
|
|
131
|
+
vara_network: 'vara',
|
|
132
|
+
bifrost: 'bifrost',
|
|
133
|
+
creditcoin: 'creditcoin',
|
|
134
|
+
joystream: 'joystream'
|
|
61
135
|
};
|
|
62
|
-
export const
|
|
63
|
-
export default SUBSCAN_CHAIN_MAP;
|
|
136
|
+
export const SUBSCAN_BALANCE_CHAIN_MAP_REVERSE = Object.fromEntries(Object.entries(SUBSCAN_BALANCE_CHAIN_MAP).map(([k, v]) => [v, k]));
|