@subwallet/extension-base 1.3.73-0 → 1.3.74-1
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 +42 -5
- package/background/KoniTypes.js +14 -1
- package/cjs/background/KoniTypes.js +16 -2
- package/cjs/core/logic-validation/transfer.js +35 -57
- package/cjs/koni/background/handlers/Extension.js +599 -144
- package/cjs/koni/background/handlers/State.js +5 -2
- package/cjs/koni/background/handlers/Tabs.js +3 -2
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +0 -2
- package/cjs/services/chain-service/handler/SubstrateApi.js +6 -1
- package/cjs/services/chain-service/index.js +1 -0
- package/cjs/services/chain-service/utils/index.js +4 -0
- package/cjs/services/event-service/index.js +1 -0
- package/cjs/services/fee-service/utils/index.js +4 -4
- package/cjs/services/inapp-notification-service/consts.js +4 -2
- package/cjs/services/inapp-notification-service/index.js +51 -6
- package/cjs/services/inapp-notification-service/interfaces.js +2 -0
- package/cjs/services/inapp-notification-service/utils/common.js +4 -0
- package/cjs/services/keyring-service/context/account-context.js +44 -0
- package/cjs/services/keyring-service/context/handlers/Multisig.js +186 -0
- package/cjs/services/keyring-service/context/state.js +12 -0
- package/cjs/services/multisig-service/index.js +627 -0
- package/cjs/services/multisig-service/utils.js +242 -0
- package/cjs/services/request-service/handler/SubstrateRequestHandler.js +25 -0
- package/cjs/services/request-service/index.js +5 -1
- package/cjs/services/storage-service/DatabaseService.js +5 -2
- package/cjs/services/storage-service/db-stores/InappNotification.js +20 -2
- package/cjs/services/substrate-proxy-service/index.js +22 -7
- package/cjs/services/transaction-service/helpers/index.js +8 -0
- package/cjs/services/transaction-service/index.js +348 -147
- package/cjs/services/transaction-service/types.js +18 -1
- package/cjs/types/account/info/keyring.js +5 -0
- package/cjs/types/account/info/proxy.js +1 -0
- package/cjs/types/multisig/index.js +14 -0
- package/cjs/types/transaction/error.js +9 -2
- package/cjs/utils/account/transform.js +28 -4
- package/cjs/utils/logger/Logger.js +294 -0
- package/cjs/utils/logger/index.js +42 -0
- package/cjs/utils/logger/types.js +1 -0
- package/core/logic-validation/transfer.d.ts +2 -2
- package/core/logic-validation/transfer.js +10 -32
- package/koni/background/handlers/Extension.d.ts +7 -0
- package/koni/background/handlers/Extension.js +498 -43
- package/koni/background/handlers/State.d.ts +2 -0
- package/koni/background/handlers/State.js +5 -2
- package/koni/background/handlers/Tabs.js +3 -2
- package/package.json +42 -6
- package/packageInfo.js +1 -1
- package/services/balance-service/helpers/subscribe/substrate/index.js +0 -2
- package/services/chain-service/handler/SubstrateApi.js +7 -2
- package/services/chain-service/index.js +1 -0
- package/services/chain-service/types.d.ts +1 -1
- package/services/chain-service/utils/index.js +4 -0
- package/services/event-service/index.d.ts +1 -0
- package/services/event-service/index.js +1 -0
- package/services/event-service/types.d.ts +1 -0
- package/services/fee-service/utils/index.js +4 -4
- package/services/inapp-notification-service/consts.d.ts +3 -1
- package/services/inapp-notification-service/consts.js +5 -3
- package/services/inapp-notification-service/index.d.ts +3 -2
- package/services/inapp-notification-service/index.js +51 -6
- package/services/inapp-notification-service/interfaces.d.ts +18 -2
- package/services/inapp-notification-service/interfaces.js +2 -0
- package/services/inapp-notification-service/utils/common.d.ts +1 -0
- package/services/inapp-notification-service/utils/common.js +3 -0
- package/services/keyring-service/context/account-context.d.ts +9 -1
- package/services/keyring-service/context/account-context.js +44 -0
- package/services/keyring-service/context/handlers/Multisig.d.ts +18 -0
- package/services/keyring-service/context/handlers/Multisig.js +180 -0
- package/services/keyring-service/context/state.d.ts +2 -0
- package/services/keyring-service/context/state.js +12 -0
- package/services/multisig-service/index.d.ts +245 -0
- package/services/multisig-service/index.js +620 -0
- package/services/multisig-service/utils.d.ts +95 -0
- package/services/multisig-service/utils.js +227 -0
- package/services/request-service/handler/SubstrateRequestHandler.d.ts +1 -0
- package/services/request-service/handler/SubstrateRequestHandler.js +25 -0
- package/services/request-service/index.d.ts +2 -1
- package/services/request-service/index.js +5 -1
- package/services/storage-service/DatabaseService.d.ts +3 -2
- package/services/storage-service/DatabaseService.js +5 -2
- package/services/storage-service/db-stores/InappNotification.d.ts +3 -2
- package/services/storage-service/db-stores/InappNotification.js +20 -2
- package/services/substrate-proxy-service/index.d.ts +4 -1
- package/services/substrate-proxy-service/index.js +22 -8
- package/services/transaction-service/helpers/index.js +8 -0
- package/services/transaction-service/index.d.ts +31 -0
- package/services/transaction-service/index.js +270 -69
- package/services/transaction-service/types.d.ts +28 -3
- package/services/transaction-service/types.js +12 -1
- package/types/account/info/keyring.d.ts +14 -1
- package/types/account/info/keyring.js +6 -0
- package/types/account/info/proxy.d.ts +1 -0
- package/types/account/info/proxy.js +1 -0
- package/types/multisig/index.d.ts +76 -0
- package/types/multisig/index.js +8 -0
- package/types/notification/index.d.ts +8 -0
- package/types/substrateProxyAccount/index.d.ts +26 -1
- package/types/transaction/error.d.ts +6 -1
- package/types/transaction/error.js +7 -1
- package/types/transaction/request.d.ts +0 -1
- package/utils/account/transform.js +28 -4
- package/utils/logger/Logger.d.ts +31 -0
- package/utils/logger/Logger.js +267 -0
- package/utils/logger/index.d.ts +15 -0
- package/utils/logger/index.js +29 -0
- package/utils/logger/types.d.ts +23 -0
- package/utils/logger/types.js +1 -0
|
@@ -11,6 +11,7 @@ export default class TransactionService {
|
|
|
11
11
|
private aliveProcessMap;
|
|
12
12
|
private readonly transactionSubject;
|
|
13
13
|
private readonly aliveProcessSubject;
|
|
14
|
+
private previousWrappedTxId;
|
|
14
15
|
private cacheProcessInfo;
|
|
15
16
|
private get transactions();
|
|
16
17
|
constructor(state: KoniState);
|
|
@@ -35,6 +36,36 @@ export default class TransactionService {
|
|
|
35
36
|
addTransaction(inputTransaction: SWTransactionInput): Promise<TransactionEmitter>;
|
|
36
37
|
addDutchTransaction(inputTransaction: SWDutchTransactionInput): TransactionEmitter;
|
|
37
38
|
generateBeforeHandleResponseErrors(errors: TransactionError[]): SWTransactionResponse;
|
|
39
|
+
/**
|
|
40
|
+
* Wrapped transaction flow:
|
|
41
|
+
*
|
|
42
|
+
* Create base transaction (WRAPPABLE)
|
|
43
|
+
* - skip fee validation
|
|
44
|
+
* - NOT submitted to chain
|
|
45
|
+
* - acts as the logical / UI-facing transaction
|
|
46
|
+
* ↓
|
|
47
|
+
* Inject event emitter into base transaction
|
|
48
|
+
* - base transaction listens to wrapped transaction events
|
|
49
|
+
* - used to resolve the original transaction promise
|
|
50
|
+
* ↓
|
|
51
|
+
* User selects signer in UI
|
|
52
|
+
* - proxy account or multisig signatory
|
|
53
|
+
* ↓
|
|
54
|
+
* Prepare wrapped transaction
|
|
55
|
+
* - resolve actual signer
|
|
56
|
+
* - build wrapped extrinsic (proxy / multisig)
|
|
57
|
+
* - attach validators & event forwarders
|
|
58
|
+
* ↓
|
|
59
|
+
* Mark base transaction as WRAP_SOURCE
|
|
60
|
+
* ↓
|
|
61
|
+
* Create & submit wrapped transaction (WRAP_RESULT)
|
|
62
|
+
* ↓
|
|
63
|
+
* Forward wrapped transaction events → base transaction
|
|
64
|
+
* ↓
|
|
65
|
+
* Cleanup temporary data
|
|
66
|
+
*
|
|
67
|
+
*/
|
|
68
|
+
handleWrappedTransaction(transaction: SWTransactionInput): Promise<SWTransactionResponse>;
|
|
38
69
|
handleTransaction(transaction: SWTransactionInput): Promise<SWTransactionResponse>;
|
|
39
70
|
handleTransactionAfterConfirmation(transaction: SWTransactionInput): Promise<SWTransactionResponse>;
|
|
40
71
|
handlePermitTransaction(transaction: SWPermitTransactionInput): Promise<SWTransactionResponse>;
|
|
@@ -12,10 +12,11 @@ import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/reques
|
|
|
12
12
|
import { TRANSACTION_TIMEOUT } from '@subwallet/extension-base/services/transaction-service/constants';
|
|
13
13
|
import { parseLiquidStakingEvents, parseLiquidStakingFastUnstakeEvents, parseTransferEventLogs, parseXcmEventLogs } from '@subwallet/extension-base/services/transaction-service/event-parser';
|
|
14
14
|
import { getBaseTransactionInfo, getTransactionId, isBitcoinTransaction, isCardanoTransaction, isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
|
|
15
|
+
import { SubstrateTransactionWrappingStatus } from '@subwallet/extension-base/services/transaction-service/types';
|
|
15
16
|
import { getExplorerLink, parseTransactionData } from '@subwallet/extension-base/services/transaction-service/utils';
|
|
16
17
|
import { isWalletConnectRequest } from '@subwallet/extension-base/services/wallet-connect-service/helpers';
|
|
17
18
|
import { BasicTxErrorType, StepStatus, YieldPoolType } from '@subwallet/extension-base/types';
|
|
18
|
-
import { anyNumberToBN,
|
|
19
|
+
import { anyNumberToBN, pairToAccount, reformatAddress } from '@subwallet/extension-base/utils';
|
|
19
20
|
import { mergeTransactionAndSignature } from '@subwallet/extension-base/utils/eth/mergeTransactionAndSignature';
|
|
20
21
|
import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction';
|
|
21
22
|
import { getId } from '@subwallet/extension-base/utils/getId';
|
|
@@ -28,12 +29,14 @@ import EventEmitter from 'eventemitter3';
|
|
|
28
29
|
import { t } from 'i18next';
|
|
29
30
|
import { BehaviorSubject, interval as rxjsInterval, map as rxjsMap } from 'rxjs';
|
|
30
31
|
import { hexToU8a, isHex } from '@polkadot/util';
|
|
32
|
+
import { blake2AsHex } from '@polkadot/util-crypto';
|
|
31
33
|
import { GovVoteType } from "../open-gov/interface.js";
|
|
32
34
|
export default class TransactionService {
|
|
33
35
|
watchTransactionSubscribes = {};
|
|
34
36
|
aliveProcessMap = new Map();
|
|
35
37
|
transactionSubject = new BehaviorSubject({});
|
|
36
38
|
aliveProcessSubject = new BehaviorSubject(this.aliveProcessMap);
|
|
39
|
+
previousWrappedTxId = {};
|
|
37
40
|
cacheProcessInfo = {};
|
|
38
41
|
get transactions() {
|
|
39
42
|
return this.transactionSubject.getValue();
|
|
@@ -52,7 +55,7 @@ export default class TransactionService {
|
|
|
52
55
|
}
|
|
53
56
|
checkDuplicate(transaction) {
|
|
54
57
|
// Check duplicated transaction
|
|
55
|
-
const existed = this.processingTransactions.filter(item => item.address === transaction.address && item.chain === transaction.chain);
|
|
58
|
+
const existed = this.processingTransactions.filter(item => item.address === transaction.address && item.chain === transaction.chain && item.id !== transaction.id);
|
|
56
59
|
if (existed.length > 0) {
|
|
57
60
|
return [new TransactionError(BasicTxErrorType.DUPLICATE_TRANSACTION)];
|
|
58
61
|
}
|
|
@@ -120,26 +123,52 @@ export default class TransactionService {
|
|
|
120
123
|
const isNonNativeTokenPayFee = tokenPayFeeSlug && !_isNativeTokenBySlug(tokenPayFeeSlug);
|
|
121
124
|
const nonNativeTokenPayFeeInfo = isNonNativeTokenPayFee ? this.state.chainService.getAssetBySlug(tokenPayFeeSlug) : undefined;
|
|
122
125
|
const priceMap = (await this.state.priceService.getPrice()).priceMap;
|
|
123
|
-
|
|
124
|
-
// Get signer account
|
|
125
|
-
let signer = address;
|
|
126
|
-
const signerSubstrateProxyAddress = transactionInput.signerSubstrateProxyAddress;
|
|
127
126
|
if (!transactionInput.skipFeeRecalculation) {
|
|
128
|
-
validationResponse.estimateFee = await estimateFeeForTransaction(validationResponse, transaction, chainInfo, evmApi, substrateApi, priceMap, feeInfo, nativeTokenInfo, nonNativeTokenPayFeeInfo, transactionInput.isTransferLocalTokenAndPayThatTokenAsFee
|
|
127
|
+
validationResponse.estimateFee = await estimateFeeForTransaction(validationResponse, transaction, chainInfo, evmApi, substrateApi, priceMap, feeInfo, nativeTokenInfo, nonNativeTokenPayFeeInfo, transactionInput.isTransferLocalTokenAndPayThatTokenAsFee);
|
|
129
128
|
}
|
|
130
129
|
const chainInfoMap = this.state.chainService.getChainInfoMap();
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
if (transaction && isSubstrateTransaction(transaction)) {
|
|
131
|
+
var _chainInfo$substrateI, _chainInfo$substrateI2;
|
|
132
|
+
if ((_chainInfo$substrateI = chainInfo.substrateInfo) !== null && _chainInfo$substrateI !== void 0 && _chainInfo$substrateI.supportMultisig && !validationResponse.wrappingStatus) {
|
|
133
|
+
const pair = keyring.getPair(address);
|
|
134
|
+
if (pair.meta.isMultisig) {
|
|
135
|
+
validationResponse.wrappingStatus = SubstrateTransactionWrappingStatus.WRAPPABLE;
|
|
136
|
+
const pendingTransaction = this.state.multisigService.getPendingTxsForMultisigAddress({
|
|
137
|
+
multisigAddress: address,
|
|
138
|
+
chain
|
|
139
|
+
});
|
|
140
|
+
if (pendingTransaction.length > 0) {
|
|
141
|
+
const extrinsicTransaction = transactionInput.transaction;
|
|
142
|
+
const callData = extrinsicTransaction.method.toHex();
|
|
143
|
+
const callHash = blake2AsHex(callData);
|
|
144
|
+
const isExistPendingTx = pendingTransaction.find(tx => tx.callHash === callHash);
|
|
145
|
+
if (isExistPendingTx) {
|
|
146
|
+
validationResponse.errors.push(new TransactionError(BasicTxErrorType.DUPLICATE_TRANSACTION, t('bg.TRANSACTION_SERVICE.services.service.transaction.existingMultisigPendingTransaction')));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if ((_chainInfo$substrateI2 = chainInfo.substrateInfo) !== null && _chainInfo$substrateI2 !== void 0 && _chainInfo$substrateI2.supportProxy && !validationResponse.wrappingStatus && !isNonNativeTokenPayFee) {
|
|
152
|
+
const {
|
|
153
|
+
substrateProxyAccounts
|
|
154
|
+
} = await this.state.substrateProxyAccountService.getSubstrateProxyAccountGroup({
|
|
155
|
+
address,
|
|
156
|
+
chain,
|
|
157
|
+
type: validationResponse.extrinsicType,
|
|
158
|
+
excludedSubstrateProxyAccounts: validationResponse.data.selectedSubstrateProxyAccounts
|
|
159
|
+
});
|
|
160
|
+
if (substrateProxyAccounts.length) {
|
|
161
|
+
validationResponse.wrappingStatus = SubstrateTransactionWrappingStatus.WRAPPABLE;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
135
164
|
}
|
|
136
165
|
|
|
137
166
|
// Check account signing transaction
|
|
138
|
-
checkSigningAccountForTransaction(validationResponse, chainInfoMap,
|
|
167
|
+
checkSigningAccountForTransaction(validationResponse, chainInfoMap, address);
|
|
139
168
|
const nativeTokenAvailable = await this.state.balanceService.getBalanceByType(address, chain, nativeTokenInfo.slug, transactionInput.balanceType, extrinsicType);
|
|
140
169
|
|
|
141
170
|
// Check available balance against transaction fee
|
|
142
|
-
checkBalanceWithTransactionFee(validationResponse, transactionInput, nativeTokenInfo, nativeTokenAvailable
|
|
171
|
+
checkBalanceWithTransactionFee(validationResponse, transactionInput, nativeTokenInfo, nativeTokenAvailable);
|
|
143
172
|
|
|
144
173
|
// Warnings Ton address if bounceable and not active
|
|
145
174
|
// if (transaction && isTonTransaction(transaction) && tonApi) {
|
|
@@ -234,6 +263,14 @@ export default class TransactionService {
|
|
|
234
263
|
|
|
235
264
|
// Add Transaction
|
|
236
265
|
transactions[transaction.id] = transaction;
|
|
266
|
+
|
|
267
|
+
// Store previous wrapped tx id for multisig tx to remove it when create new wrapped tx
|
|
268
|
+
if (transaction.wrappingStatus === SubstrateTransactionWrappingStatus.WRAP_RESULT) {
|
|
269
|
+
const data = transaction.data;
|
|
270
|
+
if (data.transactionId) {
|
|
271
|
+
this.previousWrappedTxId[data.transactionId] = transaction.id;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
237
274
|
this.transactionSubject.next({
|
|
238
275
|
...transactions
|
|
239
276
|
});
|
|
@@ -262,6 +299,135 @@ export default class TransactionService {
|
|
|
262
299
|
warnings: []
|
|
263
300
|
};
|
|
264
301
|
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Wrapped transaction flow:
|
|
305
|
+
*
|
|
306
|
+
* Create base transaction (WRAPPABLE)
|
|
307
|
+
* - skip fee validation
|
|
308
|
+
* - NOT submitted to chain
|
|
309
|
+
* - acts as the logical / UI-facing transaction
|
|
310
|
+
* ↓
|
|
311
|
+
* Inject event emitter into base transaction
|
|
312
|
+
* - base transaction listens to wrapped transaction events
|
|
313
|
+
* - used to resolve the original transaction promise
|
|
314
|
+
* ↓
|
|
315
|
+
* User selects signer in UI
|
|
316
|
+
* - proxy account or multisig signatory
|
|
317
|
+
* ↓
|
|
318
|
+
* Prepare wrapped transaction
|
|
319
|
+
* - resolve actual signer
|
|
320
|
+
* - build wrapped extrinsic (proxy / multisig)
|
|
321
|
+
* - attach validators & event forwarders
|
|
322
|
+
* ↓
|
|
323
|
+
* Mark base transaction as WRAP_SOURCE
|
|
324
|
+
* ↓
|
|
325
|
+
* Create & submit wrapped transaction (WRAP_RESULT)
|
|
326
|
+
* ↓
|
|
327
|
+
* Forward wrapped transaction events → base transaction
|
|
328
|
+
* ↓
|
|
329
|
+
* Cleanup temporary data
|
|
330
|
+
*
|
|
331
|
+
*/
|
|
332
|
+
async handleWrappedTransaction(transaction) {
|
|
333
|
+
const transactionData = transaction.data;
|
|
334
|
+
|
|
335
|
+
// Origin tx id:
|
|
336
|
+
// - transactionData.transactionId: wrapped from existing tx
|
|
337
|
+
// - transaction.id: direct wrapped tx ( when transaction was signed by proxied address )
|
|
338
|
+
const originTransactionId = transactionData.transactionId || transaction.id || '';
|
|
339
|
+
|
|
340
|
+
// Remove previous wrapped transaction (select signer flow)
|
|
341
|
+
if (this.previousWrappedTxId[originTransactionId]) {
|
|
342
|
+
this.removeTransaction(this.previousWrappedTxId[originTransactionId]);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* ─────────────────────────────
|
|
347
|
+
* Validation phase
|
|
348
|
+
* ─────────────────────────────
|
|
349
|
+
*/
|
|
350
|
+
const validatedTransaction = await this.validateTransaction(transaction);
|
|
351
|
+
const ignoreWarnings = validatedTransaction.ignoreWarnings || [];
|
|
352
|
+
const hasBlockingErrors = validatedTransaction.errors.length > 0;
|
|
353
|
+
const hasBlockingWarnings = validatedTransaction.warnings.length > 0 && validatedTransaction.warnings.some(warning => !ignoreWarnings.includes(warning.warningType));
|
|
354
|
+
if (hasBlockingErrors || hasBlockingWarnings) {
|
|
355
|
+
// Cleanup runtime-only fields before returning
|
|
356
|
+
// @ts-ignore
|
|
357
|
+
'transaction' in validatedTransaction && delete validatedTransaction.transaction;
|
|
358
|
+
'additionalValidator' in validatedTransaction && delete validatedTransaction.additionalValidator;
|
|
359
|
+
'eventsHandler' in validatedTransaction && delete validatedTransaction.eventsHandler;
|
|
360
|
+
// Remove emitter before returning response
|
|
361
|
+
'emitterTransaction' in validatedTransaction && delete validatedTransaction.emitterTransaction;
|
|
362
|
+
return validatedTransaction;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Validation passed → warnings already acknowledged
|
|
366
|
+
validatedTransaction.warnings = [];
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* ─────────────────────────────
|
|
370
|
+
* Submit wrapped transaction
|
|
371
|
+
* ─────────────────────────────
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
// Mark original transaction as wrapped
|
|
375
|
+
if (transactionData.transactionId) {
|
|
376
|
+
this.updateTransaction(transactionData.transactionId, {
|
|
377
|
+
wrappingStatus: SubstrateTransactionWrappingStatus.WRAP_SOURCE,
|
|
378
|
+
estimateFee: validatedTransaction.estimateFee,
|
|
379
|
+
errors: []
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
const emitter = await this.addTransaction(validatedTransaction);
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Async side-effect:
|
|
386
|
+
* - wait for signed / success / error / timeout
|
|
387
|
+
* - mutate validatedTransaction accordingly
|
|
388
|
+
*/
|
|
389
|
+
if (emitter) {
|
|
390
|
+
new Promise(resolve => {
|
|
391
|
+
const resolveWithResult = data => {
|
|
392
|
+
validatedTransaction.id = data.id;
|
|
393
|
+
validatedTransaction.extrinsicHash = data.extrinsicHash;
|
|
394
|
+
resolve();
|
|
395
|
+
};
|
|
396
|
+
if (transaction.resolveOnDone) {
|
|
397
|
+
emitter.on('success', resolveWithResult);
|
|
398
|
+
} else {
|
|
399
|
+
emitter.on('signed', resolveWithResult);
|
|
400
|
+
}
|
|
401
|
+
emitter.on('error', data => {
|
|
402
|
+
if (data.errors.length > 0) {
|
|
403
|
+
validatedTransaction.errors.push(...data.errors);
|
|
404
|
+
resolve();
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
emitter.on('timeout', data => {
|
|
408
|
+
if (transaction.errorOnTimeOut && data.errors.length > 0) {
|
|
409
|
+
validatedTransaction.errors.push(...data.errors);
|
|
410
|
+
resolve();
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
}).finally(() => {
|
|
414
|
+
// Cleanup runtime-only fields
|
|
415
|
+
// @ts-ignore
|
|
416
|
+
'transaction' in validatedTransaction && delete validatedTransaction.transaction;
|
|
417
|
+
'additionalValidator' in validatedTransaction && delete validatedTransaction.additionalValidator;
|
|
418
|
+
'eventsHandler' in validatedTransaction && delete validatedTransaction.eventsHandler;
|
|
419
|
+
|
|
420
|
+
// Remove base multisig transaction after approval
|
|
421
|
+
if (transactionData.multisigMetadata && transactionData.transactionId) {
|
|
422
|
+
this.removeTransaction(transactionData.transactionId);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Remove emitter before returning response
|
|
428
|
+
'emitterTransaction' in validatedTransaction && delete validatedTransaction.emitterTransaction;
|
|
429
|
+
return validatedTransaction;
|
|
430
|
+
}
|
|
265
431
|
async handleTransaction(transaction) {
|
|
266
432
|
const validatedTransaction = await this.validateTransaction(transaction);
|
|
267
433
|
const ignoreWarnings = validatedTransaction.ignoreWarnings || [];
|
|
@@ -277,7 +443,6 @@ export default class TransactionService {
|
|
|
277
443
|
validatedTransaction.warnings = [];
|
|
278
444
|
const emitter = await this.addTransaction(validatedTransaction);
|
|
279
445
|
await new Promise((resolve, reject) => {
|
|
280
|
-
// TODO
|
|
281
446
|
if (transaction.resolveOnDone) {
|
|
282
447
|
emitter.on('success', data => {
|
|
283
448
|
validatedTransaction.id = data.id;
|
|
@@ -329,7 +494,7 @@ export default class TransactionService {
|
|
|
329
494
|
// Fill transaction default info
|
|
330
495
|
const transactionUpdated = this.fillTransactionDefaultInfo(validatedTransaction);
|
|
331
496
|
|
|
332
|
-
// Add
|
|
497
|
+
// Add transaction
|
|
333
498
|
transactionsSubject[transactionUpdated.id] = {
|
|
334
499
|
...transactionUpdated,
|
|
335
500
|
emitterTransaction: emitter
|
|
@@ -493,6 +658,13 @@ export default class TransactionService {
|
|
|
493
658
|
eventsHandler,
|
|
494
659
|
step
|
|
495
660
|
} = transaction;
|
|
661
|
+
|
|
662
|
+
// Inject emitter into transaction for wrapped tx flow
|
|
663
|
+
if (transaction.wrappingStatus === SubstrateTransactionWrappingStatus.WRAPPABLE) {
|
|
664
|
+
this.updateTransaction(transaction.id, {
|
|
665
|
+
emitterTransaction: emitter
|
|
666
|
+
});
|
|
667
|
+
}
|
|
496
668
|
emitter.on('signed', data => {
|
|
497
669
|
this.onSigned(data);
|
|
498
670
|
});
|
|
@@ -712,6 +884,9 @@ export default class TransactionService {
|
|
|
712
884
|
...this.transactions
|
|
713
885
|
});
|
|
714
886
|
}
|
|
887
|
+
if (this.previousWrappedTxId[id]) {
|
|
888
|
+
delete this.previousWrappedTxId[id];
|
|
889
|
+
}
|
|
715
890
|
}
|
|
716
891
|
updateTransaction(id, data) {
|
|
717
892
|
const transaction = this.transactions[id];
|
|
@@ -1124,6 +1299,22 @@ export default class TransactionService {
|
|
|
1124
1299
|
};
|
|
1125
1300
|
break;
|
|
1126
1301
|
}
|
|
1302
|
+
case ExtrinsicType.MULTISIG_APPROVE_TX:
|
|
1303
|
+
// todo
|
|
1304
|
+
historyItem.additionalInfo = parseTransactionData(transaction.data);
|
|
1305
|
+
break;
|
|
1306
|
+
case ExtrinsicType.MULTISIG_EXECUTE_TX:
|
|
1307
|
+
// todo
|
|
1308
|
+
historyItem.additionalInfo = parseTransactionData(transaction.data);
|
|
1309
|
+
break;
|
|
1310
|
+
case ExtrinsicType.MULTISIG_CANCEL_TX:
|
|
1311
|
+
// todo
|
|
1312
|
+
historyItem.additionalInfo = parseTransactionData(transaction.data);
|
|
1313
|
+
break;
|
|
1314
|
+
case ExtrinsicType.MULTISIG_INIT_TX:
|
|
1315
|
+
// todo
|
|
1316
|
+
historyItem.additionalInfo = parseTransactionData(transaction.data);
|
|
1317
|
+
break;
|
|
1127
1318
|
case ExtrinsicType.ADD_SUBSTRATE_PROXY_ACCOUNT:
|
|
1128
1319
|
{
|
|
1129
1320
|
const data = parseTransactionData(transaction.data);
|
|
@@ -1173,6 +1364,10 @@ export default class TransactionService {
|
|
|
1173
1364
|
}
|
|
1174
1365
|
break;
|
|
1175
1366
|
}
|
|
1367
|
+
case ExtrinsicType.SUBSTRATE_PROXY_INIT_TX:
|
|
1368
|
+
// todo
|
|
1369
|
+
historyItem.additionalInfo = parseTransactionData(transaction.data);
|
|
1370
|
+
break;
|
|
1176
1371
|
case ExtrinsicType.UNKNOWN:
|
|
1177
1372
|
break;
|
|
1178
1373
|
}
|
|
@@ -1316,20 +1511,22 @@ export default class TransactionService {
|
|
|
1316
1511
|
blockHash: blockHash || '',
|
|
1317
1512
|
blockTime
|
|
1318
1513
|
}).catch(console.error);
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1514
|
+
if (transaction.wrappingStatus !== SubstrateTransactionWrappingStatus.WRAP_SOURCE) {
|
|
1515
|
+
const info = isHex(extrinsicHash) ? extrinsicHash : getBaseTransactionInfo(transaction, this.state.chainService.getChainInfoMap());
|
|
1516
|
+
this.state.notificationService.notify({
|
|
1517
|
+
type: NotificationType.SUCCESS,
|
|
1518
|
+
title: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionCompleted'),
|
|
1519
|
+
message: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionInfoCompleted', {
|
|
1520
|
+
replace: {
|
|
1521
|
+
info
|
|
1522
|
+
}
|
|
1523
|
+
}),
|
|
1524
|
+
action: {
|
|
1525
|
+
url: this.getTransactionLink(id)
|
|
1526
|
+
},
|
|
1527
|
+
notifyViaBrowser: true
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1333
1530
|
this.state.eventService.emit('transaction.done', transaction);
|
|
1334
1531
|
}
|
|
1335
1532
|
onFailed({
|
|
@@ -1355,20 +1552,22 @@ export default class TransactionService {
|
|
|
1355
1552
|
blockNumber: blockNumber || 0,
|
|
1356
1553
|
blockHash: blockHash || ''
|
|
1357
1554
|
}).catch(console.error);
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1555
|
+
if (transaction.wrappingStatus !== SubstrateTransactionWrappingStatus.WRAP_SOURCE) {
|
|
1556
|
+
const info = isHex(transaction === null || transaction === void 0 ? void 0 : transaction.extrinsicHash) ? transaction === null || transaction === void 0 ? void 0 : transaction.extrinsicHash : getBaseTransactionInfo(transaction, this.state.chainService.getChainInfoMap());
|
|
1557
|
+
this.state.notificationService.notify({
|
|
1558
|
+
type: NotificationType.ERROR,
|
|
1559
|
+
title: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionFailed'),
|
|
1560
|
+
message: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionInfoFailed', {
|
|
1561
|
+
replace: {
|
|
1562
|
+
info
|
|
1563
|
+
}
|
|
1564
|
+
}),
|
|
1565
|
+
action: {
|
|
1566
|
+
url: this.getTransactionLink(id)
|
|
1567
|
+
},
|
|
1568
|
+
notifyViaBrowser: true
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1372
1571
|
}
|
|
1373
1572
|
this.state.eventService.emit('transaction.failed', transaction);
|
|
1374
1573
|
}
|
|
@@ -1393,20 +1592,22 @@ export default class TransactionService {
|
|
|
1393
1592
|
blockNumber: blockNumber || 0,
|
|
1394
1593
|
blockHash: blockHash || ''
|
|
1395
1594
|
}).catch(console.error);
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1595
|
+
if (transaction.wrappingStatus !== SubstrateTransactionWrappingStatus.WRAP_SOURCE) {
|
|
1596
|
+
const info = isHex(transaction === null || transaction === void 0 ? void 0 : transaction.extrinsicHash) ? transaction === null || transaction === void 0 ? void 0 : transaction.extrinsicHash : getBaseTransactionInfo(transaction, this.state.chainService.getChainInfoMap());
|
|
1597
|
+
this.state.notificationService.notify({
|
|
1598
|
+
type: NotificationType.ERROR,
|
|
1599
|
+
title: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionTimedOut'),
|
|
1600
|
+
message: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionInfoTimedOut', {
|
|
1601
|
+
replace: {
|
|
1602
|
+
info
|
|
1603
|
+
}
|
|
1604
|
+
}),
|
|
1605
|
+
action: {
|
|
1606
|
+
url: this.getTransactionLink(id)
|
|
1607
|
+
},
|
|
1608
|
+
notifyViaBrowser: true
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1410
1611
|
}
|
|
1411
1612
|
this.state.eventService.emit('transaction.timeout', transaction);
|
|
1412
1613
|
}
|
|
@@ -1780,17 +1981,18 @@ export default class TransactionService {
|
|
|
1780
1981
|
});
|
|
1781
1982
|
return emitter;
|
|
1782
1983
|
}
|
|
1783
|
-
|
|
1984
|
+
signAndSendSubstrateTransaction({
|
|
1784
1985
|
address,
|
|
1785
1986
|
chain,
|
|
1987
|
+
data,
|
|
1786
1988
|
feeCustom,
|
|
1787
1989
|
id,
|
|
1788
1990
|
signAfterCreate,
|
|
1789
|
-
signerSubstrateProxyAddress,
|
|
1790
1991
|
step,
|
|
1791
1992
|
tokenPayFeeSlug,
|
|
1792
1993
|
transaction,
|
|
1793
|
-
url
|
|
1994
|
+
url,
|
|
1995
|
+
wrappingStatus
|
|
1794
1996
|
}) {
|
|
1795
1997
|
var _this$state$chainServ;
|
|
1796
1998
|
const tip = (feeCustom === null || feeCustom === void 0 ? void 0 : feeCustom.tip) || '0';
|
|
@@ -1803,13 +2005,13 @@ export default class TransactionService {
|
|
|
1803
2005
|
extrinsicHash: id,
|
|
1804
2006
|
processId: step === null || step === void 0 ? void 0 : step.processId
|
|
1805
2007
|
};
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2008
|
+
const extrinsic = transaction;
|
|
2009
|
+
const signer = address;
|
|
2010
|
+
let transactionId = id;
|
|
2011
|
+
if (wrappingStatus === SubstrateTransactionWrappingStatus.WRAP_RESULT) {
|
|
2012
|
+
// we will use the original transaction's ID for this request,
|
|
2013
|
+
// because we only want the popup to appear once and keep the old one.
|
|
2014
|
+
transactionId = data.transactionId || id;
|
|
1813
2015
|
}
|
|
1814
2016
|
|
|
1815
2017
|
// const registry = extrinsic.registry;
|
|
@@ -1821,7 +2023,7 @@ export default class TransactionService {
|
|
|
1821
2023
|
const {
|
|
1822
2024
|
signature,
|
|
1823
2025
|
signedTransaction
|
|
1824
|
-
} = await this.state.requestService.signInternalTransaction(
|
|
2026
|
+
} = await this.state.requestService.signInternalTransaction(transactionId, signer, url || EXTENSION_REQUEST_URL, payload, signAfterCreate, wrappingStatus);
|
|
1825
2027
|
return {
|
|
1826
2028
|
id: new Date().getTime(),
|
|
1827
2029
|
signature,
|
|
@@ -2091,7 +2293,6 @@ export default class TransactionService {
|
|
|
2091
2293
|
emitter.emit('extrinsicHash', eventData);
|
|
2092
2294
|
});
|
|
2093
2295
|
event.on('success', transactionStatus => {
|
|
2094
|
-
console.log(transactionStatus);
|
|
2095
2296
|
eventData.blockHash = transactionStatus.block_hash || undefined;
|
|
2096
2297
|
eventData.blockNumber = transactionStatus.block_height || undefined;
|
|
2097
2298
|
eventData.blockTime = transactionStatus.block_time ? transactionStatus.block_time * 1000 : undefined;
|
|
@@ -8,7 +8,7 @@ import EventEmitter from 'eventemitter3';
|
|
|
8
8
|
import { TransactionConfig } from 'web3-core';
|
|
9
9
|
import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
|
|
10
10
|
import { EventRecord } from '@polkadot/types/interfaces';
|
|
11
|
-
export interface SWTransactionBase extends ValidateTransactionResponse, Partial<Pick<BaseRequestSign, 'ignoreWarnings'
|
|
11
|
+
export interface SWTransactionBase extends ValidateTransactionResponse, Partial<Pick<BaseRequestSign, 'ignoreWarnings'>>, TransactionFee, SWTransactionEmitter {
|
|
12
12
|
id: string;
|
|
13
13
|
url?: string;
|
|
14
14
|
isInternal: boolean;
|
|
@@ -30,6 +30,31 @@ export interface SWTransactionBase extends ValidateTransactionResponse, Partial<
|
|
|
30
30
|
errorOnTimeOut?: boolean;
|
|
31
31
|
signAfterCreate?: (id: string) => void;
|
|
32
32
|
step?: BriefProcessStep;
|
|
33
|
+
wrappingStatus?: SubstrateTransactionWrappingStatus;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Describes how a transaction is related to wrapping (multisig / proxy).
|
|
37
|
+
*/
|
|
38
|
+
export declare enum SubstrateTransactionWrappingStatus {
|
|
39
|
+
/**
|
|
40
|
+
* This transaction can be wrapped.
|
|
41
|
+
* - It is a base transaction
|
|
42
|
+
* - Not wrapped yet
|
|
43
|
+
* - User may choose a signer (multisig / proxy)
|
|
44
|
+
*/
|
|
45
|
+
WRAPPABLE = "WRAPPABLE",
|
|
46
|
+
/**
|
|
47
|
+
* This transaction is the source of a wrap.
|
|
48
|
+
* - It has been wrapped by another transaction
|
|
49
|
+
* - This transaction itself should NOT be signed anymore
|
|
50
|
+
*/
|
|
51
|
+
WRAP_SOURCE = "WRAP_SOURCE",
|
|
52
|
+
/**
|
|
53
|
+
* This transaction is the result of wrapping another transaction.
|
|
54
|
+
* - It wraps a WRAP_SOURCE transaction
|
|
55
|
+
* - This is the transaction that will be signed and submitted
|
|
56
|
+
*/
|
|
57
|
+
WRAP_RESULT = "WRAP_RESULT"
|
|
33
58
|
}
|
|
34
59
|
export interface SWTransaction extends SWTransactionBase {
|
|
35
60
|
transaction: SubmittableExtrinsic | TransactionConfig | TonTransactionConfig | Psbt;
|
|
@@ -50,7 +75,7 @@ export interface SWTransactionEmitter {
|
|
|
50
75
|
emitterTransaction?: TransactionEmitter;
|
|
51
76
|
}
|
|
52
77
|
declare type SwInputBase = Pick<SWTransactionBase, 'address' | 'url' | 'data' | 'extrinsicType' | 'chain' | 'chainType' | 'ignoreWarnings' | 'transferNativeAmount'> & Partial<Pick<SWTransactionBase, 'additionalValidator' | 'eventsHandler'>>;
|
|
53
|
-
export interface SWTransactionInput extends SwInputBase, Partial<Pick<SWTransactionBase, 'estimateFee' | 'signAfterCreate' | 'isPassConfirmation' | 'step' | 'errorOnTimeOut' | 'xcmFeeDryRun' | '
|
|
78
|
+
export interface SWTransactionInput extends SwInputBase, Partial<Pick<SWTransactionBase, 'estimateFee' | 'signAfterCreate' | 'isPassConfirmation' | 'step' | 'errorOnTimeOut' | 'xcmFeeDryRun' | 'wrappingStatus'>>, TransactionFee {
|
|
54
79
|
id?: string;
|
|
55
80
|
transaction?: SWTransactionBase['transaction'] | null;
|
|
56
81
|
warnings?: SWTransactionBase['warnings'];
|
|
@@ -69,7 +94,7 @@ export interface SWPermitTransactionInput extends Omit<SWTransactionInput, 'tran
|
|
|
69
94
|
export interface SWDutchTransactionInput extends Omit<SWTransactionInput, 'transaction'> {
|
|
70
95
|
transaction?: SWDutchTransaction['transaction'] | null;
|
|
71
96
|
}
|
|
72
|
-
export declare type SWTransactionResponse = SwInputBase & Pick<SWTransactionBase, 'warnings' | 'errors'> & Partial<Pick<SWTransactionBase, 'id' | 'extrinsicHash' | 'status' | 'estimateFee' | 'xcmFeeDryRun'>> & TransactionFee & {
|
|
97
|
+
export declare type SWTransactionResponse = SwInputBase & Pick<SWTransactionBase, 'warnings' | 'errors'> & Partial<Pick<SWTransactionBase, 'id' | 'extrinsicHash' | 'status' | 'estimateFee' | 'xcmFeeDryRun' | 'wrappingStatus'>> & TransactionFee & {
|
|
73
98
|
processId?: string;
|
|
74
99
|
};
|
|
75
100
|
export declare type BitcoinTransactionData = {
|
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Describes how a transaction is related to wrapping (multisig / proxy).
|
|
6
|
+
*/
|
|
7
|
+
export let SubstrateTransactionWrappingStatus;
|
|
8
|
+
(function (SubstrateTransactionWrappingStatus) {
|
|
9
|
+
SubstrateTransactionWrappingStatus["WRAPPABLE"] = "WRAPPABLE";
|
|
10
|
+
SubstrateTransactionWrappingStatus["WRAP_SOURCE"] = "WRAP_SOURCE";
|
|
11
|
+
SubstrateTransactionWrappingStatus["WRAP_RESULT"] = "WRAP_RESULT";
|
|
12
|
+
})(SubstrateTransactionWrappingStatus || (SubstrateTransactionWrappingStatus = {}));
|
|
@@ -85,6 +85,18 @@ export interface AccountDeriveData {
|
|
|
85
85
|
/** Derivation path */
|
|
86
86
|
derivationPath?: string;
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* @interface AccountMultisigData
|
|
90
|
+
* @prop {boolean} [isMultisig] - Is multisig account
|
|
91
|
+
* */
|
|
92
|
+
export interface AccountMultisigData {
|
|
93
|
+
/** Is multisig account */
|
|
94
|
+
isMultisig?: boolean;
|
|
95
|
+
/** signer addresses */
|
|
96
|
+
signers?: string[];
|
|
97
|
+
/** multisig threshold */
|
|
98
|
+
threshold?: number;
|
|
99
|
+
}
|
|
88
100
|
/**
|
|
89
101
|
* Represents the comprehensive metadata associated with an account, combining various aspects of account data.
|
|
90
102
|
* This interface extends from multiple specific metadata interfaces to provide a unified view of an account's metadata.
|
|
@@ -98,7 +110,7 @@ export interface AccountDeriveData {
|
|
|
98
110
|
* @extends AccountInjectData - Covers data related to injected accounts, including the source of the injection.
|
|
99
111
|
* @extends AccountDeriveData - Holds information about derived accounts, including the parent address and derivation path (suri).
|
|
100
112
|
*/
|
|
101
|
-
export interface AccountMetadataData extends AccountExternalData, AccountLedgerData, AccountInjectData, AccountDeriveData {
|
|
113
|
+
export interface AccountMetadataData extends AccountExternalData, AccountLedgerData, AccountInjectData, AccountDeriveData, AccountMultisigData {
|
|
102
114
|
}
|
|
103
115
|
export declare enum AccountSignMode {
|
|
104
116
|
PASSWORD = "password",
|
|
@@ -107,6 +119,7 @@ export declare enum AccountSignMode {
|
|
|
107
119
|
GENERIC_LEDGER = "generic-ledger",
|
|
108
120
|
ECDSA_SUBSTRATE_LEDGER = "ecdsa-substrate-ledger",
|
|
109
121
|
READ_ONLY = "readonly",
|
|
122
|
+
MULTISIG = "multisig",
|
|
110
123
|
ALL_ACCOUNT = "all",
|
|
111
124
|
INJECTED = "injected",
|
|
112
125
|
UNKNOWN = "unknown"
|