@subwallet/extension-base 1.0.7-2 → 1.0.9-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 +3 -1
- package/background/KoniTypes.js +1 -0
- package/background/errors/TransactionError.js +5 -1
- package/cjs/background/KoniTypes.js +1 -0
- package/cjs/background/errors/TransactionError.js +4 -0
- package/cjs/constants/index.js +6 -3
- package/cjs/koni/api/dotsama/balance.js +5 -2
- package/cjs/koni/api/dotsama/crowdloan.js +1 -1
- package/cjs/koni/api/dotsama/transfer.js +19 -5
- package/cjs/koni/api/tokens/wasm/index.js +7 -0
- package/cjs/koni/api/xcm/polkadotXcm.js +18 -37
- package/cjs/koni/api/xcm/utils.js +78 -11
- package/cjs/koni/api/xcm/xTokens.js +4 -33
- package/cjs/koni/api/xcm/xcmPallet.js +4 -36
- package/cjs/koni/background/handlers/Extension.js +83 -25
- package/cjs/koni/background/handlers/State.js +1 -1
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/constants.js +9 -7
- package/cjs/services/chain-service/index.js +19 -15
- package/cjs/services/chain-service/utils.js +1 -5
- package/cjs/services/history-service/constants/index.js +13 -0
- package/cjs/services/history-service/subsquid-multi-chain-history.js +38 -3
- package/cjs/services/transaction-service/helpers/index.js +45 -2
- package/cjs/services/transaction-service/index.js +58 -24
- package/cjs/utils/eth/parseTransaction/index.js +69 -59
- package/cjs/utils/number.js +112 -0
- package/constants/index.d.ts +1 -0
- package/constants/index.js +1 -0
- package/koni/api/dotsama/balance.js +4 -2
- package/koni/api/dotsama/crowdloan.js +2 -2
- package/koni/api/dotsama/transfer.js +19 -5
- package/koni/api/tokens/wasm/index.js +7 -0
- package/koni/api/xcm/polkadotXcm.js +20 -39
- package/koni/api/xcm/utils.d.ts +36 -3
- package/koni/api/xcm/utils.js +72 -11
- package/koni/api/xcm/xTokens.js +6 -35
- package/koni/api/xcm/xcmPallet.js +5 -35
- package/koni/background/handlers/Extension.js +82 -24
- package/koni/background/handlers/State.js +2 -2
- package/package.json +18 -8
- package/packageInfo.js +1 -1
- package/services/chain-service/constants.d.ts +2 -0
- package/services/chain-service/constants.js +9 -7
- package/services/chain-service/index.js +13 -8
- package/services/chain-service/utils.d.ts +0 -1
- package/services/chain-service/utils.js +1 -4
- package/services/history-service/constants/index.d.ts +2 -0
- package/services/history-service/constants/index.js +5 -0
- package/services/history-service/subsquid-multi-chain-history.d.ts +1 -1
- package/services/history-service/subsquid-multi-chain-history.js +36 -3
- package/services/transaction-service/helpers/index.d.ts +2 -0
- package/services/transaction-service/helpers/index.js +42 -0
- package/services/transaction-service/index.js +54 -20
- package/services/transaction-service/types.d.ts +2 -2
- package/utils/eth/parseTransaction/index.js +69 -59
- package/utils/number.d.ts +9 -0
- package/utils/number.js +100 -0
|
@@ -22,11 +22,11 @@ export const _PURE_EVM_CHAINS = ['binance', 'binance_test', 'ethereum', 'ethereu
|
|
|
22
22
|
// Get balance----------------------------------------------------------------------------------------------------------
|
|
23
23
|
|
|
24
24
|
export const _BALANCE_CHAIN_GROUP = {
|
|
25
|
-
kintsugi: ['kintsugi', 'interlay', 'kintsugi_test'],
|
|
25
|
+
kintsugi: ['kintsugi', 'interlay', 'kintsugi_test', 'mangatax_para'],
|
|
26
26
|
genshiro: ['genshiro_testnet', 'genshiro'],
|
|
27
27
|
equilibrium_parachain: ['equilibrium_parachain'],
|
|
28
|
-
bifrost: ['bifrost', 'acala', 'karura', 'acala_testnet', 'pioneer', 'bitcountry'],
|
|
29
|
-
statemine: ['statemine', 'astar', 'shiden', 'statemint', 'moonbeam', 'moonbase', 'moonriver', 'crabParachain', 'darwinia2'],
|
|
28
|
+
bifrost: ['bifrost', 'acala', 'karura', 'acala_testnet', 'pioneer', 'bitcountry', 'bifrost_dot', 'hydradx_main'],
|
|
29
|
+
statemine: ['statemine', 'astar', 'shiden', 'statemint', 'moonbeam', 'moonbase', 'moonriver', 'crabParachain', 'darwinia2', 'parallel'],
|
|
30
30
|
kusama: ['kusama', 'kintsugi', 'kintsugi_test', 'interlay', 'acala', 'statemint', 'karura', 'bifrost'] // perhaps there are some runtime updates
|
|
31
31
|
};
|
|
32
32
|
|
|
@@ -176,11 +176,13 @@ export const _KNOWN_CHAIN_INFLATION_PARAMS = {
|
|
|
176
176
|
export const _TRANSFER_NOT_SUPPORTED_CHAINS = ['subspace_gemini_3a', 'kulupu', 'joystream', 'equilibrium_parachain', 'genshiro_testnet', 'genshiro'];
|
|
177
177
|
export const _TRANSFER_CHAIN_GROUP = {
|
|
178
178
|
acala: ['karura', 'acala', 'acala_testnet'],
|
|
179
|
-
kintsugi: ['kintsugi', 'kintsugi_test', 'interlay'],
|
|
179
|
+
kintsugi: ['kintsugi', 'kintsugi_test', 'interlay', 'bifrost_dot', 'hydradx_main', 'mangatax_para'],
|
|
180
180
|
genshiro: ['genshiro_testnet', 'genshiro', 'equilibrium_parachain'],
|
|
181
181
|
crab: ['crab', 'pangolin'],
|
|
182
|
-
bitcountry: ['pioneer', 'bitcountry'],
|
|
183
|
-
statemine: ['statemint', 'statemine', 'darwinia2']
|
|
182
|
+
bitcountry: ['pioneer', 'bitcountry', 'bifrost'],
|
|
183
|
+
statemine: ['statemint', 'statemine', 'darwinia2', 'astar', 'shiden', 'shibuya', 'parallel'],
|
|
184
|
+
riochain: ['riochain'],
|
|
185
|
+
sora_substrate: ['sora_substrate']
|
|
184
186
|
};
|
|
185
187
|
export const _BALANCE_PARSING_CHAIN_GROUP = {
|
|
186
188
|
bobabeam: ['bobabeam', 'bobabase']
|
|
@@ -189,7 +191,7 @@ export const _BALANCE_PARSING_CHAIN_GROUP = {
|
|
|
189
191
|
// XCM------------------------------------------------------------------------------------------------------------------
|
|
190
192
|
|
|
191
193
|
export const _XCM_CHAIN_GROUP = {
|
|
192
|
-
polkadotXcm: ['astar', 'shiden', 'statemine', 'statemint'],
|
|
194
|
+
polkadotXcm: ['astar', 'shiden', 'statemine', 'statemint', 'equilibrium_parachain'],
|
|
193
195
|
xcmPallet: ['polkadot', 'kusama']
|
|
194
196
|
// default is xTokens pallet
|
|
195
197
|
};
|
|
@@ -40,21 +40,25 @@ export class ChainService {
|
|
|
40
40
|
this.chainInfoMapSubject.next(this.dataMap.chainInfoMap);
|
|
41
41
|
this.chainStateMapSubject.next(this.dataMap.chainStateMap);
|
|
42
42
|
this.assetRegistrySubject.next(this.dataMap.assetRegistry);
|
|
43
|
-
this.xcmRefMapSubject.next(this.
|
|
43
|
+
this.xcmRefMapSubject.next(this.dataMap.assetRefMap);
|
|
44
44
|
this.logger = createLogger('chain-service');
|
|
45
45
|
this.refreshChainStateInterval(3000, 6);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Getter
|
|
49
49
|
getXcmRefMap() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
return this.dataMap.assetRefMap;
|
|
51
|
+
// const result: Record<string, _AssetRef> = {};
|
|
52
|
+
//
|
|
53
|
+
// Object.entries(AssetRefMap).forEach(([key, assetRef]) => {
|
|
54
|
+
// if (assetRef.path === _AssetRefPath.XCM) {
|
|
55
|
+
// result[key] = assetRef;
|
|
56
|
+
// }
|
|
57
|
+
// });
|
|
58
|
+
//
|
|
59
|
+
// return result;
|
|
57
60
|
}
|
|
61
|
+
|
|
58
62
|
getEvmApi(slug) {
|
|
59
63
|
return this.evmChainHandler.getEvmApiByChain(slug);
|
|
60
64
|
}
|
|
@@ -356,6 +360,7 @@ export class ChainService {
|
|
|
356
360
|
this.chainInfoMapSubject.next(this.getChainInfoMap());
|
|
357
361
|
this.chainStateMapSubject.next(this.getChainStateMap());
|
|
358
362
|
this.assetRegistrySubject.next(this.getAssetRegistry());
|
|
363
|
+
this.xcmRefMapSubject.next(this.dataMap.assetRefMap);
|
|
359
364
|
this.initApis();
|
|
360
365
|
await this.initAssetSettings();
|
|
361
366
|
}
|
|
@@ -26,7 +26,6 @@ export declare function _getSubstrateRelayParent(chainInfo: _ChainInfo): string;
|
|
|
26
26
|
export declare function _getSubstrateGenesisHash(chainInfo: _ChainInfo): string;
|
|
27
27
|
export declare function _isChainSupportSubstrateStaking(chainInfo: _ChainInfo): boolean;
|
|
28
28
|
export declare function _isChainEnabled(chainState: _ChainState): boolean;
|
|
29
|
-
export declare function _isSubstrateParachain(chainInfo: _ChainInfo): boolean;
|
|
30
29
|
export declare function _getChainSubstrateAddressPrefix(chainInfo: _ChainInfo): number;
|
|
31
30
|
export declare function _isChainSupportNativeNft(chainInfo: _ChainInfo): boolean;
|
|
32
31
|
export declare function _isChainSupportEvmNft(chainInfo: _ChainInfo): boolean;
|
|
@@ -130,9 +130,6 @@ export function _isChainSupportSubstrateStaking(chainInfo) {
|
|
|
130
130
|
export function _isChainEnabled(chainState) {
|
|
131
131
|
return chainState.active;
|
|
132
132
|
}
|
|
133
|
-
export function _isSubstrateParachain(chainInfo) {
|
|
134
|
-
return chainInfo.substrateInfo !== null && chainInfo.substrateInfo.paraId !== null;
|
|
135
|
-
}
|
|
136
133
|
export function _getChainSubstrateAddressPrefix(chainInfo) {
|
|
137
134
|
var _chainInfo$substrateI5, _chainInfo$substrateI6;
|
|
138
135
|
return (_chainInfo$substrateI5 = chainInfo === null || chainInfo === void 0 ? void 0 : (_chainInfo$substrateI6 = chainInfo.substrateInfo) === null || _chainInfo$substrateI6 === void 0 ? void 0 : _chainInfo$substrateI6.addressPrefix) !== null && _chainInfo$substrateI5 !== void 0 ? _chainInfo$substrateI5 : -1;
|
|
@@ -259,7 +256,7 @@ export function _isSubstrateRelayChain(chainInfo) {
|
|
|
259
256
|
}
|
|
260
257
|
export function _isSubstrateParaChain(chainInfo) {
|
|
261
258
|
var _chainInfo$substrateI11;
|
|
262
|
-
return ((_chainInfo$substrateI11 = chainInfo.substrateInfo) === null || _chainInfo$substrateI11 === void 0 ? void 0 : _chainInfo$substrateI11.chainType) === _SubstrateChainType.PARACHAIN;
|
|
259
|
+
return chainInfo.substrateInfo !== null && chainInfo.substrateInfo.paraId !== null && ((_chainInfo$substrateI11 = chainInfo.substrateInfo) === null || _chainInfo$substrateI11 === void 0 ? void 0 : _chainInfo$substrateI11.chainType) === _SubstrateChainType.PARACHAIN;
|
|
263
260
|
}
|
|
264
261
|
export function _getEvmAbiExplorer(chainInfo) {
|
|
265
262
|
var _chainInfo$evmInfo3;
|
|
@@ -27,4 +27,4 @@ export interface ParseInputType {
|
|
|
27
27
|
export declare type TransactionBasicData = Pick<TransactionHistoryItem, 'address' | 'origin' | 'time' | 'chainType' | 'from' | 'direction' | 'blockNumber' | 'blockHash' | 'chain' | 'data'>;
|
|
28
28
|
export declare type TransactionSpecifyType = Pick<TransactionHistoryItem, 'to' | 'type' | 'status' | 'fee' | 'amount' | 'tip' | 'signature' | 'extrinsicHash'>;
|
|
29
29
|
export declare function parseSubsquidTransactionData(address: string, type: SubsquidTransactionType, historyItem: MultiHistoryData, chainInfo: _ChainInfo, args: any, data: any): TransactionHistoryItem;
|
|
30
|
-
export declare function fetchMultiChainHistories(addresses: string[], chainMap: Record<string, _ChainInfo>, maxPage?: number): Promise<TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[]>;
|
|
30
|
+
export declare function fetchMultiChainHistories(addresses: string[], chainMap: Record<string, _ChainInfo>, maxPage?: number, countMap?: Record<string, number>, _lastId?: string): Promise<TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[]>;
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
import { ApolloClient, createHttpLink, gql, InMemoryCache } from '@apollo/client';
|
|
5
5
|
import { ChainType, ExtrinsicStatus, ExtrinsicType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
+
import { MAX_FETCH_PAGE_PER_SESSION, MIN__NUM_HISTORY_PER_ACCOUNT } from '@subwallet/extension-base/services/history-service/constants';
|
|
6
7
|
import fetch from 'cross-fetch';
|
|
8
|
+
import { isArray } from '@polkadot/util';
|
|
7
9
|
import { decodeAddress, encodeAddress, isEthereumAddress } from '@polkadot/util-crypto';
|
|
8
10
|
const MULTI_CHAIN_URL = 'https://squid.subsquid.io/multi-chain-tx/v/v1/graphql';
|
|
9
11
|
const MultiChainTxClient = new ApolloClient({
|
|
@@ -71,6 +73,17 @@ function generateSignature(input) {
|
|
|
71
73
|
const vHex = parseInt(v).toString(16);
|
|
72
74
|
return `0x${rHex}${sHex}${vHex}`;
|
|
73
75
|
}
|
|
76
|
+
const parseArgs = args => {
|
|
77
|
+
if (isArray(args)) {
|
|
78
|
+
return {
|
|
79
|
+
from: args[0],
|
|
80
|
+
to: args[1],
|
|
81
|
+
amount: args[2]
|
|
82
|
+
};
|
|
83
|
+
} else {
|
|
84
|
+
return args;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
74
87
|
export function parseSubsquidTransactionData(address, type, historyItem, chainInfo, args, data) {
|
|
75
88
|
var _chainInfo$substrateI, _chainInfo$evmInfo, _chainInfo$substrateI2, _chainInfo$evmInfo2;
|
|
76
89
|
const chainType = chainInfo.substrateInfo ? ChainType.SUBSTRATE : ChainType.EVM;
|
|
@@ -91,7 +104,7 @@ export function parseSubsquidTransactionData(address, type, historyItem, chainIn
|
|
|
91
104
|
{
|
|
92
105
|
transactionType = ExtrinsicType.TRANSFER_BALANCE;
|
|
93
106
|
const extrinsic = data.extrinsic;
|
|
94
|
-
const parsedArgs = args;
|
|
107
|
+
const parsedArgs = parseArgs(args);
|
|
95
108
|
to = autoFormatAddress(parsedArgs.to);
|
|
96
109
|
from = autoFormatAddress(parsedArgs.from);
|
|
97
110
|
amount = parsedArgs.amount;
|
|
@@ -196,10 +209,10 @@ export function parseSubsquidTransactionData(address, type, historyItem, chainIn
|
|
|
196
209
|
status: success ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL
|
|
197
210
|
};
|
|
198
211
|
}
|
|
199
|
-
export async function fetchMultiChainHistories(addresses, chainMap, maxPage =
|
|
212
|
+
export async function fetchMultiChainHistories(addresses, chainMap, maxPage = MAX_FETCH_PAGE_PER_SESSION, countMap = {}, _lastId) {
|
|
200
213
|
const responseData = [];
|
|
201
214
|
let currentPage = 0;
|
|
202
|
-
let lastId;
|
|
215
|
+
let lastId = _lastId;
|
|
203
216
|
while (true) {
|
|
204
217
|
try {
|
|
205
218
|
if (maxPage) {
|
|
@@ -228,6 +241,9 @@ export async function fetchMultiChainHistories(addresses, chainMap, maxPage = 25
|
|
|
228
241
|
}
|
|
229
242
|
const histories = [];
|
|
230
243
|
const lowerAddresses = addresses.map(a => a.toLowerCase());
|
|
244
|
+
for (const lowerAddress of lowerAddresses) {
|
|
245
|
+
countMap[lowerAddress] = countMap[lowerAddress] || 0;
|
|
246
|
+
}
|
|
231
247
|
responseData.forEach(historyItem => {
|
|
232
248
|
const {
|
|
233
249
|
_data,
|
|
@@ -248,6 +264,10 @@ export async function fetchMultiChainHistories(addresses, chainMap, maxPage = 25
|
|
|
248
264
|
|
|
249
265
|
return;
|
|
250
266
|
}
|
|
267
|
+
usedAddresses.forEach(address => {
|
|
268
|
+
const adr = address.toLowerCase();
|
|
269
|
+
countMap[adr] = (countMap[adr] || 0) + 1;
|
|
270
|
+
});
|
|
251
271
|
usedAddresses.forEach(address => {
|
|
252
272
|
try {
|
|
253
273
|
const transactionData = parseSubsquidTransactionData(address, name, historyItem, chainInfo, parseData(args), parseData(_data));
|
|
@@ -257,5 +277,18 @@ export async function fetchMultiChainHistories(addresses, chainMap, maxPage = 25
|
|
|
257
277
|
}
|
|
258
278
|
});
|
|
259
279
|
});
|
|
280
|
+
if (currentPage > 1) {
|
|
281
|
+
const retryAddresses = [];
|
|
282
|
+
for (const [address, number] of Object.entries(countMap)) {
|
|
283
|
+
if (number < MIN__NUM_HISTORY_PER_ACCOUNT) {
|
|
284
|
+
retryAddresses.push(address);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const _addresses = addresses.filter(add => retryAddresses.includes(add.toLowerCase()));
|
|
288
|
+
if (_addresses.length > 0) {
|
|
289
|
+
const retryHistories = await fetchMultiChainHistories(_addresses, chainMap, maxPage, countMap, lastId);
|
|
290
|
+
histories.push(...retryHistories);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
260
293
|
return histories;
|
|
261
294
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
1
2
|
import { SWTransaction } from '@subwallet/extension-base/services/transaction-service/types';
|
|
2
3
|
import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
|
|
3
4
|
export declare const getTransactionId: (chainType: string, chain: string, isInternal: boolean) => string;
|
|
4
5
|
export declare const getValidationId: (chainType: string, chain: string) => string;
|
|
5
6
|
export declare const isSubstrateTransaction: (tx: SWTransaction['transaction']) => tx is SubmittableExtrinsic;
|
|
7
|
+
export declare const getBaseTransactionInfo: (transaction: SWTransaction, chainInfoMap: Record<string, _ChainInfo>) => string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright 2019-2022 @subwallet/extension-base authors & contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
4
5
|
let transactionCount = 0;
|
|
5
6
|
let validationCount = 0;
|
|
6
7
|
export const getTransactionId = (chainType, chain, isInternal) => {
|
|
@@ -11,4 +12,45 @@ export const getValidationId = (chainType, chain) => {
|
|
|
11
12
|
};
|
|
12
13
|
export const isSubstrateTransaction = tx => {
|
|
13
14
|
return !!tx.send;
|
|
15
|
+
};
|
|
16
|
+
const typeName = type => {
|
|
17
|
+
switch (type) {
|
|
18
|
+
case ExtrinsicType.TRANSFER_BALANCE:
|
|
19
|
+
case ExtrinsicType.TRANSFER_TOKEN:
|
|
20
|
+
case ExtrinsicType.TRANSFER_XCM:
|
|
21
|
+
return 'Transfer';
|
|
22
|
+
case ExtrinsicType.SEND_NFT:
|
|
23
|
+
return 'Send NFT';
|
|
24
|
+
case ExtrinsicType.CROWDLOAN:
|
|
25
|
+
return 'Crowdloan contribution';
|
|
26
|
+
case ExtrinsicType.STAKING_JOIN_POOL:
|
|
27
|
+
return 'Join pool';
|
|
28
|
+
case ExtrinsicType.STAKING_LEAVE_POOL:
|
|
29
|
+
return 'Leave pool';
|
|
30
|
+
case ExtrinsicType.STAKING_BOND:
|
|
31
|
+
return 'Bond';
|
|
32
|
+
case ExtrinsicType.STAKING_UNBOND:
|
|
33
|
+
return 'Unbond';
|
|
34
|
+
case ExtrinsicType.STAKING_CLAIM_REWARD:
|
|
35
|
+
return 'Claim reward';
|
|
36
|
+
case ExtrinsicType.STAKING_WITHDRAW:
|
|
37
|
+
return 'Withdraw';
|
|
38
|
+
case ExtrinsicType.STAKING_CANCEL_UNSTAKE:
|
|
39
|
+
return 'Cancel unstake';
|
|
40
|
+
case ExtrinsicType.STAKING_COMPOUNDING:
|
|
41
|
+
return 'Stake compound';
|
|
42
|
+
case ExtrinsicType.EVM_EXECUTE:
|
|
43
|
+
return 'EVM execute';
|
|
44
|
+
case ExtrinsicType.STAKING_CANCEL_COMPOUNDING:
|
|
45
|
+
return 'Cancel compounding';
|
|
46
|
+
case ExtrinsicType.STAKING_POOL_WITHDRAW:
|
|
47
|
+
return 'Withdraw pool';
|
|
48
|
+
case ExtrinsicType.UNKNOWN:
|
|
49
|
+
default:
|
|
50
|
+
return 'unknown';
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
export const getBaseTransactionInfo = (transaction, chainInfoMap) => {
|
|
54
|
+
var _chainInfoMap$transac;
|
|
55
|
+
return `${typeName(transaction.extrinsicType)} on ${((_chainInfoMap$transac = chainInfoMap[transaction.chain]) === null || _chainInfoMap$transac === void 0 ? void 0 : _chainInfoMap$transac.name) || 'unknown network'}`;
|
|
14
56
|
};
|
|
@@ -6,11 +6,12 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr
|
|
|
6
6
|
import { BasicTxErrorType, BasicTxWarningCode, ChainType, EvmProviderErrorType, ExtrinsicStatus, ExtrinsicType, NotificationType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
|
|
7
7
|
import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning';
|
|
8
8
|
import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
|
|
9
|
+
import { _TRANSFER_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
9
10
|
import { _getChainNativeTokenBasicInfo, _getEvmChainId } from '@subwallet/extension-base/services/chain-service/utils';
|
|
10
11
|
import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants';
|
|
11
12
|
import { TRANSACTION_TIMEOUT } from '@subwallet/extension-base/services/transaction-service/constants';
|
|
12
13
|
import { parseTransferEventLogs, parseXcmEventLogs } from '@subwallet/extension-base/services/transaction-service/event-parser';
|
|
13
|
-
import { getTransactionId, isSubstrateTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
|
|
14
|
+
import { getBaseTransactionInfo, getTransactionId, isSubstrateTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
|
|
14
15
|
import { getExplorerLink, parseTransactionData } from '@subwallet/extension-base/services/transaction-service/utils';
|
|
15
16
|
import { anyNumberToBN } from '@subwallet/extension-base/utils/eth';
|
|
16
17
|
import { parseTxAndSignature } from '@subwallet/extension-base/utils/eth/mergeTransactionAndSignature';
|
|
@@ -19,7 +20,7 @@ import keyring from '@subwallet/ui-keyring';
|
|
|
19
20
|
import EventEmitter from 'eventemitter3';
|
|
20
21
|
import RLP from 'rlp';
|
|
21
22
|
import { BehaviorSubject } from 'rxjs';
|
|
22
|
-
import { u8aToHex } from '@polkadot/util';
|
|
23
|
+
import { isHex, u8aToHex } from '@polkadot/util';
|
|
23
24
|
export default class TransactionService {
|
|
24
25
|
transactionSubject = new BehaviorSubject({});
|
|
25
26
|
get transactions() {
|
|
@@ -109,6 +110,10 @@ export default class TransactionService {
|
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
} catch (e) {
|
|
113
|
+
const error = e;
|
|
114
|
+
if (error.message.includes('gas required exceeds allowance')) {
|
|
115
|
+
validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
|
|
116
|
+
}
|
|
112
117
|
estimateFee.value = '0';
|
|
113
118
|
}
|
|
114
119
|
}
|
|
@@ -135,16 +140,22 @@ export default class TransactionService {
|
|
|
135
140
|
const balanceNum = parseInt(balance.value);
|
|
136
141
|
const edNum = parseInt(existentialDeposit);
|
|
137
142
|
const transferNativeNum = parseInt(transferNative);
|
|
138
|
-
if (
|
|
139
|
-
if (
|
|
143
|
+
if (transferNativeNum + feeNum > balanceNum) {
|
|
144
|
+
if (!isTransferAll) {
|
|
140
145
|
validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
|
|
141
146
|
} else {
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
if ([..._TRANSFER_CHAIN_GROUP.acala, ..._TRANSFER_CHAIN_GROUP.genshiro, ..._TRANSFER_CHAIN_GROUP.bitcountry, ..._TRANSFER_CHAIN_GROUP.statemine].includes(chain)) {
|
|
148
|
+
// Chain not have transfer all function
|
|
149
|
+
validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (!isTransferAll) {
|
|
154
|
+
if (balanceNum - (transferNativeNum + feeNum) < edNum) {
|
|
155
|
+
if (edAsWarning) {
|
|
156
|
+
validationResponse.warnings.push(new TransactionWarning(BasicTxWarningCode.NOT_ENOUGH_EXISTENTIAL_DEPOSIT, ''));
|
|
157
|
+
} else {
|
|
158
|
+
validationResponse.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_EXISTENTIAL_DEPOSIT, ''));
|
|
148
159
|
}
|
|
149
160
|
}
|
|
150
161
|
}
|
|
@@ -206,6 +217,7 @@ export default class TransactionService {
|
|
|
206
217
|
// @ts-ignore
|
|
207
218
|
'transaction' in validatedTransaction && delete validatedTransaction.transaction;
|
|
208
219
|
'additionalValidator' in validatedTransaction && delete validatedTransaction.additionalValidator;
|
|
220
|
+
'eventsHandler' in validatedTransaction && delete validatedTransaction.eventsHandler;
|
|
209
221
|
return validatedTransaction;
|
|
210
222
|
}
|
|
211
223
|
validatedTransaction.warnings = [];
|
|
@@ -227,11 +239,15 @@ export default class TransactionService {
|
|
|
227
239
|
// @ts-ignore
|
|
228
240
|
'transaction' in validatedTransaction && delete validatedTransaction.transaction;
|
|
229
241
|
'additionalValidator' in validatedTransaction && delete validatedTransaction.additionalValidator;
|
|
242
|
+
'eventsHandler' in validatedTransaction && delete validatedTransaction.eventsHandler;
|
|
230
243
|
return validatedTransaction;
|
|
231
244
|
}
|
|
232
245
|
async sendTransaction(transaction) {
|
|
233
246
|
// Send Transaction
|
|
234
247
|
const emitter = transaction.chainType === 'substrate' ? this.signAndSendSubstrateTransaction(transaction) : await this.signAndSendEvmTransaction(transaction);
|
|
248
|
+
const {
|
|
249
|
+
eventsHandler
|
|
250
|
+
} = transaction;
|
|
235
251
|
emitter.on('signed', data => {
|
|
236
252
|
this.onSigned(data);
|
|
237
253
|
});
|
|
@@ -255,6 +271,7 @@ export default class TransactionService {
|
|
|
255
271
|
|
|
256
272
|
// Todo: handle any event with transaction.eventsHandler
|
|
257
273
|
|
|
274
|
+
eventsHandler === null || eventsHandler === void 0 ? void 0 : eventsHandler(emitter);
|
|
258
275
|
return emitter;
|
|
259
276
|
}
|
|
260
277
|
removeTransaction(id) {
|
|
@@ -281,6 +298,7 @@ export default class TransactionService {
|
|
|
281
298
|
}
|
|
282
299
|
transactionToHistories(id, startBlock, nonce, eventLogs) {
|
|
283
300
|
const transaction = this.getTransaction(id);
|
|
301
|
+
const extrinsicType = transaction.extrinsicType;
|
|
284
302
|
const historyItem = {
|
|
285
303
|
origin: 'app',
|
|
286
304
|
chain: transaction.chain,
|
|
@@ -311,7 +329,7 @@ export default class TransactionService {
|
|
|
311
329
|
};
|
|
312
330
|
|
|
313
331
|
// Fill data by extrinsicType
|
|
314
|
-
switch (
|
|
332
|
+
switch (extrinsicType) {
|
|
315
333
|
case ExtrinsicType.TRANSFER_BALANCE:
|
|
316
334
|
{
|
|
317
335
|
const inputData = parseTransactionData(transaction.data);
|
|
@@ -350,9 +368,10 @@ export default class TransactionService {
|
|
|
350
368
|
};
|
|
351
369
|
|
|
352
370
|
// @ts-ignore
|
|
353
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
354
371
|
historyItem.additionalInfo = {
|
|
355
|
-
destinationChain: (inputData === null || inputData === void 0 ? void 0 : inputData.destinationNetworkKey) || ''
|
|
372
|
+
destinationChain: (inputData === null || inputData === void 0 ? void 0 : inputData.destinationNetworkKey) || '',
|
|
373
|
+
originalChain: inputData.originNetworkKey || '',
|
|
374
|
+
fee: transaction.estimateFee
|
|
356
375
|
};
|
|
357
376
|
eventLogs && parseXcmEventLogs(historyItem, eventLogs, transaction.chain, sendingTokenInfo, chainInfo);
|
|
358
377
|
}
|
|
@@ -451,11 +470,22 @@ export default class TransactionService {
|
|
|
451
470
|
// Return one more history record if transaction send to account in the wallets
|
|
452
471
|
const toAccount = (historyItem === null || historyItem === void 0 ? void 0 : historyItem.to) && keyring.getPair(historyItem.to);
|
|
453
472
|
if (toAccount) {
|
|
454
|
-
|
|
473
|
+
const receiverHistory = {
|
|
455
474
|
...historyItem,
|
|
456
475
|
address: toAccount.address,
|
|
457
476
|
direction: TransactionDirection.RECEIVED
|
|
458
|
-
}
|
|
477
|
+
};
|
|
478
|
+
switch (extrinsicType) {
|
|
479
|
+
case ExtrinsicType.TRANSFER_XCM:
|
|
480
|
+
{
|
|
481
|
+
const inputData = parseTransactionData(transaction.data);
|
|
482
|
+
receiverHistory.chain = inputData.destinationNetworkKey;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
default:
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
return [historyItem, receiverHistory];
|
|
459
489
|
}
|
|
460
490
|
} catch (e) {
|
|
461
491
|
console.warn(e);
|
|
@@ -543,10 +573,11 @@ export default class TransactionService {
|
|
|
543
573
|
blockNumber: blockNumber || 0,
|
|
544
574
|
blockHash: blockHash || ''
|
|
545
575
|
}).catch(console.error);
|
|
576
|
+
const info = isHex(extrinsicHash) ? extrinsicHash : getBaseTransactionInfo(transaction, this.chainService.getChainInfoMap());
|
|
546
577
|
this.notificationService.notify({
|
|
547
578
|
type: NotificationType.SUCCESS,
|
|
548
579
|
title: 'Transaction completed',
|
|
549
|
-
message: `Transaction ${
|
|
580
|
+
message: `Transaction ${info} completed`,
|
|
550
581
|
action: {
|
|
551
582
|
url: this.getTransactionLink(id)
|
|
552
583
|
},
|
|
@@ -577,10 +608,11 @@ export default class TransactionService {
|
|
|
577
608
|
blockNumber: blockNumber || 0,
|
|
578
609
|
blockHash: blockHash || ''
|
|
579
610
|
}).catch(console.error);
|
|
611
|
+
const info = isHex(transaction === null || transaction === void 0 ? void 0 : transaction.extrinsicHash) ? transaction === null || transaction === void 0 ? void 0 : transaction.extrinsicHash : getBaseTransactionInfo(transaction, this.chainService.getChainInfoMap());
|
|
580
612
|
this.notificationService.notify({
|
|
581
613
|
type: NotificationType.ERROR,
|
|
582
614
|
title: 'Transaction failed',
|
|
583
|
-
message: `Transaction ${
|
|
615
|
+
message: `Transaction ${info} failed`,
|
|
584
616
|
action: {
|
|
585
617
|
url: this.getTransactionLink(id)
|
|
586
618
|
},
|
|
@@ -674,7 +706,8 @@ export default class TransactionService {
|
|
|
674
706
|
const eventData = {
|
|
675
707
|
id,
|
|
676
708
|
errors: [],
|
|
677
|
-
warnings: []
|
|
709
|
+
warnings: [],
|
|
710
|
+
extrinsicHash: id
|
|
678
711
|
};
|
|
679
712
|
this.requestService.addConfirmation(id, url || EXTENSION_REQUEST_URL, 'evmSendTransactionRequest', payload, {}).then(async ({
|
|
680
713
|
isApproved,
|
|
@@ -745,7 +778,8 @@ export default class TransactionService {
|
|
|
745
778
|
const eventData = {
|
|
746
779
|
id,
|
|
747
780
|
errors: [],
|
|
748
|
-
warnings: []
|
|
781
|
+
warnings: [],
|
|
782
|
+
extrinsicHash: id
|
|
749
783
|
};
|
|
750
784
|
transaction.signAsync(address, {
|
|
751
785
|
signer: {
|
|
@@ -775,7 +809,7 @@ export default class TransactionService {
|
|
|
775
809
|
}
|
|
776
810
|
if (txState.status.isInBlock) {
|
|
777
811
|
eventData.eventLogs = txState.events;
|
|
778
|
-
if (!eventData.extrinsicHash || eventData.extrinsicHash === '') {
|
|
812
|
+
if (!eventData.extrinsicHash || eventData.extrinsicHash === '' || !isHex(eventData.extrinsicHash)) {
|
|
779
813
|
eventData.extrinsicHash = txState.txHash.toHex();
|
|
780
814
|
eventData.blockHash = txState.status.asInBlock.toHex();
|
|
781
815
|
emitter.emit('extrinsicHash', eventData);
|
|
@@ -21,8 +21,8 @@ export interface SWTransaction extends ValidateTransactionResponse, Partial<Pick
|
|
|
21
21
|
additionalValidator?: (inputTransaction: SWTransactionResponse) => Promise<void>;
|
|
22
22
|
eventsHandler?: (eventEmitter: TransactionEmitter) => void;
|
|
23
23
|
}
|
|
24
|
-
export declare type SWTransactionResult = Omit<SWTransaction, 'transaction' | 'additionalValidator'>;
|
|
25
|
-
declare type SwInputBase = Pick<SWTransaction, 'address' | 'url' | 'data' | 'extrinsicType' | 'chain' | 'chainType' | 'ignoreWarnings' | 'transferNativeAmount'> & Partial<Pick<SWTransaction, 'additionalValidator'>>;
|
|
24
|
+
export declare type SWTransactionResult = Omit<SWTransaction, 'transaction' | 'additionalValidator' | 'eventsHandler'>;
|
|
25
|
+
declare type SwInputBase = Pick<SWTransaction, 'address' | 'url' | 'data' | 'extrinsicType' | 'chain' | 'chainType' | 'ignoreWarnings' | 'transferNativeAmount'> & Partial<Pick<SWTransaction, 'additionalValidator' | 'eventsHandler'>>;
|
|
26
26
|
export interface SWTransactionInput extends SwInputBase {
|
|
27
27
|
transaction?: SWTransaction['transaction'] | null;
|
|
28
28
|
warnings?: SWTransaction['warnings'];
|
|
@@ -100,44 +100,59 @@ export const isContractAddress = async (address, evmApi) => {
|
|
|
100
100
|
return code !== '0x';
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
|
+
const parseInputWithAbi = (input, abi) => {
|
|
104
|
+
const decoder = new InputDataDecoder(abi);
|
|
105
|
+
const raw = decoder.decodeData(input);
|
|
106
|
+
if (raw.method && raw.methodName) {
|
|
107
|
+
const temp = {
|
|
108
|
+
method: raw.method,
|
|
109
|
+
methodName: raw.methodName,
|
|
110
|
+
args: []
|
|
111
|
+
};
|
|
112
|
+
raw.types.forEach((type, index) => {
|
|
113
|
+
temp.args.push(parseResult(type, raw.inputs[index], raw.names[index]));
|
|
114
|
+
});
|
|
115
|
+
return temp;
|
|
116
|
+
} else {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
103
120
|
export const parseContractInput = async (input, contractAddress, network) => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
for (const abi of ABIs) {
|
|
122
|
+
const temp = parseInputWithAbi(input, abi);
|
|
123
|
+
if (temp) {
|
|
124
|
+
return {
|
|
125
|
+
result: temp
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
108
129
|
if (contractAddress && network) {
|
|
130
|
+
console.log('parseOnline');
|
|
109
131
|
if (_getEvmAbiExplorer(network)) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
132
|
+
try {
|
|
133
|
+
const res = await axios.get(_getEvmAbiExplorer(network), {
|
|
134
|
+
params: {
|
|
135
|
+
address: contractAddress
|
|
136
|
+
},
|
|
137
|
+
timeout: 3000
|
|
138
|
+
});
|
|
115
139
|
|
|
116
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
117
|
-
if (res.status === 200 && res.data.status === '1') {
|
|
118
140
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
args: []
|
|
131
|
-
};
|
|
132
|
-
raw.types.forEach((type, index) => {
|
|
133
|
-
temp.args.push(parseResult(type, raw.inputs[index], raw.names[index]));
|
|
134
|
-
});
|
|
135
|
-
result = temp;
|
|
136
|
-
break;
|
|
141
|
+
if (res.status === 200 && res.data.status === '1') {
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
|
|
143
|
+
const abi = res.data.result;
|
|
144
|
+
const temp = parseInputWithAbi(input, abi);
|
|
145
|
+
if (temp) {
|
|
146
|
+
return {
|
|
147
|
+
result: temp
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} catch (e) {}
|
|
137
152
|
}
|
|
138
153
|
}
|
|
139
154
|
return {
|
|
140
|
-
result
|
|
155
|
+
result: input
|
|
141
156
|
};
|
|
142
157
|
};
|
|
143
158
|
const getChainInfoByChainId = (networkMap, chainId) => {
|
|
@@ -179,42 +194,37 @@ export const parseEvmRlp = async (data, networkMap, evmApiMap) => {
|
|
|
179
194
|
nonce: new BigN(tx.nonce).toNumber()
|
|
180
195
|
};
|
|
181
196
|
const network = getChainInfoByChainId(networkMap, parseInt(tx.ethereumChainId));
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
197
|
+
for (const abi of ABIs) {
|
|
198
|
+
const temp = parseInputWithAbi(tx.data, abi);
|
|
199
|
+
if (temp) {
|
|
200
|
+
result.data = temp;
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
185
204
|
if (tx.action && network) {
|
|
186
205
|
if (await isContractAddress(tx.action, evmApiMap[network.slug])) {
|
|
187
206
|
if (_getEvmAbiExplorer(network) !== '') {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
207
|
+
try {
|
|
208
|
+
const res = await axios.get(_getEvmAbiExplorer(network), {
|
|
209
|
+
params: {
|
|
210
|
+
address: tx.action
|
|
211
|
+
},
|
|
212
|
+
timeout: 2000
|
|
213
|
+
});
|
|
193
214
|
|
|
194
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
195
|
-
if (res.status === 200 && res.data.status === '1') {
|
|
196
215
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
197
|
-
|
|
198
|
-
|
|
216
|
+
if (res.status === 200 && res.data.status === '1') {
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
|
|
218
|
+
const abi = res.data.result;
|
|
219
|
+
const temp = parseInputWithAbi(tx.data, abi);
|
|
220
|
+
if (temp) {
|
|
221
|
+
result.data = temp;
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} catch (e) {}
|
|
199
226
|
}
|
|
200
227
|
}
|
|
201
228
|
}
|
|
202
|
-
for (const abi of _ABIs) {
|
|
203
|
-
const decoder = new InputDataDecoder(abi);
|
|
204
|
-
const raw = decoder.decodeData(tx.data);
|
|
205
|
-
if (raw.method && raw.methodName) {
|
|
206
|
-
const temp = {
|
|
207
|
-
method: raw.method,
|
|
208
|
-
methodName: raw.methodName,
|
|
209
|
-
args: []
|
|
210
|
-
};
|
|
211
|
-
raw.types.forEach((type, index) => {
|
|
212
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
|
|
213
|
-
temp.args.push(parseResult(type, raw.inputs[index], raw.names[index]));
|
|
214
|
-
});
|
|
215
|
-
result.data = temp;
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
229
|
return result;
|
|
220
230
|
};
|