@subwallet/extension-base 1.0.5-1 → 1.0.5-3
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 +2 -1
- package/cjs/koni/api/staking/bonding/relayChain.js +2 -7
- package/cjs/koni/api/staking/bonding/utils.js +9 -0
- package/cjs/koni/background/handlers/Extension.js +4 -2
- package/cjs/koni/background/handlers/Tabs.js +24 -23
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/constants.js +2 -2
- package/cjs/services/chain-service/index.js +5 -0
- package/cjs/services/chain-service/utils.js +15 -10
- package/cjs/services/history-service/helpers/recoverHistoryStatus.js +157 -38
- package/cjs/services/history-service/index.js +26 -19
- package/cjs/services/history-service/subsquid-multi-chain-history.js +2 -2
- package/cjs/services/notification-service/NotificationService.js +1 -1
- package/cjs/services/storage-service/DatabaseService.js +1 -1
- package/cjs/services/transaction-service/index.js +41 -14
- package/cjs/services/transaction-service/utils.js +3 -0
- package/cjs/utils/index.js +3 -0
- package/koni/api/staking/bonding/relayChain.js +3 -8
- package/koni/api/staking/bonding/utils.d.ts +1 -0
- package/koni/api/staking/bonding/utils.js +8 -0
- package/koni/background/handlers/Extension.js +5 -3
- package/koni/background/handlers/Tabs.js +24 -23
- package/package.json +6 -6
- package/packageInfo.js +1 -1
- package/services/chain-service/constants.js +2 -2
- package/services/chain-service/index.js +5 -0
- package/services/chain-service/utils.d.ts +1 -0
- package/services/chain-service/utils.js +14 -10
- package/services/history-service/helpers/recoverHistoryStatus.d.ts +7 -1
- package/services/history-service/helpers/recoverHistoryStatus.js +151 -35
- package/services/history-service/index.d.ts +1 -1
- package/services/history-service/index.js +26 -19
- package/services/history-service/subsquid-multi-chain-history.js +2 -2
- package/services/notification-service/NotificationService.js +1 -1
- package/services/storage-service/DatabaseService.d.ts +1 -1
- package/services/storage-service/DatabaseService.js +1 -1
- package/services/transaction-service/index.js +41 -14
- package/services/transaction-service/types.d.ts +5 -3
- package/services/transaction-service/utils.js +3 -0
- package/utils/index.js +3 -0
|
@@ -419,6 +419,8 @@ export interface TransactionHistoryItem<ET extends ExtrinsicType = ExtrinsicType
|
|
|
419
419
|
fee?: AmountData;
|
|
420
420
|
explorerUrl?: string;
|
|
421
421
|
additionalInfo?: TransactionAdditionalInfo<ET>;
|
|
422
|
+
startBlock?: number;
|
|
423
|
+
nonce?: number;
|
|
422
424
|
}
|
|
423
425
|
export interface SWError extends Error {
|
|
424
426
|
code?: number;
|
|
@@ -1073,7 +1075,6 @@ export interface ChainStakingMetadata {
|
|
|
1073
1075
|
minJoinNominationPool?: string;
|
|
1074
1076
|
minStake: string;
|
|
1075
1077
|
nominatorCount?: number;
|
|
1076
|
-
minPoolBonding?: string;
|
|
1077
1078
|
maxValidatorPerNominator: number;
|
|
1078
1079
|
maxWithdrawalRequestPerValidator: number;
|
|
1079
1080
|
allowCancelUnstaking: boolean;
|
|
@@ -34,7 +34,7 @@ function validateRelayUnbondingCondition(amount, chainStakingMetadata, nominator
|
|
|
34
34
|
const errors = [];
|
|
35
35
|
const bnActiveStake = new _util.BN(nominatorMetadata.activeStake);
|
|
36
36
|
const bnRemainingStake = bnActiveStake.sub(new _util.BN(amount));
|
|
37
|
-
const minStake = new _util.BN(chainStakingMetadata.
|
|
37
|
+
const minStake = new _util.BN(chainStakingMetadata.minJoinNominationPool || '0');
|
|
38
38
|
if (!(bnRemainingStake.isZero() || bnRemainingStake.gte(minStake))) {
|
|
39
39
|
errors.push(new _TransactionError.TransactionError(_KoniTypes.StakingTxErrorType.INVALID_ACTIVE_STAKE));
|
|
40
40
|
}
|
|
@@ -48,7 +48,7 @@ function validatePoolBondingCondition(chainInfo, amount, selectedPool, address,
|
|
|
48
48
|
// amount >= min stake
|
|
49
49
|
const errors = [];
|
|
50
50
|
let bnTotalStake = new _util.BN(amount);
|
|
51
|
-
const bnMinStake = new _util.BN(chainStakingMetadata.
|
|
51
|
+
const bnMinStake = new _util.BN(chainStakingMetadata.minJoinNominationPool || '0');
|
|
52
52
|
if (selectedPool.state !== 'Open') {
|
|
53
53
|
errors.push(new _TransactionError.TransactionError(_KoniTypes.StakingTxErrorType.INACTIVE_NOMINATION_POOL));
|
|
54
54
|
}
|
|
@@ -90,9 +90,6 @@ function validateRelayBondingCondition(chainInfo, amount, selectedValidators, ad
|
|
|
90
90
|
async function getRelayChainStakingMetadata(chainInfo, substrateApi) {
|
|
91
91
|
var _chainApi$api$query$a, _chainApi$api$query, _chainApi$api$query$s, _chainApi$api$query2, _chainApi$api$query2$, _chainApi$api$query3, _chainApi$api$query3$;
|
|
92
92
|
const chain = chainInfo.slug;
|
|
93
|
-
const {
|
|
94
|
-
decimals
|
|
95
|
-
} = (0, _utils2._getChainNativeTokenBasicInfo)(chainInfo);
|
|
96
93
|
const chainApi = await substrateApi.isReady;
|
|
97
94
|
const _era = await chainApi.api.query.staking.currentEra();
|
|
98
95
|
const currentEra = _era.toString();
|
|
@@ -136,8 +133,6 @@ async function getRelayChainStakingMetadata(chainInfo, substrateApi) {
|
|
|
136
133
|
// in %, annually
|
|
137
134
|
inflation,
|
|
138
135
|
minStake: minStake.toString(),
|
|
139
|
-
minPoolBonding: (10 ** decimals).toString(),
|
|
140
|
-
// default is 1
|
|
141
136
|
maxValidatorPerNominator: parseInt(maxNominations),
|
|
142
137
|
maxWithdrawalRequestPerValidator: parseInt(maxUnlockingChunks),
|
|
143
138
|
allowCancelUnstaking: true,
|
|
@@ -17,6 +17,7 @@ exports.getParaCurrentInflation = getParaCurrentInflation;
|
|
|
17
17
|
exports.getStakingAvailableActionsByChain = getStakingAvailableActionsByChain;
|
|
18
18
|
exports.getStakingAvailableActionsByNominator = getStakingAvailableActionsByNominator;
|
|
19
19
|
exports.getStakingStatusByNominations = getStakingStatusByNominations;
|
|
20
|
+
exports.getValidatorLabel = getValidatorLabel;
|
|
20
21
|
exports.getWithdrawalInfo = getWithdrawalInfo;
|
|
21
22
|
exports.isActionFromValidator = isActionFromValidator;
|
|
22
23
|
exports.isShowNominationByValidator = isShowNominationByValidator;
|
|
@@ -268,4 +269,12 @@ function getStakingStatusByNominations(bnTotalActiveStake, nominationList) {
|
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
271
|
return stakingStatus;
|
|
272
|
+
}
|
|
273
|
+
function getValidatorLabel(chain) {
|
|
274
|
+
if (_constants._STAKING_CHAIN_GROUP.astar.includes(chain)) {
|
|
275
|
+
return 'dApp';
|
|
276
|
+
} else if (_constants._STAKING_CHAIN_GROUP.relay.includes(chain)) {
|
|
277
|
+
return 'Validator';
|
|
278
|
+
}
|
|
279
|
+
return 'Collator';
|
|
271
280
|
}
|
|
@@ -1299,7 +1299,7 @@ class KoniExtension {
|
|
|
1299
1299
|
const isPasswordValidated = this.validatedAccountsPassword(file, password);
|
|
1300
1300
|
if (isPasswordValidated) {
|
|
1301
1301
|
try {
|
|
1302
|
-
this._saveCurrentAccountAddress(
|
|
1302
|
+
this._saveCurrentAccountAddress(_constants.ALL_ACCOUNT_KEY, () => {
|
|
1303
1303
|
_uiKeyring.keyring.restoreAccounts(file, password);
|
|
1304
1304
|
this._addAddressesToAuthList(addressList, isAllowed);
|
|
1305
1305
|
});
|
|
@@ -1446,7 +1446,8 @@ class KoniExtension {
|
|
|
1446
1446
|
|
|
1447
1447
|
// Get native token amount
|
|
1448
1448
|
const freeBalance = await this.#koniState.balanceService.getTokenFreeBalance(from, networkKey, tokenSlug);
|
|
1449
|
-
if ((0, _utilCrypto.isEthereumAddress)(from) && (0, _utilCrypto.isEthereumAddress)(to)) {
|
|
1449
|
+
if ((0, _utilCrypto.isEthereumAddress)(from) && (0, _utilCrypto.isEthereumAddress)(to) && (0, _utils._isTokenTransferredByEvm)(tokenInfo)) {
|
|
1450
|
+
// TODO: review this
|
|
1450
1451
|
chainType = _KoniTypes.ChainType.EVM;
|
|
1451
1452
|
const txVal = transferAll ? freeBalance.value : value || '0';
|
|
1452
1453
|
|
|
@@ -2917,6 +2918,7 @@ class KoniExtension {
|
|
|
2917
2918
|
return Object.fromEntries(Object.entries(rs).map(_ref70 => {
|
|
2918
2919
|
let [key, value] = _ref70;
|
|
2919
2920
|
const {
|
|
2921
|
+
additionalValidator,
|
|
2920
2922
|
transaction,
|
|
2921
2923
|
...transactionResult
|
|
2922
2924
|
} = value;
|
|
@@ -445,35 +445,36 @@ class KoniTabs {
|
|
|
445
445
|
const chainIdNum = parseInt(chainId, 16);
|
|
446
446
|
const [existedNetworkSlug, existedChainInfo] = this.#koniState.findNetworkKeyByChainId(chainIdNum);
|
|
447
447
|
if (existedNetworkSlug && existedChainInfo && existedChainInfo !== null && existedChainInfo !== void 0 && existedChainInfo.evmInfo) {
|
|
448
|
-
const evmInfo = existedChainInfo.evmInfo;
|
|
449
|
-
const substrateInfo = existedChainInfo.substrateInfo;
|
|
450
|
-
const chainState = this.#koniState.getChainStateByKey(existedNetworkSlug);
|
|
451
|
-
await this.#koniState.addNetworkConfirm(id, url, {
|
|
452
|
-
mode: 'update',
|
|
453
|
-
chainSpec: {
|
|
454
|
-
evmChainId: evmInfo.evmChainId,
|
|
455
|
-
decimals: evmInfo.decimals,
|
|
456
|
-
existentialDeposit: evmInfo.existentialDeposit,
|
|
457
|
-
genesisHash: (substrateInfo === null || substrateInfo === void 0 ? void 0 : substrateInfo.genesisHash) || '',
|
|
458
|
-
paraId: (substrateInfo === null || substrateInfo === void 0 ? void 0 : substrateInfo.paraId) || null,
|
|
459
|
-
addressPrefix: (substrateInfo === null || substrateInfo === void 0 ? void 0 : substrateInfo.addressPrefix) || 0
|
|
460
|
-
},
|
|
461
|
-
chainEditInfo: {
|
|
462
|
-
blockExplorer: blockExplorerUrls === null || blockExplorerUrls === void 0 ? void 0 : blockExplorerUrls[0],
|
|
463
|
-
slug: existedNetworkSlug,
|
|
464
|
-
currentProvider: chainState.currentProvider,
|
|
465
|
-
providers: existedChainInfo.providers,
|
|
466
|
-
symbol: evmInfo.symbol,
|
|
467
|
-
chainType: 'EVM',
|
|
468
|
-
name: existedChainInfo.name
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
448
|
return await this.switchEvmChain(id, url, {
|
|
472
449
|
method: 'wallet_switchEthereumChain',
|
|
473
450
|
params: [{
|
|
474
451
|
chainId
|
|
475
452
|
}]
|
|
476
453
|
});
|
|
454
|
+
// const evmInfo = existedChainInfo.evmInfo;
|
|
455
|
+
// const substrateInfo = existedChainInfo.substrateInfo;
|
|
456
|
+
// const chainState = this.#koniState.getChainStateByKey(existedNetworkSlug);
|
|
457
|
+
//
|
|
458
|
+
// return await this.#koniState.addNetworkConfirm(id, url, {
|
|
459
|
+
// mode: 'update',
|
|
460
|
+
// chainSpec: {
|
|
461
|
+
// evmChainId: evmInfo.evmChainId,
|
|
462
|
+
// decimals: evmInfo.decimals,
|
|
463
|
+
// existentialDeposit: evmInfo.existentialDeposit,
|
|
464
|
+
// genesisHash: substrateInfo?.genesisHash || '',
|
|
465
|
+
// paraId: substrateInfo?.paraId || null,
|
|
466
|
+
// addressPrefix: substrateInfo?.addressPrefix || 0
|
|
467
|
+
// },
|
|
468
|
+
// chainEditInfo: {
|
|
469
|
+
// blockExplorer: blockExplorerUrls?.[0],
|
|
470
|
+
// slug: existedNetworkSlug,
|
|
471
|
+
// currentProvider: chainState.currentProvider,
|
|
472
|
+
// providers: existedChainInfo.providers,
|
|
473
|
+
// symbol: evmInfo.symbol,
|
|
474
|
+
// chainType: 'EVM',
|
|
475
|
+
// name: existedChainInfo.name
|
|
476
|
+
// }
|
|
477
|
+
// });
|
|
477
478
|
} else if (rpcUrls && chainName) {
|
|
478
479
|
const filteredUrls = rpcUrls.filter(targetString => {
|
|
479
480
|
let url;
|
package/cjs/packageInfo.js
CHANGED
|
@@ -36,7 +36,7 @@ const _BALANCE_CHAIN_GROUP = {
|
|
|
36
36
|
genshiro: ['genshiro_testnet', 'genshiro'],
|
|
37
37
|
equilibrium_parachain: ['equilibrium_parachain'],
|
|
38
38
|
bifrost: ['bifrost', 'acala', 'karura', 'acala_testnet', 'pioneer', 'bitcountry'],
|
|
39
|
-
statemine: ['statemine', 'astar', 'shiden', 'statemint', 'moonbeam', 'moonbase', 'moonriver', 'crabParachain'],
|
|
39
|
+
statemine: ['statemine', 'astar', 'shiden', 'statemint', 'moonbeam', 'moonbase', 'moonriver', 'crabParachain', 'darwinia2'],
|
|
40
40
|
kusama: ['kusama', 'kintsugi', 'kintsugi_test', 'interlay', 'acala', 'statemint', 'karura', 'bifrost'] // perhaps there are some runtime updates
|
|
41
41
|
};
|
|
42
42
|
exports._BALANCE_CHAIN_GROUP = _BALANCE_CHAIN_GROUP;
|
|
@@ -194,7 +194,7 @@ const _TRANSFER_CHAIN_GROUP = {
|
|
|
194
194
|
genshiro: ['genshiro_testnet', 'genshiro', 'equilibrium_parachain'],
|
|
195
195
|
crab: ['crab', 'pangolin'],
|
|
196
196
|
bitcountry: ['pioneer', 'bitcountry'],
|
|
197
|
-
statemine: ['statemint', 'statemine']
|
|
197
|
+
statemine: ['statemint', 'statemine', 'darwinia2']
|
|
198
198
|
};
|
|
199
199
|
exports._TRANSFER_CHAIN_GROUP = _TRANSFER_CHAIN_GROUP;
|
|
200
200
|
const _BALANCE_PARSING_CHAIN_GROUP = {
|
|
@@ -720,6 +720,11 @@ class ChainService {
|
|
|
720
720
|
targetChainInfo.substrateInfo.crowdloanUrl = params.chainEditInfo.crowdloanUrl;
|
|
721
721
|
}
|
|
722
722
|
}
|
|
723
|
+
if (targetChainInfo.evmInfo) {
|
|
724
|
+
if (params.chainEditInfo.blockExplorer !== undefined) {
|
|
725
|
+
targetChainInfo.evmInfo.blockExplorer = params.chainEditInfo.blockExplorer;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
723
728
|
this.updateChainInfoMapSubscription();
|
|
724
729
|
this.dbService.updateChainStore({
|
|
725
730
|
...targetChainInfo,
|
|
@@ -61,6 +61,7 @@ exports._isSubstrateParaChain = _isSubstrateParaChain;
|
|
|
61
61
|
exports._isSubstrateParachain = _isSubstrateParachain;
|
|
62
62
|
exports._isSubstrateRelayChain = _isSubstrateRelayChain;
|
|
63
63
|
exports._isTokenEvmSmartContract = _isTokenEvmSmartContract;
|
|
64
|
+
exports._isTokenTransferredByEvm = _isTokenTransferredByEvm;
|
|
64
65
|
exports._isTokenWasmSmartContract = _isTokenWasmSmartContract;
|
|
65
66
|
exports._isXcmPathSupported = _isXcmPathSupported;
|
|
66
67
|
exports._parseAssetRefKey = _parseAssetRefKey;
|
|
@@ -128,6 +129,10 @@ function _getContractAddressOfToken(tokenInfo) {
|
|
|
128
129
|
var _tokenInfo$metadata;
|
|
129
130
|
return ((_tokenInfo$metadata = tokenInfo.metadata) === null || _tokenInfo$metadata === void 0 ? void 0 : _tokenInfo$metadata.contractAddress) || '';
|
|
130
131
|
}
|
|
132
|
+
function _isTokenTransferredByEvm(tokenInfo) {
|
|
133
|
+
var _tokenInfo$metadata2;
|
|
134
|
+
return !!((_tokenInfo$metadata2 = tokenInfo.metadata) !== null && _tokenInfo$metadata2 !== void 0 && _tokenInfo$metadata2.contractAddress) || _isNativeToken(tokenInfo);
|
|
135
|
+
}
|
|
131
136
|
function _checkSmartContractSupportByChain(chainInfo, contractType) {
|
|
132
137
|
// EVM chains support smart contract by default so just checking Substrate chains
|
|
133
138
|
if (chainInfo.substrateInfo === null || chainInfo.substrateInfo && chainInfo.substrateInfo.supportSmartContract === null) {
|
|
@@ -138,12 +143,12 @@ function _checkSmartContractSupportByChain(chainInfo, contractType) {
|
|
|
138
143
|
|
|
139
144
|
// Utils for balance functions
|
|
140
145
|
function _getTokenOnChainAssetId(tokenInfo) {
|
|
141
|
-
var _tokenInfo$
|
|
142
|
-
return ((_tokenInfo$
|
|
146
|
+
var _tokenInfo$metadata3;
|
|
147
|
+
return ((_tokenInfo$metadata3 = tokenInfo.metadata) === null || _tokenInfo$metadata3 === void 0 ? void 0 : _tokenInfo$metadata3.assetId) || '-1';
|
|
143
148
|
}
|
|
144
149
|
function _getTokenOnChainInfo(tokenInfo) {
|
|
145
|
-
var _tokenInfo$
|
|
146
|
-
return (_tokenInfo$
|
|
150
|
+
var _tokenInfo$metadata4;
|
|
151
|
+
return (_tokenInfo$metadata4 = tokenInfo.metadata) === null || _tokenInfo$metadata4 === void 0 ? void 0 : _tokenInfo$metadata4.onChainInfo;
|
|
147
152
|
}
|
|
148
153
|
function _getTokenMinAmount(tokenInfo) {
|
|
149
154
|
return tokenInfo.minAmount || '0';
|
|
@@ -296,16 +301,16 @@ function _isXcmPathSupported(originTokenSlug, destinationTokenSlug, assetRefMap)
|
|
|
296
301
|
return assetRef.path === _types._AssetRefPath.XCM;
|
|
297
302
|
}
|
|
298
303
|
function _getXcmAssetType(tokenInfo) {
|
|
299
|
-
var _tokenInfo$
|
|
300
|
-
return ((_tokenInfo$
|
|
304
|
+
var _tokenInfo$metadata5;
|
|
305
|
+
return ((_tokenInfo$metadata5 = tokenInfo.metadata) === null || _tokenInfo$metadata5 === void 0 ? void 0 : _tokenInfo$metadata5.assetType) || '';
|
|
301
306
|
}
|
|
302
307
|
function _getXcmAssetId(tokenInfo) {
|
|
303
|
-
var _tokenInfo$
|
|
304
|
-
return ((_tokenInfo$
|
|
308
|
+
var _tokenInfo$metadata6;
|
|
309
|
+
return ((_tokenInfo$metadata6 = tokenInfo.metadata) === null || _tokenInfo$metadata6 === void 0 ? void 0 : _tokenInfo$metadata6.assetId) || '-1';
|
|
305
310
|
}
|
|
306
311
|
function _getXcmAssetMultilocation(tokenInfo) {
|
|
307
|
-
var _tokenInfo$
|
|
308
|
-
return (_tokenInfo$
|
|
312
|
+
var _tokenInfo$metadata7;
|
|
313
|
+
return (_tokenInfo$metadata7 = tokenInfo.metadata) === null || _tokenInfo$metadata7 === void 0 ? void 0 : _tokenInfo$metadata7.multilocation;
|
|
309
314
|
}
|
|
310
315
|
function _getXcmTransferType(originChainInfo, destinationChainInfo) {
|
|
311
316
|
var _originChainInfo$subs, _destinationChainInfo;
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.historyRecover = exports.HistoryRecoverStatus = void 0;
|
|
7
|
+
var _utils = require("@subwallet/extension-base/utils");
|
|
7
8
|
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
|
|
8
9
|
// SPDX-License-Identifier: Apache-2.0
|
|
9
10
|
let HistoryRecoverStatus;
|
|
@@ -16,78 +17,194 @@ exports.HistoryRecoverStatus = HistoryRecoverStatus;
|
|
|
16
17
|
HistoryRecoverStatus["FAIL_DETECT"] = "FAIL_DETECT";
|
|
17
18
|
HistoryRecoverStatus["UNKNOWN"] = "UNKNOWN";
|
|
18
19
|
})(HistoryRecoverStatus || (exports.HistoryRecoverStatus = HistoryRecoverStatus = {}));
|
|
20
|
+
const BLOCK_LIMIT = 6;
|
|
19
21
|
const substrateRecover = async (history, chainService) => {
|
|
20
22
|
const {
|
|
23
|
+
address,
|
|
21
24
|
blockHash,
|
|
22
25
|
chain,
|
|
23
|
-
extrinsicHash
|
|
26
|
+
extrinsicHash,
|
|
27
|
+
from,
|
|
28
|
+
nonce,
|
|
29
|
+
startBlock
|
|
24
30
|
} = history;
|
|
31
|
+
const result = {
|
|
32
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
33
|
+
};
|
|
25
34
|
try {
|
|
26
35
|
const substrateApi = chainService.getSubstrateApi(chain);
|
|
27
36
|
if (substrateApi) {
|
|
28
37
|
const _api = await substrateApi.isReady;
|
|
29
38
|
const api = _api.api;
|
|
30
39
|
if (!blockHash) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const extrinsics = block.block.extrinsics;
|
|
37
|
-
let index;
|
|
38
|
-
extrinsics.forEach((extrinsic, _idx) => {
|
|
39
|
-
if (extrinsicHash === extrinsic.hash.toHex()) {
|
|
40
|
-
index = _idx;
|
|
40
|
+
if (!nonce || !startBlock) {
|
|
41
|
+
console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
|
|
42
|
+
return {
|
|
43
|
+
status: HistoryRecoverStatus.LACK_INFO
|
|
44
|
+
};
|
|
41
45
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
46
|
+
const currentBlock = (await api.query.system.number()).toPrimitive();
|
|
47
|
+
for (let i = 1, found = false; i < BLOCK_LIMIT && !found && startBlock + i <= currentBlock; i++) {
|
|
48
|
+
const blockHash = (await api.rpc.chain.getBlockHash(startBlock + i)).toHex();
|
|
49
|
+
const block = await api.rpc.chain.getBlock(blockHash);
|
|
50
|
+
const extrinsics = block.block.extrinsics;
|
|
51
|
+
let index;
|
|
52
|
+
for (const [idx, extrinsic] of Object.entries(extrinsics)) {
|
|
53
|
+
if (extrinsic.signer && (0, _utils.isSameAddress)(from, extrinsic.signer.toString()) && nonce === extrinsic.nonce.toNumber()) {
|
|
54
|
+
index = parseInt(idx);
|
|
55
|
+
found = true;
|
|
56
|
+
result.extrinsicHash = extrinsic.hash.toHex();
|
|
57
|
+
result.blockHash = block.block.hash.toHex();
|
|
58
|
+
result.blockNumber = block.block.header.number.toNumber();
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (index !== undefined) {
|
|
63
|
+
const allEvents = await api.query.system.events.at(blockHash);
|
|
64
|
+
const events = allEvents.filter(_ref => {
|
|
65
|
+
let {
|
|
66
|
+
phase
|
|
67
|
+
} = _ref;
|
|
68
|
+
return phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index);
|
|
69
|
+
});
|
|
70
|
+
for (const {
|
|
71
|
+
event
|
|
72
|
+
} of events) {
|
|
73
|
+
if (api.events.system.ExtrinsicSuccess.is(event)) {
|
|
74
|
+
return {
|
|
75
|
+
...result,
|
|
76
|
+
status: HistoryRecoverStatus.SUCCESS
|
|
77
|
+
};
|
|
78
|
+
} else if (api.events.system.ExtrinsicFailed.is(event)) {
|
|
79
|
+
return {
|
|
80
|
+
...result,
|
|
81
|
+
status: HistoryRecoverStatus.FAILED
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
const block = await api.rpc.chain.getBlock(blockHash);
|
|
89
|
+
const allEvents = await api.query.system.events.at(blockHash);
|
|
90
|
+
const extrinsics = block.block.extrinsics;
|
|
91
|
+
let index;
|
|
92
|
+
for (const [idx, extrinsic] of Object.entries(extrinsics)) {
|
|
93
|
+
if (extrinsicHash === extrinsic.hash.toHex()) {
|
|
94
|
+
index = parseInt(idx);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (index === undefined) {
|
|
99
|
+
console.log(`Fail to find extrinsic ${extrinsicHash} on ${chain}`);
|
|
100
|
+
return {
|
|
101
|
+
status: HistoryRecoverStatus.FAIL_DETECT
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const events = allEvents.filter(_ref2 => {
|
|
105
|
+
let {
|
|
106
|
+
phase
|
|
107
|
+
} = _ref2;
|
|
108
|
+
return phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index);
|
|
109
|
+
});
|
|
110
|
+
for (const {
|
|
111
|
+
event
|
|
112
|
+
} of events) {
|
|
113
|
+
if (api.events.system.ExtrinsicSuccess.is(event)) {
|
|
114
|
+
return {
|
|
115
|
+
...result,
|
|
116
|
+
status: HistoryRecoverStatus.SUCCESS
|
|
117
|
+
};
|
|
118
|
+
} else if (api.events.system.ExtrinsicFailed.is(event)) {
|
|
119
|
+
return {
|
|
120
|
+
...result,
|
|
121
|
+
status: HistoryRecoverStatus.FAILED
|
|
122
|
+
};
|
|
123
|
+
}
|
|
60
124
|
}
|
|
61
125
|
}
|
|
62
|
-
return
|
|
126
|
+
return {
|
|
127
|
+
status: HistoryRecoverStatus.FAIL_DETECT
|
|
128
|
+
};
|
|
63
129
|
} else {
|
|
64
130
|
console.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`);
|
|
65
|
-
return
|
|
131
|
+
return {
|
|
132
|
+
status: HistoryRecoverStatus.API_INACTIVE
|
|
133
|
+
};
|
|
66
134
|
}
|
|
67
135
|
} catch (e) {
|
|
68
136
|
console.error(`Fail to update history ${chain}-${extrinsicHash}:`, e.message);
|
|
69
|
-
return
|
|
137
|
+
return {
|
|
138
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
139
|
+
};
|
|
70
140
|
}
|
|
71
141
|
};
|
|
72
142
|
const evmRecover = async (history, chainService) => {
|
|
73
143
|
const {
|
|
144
|
+
address,
|
|
74
145
|
chain,
|
|
75
|
-
extrinsicHash
|
|
146
|
+
extrinsicHash,
|
|
147
|
+
from,
|
|
148
|
+
nonce,
|
|
149
|
+
startBlock
|
|
76
150
|
} = history;
|
|
151
|
+
const result = {
|
|
152
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
153
|
+
};
|
|
77
154
|
try {
|
|
78
155
|
const evmApi = chainService.getEvmApi(chain);
|
|
79
156
|
if (evmApi) {
|
|
80
157
|
const _api = await evmApi.isReady;
|
|
81
158
|
const api = _api.api;
|
|
82
|
-
|
|
83
|
-
|
|
159
|
+
if (extrinsicHash) {
|
|
160
|
+
const transactionReceipt = await api.eth.getTransactionReceipt(extrinsicHash);
|
|
161
|
+
return {
|
|
162
|
+
...result,
|
|
163
|
+
status: transactionReceipt.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED
|
|
164
|
+
};
|
|
165
|
+
} else {
|
|
166
|
+
if (!nonce || !startBlock) {
|
|
167
|
+
console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
|
|
168
|
+
return {
|
|
169
|
+
...result,
|
|
170
|
+
status: HistoryRecoverStatus.LACK_INFO
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const currentBlock = await api.eth.getBlockNumber();
|
|
174
|
+
for (let i = 1, found = false; i < BLOCK_LIMIT && !found && startBlock + i <= currentBlock; i++) {
|
|
175
|
+
const block = await api.eth.getBlock(startBlock + i, true);
|
|
176
|
+
for (const transaction of block.transactions) {
|
|
177
|
+
if ((0, _utils.isSameAddress)(transaction.from, from) && nonce === transaction.nonce) {
|
|
178
|
+
result.extrinsicHash = transaction.hash;
|
|
179
|
+
result.blockHash = block.hash;
|
|
180
|
+
result.blockNumber = block.number;
|
|
181
|
+
found = true;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (result.extrinsicHash) {
|
|
186
|
+
const transactionReceipt = await api.eth.getTransactionReceipt(result.extrinsicHash);
|
|
187
|
+
return {
|
|
188
|
+
...result,
|
|
189
|
+
status: transactionReceipt.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
status: HistoryRecoverStatus.FAIL_DETECT
|
|
196
|
+
};
|
|
84
197
|
} else {
|
|
85
198
|
console.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`);
|
|
86
|
-
return
|
|
199
|
+
return {
|
|
200
|
+
status: HistoryRecoverStatus.API_INACTIVE
|
|
201
|
+
};
|
|
87
202
|
}
|
|
88
203
|
} catch (e) {
|
|
89
204
|
console.error(`Fail to update history ${chain}-${extrinsicHash}:`, e.message);
|
|
90
|
-
return
|
|
205
|
+
return {
|
|
206
|
+
status: HistoryRecoverStatus.UNKNOWN
|
|
207
|
+
};
|
|
91
208
|
}
|
|
92
209
|
};
|
|
93
210
|
|
|
@@ -102,7 +219,9 @@ const historyRecover = async (history, chainService) => {
|
|
|
102
219
|
const checkFunction = chainType === 'substrate' ? substrateRecover : evmRecover;
|
|
103
220
|
return await checkFunction(history, chainService);
|
|
104
221
|
} else {
|
|
105
|
-
return
|
|
222
|
+
return {
|
|
223
|
+
status: HistoryRecoverStatus.LACK_INFO
|
|
224
|
+
};
|
|
106
225
|
}
|
|
107
226
|
};
|
|
108
227
|
exports.historyRecover = historyRecover;
|
|
@@ -17,7 +17,7 @@ var _subsquidMultiChainHistory = require("./subsquid-multi-chain-history");
|
|
|
17
17
|
|
|
18
18
|
class HistoryService {
|
|
19
19
|
historySubject = new _rxjs.BehaviorSubject([]);
|
|
20
|
-
#
|
|
20
|
+
#needRecoveryHistories = {};
|
|
21
21
|
constructor(dbService, chainService, eventService, keyringService) {
|
|
22
22
|
this.dbService = dbService;
|
|
23
23
|
this.chainService = chainService;
|
|
@@ -80,7 +80,7 @@ class HistoryService {
|
|
|
80
80
|
await this.addHistoryItems(updatedRecords);
|
|
81
81
|
}
|
|
82
82
|
async updateHistoryByExtrinsicHash(extrinsicHash, updateData) {
|
|
83
|
-
await this.dbService.
|
|
83
|
+
await this.dbService.updateHistoryByExtrinsicHash(extrinsicHash, updateData);
|
|
84
84
|
this.historySubject.next(await this.dbService.getHistories());
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -139,7 +139,7 @@ class HistoryService {
|
|
|
139
139
|
}
|
|
140
140
|
async recoverHistories() {
|
|
141
141
|
const list = [];
|
|
142
|
-
for (const processingHistory of Object.values(this.#
|
|
142
|
+
for (const processingHistory of Object.values(this.#needRecoveryHistories)) {
|
|
143
143
|
const chainState = this.chainService.getChainStateByKey(processingHistory.chain);
|
|
144
144
|
if (chainState.active) {
|
|
145
145
|
list.push(processingHistory);
|
|
@@ -149,24 +149,28 @@ class HistoryService {
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
const promises = list.map(history => (0, _recoverHistoryStatus.historyRecover)(history, this.chainService));
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
152
|
+
const results = await Promise.all(promises);
|
|
153
|
+
results.forEach((recoverResult, index) => {
|
|
154
|
+
const currentExtrinsicHash = list[index].extrinsicHash;
|
|
155
|
+
const updateData = {
|
|
156
|
+
...recoverResult,
|
|
157
|
+
status: _KoniTypes.ExtrinsicStatus.UNKNOWN
|
|
158
|
+
};
|
|
159
|
+
switch (recoverResult.status) {
|
|
156
160
|
case _recoverHistoryStatus.HistoryRecoverStatus.API_INACTIVE:
|
|
157
161
|
break;
|
|
158
162
|
case _recoverHistoryStatus.HistoryRecoverStatus.FAILED:
|
|
159
163
|
case _recoverHistoryStatus.HistoryRecoverStatus.SUCCESS:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
delete this.#processingHistories[extrinsicHash];
|
|
164
|
+
updateData.status = recoverResult.status === _recoverHistoryStatus.HistoryRecoverStatus.SUCCESS ? _KoniTypes.ExtrinsicStatus.SUCCESS : _KoniTypes.ExtrinsicStatus.FAIL;
|
|
165
|
+
this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
|
|
166
|
+
delete this.#needRecoveryHistories[currentExtrinsicHash];
|
|
164
167
|
break;
|
|
165
168
|
default:
|
|
166
|
-
|
|
169
|
+
this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
|
|
170
|
+
delete this.#needRecoveryHistories[currentExtrinsicHash];
|
|
167
171
|
}
|
|
168
172
|
});
|
|
169
|
-
if (!Object.keys(this.#
|
|
173
|
+
if (!Object.keys(this.#needRecoveryHistories).length) {
|
|
170
174
|
await this.stopRecoverHistories();
|
|
171
175
|
}
|
|
172
176
|
}
|
|
@@ -176,7 +180,7 @@ class HistoryService {
|
|
|
176
180
|
await this.loadData();
|
|
177
181
|
Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
|
|
178
182
|
this.getHistories().catch(console.log);
|
|
179
|
-
this.
|
|
183
|
+
this.recoverProcessingHistory().catch(console.error);
|
|
180
184
|
this.eventService.on('account.add', () => {
|
|
181
185
|
(async () => {
|
|
182
186
|
await this.stopCron();
|
|
@@ -189,14 +193,18 @@ class HistoryService {
|
|
|
189
193
|
}).catch(console.error);
|
|
190
194
|
this.status = _types.ServiceStatus.INITIALIZED;
|
|
191
195
|
}
|
|
192
|
-
async
|
|
196
|
+
async recoverProcessingHistory() {
|
|
193
197
|
const histories = await this.dbService.getHistories();
|
|
194
|
-
this.#
|
|
198
|
+
this.#needRecoveryHistories = {};
|
|
195
199
|
histories.filter(history => {
|
|
196
|
-
return history.status
|
|
200
|
+
return [_KoniTypes.ExtrinsicStatus.PROCESSING, _KoniTypes.ExtrinsicStatus.SUBMITTING].includes(history.status);
|
|
197
201
|
}).forEach(history => {
|
|
198
|
-
this.#
|
|
202
|
+
this.#needRecoveryHistories[history.extrinsicHash] = history;
|
|
199
203
|
});
|
|
204
|
+
const recoverNumber = Object.keys(this.#needRecoveryHistories).length;
|
|
205
|
+
if (recoverNumber > 0) {
|
|
206
|
+
console.log(`Recover ${recoverNumber} processing history`);
|
|
207
|
+
}
|
|
200
208
|
this.startRecoverHistories().catch(console.error);
|
|
201
209
|
}
|
|
202
210
|
async start() {
|
|
@@ -204,7 +212,6 @@ class HistoryService {
|
|
|
204
212
|
this.startPromiseHandler = (0, _promise.createPromiseHandler)();
|
|
205
213
|
this.status = _types.ServiceStatus.STARTING;
|
|
206
214
|
await this.startCron();
|
|
207
|
-
await this.startRecoverHistories();
|
|
208
215
|
this.status = _types.ServiceStatus.STARTED;
|
|
209
216
|
this.startPromiseHandler.resolve();
|
|
210
217
|
} catch (e) {
|
|
@@ -255,7 +255,7 @@ async function fetchMultiChainHistories(addresses, chainMap) {
|
|
|
255
255
|
const usedAddresses = relatedAddresses.filter(a => lowerAddresses.includes(a.toLowerCase()));
|
|
256
256
|
const chainInfo = chainMap[chainId];
|
|
257
257
|
if (chainInfo === undefined) {
|
|
258
|
-
console.
|
|
258
|
+
console.debug(`Not found chain info for chain id: ${chainId}`); // TODO: resolve conflicting chainId
|
|
259
259
|
|
|
260
260
|
return;
|
|
261
261
|
}
|
|
@@ -264,7 +264,7 @@ async function fetchMultiChainHistories(addresses, chainMap) {
|
|
|
264
264
|
const transactionData = parseSubsquidTransactionData(address, name, historyItem, chainInfo, parseData(args), parseData(_data));
|
|
265
265
|
histories.push(transactionData);
|
|
266
266
|
} catch (e) {
|
|
267
|
-
console.
|
|
267
|
+
console.debug('Parse transaction data failed', address, e);
|
|
268
268
|
}
|
|
269
269
|
});
|
|
270
270
|
});
|
|
@@ -120,7 +120,7 @@ class DatabaseService {
|
|
|
120
120
|
const cleanedHistory = histories.filter(x => x && x.address && x.chain && x.extrinsicHash);
|
|
121
121
|
return this.stores.transaction.bulkUpsert(cleanedHistory);
|
|
122
122
|
}
|
|
123
|
-
async
|
|
123
|
+
async updateHistoryByExtrinsicHash(extrinsicHash, updateData) {
|
|
124
124
|
const canUpdate = updateData && extrinsicHash;
|
|
125
125
|
if (!canUpdate) {
|
|
126
126
|
return;
|