@subwallet/extension-base 1.3.46-0 → 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/cjs/koni/api/nft/ordinal_nft/index.js +3 -2
- package/cjs/koni/background/handlers/State.js +3 -0
- package/cjs/packageInfo.js +1 -1
- 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/utils/index.js +3 -0
- package/cjs/services/chain-service/utils/patch.js +1 -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 +37 -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 +16 -0
- package/cjs/services/earning-service/handlers/native-staking/tao.js +5 -0
- package/cjs/services/earning-service/service.js +26 -5
- package/cjs/services/history-service/index.js +12 -7
- 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/utils/gear/combine.js +4 -3
- package/cjs/utils/gear/vft.js +104 -135
- package/koni/api/nft/ordinal_nft/index.js +3 -2
- package/koni/background/handlers/State.js +4 -1
- package/package.json +20 -9
- package/packageInfo.js +1 -1
- package/services/balance-service/helpers/subscribe/substrate/index.js +8 -14
- package/services/buy-service/index.js +2 -0
- package/services/chain-service/utils/index.js +3 -0
- package/services/chain-service/utils/patch.js +1 -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 +1 -0
- package/services/earning-service/handlers/native-staking/base.js +37 -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 +16 -0
- 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/service.d.ts +1 -0
- package/services/earning-service/service.js +26 -5
- package/services/history-service/index.js +12 -7
- 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/buy.d.ts +1 -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
|
@@ -119,6 +119,34 @@ export default class MythosNativeStakingPoolHandler extends BaseParaStakingPoolH
|
|
|
119
119
|
|
|
120
120
|
/* Subscribe pool position */
|
|
121
121
|
|
|
122
|
+
async checkAccountHaveStake(useAddresses) {
|
|
123
|
+
var _substrateApi$api$que, _substrateApi$api$que2, _substrateApi$api$que3;
|
|
124
|
+
const result = [];
|
|
125
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
126
|
+
const ledgers = await ((_substrateApi$api$que = substrateApi.api.query.collatorStaking) === null || _substrateApi$api$que === void 0 ? void 0 : (_substrateApi$api$que2 = _substrateApi$api$que.userStake) === null || _substrateApi$api$que2 === void 0 ? void 0 : (_substrateApi$api$que3 = _substrateApi$api$que2.multi) === null || _substrateApi$api$que3 === void 0 ? void 0 : _substrateApi$api$que3.call(_substrateApi$api$que2, useAddresses));
|
|
127
|
+
const _unstakings = await Promise.all(useAddresses.map(stakerAddress => {
|
|
128
|
+
var _substrateApi$api$que4, _substrateApi$api$que5;
|
|
129
|
+
return (_substrateApi$api$que4 = substrateApi.api.query.collatorStaking) === null || _substrateApi$api$que4 === void 0 ? void 0 : (_substrateApi$api$que5 = _substrateApi$api$que4.releaseQueues) === null || _substrateApi$api$que5 === void 0 ? void 0 : _substrateApi$api$que5.call(_substrateApi$api$que4, stakerAddress);
|
|
130
|
+
}));
|
|
131
|
+
if (!ledgers || !_unstakings) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
for (let i = 0; i < useAddresses.length; i++) {
|
|
135
|
+
const owner = useAddresses[i];
|
|
136
|
+
const _userStake = ledgers[i];
|
|
137
|
+
const userStake = _userStake.toPrimitive();
|
|
138
|
+
const _unstaking = _unstakings[i];
|
|
139
|
+
const unstakings = _unstaking.toPrimitive();
|
|
140
|
+
|
|
141
|
+
// TODO: Need to improve, check if can only load stake info
|
|
142
|
+
if (userStake && userStake.stake !== '0') {
|
|
143
|
+
result.push(owner);
|
|
144
|
+
} else if (unstakings && unstakings.some(unstake => unstake.amount !== '0')) {
|
|
145
|
+
result.push(owner);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
122
150
|
async subscribePoolPosition(useAddresses, resultCallback) {
|
|
123
151
|
let cancel = false;
|
|
124
152
|
const substrateApi = await this.substrateApi.isReady;
|
|
@@ -7,6 +7,7 @@ export default class ParaNativeStakingPoolHandler extends BaseParaNativeStakingP
|
|
|
7
7
|
subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
|
|
8
8
|
parseNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, delegatorState: PalletParachainStakingDelegator): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
|
|
9
9
|
subscribePoolPosition(useAddresses: string[], resultCallback: (rs: YieldPositionInfo) => void): Promise<VoidFunction>;
|
|
10
|
+
checkAccountHaveStake(useAddresses: string[]): Promise<string[]>;
|
|
10
11
|
getMantaPoolTargets(): Promise<ValidatorInfo[]>;
|
|
11
12
|
getParachainPoolTargets(): Promise<ValidatorInfo[]>;
|
|
12
13
|
getPoolTargets(): Promise<ValidatorInfo[]>;
|
|
@@ -268,6 +268,23 @@ export default class ParaNativeStakingPoolHandler extends BaseParaNativeStakingP
|
|
|
268
268
|
unsub();
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
|
+
async checkAccountHaveStake(useAddresses) {
|
|
272
|
+
var _substrateApi$api$que, _substrateApi$api$que2, _substrateApi$api$que3;
|
|
273
|
+
const result = [];
|
|
274
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
275
|
+
const ledgers = await ((_substrateApi$api$que = substrateApi.api.query.parachainStaking) === null || _substrateApi$api$que === void 0 ? void 0 : (_substrateApi$api$que2 = _substrateApi$api$que.delegatorState) === null || _substrateApi$api$que2 === void 0 ? void 0 : (_substrateApi$api$que3 = _substrateApi$api$que2.multi) === null || _substrateApi$api$que3 === void 0 ? void 0 : _substrateApi$api$que3.call(_substrateApi$api$que2, useAddresses));
|
|
276
|
+
if (!ledgers) {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
for (let i = 0; i < useAddresses.length; i++) {
|
|
280
|
+
const owner = useAddresses[i];
|
|
281
|
+
const delegatorState = ledgers[i].toPrimitive();
|
|
282
|
+
if (delegatorState && delegatorState.total > 0) {
|
|
283
|
+
result.push(owner);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
271
288
|
|
|
272
289
|
/* Subscribe pool position */
|
|
273
290
|
|
|
@@ -12,6 +12,7 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
|
|
|
12
12
|
parseNominatorMetadata(chainInfo: _ChainInfo, address: string, substrateApi: _SubstrateApi, ledger: PalletStakingStakingLedger, currentEra: string, minStake: BN, _deriveSessionProgress: DeriveSessionProgress): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
|
|
13
13
|
handleNominationsList(substrateApi: _SubstrateApi, chain: string, nominations: PalletStakingNominations, currentEra: string, address: string, maxNominatorRewardedPerValidator: number | undefined): Promise<NominationInfo[]>;
|
|
14
14
|
subscribePoolPosition(useAddresses: string[], resultCallback: (rs: YieldPositionInfo) => void): Promise<VoidFunction>;
|
|
15
|
+
checkAccountHaveStake(useAddresses: string[]): Promise<string[]>;
|
|
15
16
|
getPoolTargets(): Promise<ValidatorInfo[]>;
|
|
16
17
|
private getValidatorExpectedReturn;
|
|
17
18
|
private parseEraStakerData;
|
|
@@ -283,6 +283,22 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
|
|
|
283
283
|
unsub === null || unsub === void 0 ? void 0 : unsub();
|
|
284
284
|
};
|
|
285
285
|
}
|
|
286
|
+
async checkAccountHaveStake(useAddresses) {
|
|
287
|
+
var _substrateApi$api$que22, _substrateApi$api$que23, _substrateApi$api$que24;
|
|
288
|
+
const result = [];
|
|
289
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
290
|
+
const ledgers = await ((_substrateApi$api$que22 = substrateApi.api.query.staking) === null || _substrateApi$api$que22 === void 0 ? void 0 : (_substrateApi$api$que23 = _substrateApi$api$que22.ledger) === null || _substrateApi$api$que23 === void 0 ? void 0 : (_substrateApi$api$que24 = _substrateApi$api$que23.multi) === null || _substrateApi$api$que24 === void 0 ? void 0 : _substrateApi$api$que24.call(_substrateApi$api$que23, useAddresses));
|
|
291
|
+
if (ledgers) {
|
|
292
|
+
for (let i = 0; i < useAddresses.length; i++) {
|
|
293
|
+
const address = useAddresses[i];
|
|
294
|
+
const _ledger = ledgers[i].toPrimitive();
|
|
295
|
+
if (_ledger.total > 0) {
|
|
296
|
+
result.push(address);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
286
302
|
|
|
287
303
|
/* Subscribe pool position */
|
|
288
304
|
|
|
@@ -57,6 +57,7 @@ export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHand
|
|
|
57
57
|
subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
|
|
58
58
|
parseNominatorMetadata(chainInfo: _ChainInfo, address: string, delegatorState: TaoStakingStakeOption[]): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
|
|
59
59
|
subscribePoolPosition(useAddresses: string[], rsCallback: (rs: YieldPositionInfo) => void): Promise<VoidFunction>;
|
|
60
|
+
checkAccountHaveStake(useAddresses: string[]): Promise<string[]>;
|
|
60
61
|
private getDevnetPoolTargets;
|
|
61
62
|
private getMainnetPoolTargets;
|
|
62
63
|
getPoolTargets(): Promise<ValidatorInfo[]>;
|
|
@@ -380,6 +380,11 @@ export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHand
|
|
|
380
380
|
};
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
// Because not have subscan api
|
|
384
|
+
async checkAccountHaveStake(useAddresses) {
|
|
385
|
+
return Promise.resolve([]);
|
|
386
|
+
}
|
|
387
|
+
|
|
383
388
|
/* Subscribe pool position */
|
|
384
389
|
|
|
385
390
|
/* Get pool targets */
|
|
@@ -83,6 +83,7 @@ export default class EarningService implements StoppableServiceInterface, Persis
|
|
|
83
83
|
subscribeEarningRewardHistory(): BehaviorSubject<Record<string, EarningRewardHistoryItem>>;
|
|
84
84
|
getEarningRewardHistory(): Record<string, EarningRewardHistoryItem>;
|
|
85
85
|
earningsRewardHistoryInterval: NodeJS.Timer | undefined;
|
|
86
|
+
private unSubFetchEarningRewardHistory;
|
|
86
87
|
runSubscribeEarningRewardHistoryInterval(): void;
|
|
87
88
|
runUnsubscribeEarningRewardHistoryInterval(): void;
|
|
88
89
|
/**
|
|
@@ -660,18 +660,39 @@ export default class EarningService {
|
|
|
660
660
|
if (!addresses.length) {
|
|
661
661
|
return;
|
|
662
662
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
663
|
+
let cancel = false;
|
|
664
|
+
let unsub;
|
|
665
|
+
this.unSubFetchEarningRewardHistory = () => {
|
|
666
|
+
if (!cancel) {
|
|
667
|
+
var _unsub2;
|
|
668
|
+
(_unsub2 = unsub) === null || _unsub2 === void 0 ? void 0 : _unsub2();
|
|
669
|
+
cancel = true;
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
const fetchData = () => {
|
|
667
673
|
this.fetchPoolRewardHistory(addresses, result => {
|
|
674
|
+
if (cancel) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
668
677
|
this.updateEarningRewardHistory(result);
|
|
678
|
+
}).then(_unsub => {
|
|
679
|
+
if (!cancel) {
|
|
680
|
+
var _unsub3;
|
|
681
|
+
(_unsub3 = unsub) === null || _unsub3 === void 0 ? void 0 : _unsub3();
|
|
682
|
+
unsub = _unsub;
|
|
683
|
+
}
|
|
669
684
|
}).catch(console.error);
|
|
670
|
-
}
|
|
685
|
+
};
|
|
686
|
+
if (!cancel) {
|
|
687
|
+
fetchData();
|
|
688
|
+
}
|
|
689
|
+
this.earningsRewardHistoryInterval = setInterval(fetchData, CRON_REFRESH_EARNING_REWARD_HISTORY_INTERVAL);
|
|
671
690
|
}
|
|
672
691
|
runUnsubscribeEarningRewardHistoryInterval() {
|
|
692
|
+
var _this$unSubFetchEarni;
|
|
673
693
|
removeLazy('updateEarningRewardHistory');
|
|
674
694
|
this.earningRewardHistoryQueue = [];
|
|
695
|
+
(_this$unSubFetchEarni = this.unSubFetchEarningRewardHistory) === null || _this$unSubFetchEarni === void 0 ? void 0 : _this$unSubFetchEarni.call(this);
|
|
675
696
|
this.earningsRewardHistoryInterval && clearInterval(this.earningsRewardHistoryInterval);
|
|
676
697
|
}
|
|
677
698
|
|
|
@@ -74,7 +74,7 @@ export class HistoryService {
|
|
|
74
74
|
/**
|
|
75
75
|
* @todo: Must improve performance of this function
|
|
76
76
|
* */
|
|
77
|
-
fetchSubscanTransactionHistory(chain, addresses) {
|
|
77
|
+
fetchSubscanTransactionHistory(chain, addresses, groupId) {
|
|
78
78
|
if (!this.subscanService.checkSupportedSubscanChain(chain) || !addresses.length) {
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
@@ -87,7 +87,7 @@ export class HistoryService {
|
|
|
87
87
|
// However, fetchAllPossibleTransferItems-sent must run after fetchAllPossibleExtrinsicItems,
|
|
88
88
|
// to avoid "duplicate Extrinsic Hash between items" problem
|
|
89
89
|
|
|
90
|
-
this.subscanService.fetchAllPossibleExtrinsicItems(chain, address, extrinsicItems => {
|
|
90
|
+
this.subscanService.fetchAllPossibleExtrinsicItems(groupId, chain, address, extrinsicItems => {
|
|
91
91
|
const result = [];
|
|
92
92
|
extrinsicItems.forEach(x => {
|
|
93
93
|
const item = parseSubscanExtrinsicData(address, x, chainInfo);
|
|
@@ -105,7 +105,7 @@ export class HistoryService {
|
|
|
105
105
|
excludeTransferExtrinsicHash.push(x.extrinsic_hash);
|
|
106
106
|
}
|
|
107
107
|
});
|
|
108
|
-
this.subscanService.fetchAllPossibleTransferItems(chain, address, 'sent').then(rsMap => {
|
|
108
|
+
this.subscanService.fetchAllPossibleTransferItems(groupId, chain, address, 'sent').then(rsMap => {
|
|
109
109
|
const result = [];
|
|
110
110
|
Object.keys(rsMap).forEach(hash => {
|
|
111
111
|
// only push item that does not have same hash with another item
|
|
@@ -125,7 +125,7 @@ export class HistoryService {
|
|
|
125
125
|
}).catch(e => {
|
|
126
126
|
console.log('fetchAllPossibleExtrinsicItems error', e);
|
|
127
127
|
});
|
|
128
|
-
this.subscanService.fetchAllPossibleTransferItems(chain, address, 'received').then(rsMap => {
|
|
128
|
+
this.subscanService.fetchAllPossibleTransferItems(groupId, chain, address, 'received').then(rsMap => {
|
|
129
129
|
const result = [];
|
|
130
130
|
Object.keys(rsMap).forEach(hash => {
|
|
131
131
|
// only push item that does not have same hash with another item
|
|
@@ -172,14 +172,19 @@ export class HistoryService {
|
|
|
172
172
|
const evmAddresses = getAddressesByChainType(addresses, [ChainType.EVM]);
|
|
173
173
|
const substrateAddresses = getAddressesByChainType(addresses, [ChainType.SUBSTRATE]);
|
|
174
174
|
const bitcoinAddresses = getAddressesByChainType(addresses, [ChainType.BITCOIN], chainInfo);
|
|
175
|
+
const groupId = this.subscanService.getGroupId();
|
|
175
176
|
const subscription = this.historySubject.subscribe(items => {
|
|
176
177
|
cb(items.filter(filterHistoryItemByAddressAndChain(chain, addresses)));
|
|
177
178
|
});
|
|
179
|
+
const unsubscribe = () => {
|
|
180
|
+
subscription.unsubscribe();
|
|
181
|
+
this.subscanService.cancelGroupRequest(groupId);
|
|
182
|
+
};
|
|
178
183
|
if (_isChainSubstrateCompatible(chainInfo)) {
|
|
179
184
|
if (_isChainEvmCompatible(chainInfo)) {
|
|
180
|
-
this.fetchSubscanTransactionHistory(chain, evmAddresses);
|
|
185
|
+
this.fetchSubscanTransactionHistory(chain, evmAddresses, groupId);
|
|
181
186
|
} else {
|
|
182
|
-
this.fetchSubscanTransactionHistory(chain, substrateAddresses);
|
|
187
|
+
this.fetchSubscanTransactionHistory(chain, substrateAddresses, groupId);
|
|
183
188
|
}
|
|
184
189
|
} else if (_isChainBitcoinCompatible(chainInfo)) {
|
|
185
190
|
this.fetchBitcoinTransactionHistory(chain, bitcoinAddresses).catch(e => {
|
|
@@ -187,7 +192,7 @@ export class HistoryService {
|
|
|
187
192
|
});
|
|
188
193
|
}
|
|
189
194
|
return {
|
|
190
|
-
unsubscribe
|
|
195
|
+
unsubscribe,
|
|
191
196
|
value: this.historySubject.getValue().filter(filterHistoryItemByAddressAndChain(chain, addresses))
|
|
192
197
|
};
|
|
193
198
|
}
|
|
@@ -1,44 +1,30 @@
|
|
|
1
|
-
import { CrowdloanContributionsResponse, ExtrinsicItem, ExtrinsicsListResponse, IMultiChainBalance, RequestBlockRange, RewardHistoryListResponse,
|
|
1
|
+
import { CrowdloanContributionsResponse, ExtrinsicItem, ExtrinsicsListResponse, IMultiChainBalance, RequestBlockRange, RewardHistoryListResponse, TransferItem, TransfersListResponse } from '@subwallet/extension-base/services/subscan-service/types';
|
|
2
|
+
import { ApiRequestContextProps } from '@subwallet/extension-base/strategy/api-request-strategy/types';
|
|
3
|
+
import { BaseApiRequestStrategyV2 } from '@subwallet/extension-base/strategy/api-request-strategy-v2';
|
|
2
4
|
import { SubscanEventBaseItemData, SubscanExtrinsicParam } from '@subwallet/extension-base/types';
|
|
3
|
-
export declare class SubscanService {
|
|
5
|
+
export declare class SubscanService extends BaseApiRequestStrategyV2 {
|
|
4
6
|
private subscanChainMap;
|
|
5
|
-
|
|
6
|
-
private limitRate;
|
|
7
|
-
private intervalCheck;
|
|
8
|
-
private maxRetry;
|
|
9
|
-
private rollbackRateTime;
|
|
10
|
-
private timeoutRollbackRate;
|
|
11
|
-
private requestMap;
|
|
12
|
-
private nextId;
|
|
13
|
-
private isRunning;
|
|
14
|
-
private getId;
|
|
15
|
-
constructor(subscanChainMap: Record<string, string>, options?: {
|
|
16
|
-
limitRate?: number;
|
|
17
|
-
intervalCheck?: number;
|
|
18
|
-
maxRetry?: number;
|
|
19
|
-
});
|
|
20
|
-
private reduceLimitRate;
|
|
7
|
+
constructor(subscanChainMap: Record<string, string>, options?: Partial<ApiRequestContextProps>);
|
|
21
8
|
private getApiUrl;
|
|
22
9
|
private postRequest;
|
|
23
|
-
|
|
24
|
-
private process;
|
|
10
|
+
isRateLimited(e: Error): boolean;
|
|
25
11
|
checkSupportedSubscanChain(chain: string): boolean;
|
|
26
12
|
setSubscanChainMap(subscanChainMap: Record<string, string>): void;
|
|
27
13
|
getMultiChainBalance(address: string): Promise<IMultiChainBalance[]>;
|
|
28
14
|
getCrowdloanContributions(relayChain: string, address: string, page?: number): Promise<CrowdloanContributionsResponse>;
|
|
29
|
-
getExtrinsicsList(chain: string, address: string, page?: number, blockRange?: RequestBlockRange): Promise<ExtrinsicsListResponse>;
|
|
30
|
-
fetchAllPossibleExtrinsicItems(chain: string, address: string, cbAfterEachRequest?: (items: ExtrinsicItem[]) => void, limit?: {
|
|
15
|
+
getExtrinsicsList(groupId: number, chain: string, address: string, page?: number, blockRange?: RequestBlockRange): Promise<ExtrinsicsListResponse>;
|
|
16
|
+
fetchAllPossibleExtrinsicItems(groupId: number, chain: string, address: string, cbAfterEachRequest?: (items: ExtrinsicItem[]) => void, limit?: {
|
|
31
17
|
page: number;
|
|
32
18
|
record: number;
|
|
33
19
|
}): Promise<ExtrinsicItem[]>;
|
|
34
|
-
getTransfersList(chain: string, address: string, page?: number, direction?: 'sent' | 'received', blockRange?: RequestBlockRange): Promise<TransfersListResponse>;
|
|
35
|
-
fetchAllPossibleTransferItems(chain: string, address: string, direction?: 'sent' | 'received', cbAfterEachRequest?: (items: TransferItem[]) => void, limit?: {
|
|
20
|
+
getTransfersList(groupId: number, chain: string, address: string, page?: number, direction?: 'sent' | 'received', blockRange?: RequestBlockRange): Promise<TransfersListResponse>;
|
|
21
|
+
fetchAllPossibleTransferItems(groupId: number, chain: string, address: string, direction?: 'sent' | 'received', cbAfterEachRequest?: (items: TransferItem[]) => void, limit?: {
|
|
36
22
|
page: number;
|
|
37
23
|
record: number;
|
|
38
24
|
}): Promise<Record<string, TransferItem[]>>;
|
|
39
|
-
getRewardHistoryList(chain: string, address: string, page?: number): Promise<RewardHistoryListResponse>;
|
|
40
|
-
getAccountRemarkEvents(chain: string, address: string): Promise<SubscanEventBaseItemData[]>;
|
|
41
|
-
getExtrinsicParams(chain: string, extrinsicIndexes: string[], ordinal?: number): Promise<SubscanExtrinsicParam[]>;
|
|
25
|
+
getRewardHistoryList(groupId: number, chain: string, address: string, page?: number): Promise<RewardHistoryListResponse>;
|
|
26
|
+
getAccountRemarkEvents(groupId: number, chain: string, address: string): Promise<SubscanEventBaseItemData[]>;
|
|
27
|
+
getExtrinsicParams(groupId: number, chain: string, extrinsicIndexes: string[], ordinal?: number): Promise<SubscanExtrinsicParam[]>;
|
|
42
28
|
private static _instance;
|
|
43
29
|
static getInstance(): SubscanService;
|
|
44
30
|
}
|
|
@@ -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
|
+
}
|