@sidhujag/sysweb3-keyring 2.1.7 → 2.1.9

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 (105) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/cjs/hardware-transaction-authority.js +15 -11
  3. package/cjs/hardware-transaction-authority.js.map +1 -1
  4. package/cjs/hardware-wallet-manager.js +74 -119
  5. package/cjs/hardware-wallet-manager.js.map +1 -1
  6. package/cjs/hardware-wallet-types.js +16 -0
  7. package/cjs/hardware-wallet-types.js.map +1 -0
  8. package/cjs/host-keyring.js +32 -0
  9. package/cjs/host-keyring.js.map +1 -0
  10. package/cjs/index.js +1 -0
  11. package/cjs/index.js.map +1 -1
  12. package/cjs/keyring-core.js +96 -61
  13. package/cjs/keyring-core.js.map +1 -1
  14. package/cjs/keyring-manager.js +15 -16
  15. package/cjs/keyring-manager.js.map +1 -1
  16. package/cjs/ledger/host-types.js.map +1 -1
  17. package/cjs/ledger/index.js +24 -4
  18. package/cjs/ledger/index.js.map +1 -1
  19. package/cjs/ledger-hardware.js +15 -0
  20. package/cjs/ledger-hardware.js.map +1 -0
  21. package/cjs/software.js +6 -25
  22. package/cjs/software.js.map +1 -1
  23. package/cjs/transactions/ethereum.js +371 -494
  24. package/cjs/transactions/ethereum.js.map +1 -1
  25. package/cjs/transactions/evm-submission-failure.js +73 -0
  26. package/cjs/transactions/evm-submission-failure.js.map +1 -0
  27. package/cjs/transactions/evm-submission.js +35 -61
  28. package/cjs/transactions/evm-submission.js.map +1 -1
  29. package/cjs/transactions/ledger-signing.js +52 -0
  30. package/cjs/transactions/ledger-signing.js.map +1 -0
  31. package/cjs/transactions/prepared-evm.js +24 -1
  32. package/cjs/transactions/prepared-evm.js.map +1 -1
  33. package/cjs/transactions/trezor-signing.js +90 -0
  34. package/cjs/transactions/trezor-signing.js.map +1 -0
  35. package/cjs/trezor/connect.js +238 -243
  36. package/cjs/trezor/connect.js.map +1 -1
  37. package/cjs/trezor/host-types.js +19 -0
  38. package/cjs/trezor/host-types.js.map +1 -0
  39. package/cjs/trezor/index.js +75 -23
  40. package/cjs/trezor/index.js.map +1 -1
  41. package/cjs/trezor/webextension-host.js +118 -0
  42. package/cjs/trezor/webextension-host.js.map +1 -0
  43. package/cjs/trezor-hardware.js +16 -0
  44. package/cjs/trezor-hardware.js.map +1 -0
  45. package/cjs/types.js.map +1 -1
  46. package/esm/hardware-transaction-authority.js +14 -11
  47. package/esm/hardware-transaction-authority.js.map +1 -1
  48. package/esm/hardware-wallet-manager.js +20 -32
  49. package/esm/hardware-wallet-manager.js.map +1 -1
  50. package/esm/hardware-wallet-types.js +13 -0
  51. package/esm/hardware-wallet-types.js.map +1 -0
  52. package/esm/keyring-core.js +98 -63
  53. package/esm/keyring-core.js.map +1 -1
  54. package/esm/ledger/dmk-host.js +2 -0
  55. package/esm/ledger/dmk-host.js.map +1 -1
  56. package/esm/ledger/dmk-session.js +73 -8
  57. package/esm/ledger/dmk-session.js.map +1 -1
  58. package/esm/ledger/host-types.js.map +1 -1
  59. package/esm/ledger/index.js +22 -2
  60. package/esm/ledger/index.js.map +1 -1
  61. package/esm/transactions/ethereum.js +372 -495
  62. package/esm/transactions/ethereum.js.map +1 -1
  63. package/esm/transactions/evm-submission-failure.js +68 -0
  64. package/esm/transactions/evm-submission-failure.js.map +1 -0
  65. package/esm/transactions/evm-submission.js +32 -59
  66. package/esm/transactions/evm-submission.js.map +1 -1
  67. package/esm/transactions/ledger-signing.js +49 -0
  68. package/esm/transactions/ledger-signing.js.map +1 -0
  69. package/esm/transactions/prepared-evm.js +23 -1
  70. package/esm/transactions/prepared-evm.js.map +1 -1
  71. package/esm/transactions/trezor-signing.js +87 -0
  72. package/esm/transactions/trezor-signing.js.map +1 -0
  73. package/esm/trezor/connect.js +236 -209
  74. package/esm/trezor/connect.js.map +1 -1
  75. package/esm/trezor/host-types.js +16 -0
  76. package/esm/trezor/host-types.js.map +1 -0
  77. package/esm/trezor/index.js +74 -22
  78. package/esm/trezor/index.js.map +1 -1
  79. package/esm/types.js.map +1 -1
  80. package/package.json +61 -1
  81. package/types/hardware-transaction-authority.d.ts +1 -0
  82. package/types/hardware-wallet-manager.d.ts +6 -22
  83. package/types/hardware-wallet-types.d.ts +21 -0
  84. package/types/host-keyring.d.ts +16 -0
  85. package/types/index.d.ts +1 -0
  86. package/types/keyring-core.d.ts +12 -4
  87. package/types/keyring-manager.d.ts +5 -3
  88. package/types/ledger/dmk-host.d.ts +2 -0
  89. package/types/ledger/dmk-session.d.ts +9 -0
  90. package/types/ledger/host-types.d.ts +2 -0
  91. package/types/ledger/index.d.ts +3 -1
  92. package/types/ledger-hardware.d.ts +5 -0
  93. package/types/software.d.ts +2 -16
  94. package/types/transactions/ethereum.d.ts +11 -1
  95. package/types/transactions/evm-submission-failure.d.ts +11 -0
  96. package/types/transactions/evm-submission.d.ts +6 -8
  97. package/types/transactions/ledger-signing.d.ts +13 -0
  98. package/types/transactions/prepared-evm.d.ts +12 -0
  99. package/types/transactions/trezor-signing.d.ts +13 -0
  100. package/types/trezor/connect.d.ts +11 -9
  101. package/types/trezor/host-types.d.ts +25 -0
  102. package/types/trezor/index.d.ts +7 -7
  103. package/types/trezor/webextension-host.d.ts +7 -0
  104. package/types/trezor-hardware.d.ts +6 -0
  105. package/types/types.d.ts +16 -4
@@ -7,6 +7,7 @@ exports.EthereumTransactions = void 0;
7
7
  const eth_sig_util_1 = require("@metamask/eth-sig-util");
8
8
  const sysweb3_network_1 = require("@sidhujag/sysweb3-network");
9
9
  const sysweb3_utils_1 = require("@sidhujag/sysweb3-utils");
10
+ const address_1 = require("ethers/address");
10
11
  const transaction_1 = require("ethers/transaction");
11
12
  const utils_1 = require("ethers/utils");
12
13
  const omit_1 = __importDefault(require("lodash/omit"));
@@ -15,9 +16,12 @@ const evm_fees_1 = require("../evm-fees");
15
16
  const providers_1 = require("../providers");
16
17
  const types_1 = require("../types");
17
18
  const evm_cancellation_1 = require("./evm-cancellation");
19
+ const evm_envelope_1 = require("./evm-envelope");
18
20
  const evm_local_signer_1 = require("./evm-local-signer");
19
21
  const evm_submission_1 = require("./evm-submission");
22
+ const ledger_signing_1 = require("./ledger-signing");
20
23
  const prepared_evm_1 = require("./prepared-evm");
24
+ const trezor_signing_1 = require("./trezor-signing");
21
25
  const derivation_paths_1 = require("../utils/derivation-paths");
22
26
  const hardwareSignerUnavailable = (hardware) => Object.assign(new Error(`${hardware} signer is unavailable in this host`), {
23
27
  code: 'HARDWARE_SIGNER_UNAVAILABLE',
@@ -35,26 +39,6 @@ const stripHexPrefix = (value) => {
35
39
  ? value.slice(2)
36
40
  : value;
37
41
  };
38
- // Connect returns hexadecimal signature fields; normalize their encoding
39
- // without mutating the response or reparsing an already numeric recovery v.
40
- const trezorSignature = (signature) => {
41
- const { r, s, v } = signature;
42
- if (![r, s].every((value) => /^(?:0x)?[0-9a-f]{64}$/i.test(value))) {
43
- throw new Error('Invalid Trezor signature scalar encoding');
44
- }
45
- if (typeof v === 'string' && !/^(?:0x)?[0-9a-f]+$/i.test(v)) {
46
- throw new Error('Invalid Trezor signature recovery value');
47
- }
48
- const recovery = typeof v === 'number' ? v : Number.parseInt(v, 16);
49
- if (!Number.isSafeInteger(recovery) || recovery < 0) {
50
- throw new Error('Invalid Trezor signature recovery value');
51
- }
52
- return {
53
- r: `0x${stripHexPrefix(r)}`,
54
- s: `0x${stripHexPrefix(s)}`,
55
- v: recovery,
56
- };
57
- };
58
42
  const normalizeEthersOverrideValue = (value) => (0, ethers_v6_1.normalizeTxValue)(value);
59
43
  // The same protocol bound applies to software and external-device envelopes.
60
44
  // Keep this at serialization as well as before handing a request to a device.
@@ -160,7 +144,7 @@ class EthereumTransactions {
160
144
  }
161
145
  return () => assertSynchronousOriginalValidation(guard(), 'Signing context guard must be synchronous');
162
146
  };
163
- this.captureEvmSigningContext = (target) => {
147
+ this.captureEvmAccountContext = (target) => {
164
148
  this.assertHardwareSignerAvailable(target);
165
149
  const state = this.getState();
166
150
  const selectedType = state.activeAccountType;
@@ -174,7 +158,6 @@ class EthereumTransactions {
174
158
  const account = { address: selectedAccount.address };
175
159
  const network = { ...state.activeNetwork };
176
160
  const assertSession = this.captureSessionGuard();
177
- const provider = this.web3Provider;
178
161
  const assertCurrent = () => {
179
162
  assertSession();
180
163
  const current = this.getState();
@@ -188,8 +171,7 @@ class EthereumTransactions {
188
171
  [current.activeNetwork, this.getNetwork()].some((selected) => selected.kind !== network.kind ||
189
172
  selected.chainId !== network.chainId ||
190
173
  selected.slip44 !== network.slip44 ||
191
- selected.url !== network.url) ||
192
- this.web3Provider !== provider)
174
+ selected.url !== network.url))
193
175
  throw new Error('Wallet signing context changed');
194
176
  };
195
177
  assertCurrent();
@@ -198,10 +180,20 @@ class EthereumTransactions {
198
180
  activeAccountType,
199
181
  activeAccountId,
200
182
  activeNetwork: network,
201
- provider,
202
183
  assertCurrent,
203
184
  };
204
185
  };
186
+ this.captureEvmSigningContext = (target) => {
187
+ const context = this.captureEvmAccountContext(target);
188
+ const provider = this.web3Provider;
189
+ const assertCurrent = () => {
190
+ context.assertCurrent();
191
+ if (this.web3Provider !== provider)
192
+ throw new Error('Wallet signing context changed');
193
+ };
194
+ assertCurrent();
195
+ return { ...context, provider, assertCurrent };
196
+ };
205
197
  this.captureSubmission = (operation, account, type, id, network, assertCurrent, details = {}) => {
206
198
  if (!this.captureSubmissionLifecycle)
207
199
  throw new TypeError('A durable EVM submission lifecycle is required');
@@ -302,10 +294,51 @@ class EthereumTransactions {
302
294
  throw error;
303
295
  }
304
296
  };
305
- this.ethSign = async (params) => {
306
- const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
307
- const { accounts, activeAccountId, activeAccountType, activeNetwork } = this.getState();
308
- const activeAccount = accounts[activeAccountType][activeAccountId];
297
+ this.ethSign = async (params, input) => {
298
+ const selected = this.captureEvmAccountContext();
299
+ if (!Array.isArray(params) || params.length !== 2)
300
+ throw new Error('Invalid digest request');
301
+ const first = Object.getOwnPropertyDescriptor(params, '0');
302
+ const second = Object.getOwnPropertyDescriptor(params, '1');
303
+ if (!first ||
304
+ !second ||
305
+ !('value' in first) ||
306
+ !('value' in second) ||
307
+ typeof first.value !== 'string' ||
308
+ typeof second.value !== 'string')
309
+ throw new Error('Invalid digest request');
310
+ params = [first.value, second.value];
311
+ const options = (0, evm_envelope_1.readEvmOwnData)(input, [
312
+ 'selectedAccount',
313
+ 'targetAccount',
314
+ 'assertCurrent',
315
+ ]);
316
+ const selectedAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.selectedAccount);
317
+ const targetAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.targetAccount);
318
+ const hostGuard = (0, prepared_evm_1.preparedEvmGuard)({
319
+ assertCurrent: options.assertCurrent,
320
+ });
321
+ const target = {
322
+ id: targetAccount.id,
323
+ type: targetAccount.type,
324
+ };
325
+ const context = this.captureEvmAccountContext(target);
326
+ const assertCurrent = () => {
327
+ hostGuard();
328
+ selected.assertCurrent();
329
+ context.assertCurrent();
330
+ if (selected.activeAccountId !== selectedAccount.id ||
331
+ selected.activeAccountType !== selectedAccount.type ||
332
+ (0, address_1.getAddress)(selected.activeAccount.address) !==
333
+ selectedAccount.expectedAddress ||
334
+ (0, address_1.getAddress)(context.activeAccount.address) !==
335
+ targetAccount.expectedAddress ||
336
+ targetAccount.type === 'SmartAccount')
337
+ throw new Error('EVM digest signing context changed');
338
+ };
339
+ assertCurrent();
340
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(target);
341
+ const { activeAccountId, activeAccountType, activeNetwork, activeAccount } = context;
309
342
  // Validate that the derived address matches the active account to prevent race conditions
310
343
  if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
311
344
  throw {
@@ -374,14 +407,19 @@ class EthereumTransactions {
374
407
  throw error;
375
408
  }
376
409
  };
410
+ let signature;
377
411
  switch (activeAccountType) {
378
412
  case types_1.KeyringAccountType.Trezor:
379
- return await signWithTrezor();
413
+ signature = await signWithTrezor();
414
+ break;
380
415
  case types_1.KeyringAccountType.Ledger:
381
- return await signWithLedger();
416
+ signature = await signWithLedger();
417
+ break;
382
418
  default:
383
- return sign();
419
+ signature = sign();
384
420
  }
421
+ assertCurrent();
422
+ return signature;
385
423
  };
386
424
  this.signPersonalMessage = async (params) => {
387
425
  const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
@@ -951,33 +989,18 @@ class EthereumTransactions {
951
989
  const rawTx = serializeTransaction(txFormattedForEthers);
952
990
  if (retained)
953
991
  assertCancellationEnvelope(rawTx);
954
- const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
955
- rawTx: rawTx.replace('0x', ''),
992
+ const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
993
+ unsignedTransaction: rawTx,
956
994
  accountIndex: activeAccountId,
957
995
  expectedAddress: activeAccount.address,
958
996
  }, await this.authorizeHardwareTransaction(provider, assertCurrent));
959
997
  assertCurrent();
960
- const formattedSignature = {
961
- r: `0x${signature.r}`,
962
- s: `0x${signature.s}`,
963
- v: parseInt(signature.v, 16),
998
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
999
+ const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
1000
+ return {
1001
+ isCanceled: true,
1002
+ transaction: transactionResponse,
964
1003
  };
965
- if (signature) {
966
- const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
967
- assertCurrent();
968
- assertHardwareTransactionSender(signedTx, activeAccount.address);
969
- const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
970
- return {
971
- isCanceled: true,
972
- transaction: transactionResponse,
973
- };
974
- }
975
- else {
976
- return {
977
- isCanceled: false,
978
- error: true,
979
- };
980
- }
981
1004
  }
982
1005
  catch (error) {
983
1006
  return {
@@ -1025,29 +1048,20 @@ class EthereumTransactions {
1025
1048
  const expectedUnsignedTransaction = serializeTransaction(txFormattedForTrezor);
1026
1049
  if (retained)
1027
1050
  assertCancellationEnvelope(expectedUnsignedTransaction);
1028
- const signature = await this.requireTrezorSigner().signEthTransaction({
1051
+ const { rawTransaction: signedTx } = await (0, trezor_signing_1.signTrezorEvmTransaction)(this.requireTrezorSigner(), {
1052
+ accountIndex: activeAccountId,
1029
1053
  coin: trezorCoin,
1030
- tx: txFormattedForTrezor,
1031
- index: activeAccountId.toString(),
1054
+ expectedAddress: activeAccount.address,
1032
1055
  slip44: activeNetwork.slip44,
1056
+ unsignedTransaction: expectedUnsignedTransaction,
1033
1057
  }, await this.authorizeHardwareTransaction(provider, assertCurrent));
1034
1058
  assertCurrent();
1035
- if (signature.success) {
1036
- const signedTx = serializeTransaction(txFormattedForTrezor, trezorSignature(signature.payload));
1037
- assertCurrent();
1038
- assertHardwareTransactionSender(signedTx, activeAccount.address);
1039
- const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
1040
- return {
1041
- isCanceled: true,
1042
- transaction: transactionResponse,
1043
- };
1044
- }
1045
- else {
1046
- return {
1047
- isCanceled: false,
1048
- error: true,
1049
- };
1050
- }
1059
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
1060
+ const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
1061
+ return {
1062
+ isCanceled: true,
1063
+ transaction: transactionResponse,
1064
+ };
1051
1065
  }
1052
1066
  catch (error) {
1053
1067
  return {
@@ -1108,12 +1122,21 @@ class EthereumTransactions {
1108
1122
  typeof options !== 'object' ||
1109
1123
  Array.isArray(options) ||
1110
1124
  (options.mode !== 'reviewed-native' &&
1125
+ options.mode !== 'reviewed-generic' &&
1111
1126
  options.mode !== 'specialized') ||
1112
1127
  typeof options.assertCurrent !== 'function')
1113
1128
  throw new Error('Explicit transaction approval is required');
1114
1129
  // Capture once; later caller mutations cannot replace this invocation's
1115
1130
  // admission decision while chain checks or device approval are pending.
1116
1131
  const { assertCurrent: assertHostCurrent, mode, walletNonce } = options;
1132
+ const reviewId = mode === 'reviewed-generic' ? options.reviewId : undefined;
1133
+ if (mode === 'reviewed-generic' &&
1134
+ (typeof reviewId !== 'string' ||
1135
+ !/^[A-Za-z0-9_-]{1,128}$/.test(reviewId) ||
1136
+ walletNonce === undefined))
1137
+ throw new Error('An issued fee review and approved nonce are required');
1138
+ const selectedAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.selectedAccount);
1139
+ const targetAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.targetAccount);
1117
1140
  const nonceApproval = walletNonce === undefined ? undefined : { ...walletNonce };
1118
1141
  const assertApproved = () => {
1119
1142
  const result = assertHostCurrent();
@@ -1125,14 +1148,14 @@ class EthereumTransactions {
1125
1148
  assertApproved();
1126
1149
  return await this.sendFormattedTransactionInternal(params, isLegacy, () => {
1127
1150
  broadcastAttempted = true;
1128
- }, assertApproved, mode, nonceApproval);
1151
+ }, assertApproved, mode, nonceApproval, selectedAccount, targetAccount, reviewId);
1129
1152
  }
1130
1153
  catch (error) {
1131
1154
  // A broadcast transport error may mean the node accepted the signed
1132
1155
  // transaction. Derive this marker from this invocation, never RPC data.
1133
1156
  const submissionError = Object.assign(new Error(error instanceof Error ? error.message : String(error)), error, {
1134
1157
  transactionNotBroadcast: !broadcastAttempted ||
1135
- (0, evm_submission_1.evmSubmissionFailure)(error).transactionNotBroadcast,
1158
+ (0, evm_submission_1.evmSubmissionFailure)(error)?.transactionNotBroadcast === true,
1136
1159
  });
1137
1160
  if (error instanceof Error) {
1138
1161
  submissionError.name = error.name;
@@ -1142,19 +1165,60 @@ class EthereumTransactions {
1142
1165
  throw submissionError;
1143
1166
  }
1144
1167
  };
1145
- this.sendFormattedTransactionInternal = async (input, isLegacy, beforeBroadcast, assertHostCurrent, mode, walletNonce) => {
1168
+ this.sendFormattedTransactionInternal = async (input, isLegacy, beforeBroadcast, assertHostCurrent, mode, walletNonce, selectedIdentity, targetIdentity, reviewId) => {
1146
1169
  // Hardware approval may outlive the selected account, network or unlocked
1147
1170
  // session. Keep immutable identities and one provider for this invocation.
1148
- const { activeAccount, activeAccountType, activeAccountId, activeNetwork, provider, assertCurrent: assertKeyringCurrent, } = this.captureEvmSigningContext();
1171
+ const selectedContext = this.captureEvmAccountContext();
1172
+ const targetAccount = {
1173
+ id: targetIdentity.id,
1174
+ type: targetIdentity.type,
1175
+ };
1176
+ if (targetAccount.type === types_1.KeyringAccountType.SmartAccount)
1177
+ throw new Error('Invalid EVM payer');
1178
+ const { activeAccount, activeAccountType, activeAccountId, activeNetwork, provider, assertCurrent: assertKeyringCurrent, } = this.captureEvmSigningContext(targetAccount);
1149
1179
  const assertSigningCurrent = () => {
1150
1180
  assertHostCurrent();
1181
+ selectedContext.assertCurrent();
1151
1182
  assertKeyringCurrent();
1183
+ if (selectedContext.activeAccountId !== selectedIdentity.id ||
1184
+ selectedContext.activeAccountType !== selectedIdentity.type ||
1185
+ (0, address_1.getAddress)(selectedContext.activeAccount.address) !==
1186
+ selectedIdentity.expectedAddress ||
1187
+ (0, address_1.getAddress)(activeAccount.address) !== targetIdentity.expectedAddress)
1188
+ throw new Error('EVM payer approval context changed');
1152
1189
  };
1190
+ assertSigningCurrent();
1191
+ // Generic reviewed calls keep the exact prepared envelope, including
1192
+ // contract creation, calldata and access lists, through existing signers.
1193
+ const reviewed = mode === 'reviewed-generic'
1194
+ ? (0, evm_envelope_1.snapshotPreparedEvmTransaction)(input)
1195
+ : undefined;
1196
+ if (reviewed) {
1197
+ if (reviewed.from !== targetIdentity.expectedAddress ||
1198
+ reviewed.chainId !== String(activeNetwork.chainId) ||
1199
+ reviewed.nonce !== String(walletNonce?.nonce) ||
1200
+ (isLegacy !== undefined && isLegacy !== (reviewed.type === 0)) ||
1201
+ (this.gasOverrides.minGasLimit &&
1202
+ BigInt(reviewed.gasLimit) < this.gasOverrides.minGasLimit.toBigInt()))
1203
+ throw new Error('Reviewed EVM transaction does not match its approval');
1204
+ input = reviewed;
1205
+ isLegacy = reviewed.type === 0;
1206
+ }
1153
1207
  const assertBeforeBroadcast = () => {
1154
1208
  assertCurrent();
1155
1209
  beforeBroadcast();
1156
1210
  };
1157
- const submission = this.captureSubmission('send', activeAccount, activeAccountType, activeAccountId, activeNetwork, assertSigningCurrent, { walletNonce });
1211
+ const submission = this.captureSubmission('send', activeAccount, activeAccountType, activeAccountId, activeNetwork, assertSigningCurrent, {
1212
+ walletNonce,
1213
+ ...(reviewed
1214
+ ? {
1215
+ review: {
1216
+ id: reviewId,
1217
+ unsignedHash: transaction_1.Transaction.from((0, evm_envelope_1.serializePreparedEvmTransaction)(reviewed)).unsignedHash,
1218
+ },
1219
+ }
1220
+ : {}),
1221
+ });
1158
1222
  const assertCurrent = submission.assertCurrent;
1159
1223
  const approvedNonce = submission.context.walletNonce?.nonce;
1160
1224
  const assertApprovedNonce = (nonce) => {
@@ -1163,6 +1227,7 @@ class EthereumTransactions {
1163
1227
  };
1164
1228
  if (mode === 'reviewed-native') {
1165
1229
  const { transaction } = (0, prepared_evm_1.snapshotPreparedEvmRequest)({
1230
+ selectedAccount: selectedIdentity,
1166
1231
  account: {
1167
1232
  id: activeAccountId,
1168
1233
  type: activeAccountType,
@@ -1193,7 +1258,7 @@ class EthereumTransactions {
1193
1258
  assertCurrent();
1194
1259
  if (this.gasOverrides.minGasLimit !== minimum)
1195
1260
  throw new Error('Reviewed native gas policy changed');
1196
- const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
1261
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(targetAccount);
1197
1262
  if (address.toLowerCase() !== transaction.from.toLowerCase())
1198
1263
  throw new Error('Reviewed native signer does not match the approved account');
1199
1264
  assertCurrent();
@@ -1206,6 +1271,9 @@ class EthereumTransactions {
1206
1271
  if (!params || typeof params !== 'object' || Array.isArray(params))
1207
1272
  throw new TypeError('Invalid EVM transaction request');
1208
1273
  const supplied = { ...params };
1274
+ if (supplied.from !== undefined &&
1275
+ (0, address_1.getAddress)(supplied.from) !== targetIdentity.expectedAddress)
1276
+ throw new Error('EVM transaction sender does not match the approved payer');
1209
1277
  // Validate original scalar spellings before conversion. Normalization's
1210
1278
  // permissive zero coercion must not bypass the bounded wire parser.
1211
1279
  for (const field of [
@@ -1258,7 +1326,8 @@ class EthereumTransactions {
1258
1326
  const validateEip1559Fees = () => {
1259
1327
  const maximum = nonNegativeFeeQuantity(params.maxFeePerGas, 'maximum fee');
1260
1328
  const priority = nonNegativeFeeQuantity(params.maxPriorityFeePerGas, 'priority fee');
1261
- if (maximum.isZero() || priority.gt(maximum))
1329
+ if ((mode !== 'reviewed-generic' && maximum.isZero()) ||
1330
+ priority.gt(maximum))
1262
1331
  throw new Error('Invalid EIP-1559 fees');
1263
1332
  params.maxFeePerGas = maximum;
1264
1333
  params.maxPriorityFeePerGas = priority;
@@ -1269,7 +1338,9 @@ class EthereumTransactions {
1269
1338
  validateEip1559Fees();
1270
1339
  // Only apply a minimum gas limit when a network-specific override is set.
1271
1340
  // Otherwise keep the user/dapp-approved gas limit unchanged.
1272
- if (params.gasLimit != null && this.gasOverrides.minGasLimit) {
1341
+ if (mode !== 'reviewed-generic' &&
1342
+ params.gasLimit != null &&
1343
+ this.gasOverrides.minGasLimit) {
1273
1344
  const minGasLimit = this.gasOverrides.minGasLimit;
1274
1345
  const currentGasLimit = ethers_v6_1.BigNumber.from(params.gasLimit);
1275
1346
  if (currentGasLimit.lt(minGasLimit)) {
@@ -1340,31 +1411,15 @@ class EthereumTransactions {
1340
1411
  type: 2, // Need explicit type for hardware wallet serialization
1341
1412
  };
1342
1413
  const rawTx = serializeTransaction(txFormattedForEthers);
1343
- const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
1344
- rawTx: rawTx.replace('0x', ''),
1414
+ const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
1415
+ unsignedTransaction: rawTx,
1345
1416
  accountIndex: activeAccountId,
1346
1417
  expectedAddress: activeAccount.address,
1347
1418
  }, await this.authorizeHardwareTransaction(provider, assertCurrent));
1348
1419
  assertCurrent();
1349
- const formattedSignature = {
1350
- r: `0x${signature.r}`,
1351
- s: `0x${signature.s}`,
1352
- v: parseInt(signature.v, 16),
1353
- };
1354
- if (signature) {
1355
- try {
1356
- const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
1357
- assertHardwareTransactionSender(signedTx, activeAccount.address);
1358
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
1359
- return finalTx;
1360
- }
1361
- catch (error) {
1362
- throw error;
1363
- }
1364
- }
1365
- else {
1366
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
1367
- }
1420
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
1421
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
1422
+ return finalTx;
1368
1423
  };
1369
1424
  const sendEVMTrezorTransaction = async () => {
1370
1425
  assertCurrent();
@@ -1421,44 +1476,21 @@ class EthereumTransactions {
1421
1476
  ...txFormattedForTrezor,
1422
1477
  type: isLegacy ? 0 : 2,
1423
1478
  });
1424
- const signature = await this.requireTrezorSigner().signEthTransaction({
1425
- index: `${activeAccountId}`,
1426
- tx: txFormattedForTrezor,
1479
+ const { rawTransaction: signedTx } = await (0, trezor_signing_1.signTrezorEvmTransaction)(this.requireTrezorSigner(), {
1480
+ accountIndex: activeAccountId,
1427
1481
  coin: activeNetwork.currency,
1482
+ expectedAddress: activeAccount.address,
1428
1483
  slip44: activeNetwork.slip44,
1484
+ unsignedTransaction: expectedUnsignedTransaction,
1429
1485
  }, await this.authorizeHardwareTransaction(provider, assertCurrent));
1430
1486
  assertCurrent();
1431
- if (signature.success) {
1432
- try {
1433
- const txFormattedForEthers = isLegacy
1434
- ? {
1435
- ...formatParams,
1436
- nonce: transactionNonce,
1437
- chainId: activeNetwork.chainId,
1438
- type: 0, // Force Type 0 for legacy
1439
- }
1440
- : {
1441
- ...formatParams,
1442
- nonce: transactionNonce,
1443
- chainId: activeNetwork.chainId,
1444
- type: 2, // Need explicit type for hardware wallet serialization
1445
- };
1446
- const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
1447
- assertHardwareTransactionSender(signedTx, activeAccount.address);
1448
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, expectedUnsignedTransaction);
1449
- return finalTx;
1450
- }
1451
- catch (error) {
1452
- throw error;
1453
- }
1454
- }
1455
- else {
1456
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
1457
- }
1487
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
1488
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, expectedUnsignedTransaction);
1489
+ return finalTx;
1458
1490
  };
1459
1491
  const sendEVMTransaction = async () => {
1460
1492
  assertCurrent();
1461
- const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
1493
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(targetAccount);
1462
1494
  // Validate that we have the correct private key for the active account to prevent race conditions
1463
1495
  // This is critical for transaction security during account switches
1464
1496
  if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
@@ -1715,32 +1747,18 @@ class EthereumTransactions {
1715
1747
  };
1716
1748
  const rawTx = serializeTransaction(txFormattedForEthers);
1717
1749
  assertCurrent();
1718
- const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
1719
- rawTx: rawTx.replace('0x', ''),
1750
+ const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
1751
+ unsignedTransaction: rawTx,
1720
1752
  accountIndex: activeAccountId,
1721
1753
  expectedAddress: activeAccount.address,
1722
1754
  }, await this.authorizeHardwareTransaction(provider, assertCurrent));
1723
- const formattedSignature = {
1724
- r: `0x${signature.r}`,
1725
- s: `0x${signature.s}`,
1726
- v: parseInt(signature.v, 16),
1755
+ assertSignedSender(signedTx);
1756
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
1757
+ const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
1758
+ return {
1759
+ isSpeedUp: true,
1760
+ transaction: transactionResponse,
1727
1761
  };
1728
- if (signature) {
1729
- const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
1730
- assertSignedSender(signedTx);
1731
- assertHardwareTransactionSender(signedTx, activeAccount.address);
1732
- const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
1733
- return {
1734
- isSpeedUp: true,
1735
- transaction: transactionResponse,
1736
- };
1737
- }
1738
- else {
1739
- return {
1740
- isSpeedUp: false,
1741
- error: true,
1742
- };
1743
- }
1744
1762
  }
1745
1763
  catch (error) {
1746
1764
  console.error('[SpeedUp] Failed to send replacement transaction with Ledger:', error);
@@ -1800,28 +1818,20 @@ class EthereumTransactions {
1800
1818
  assertCurrent();
1801
1819
  assertTransactionGasLimit(txFormattedForTrezor);
1802
1820
  const expectedUnsignedTransaction = serializeTransaction(txFormattedForTrezor);
1803
- const signature = await this.requireTrezorSigner().signEthTransaction({
1821
+ const { rawTransaction: signedTx } = await (0, trezor_signing_1.signTrezorEvmTransaction)(this.requireTrezorSigner(), {
1822
+ accountIndex: activeAccountId,
1804
1823
  coin: trezorCoin,
1805
- tx: txFormattedForTrezor,
1806
- index: activeAccountId.toString(),
1824
+ expectedAddress: activeAccount.address,
1807
1825
  slip44: activeNetwork.slip44,
1826
+ unsignedTransaction: expectedUnsignedTransaction,
1808
1827
  }, await this.authorizeHardwareTransaction(provider, assertCurrent));
1809
- if (signature.success) {
1810
- const signedTx = serializeTransaction(txFormattedForTrezor, trezorSignature(signature.payload));
1811
- assertSignedSender(signedTx);
1812
- assertHardwareTransactionSender(signedTx, activeAccount.address);
1813
- const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, expectedUnsignedTransaction);
1814
- return {
1815
- isSpeedUp: true,
1816
- transaction: transactionResponse,
1817
- };
1818
- }
1819
- else {
1820
- return {
1821
- isSpeedUp: false,
1822
- error: true,
1823
- };
1824
- }
1828
+ assertSignedSender(signedTx);
1829
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
1830
+ const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, expectedUnsignedTransaction);
1831
+ return {
1832
+ isSpeedUp: true,
1833
+ transaction: transactionResponse,
1834
+ };
1825
1835
  }
1826
1836
  catch (error) {
1827
1837
  console.error('[SpeedUp] Failed to send replacement transaction with Trezor:', error);
@@ -1953,73 +1963,51 @@ class EthereumTransactions {
1953
1963
  };
1954
1964
  const sendERC20TokenOnLedger = async () => {
1955
1965
  assertCurrent();
1956
- try {
1957
- const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc20Abi)(), provider);
1958
- const txData = _contract.interface.encodeFunctionData('transfer', [
1959
- receiver,
1960
- exactTokenAmount,
1961
- ]);
1962
- let txFormattedForEthers;
1963
- if (isLegacy) {
1964
- txFormattedForEthers = {
1965
- to: tokenAddress,
1966
- value: '0x0',
1967
- gasLimit: gasLimit,
1968
- gasPrice,
1969
- data: txData,
1970
- nonce,
1971
- chainId: activeNetwork.chainId,
1972
- type: 0,
1973
- };
1974
- }
1975
- else {
1976
- txFormattedForEthers = {
1977
- to: tokenAddress,
1978
- value: '0x0',
1979
- gasLimit: gasLimit,
1980
- maxFeePerGas,
1981
- maxPriorityFeePerGas,
1982
- data: txData,
1983
- nonce,
1984
- chainId: activeNetwork.chainId,
1985
- type: 2, // Need explicit type for hardware wallet serialization
1986
- };
1987
- }
1988
- const rawTx = serializeTransaction(txFormattedForEthers);
1989
- const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
1990
- rawTx: rawTx.replace('0x', ''),
1991
- accountIndex: activeAccountId,
1992
- expectedAddress: activeAccount.address,
1993
- }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
1994
- assertCurrent();
1995
- const formattedSignature = {
1996
- r: `0x${signature.r}`,
1997
- s: `0x${signature.s}`,
1998
- v: parseInt(signature.v, 16),
1966
+ const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc20Abi)(), provider);
1967
+ const txData = _contract.interface.encodeFunctionData('transfer', [
1968
+ receiver,
1969
+ exactTokenAmount,
1970
+ ]);
1971
+ let txFormattedForEthers;
1972
+ if (isLegacy) {
1973
+ txFormattedForEthers = {
1974
+ to: tokenAddress,
1975
+ value: '0x0',
1976
+ gasLimit: gasLimit,
1977
+ gasPrice,
1978
+ data: txData,
1979
+ nonce,
1980
+ chainId: activeNetwork.chainId,
1981
+ type: 0,
1999
1982
  };
2000
- if (signature) {
2001
- try {
2002
- const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
2003
- assertCurrent();
2004
- assertHardwareTransactionSender(signedTx, activeAccount.address);
2005
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
2006
- const response = await admit(() => provider.sendTransaction(rawTransaction));
2007
- saveTrezorTx && saveTrezorTx(response);
2008
- return response;
2009
- }, submission, undefined, rawTx);
2010
- return finalTx;
2011
- }
2012
- catch (error) {
2013
- throw error;
2014
- }
2015
- }
2016
- else {
2017
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
2018
- }
2019
1983
  }
2020
- catch (error) {
2021
- throw error;
1984
+ else {
1985
+ txFormattedForEthers = {
1986
+ to: tokenAddress,
1987
+ value: '0x0',
1988
+ gasLimit: gasLimit,
1989
+ maxFeePerGas,
1990
+ maxPriorityFeePerGas,
1991
+ data: txData,
1992
+ nonce,
1993
+ chainId: activeNetwork.chainId,
1994
+ type: 2, // Need explicit type for hardware wallet serialization
1995
+ };
2022
1996
  }
1997
+ const rawTx = serializeTransaction(txFormattedForEthers);
1998
+ const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
1999
+ unsignedTransaction: rawTx,
2000
+ accountIndex: activeAccountId,
2001
+ expectedAddress: activeAccount.address,
2002
+ }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2003
+ assertCurrent();
2004
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
2005
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
2006
+ const response = await admit(() => provider.sendTransaction(rawTransaction));
2007
+ saveTrezorTx && saveTrezorTx(response);
2008
+ return response;
2009
+ }, submission, undefined, rawTx);
2010
+ return finalTx;
2023
2011
  };
2024
2012
  const sendERC20TokenOnTrezor = async () => {
2025
2013
  assertCurrent();
@@ -2058,58 +2046,21 @@ class EthereumTransactions {
2058
2046
  ...txToBeSignedByTrezor,
2059
2047
  type: isLegacy ? 0 : 2,
2060
2048
  });
2061
- const signature = await this.requireTrezorSigner().signEthTransaction({
2062
- index: `${activeAccountId}`,
2063
- tx: txToBeSignedByTrezor,
2049
+ const { rawTransaction: signedTx } = await (0, trezor_signing_1.signTrezorEvmTransaction)(this.requireTrezorSigner(), {
2050
+ accountIndex: activeAccountId,
2064
2051
  coin: activeNetwork.currency,
2052
+ expectedAddress: activeAccount.address,
2065
2053
  slip44: activeNetwork.slip44,
2054
+ unsignedTransaction: expectedUnsignedTransaction,
2066
2055
  }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2067
2056
  assertCurrent();
2068
- if (signature.success) {
2069
- try {
2070
- let txFormattedForEthers;
2071
- if (isLegacy) {
2072
- txFormattedForEthers = {
2073
- to: tokenAddress,
2074
- value: '0x0',
2075
- gasLimit: gasLimit,
2076
- gasPrice,
2077
- data: txData,
2078
- nonce,
2079
- chainId: activeNetwork.chainId,
2080
- type: 0,
2081
- };
2082
- }
2083
- else {
2084
- txFormattedForEthers = {
2085
- to: tokenAddress,
2086
- value: '0x0',
2087
- gasLimit: gasLimit,
2088
- maxFeePerGas,
2089
- maxPriorityFeePerGas,
2090
- data: txData,
2091
- nonce,
2092
- chainId: activeNetwork.chainId,
2093
- type: 2, // Need explicit type for hardware wallet serialization
2094
- };
2095
- }
2096
- const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
2097
- assertCurrent();
2098
- assertHardwareTransactionSender(signedTx, activeAccount.address);
2099
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
2100
- const response = await admit(() => provider.sendTransaction(rawTransaction));
2101
- saveTrezorTx && saveTrezorTx(response);
2102
- return response;
2103
- }, submission, undefined, expectedUnsignedTransaction);
2104
- return finalTx;
2105
- }
2106
- catch (error) {
2107
- throw error;
2108
- }
2109
- }
2110
- else {
2111
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
2112
- }
2057
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
2058
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
2059
+ const response = await admit(() => provider.sendTransaction(rawTransaction));
2060
+ saveTrezorTx && saveTrezorTx(response);
2061
+ return response;
2062
+ }, submission, undefined, expectedUnsignedTransaction);
2063
+ return finalTx;
2113
2064
  }
2114
2065
  catch (error) {
2115
2066
  throw error;
@@ -2180,70 +2131,48 @@ class EthereumTransactions {
2180
2131
  };
2181
2132
  const sendERC721TokenOnLedger = async () => {
2182
2133
  assertCurrent();
2183
- try {
2184
- const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc21Abi)(), provider);
2185
- const txData = _contract.interface.encodeFunctionData('transferFrom', [
2186
- activeAccountAddress,
2187
- receiver,
2188
- normalizedTokenId,
2189
- ]);
2190
- let txFormattedForEthers;
2191
- if (isLegacy) {
2192
- txFormattedForEthers = {
2193
- to: tokenAddress,
2194
- value: '0x0',
2195
- gasLimit,
2196
- gasPrice,
2197
- data: txData,
2198
- nonce,
2199
- chainId: activeNetwork.chainId,
2200
- type: 0,
2201
- };
2202
- }
2203
- else {
2204
- txFormattedForEthers = {
2205
- to: tokenAddress,
2206
- value: '0x0',
2207
- gasLimit,
2208
- maxFeePerGas,
2209
- maxPriorityFeePerGas,
2210
- data: txData,
2211
- nonce,
2212
- chainId: activeNetwork.chainId,
2213
- type: 2, // Need explicit type for hardware wallet serialization
2214
- };
2215
- }
2216
- const rawTx = serializeTransaction(txFormattedForEthers);
2217
- const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
2218
- rawTx: rawTx.replace('0x', ''),
2219
- accountIndex: activeAccountId,
2220
- expectedAddress: activeAccount.address,
2221
- }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2222
- assertCurrent();
2223
- const formattedSignature = {
2224
- r: `0x${signature.r}`,
2225
- s: `0x${signature.s}`,
2226
- v: parseInt(signature.v, 16),
2134
+ const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc21Abi)(), provider);
2135
+ const txData = _contract.interface.encodeFunctionData('transferFrom', [
2136
+ activeAccountAddress,
2137
+ receiver,
2138
+ normalizedTokenId,
2139
+ ]);
2140
+ let txFormattedForEthers;
2141
+ if (isLegacy) {
2142
+ txFormattedForEthers = {
2143
+ to: tokenAddress,
2144
+ value: '0x0',
2145
+ gasLimit,
2146
+ gasPrice,
2147
+ data: txData,
2148
+ nonce,
2149
+ chainId: activeNetwork.chainId,
2150
+ type: 0,
2227
2151
  };
2228
- if (signature) {
2229
- try {
2230
- const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
2231
- assertCurrent();
2232
- assertHardwareTransactionSender(signedTx, activeAccount.address);
2233
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
2234
- return finalTx;
2235
- }
2236
- catch (error) {
2237
- throw error;
2238
- }
2239
- }
2240
- else {
2241
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
2242
- }
2243
2152
  }
2244
- catch (error) {
2245
- throw error;
2153
+ else {
2154
+ txFormattedForEthers = {
2155
+ to: tokenAddress,
2156
+ value: '0x0',
2157
+ gasLimit,
2158
+ maxFeePerGas,
2159
+ maxPriorityFeePerGas,
2160
+ data: txData,
2161
+ nonce,
2162
+ chainId: activeNetwork.chainId,
2163
+ type: 2, // Need explicit type for hardware wallet serialization
2164
+ };
2246
2165
  }
2166
+ const rawTx = serializeTransaction(txFormattedForEthers);
2167
+ const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
2168
+ unsignedTransaction: rawTx,
2169
+ accountIndex: activeAccountId,
2170
+ expectedAddress: activeAccount.address,
2171
+ }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2172
+ assertCurrent();
2173
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
2174
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
2175
+ return finalTx;
2247
2176
  };
2248
2177
  const sendERC721TokenOnTrezor = async () => {
2249
2178
  assertCurrent();
@@ -2286,55 +2215,17 @@ class EthereumTransactions {
2286
2215
  ...txToBeSignedByTrezor,
2287
2216
  type: isLegacy ? 0 : 2,
2288
2217
  });
2289
- const signature = await this.requireTrezorSigner().signEthTransaction({
2290
- index: `${activeAccountId}`,
2291
- tx: txToBeSignedByTrezor,
2218
+ const { rawTransaction: signedTx } = await (0, trezor_signing_1.signTrezorEvmTransaction)(this.requireTrezorSigner(), {
2219
+ accountIndex: activeAccountId,
2292
2220
  coin: trezorCoin,
2221
+ expectedAddress: activeAccount.address,
2293
2222
  slip44: activeNetwork.slip44,
2223
+ unsignedTransaction: expectedUnsignedTransaction,
2294
2224
  }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2295
2225
  assertCurrent();
2296
- if (signature.success) {
2297
- try {
2298
- let txFormattedForEthers;
2299
- if (isLegacy) {
2300
- txFormattedForEthers = {
2301
- to: tokenAddress,
2302
- value: '0x0',
2303
- gasLimit,
2304
- gasPrice,
2305
- data: txData,
2306
- nonce,
2307
- chainId: activeNetwork.chainId,
2308
- type: 0,
2309
- };
2310
- }
2311
- else {
2312
- txFormattedForEthers = {
2313
- to: tokenAddress,
2314
- value: '0x0',
2315
- gasLimit,
2316
- maxFeePerGas,
2317
- maxPriorityFeePerGas,
2318
- data: txData,
2319
- nonce,
2320
- chainId: activeNetwork.chainId,
2321
- type: 2, // Need explicit type for hardware wallet serialization
2322
- };
2323
- }
2324
- const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
2325
- assertCurrent();
2326
- assertHardwareTransactionSender(signedTx, activeAccount.address);
2327
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
2328
- return finalTx;
2329
- }
2330
- catch (error) {
2331
- console.log({ error });
2332
- throw error;
2333
- }
2334
- }
2335
- else {
2336
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
2337
- }
2226
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
2227
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
2228
+ return finalTx;
2338
2229
  }
2339
2230
  catch (error) {
2340
2231
  console.log({ errorDois: error });
@@ -2410,66 +2301,44 @@ class EthereumTransactions {
2410
2301
  };
2411
2302
  const sendERC1155TokenOnLedger = async () => {
2412
2303
  assertCurrent();
2413
- try {
2414
- const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc55Abi)(), provider);
2415
- const txData = _contract.interface.encodeFunctionData('safeTransferFrom', [activeAccountAddress, receiver, normalizedTokenId, amount, '0x']);
2416
- let txFormattedForEthers;
2417
- if (isLegacy) {
2418
- txFormattedForEthers = {
2419
- to: tokenAddress,
2420
- value: '0x0',
2421
- gasLimit,
2422
- gasPrice,
2423
- data: txData,
2424
- nonce,
2425
- chainId: activeNetwork.chainId,
2426
- type: 0,
2427
- };
2428
- }
2429
- else {
2430
- txFormattedForEthers = {
2431
- to: tokenAddress,
2432
- value: '0x0',
2433
- gasLimit,
2434
- maxFeePerGas,
2435
- maxPriorityFeePerGas,
2436
- data: txData,
2437
- nonce,
2438
- chainId: activeNetwork.chainId,
2439
- type: 2, // Need explicit type for hardware wallet serialization
2440
- };
2441
- }
2442
- const rawTx = serializeTransaction(txFormattedForEthers);
2443
- const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
2444
- rawTx: rawTx.replace('0x', ''),
2445
- accountIndex: activeAccountId,
2446
- expectedAddress: activeAccount.address,
2447
- }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2448
- assertCurrent();
2449
- const formattedSignature = {
2450
- r: `0x${signature.r}`,
2451
- s: `0x${signature.s}`,
2452
- v: parseInt(signature.v, 16),
2304
+ const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc55Abi)(), provider);
2305
+ const txData = _contract.interface.encodeFunctionData('safeTransferFrom', [activeAccountAddress, receiver, normalizedTokenId, amount, '0x']);
2306
+ let txFormattedForEthers;
2307
+ if (isLegacy) {
2308
+ txFormattedForEthers = {
2309
+ to: tokenAddress,
2310
+ value: '0x0',
2311
+ gasLimit,
2312
+ gasPrice,
2313
+ data: txData,
2314
+ nonce,
2315
+ chainId: activeNetwork.chainId,
2316
+ type: 0,
2453
2317
  };
2454
- if (signature) {
2455
- try {
2456
- const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
2457
- assertCurrent();
2458
- assertHardwareTransactionSender(signedTx, activeAccount.address);
2459
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
2460
- return finalTx;
2461
- }
2462
- catch (error) {
2463
- throw error;
2464
- }
2465
- }
2466
- else {
2467
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
2468
- }
2469
2318
  }
2470
- catch (error) {
2471
- throw error;
2319
+ else {
2320
+ txFormattedForEthers = {
2321
+ to: tokenAddress,
2322
+ value: '0x0',
2323
+ gasLimit,
2324
+ maxFeePerGas,
2325
+ maxPriorityFeePerGas,
2326
+ data: txData,
2327
+ nonce,
2328
+ chainId: activeNetwork.chainId,
2329
+ type: 2, // Need explicit type for hardware wallet serialization
2330
+ };
2472
2331
  }
2332
+ const rawTx = serializeTransaction(txFormattedForEthers);
2333
+ const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
2334
+ unsignedTransaction: rawTx,
2335
+ accountIndex: activeAccountId,
2336
+ expectedAddress: activeAccount.address,
2337
+ }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2338
+ assertCurrent();
2339
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
2340
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
2341
+ return finalTx;
2473
2342
  };
2474
2343
  const sendERC1155TokenOnTrezor = async () => {
2475
2344
  assertCurrent();
@@ -2505,55 +2374,17 @@ class EthereumTransactions {
2505
2374
  ...txToBeSignedByTrezor,
2506
2375
  type: isLegacy ? 0 : 2,
2507
2376
  });
2508
- const signature = await this.requireTrezorSigner().signEthTransaction({
2509
- index: `${activeAccountId}`,
2510
- tx: txToBeSignedByTrezor,
2377
+ const { rawTransaction: signedTx } = await (0, trezor_signing_1.signTrezorEvmTransaction)(this.requireTrezorSigner(), {
2378
+ accountIndex: activeAccountId,
2511
2379
  coin: activeNetwork.currency,
2380
+ expectedAddress: activeAccount.address,
2512
2381
  slip44: activeNetwork.slip44,
2382
+ unsignedTransaction: expectedUnsignedTransaction,
2513
2383
  }, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
2514
2384
  assertCurrent();
2515
- if (signature.success) {
2516
- try {
2517
- let txFormattedForEthers;
2518
- if (isLegacy) {
2519
- txFormattedForEthers = {
2520
- to: tokenAddress,
2521
- value: '0x0',
2522
- gasLimit,
2523
- gasPrice,
2524
- data: txData,
2525
- nonce,
2526
- chainId: activeNetwork.chainId,
2527
- type: 0,
2528
- };
2529
- }
2530
- else {
2531
- txFormattedForEthers = {
2532
- to: tokenAddress,
2533
- value: '0x0',
2534
- gasLimit,
2535
- maxFeePerGas,
2536
- maxPriorityFeePerGas,
2537
- data: txData,
2538
- nonce,
2539
- chainId: activeNetwork.chainId,
2540
- type: 2, // Need explicit type for hardware wallet serialization
2541
- };
2542
- }
2543
- const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
2544
- assertCurrent();
2545
- assertHardwareTransactionSender(signedTx, activeAccount.address);
2546
- const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
2547
- return finalTx;
2548
- }
2549
- catch (error) {
2550
- console.log({ error });
2551
- throw error;
2552
- }
2553
- }
2554
- else {
2555
- throw new Error(`Transaction Signature Failed. Error: ${signature}`);
2556
- }
2385
+ assertHardwareTransactionSender(signedTx, activeAccount.address);
2386
+ const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
2387
+ return finalTx;
2557
2388
  }
2558
2389
  catch (error) {
2559
2390
  console.log({ error });
@@ -2791,6 +2622,52 @@ class EthereumTransactions {
2791
2622
  console.log('[EthereumTransactions] Deferring provider initialization:', error?.message || error);
2792
2623
  }
2793
2624
  }
2625
+ signPreparedEvmTransaction(input, options) {
2626
+ const selected = this.captureEvmAccountContext();
2627
+ const request = (0, prepared_evm_1.snapshotPreparedEvmRequest)(input);
2628
+ const target = {
2629
+ id: request.account.id,
2630
+ type: request.account.type,
2631
+ };
2632
+ const context = this.captureEvmAccountContext(target);
2633
+ const hostGuard = (0, prepared_evm_1.preparedEvmGuard)(options);
2634
+ const targetRecord = this.getState().accounts[target.type]?.[target.id];
2635
+ const encryptedKey = targetRecord?.xprv;
2636
+ const assertCurrent = () => {
2637
+ selected.assertCurrent();
2638
+ context.assertCurrent();
2639
+ const live = this.getState().accounts[target.type]?.[target.id];
2640
+ if (!live ||
2641
+ live.id !== target.id ||
2642
+ live.isSmartAccount ||
2643
+ live.isLedgerWallet ||
2644
+ live.isTrezorWallet ||
2645
+ typeof encryptedKey !== 'string' ||
2646
+ !encryptedKey ||
2647
+ live.xprv !== encryptedKey ||
2648
+ selected.activeAccountId !== request.selectedAccount.id ||
2649
+ selected.activeAccountType !== request.selectedAccount.type ||
2650
+ (0, address_1.getAddress)(selected.activeAccount.address) !==
2651
+ request.selectedAccount.expectedAddress ||
2652
+ (0, address_1.getAddress)(context.activeAccount.address) !==
2653
+ request.account.expectedAddress ||
2654
+ context.activeNetwork.kind !== 'ethereum' ||
2655
+ context.activeNetwork.slip44 !== 60 ||
2656
+ String(context.activeNetwork.chainId) !== request.network.chainId ||
2657
+ context.activeNetwork.url !== request.network.url)
2658
+ throw new Error('Prepared EVM signing context changed or is unsupported');
2659
+ };
2660
+ assertCurrent();
2661
+ hostGuard();
2662
+ assertCurrent();
2663
+ const key = this.getDecryptedPrivateKey(target);
2664
+ if ((0, address_1.getAddress)(key.address) !== request.account.expectedAddress)
2665
+ throw new Error('Prepared EVM signer address mismatch');
2666
+ const { signed } = (0, prepared_evm_1.signPreparedEvmEnvelope)(request.transaction, key.decryptedPrivateKey);
2667
+ hostGuard();
2668
+ assertCurrent();
2669
+ return signed;
2670
+ }
2794
2671
  setWeb3Provider(network) {
2795
2672
  this.abortController.abort();
2796
2673
  this.abortController = new AbortController();