@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.
Files changed (108) hide show
  1. package/background/KoniTypes.d.ts +42 -5
  2. package/background/KoniTypes.js +14 -1
  3. package/cjs/background/KoniTypes.js +16 -2
  4. package/cjs/core/logic-validation/transfer.js +35 -57
  5. package/cjs/koni/background/handlers/Extension.js +599 -144
  6. package/cjs/koni/background/handlers/State.js +5 -2
  7. package/cjs/koni/background/handlers/Tabs.js +3 -2
  8. package/cjs/packageInfo.js +1 -1
  9. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +0 -2
  10. package/cjs/services/chain-service/handler/SubstrateApi.js +6 -1
  11. package/cjs/services/chain-service/index.js +1 -0
  12. package/cjs/services/chain-service/utils/index.js +4 -0
  13. package/cjs/services/event-service/index.js +1 -0
  14. package/cjs/services/fee-service/utils/index.js +4 -4
  15. package/cjs/services/inapp-notification-service/consts.js +4 -2
  16. package/cjs/services/inapp-notification-service/index.js +51 -6
  17. package/cjs/services/inapp-notification-service/interfaces.js +2 -0
  18. package/cjs/services/inapp-notification-service/utils/common.js +4 -0
  19. package/cjs/services/keyring-service/context/account-context.js +44 -0
  20. package/cjs/services/keyring-service/context/handlers/Multisig.js +186 -0
  21. package/cjs/services/keyring-service/context/state.js +12 -0
  22. package/cjs/services/multisig-service/index.js +627 -0
  23. package/cjs/services/multisig-service/utils.js +242 -0
  24. package/cjs/services/request-service/handler/SubstrateRequestHandler.js +25 -0
  25. package/cjs/services/request-service/index.js +5 -1
  26. package/cjs/services/storage-service/DatabaseService.js +5 -2
  27. package/cjs/services/storage-service/db-stores/InappNotification.js +20 -2
  28. package/cjs/services/substrate-proxy-service/index.js +22 -7
  29. package/cjs/services/transaction-service/helpers/index.js +8 -0
  30. package/cjs/services/transaction-service/index.js +348 -147
  31. package/cjs/services/transaction-service/types.js +18 -1
  32. package/cjs/types/account/info/keyring.js +5 -0
  33. package/cjs/types/account/info/proxy.js +1 -0
  34. package/cjs/types/multisig/index.js +14 -0
  35. package/cjs/types/transaction/error.js +9 -2
  36. package/cjs/utils/account/transform.js +28 -4
  37. package/cjs/utils/logger/Logger.js +294 -0
  38. package/cjs/utils/logger/index.js +42 -0
  39. package/cjs/utils/logger/types.js +1 -0
  40. package/core/logic-validation/transfer.d.ts +2 -2
  41. package/core/logic-validation/transfer.js +10 -32
  42. package/koni/background/handlers/Extension.d.ts +7 -0
  43. package/koni/background/handlers/Extension.js +498 -43
  44. package/koni/background/handlers/State.d.ts +2 -0
  45. package/koni/background/handlers/State.js +5 -2
  46. package/koni/background/handlers/Tabs.js +3 -2
  47. package/package.json +42 -6
  48. package/packageInfo.js +1 -1
  49. package/services/balance-service/helpers/subscribe/substrate/index.js +0 -2
  50. package/services/chain-service/handler/SubstrateApi.js +7 -2
  51. package/services/chain-service/index.js +1 -0
  52. package/services/chain-service/types.d.ts +1 -1
  53. package/services/chain-service/utils/index.js +4 -0
  54. package/services/event-service/index.d.ts +1 -0
  55. package/services/event-service/index.js +1 -0
  56. package/services/event-service/types.d.ts +1 -0
  57. package/services/fee-service/utils/index.js +4 -4
  58. package/services/inapp-notification-service/consts.d.ts +3 -1
  59. package/services/inapp-notification-service/consts.js +5 -3
  60. package/services/inapp-notification-service/index.d.ts +3 -2
  61. package/services/inapp-notification-service/index.js +51 -6
  62. package/services/inapp-notification-service/interfaces.d.ts +18 -2
  63. package/services/inapp-notification-service/interfaces.js +2 -0
  64. package/services/inapp-notification-service/utils/common.d.ts +1 -0
  65. package/services/inapp-notification-service/utils/common.js +3 -0
  66. package/services/keyring-service/context/account-context.d.ts +9 -1
  67. package/services/keyring-service/context/account-context.js +44 -0
  68. package/services/keyring-service/context/handlers/Multisig.d.ts +18 -0
  69. package/services/keyring-service/context/handlers/Multisig.js +180 -0
  70. package/services/keyring-service/context/state.d.ts +2 -0
  71. package/services/keyring-service/context/state.js +12 -0
  72. package/services/multisig-service/index.d.ts +245 -0
  73. package/services/multisig-service/index.js +620 -0
  74. package/services/multisig-service/utils.d.ts +95 -0
  75. package/services/multisig-service/utils.js +227 -0
  76. package/services/request-service/handler/SubstrateRequestHandler.d.ts +1 -0
  77. package/services/request-service/handler/SubstrateRequestHandler.js +25 -0
  78. package/services/request-service/index.d.ts +2 -1
  79. package/services/request-service/index.js +5 -1
  80. package/services/storage-service/DatabaseService.d.ts +3 -2
  81. package/services/storage-service/DatabaseService.js +5 -2
  82. package/services/storage-service/db-stores/InappNotification.d.ts +3 -2
  83. package/services/storage-service/db-stores/InappNotification.js +20 -2
  84. package/services/substrate-proxy-service/index.d.ts +4 -1
  85. package/services/substrate-proxy-service/index.js +22 -8
  86. package/services/transaction-service/helpers/index.js +8 -0
  87. package/services/transaction-service/index.d.ts +31 -0
  88. package/services/transaction-service/index.js +270 -69
  89. package/services/transaction-service/types.d.ts +28 -3
  90. package/services/transaction-service/types.js +12 -1
  91. package/types/account/info/keyring.d.ts +14 -1
  92. package/types/account/info/keyring.js +6 -0
  93. package/types/account/info/proxy.d.ts +1 -0
  94. package/types/account/info/proxy.js +1 -0
  95. package/types/multisig/index.d.ts +76 -0
  96. package/types/multisig/index.js +8 -0
  97. package/types/notification/index.d.ts +8 -0
  98. package/types/substrateProxyAccount/index.d.ts +26 -1
  99. package/types/transaction/error.d.ts +6 -1
  100. package/types/transaction/error.js +7 -1
  101. package/types/transaction/request.d.ts +0 -1
  102. package/utils/account/transform.js +28 -4
  103. package/utils/logger/Logger.d.ts +31 -0
  104. package/utils/logger/Logger.js +267 -0
  105. package/utils/logger/index.d.ts +15 -0
  106. package/utils/logger/index.js +29 -0
  107. package/utils/logger/types.d.ts +23 -0
  108. 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, isSameAddress, pairToAccount, reformatAddress } from '@subwallet/extension-base/utils';
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, signerSubstrateProxyAddress);
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
- let substrateProxyAccountNativeTokenAvailable;
132
- if (signerSubstrateProxyAddress && !isSameAddress(signerSubstrateProxyAddress, address)) {
133
- signer = signerSubstrateProxyAddress;
134
- substrateProxyAccountNativeTokenAvailable = await this.state.balanceService.getTransferableBalance(signerSubstrateProxyAddress, chain, nativeTokenInfo.slug, extrinsicType);
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, signer);
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, substrateProxyAccountNativeTokenAvailable);
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 Transaction
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
- const info = isHex(extrinsicHash) ? extrinsicHash : getBaseTransactionInfo(transaction, this.state.chainService.getChainInfoMap());
1320
- this.state.notificationService.notify({
1321
- type: NotificationType.SUCCESS,
1322
- title: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionCompleted'),
1323
- message: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionInfoCompleted', {
1324
- replace: {
1325
- info
1326
- }
1327
- }),
1328
- action: {
1329
- url: this.getTransactionLink(id)
1330
- },
1331
- notifyViaBrowser: true
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
- 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());
1359
- this.state.notificationService.notify({
1360
- type: NotificationType.ERROR,
1361
- title: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionFailed'),
1362
- message: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionInfoFailed', {
1363
- replace: {
1364
- info
1365
- }
1366
- }),
1367
- action: {
1368
- url: this.getTransactionLink(id)
1369
- },
1370
- notifyViaBrowser: true
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
- 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());
1397
- this.state.notificationService.notify({
1398
- type: NotificationType.ERROR,
1399
- title: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionTimedOut'),
1400
- message: t('bg.TRANSACTION_SERVICE.services.service.transaction.transactionInfoTimedOut', {
1401
- replace: {
1402
- info
1403
- }
1404
- }),
1405
- action: {
1406
- url: this.getTransactionLink(id)
1407
- },
1408
- notifyViaBrowser: true
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
- async signAndSendSubstrateTransaction({
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
- let extrinsic = transaction;
1807
- let signer = address;
1808
- if (signerSubstrateProxyAddress && signerSubstrateProxyAddress !== address) {
1809
- const substrateApi = this.state.chainService.getSubstrateApi(chain);
1810
- await substrateApi.isReady;
1811
- signer = signerSubstrateProxyAddress;
1812
- extrinsic = substrateApi.api.tx.proxy.proxy(address, null, transaction);
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(id, signer, url || EXTENSION_REQUEST_URL, payload, signAfterCreate);
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' | 'signerSubstrateProxyAddress'>>, TransactionFee, SWTransactionEmitter {
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' | 'signerSubstrateProxyAddress'>>, TransactionFee {
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
- export {};
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"