@sidhujag/sysweb3-keyring 2.1.7 → 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/cjs/hardware-transaction-authority.js +15 -11
- package/cjs/hardware-transaction-authority.js.map +1 -1
- package/cjs/hardware-wallet-manager.js +74 -119
- package/cjs/hardware-wallet-manager.js.map +1 -1
- package/cjs/hardware-wallet-types.js +16 -0
- package/cjs/hardware-wallet-types.js.map +1 -0
- package/cjs/host-keyring.js +32 -0
- package/cjs/host-keyring.js.map +1 -0
- package/cjs/index.js +1 -0
- package/cjs/index.js.map +1 -1
- package/cjs/keyring-core.js +96 -61
- package/cjs/keyring-core.js.map +1 -1
- package/cjs/keyring-manager.js +15 -16
- package/cjs/keyring-manager.js.map +1 -1
- package/cjs/ledger/host-types.js.map +1 -1
- package/cjs/ledger/index.js +24 -4
- package/cjs/ledger/index.js.map +1 -1
- package/cjs/ledger-hardware.js +15 -0
- package/cjs/ledger-hardware.js.map +1 -0
- package/cjs/software.js +6 -25
- package/cjs/software.js.map +1 -1
- package/cjs/transactions/ethereum.js +317 -268
- package/cjs/transactions/ethereum.js.map +1 -1
- package/cjs/transactions/evm-submission.js +32 -4
- package/cjs/transactions/evm-submission.js.map +1 -1
- package/cjs/transactions/ledger-signing.js +44 -0
- package/cjs/transactions/ledger-signing.js.map +1 -0
- package/cjs/transactions/prepared-evm.js +24 -1
- package/cjs/transactions/prepared-evm.js.map +1 -1
- package/cjs/trezor/connect.js +238 -243
- package/cjs/trezor/connect.js.map +1 -1
- package/cjs/trezor/host-types.js +19 -0
- package/cjs/trezor/host-types.js.map +1 -0
- package/cjs/trezor/index.js +75 -23
- package/cjs/trezor/index.js.map +1 -1
- package/cjs/trezor/webextension-host.js +118 -0
- package/cjs/trezor/webextension-host.js.map +1 -0
- package/cjs/trezor-hardware.js +16 -0
- package/cjs/trezor-hardware.js.map +1 -0
- package/cjs/types.js.map +1 -1
- package/esm/hardware-transaction-authority.js +14 -11
- package/esm/hardware-transaction-authority.js.map +1 -1
- package/esm/hardware-wallet-manager.js +20 -32
- package/esm/hardware-wallet-manager.js.map +1 -1
- package/esm/hardware-wallet-types.js +13 -0
- package/esm/hardware-wallet-types.js.map +1 -0
- package/esm/keyring-core.js +98 -63
- package/esm/keyring-core.js.map +1 -1
- package/esm/ledger/dmk-host.js +2 -0
- package/esm/ledger/dmk-host.js.map +1 -1
- package/esm/ledger/dmk-session.js +73 -8
- package/esm/ledger/dmk-session.js.map +1 -1
- package/esm/ledger/host-types.js.map +1 -1
- package/esm/ledger/index.js +22 -2
- package/esm/ledger/index.js.map +1 -1
- package/esm/transactions/ethereum.js +318 -269
- package/esm/transactions/ethereum.js.map +1 -1
- package/esm/transactions/evm-submission.js +32 -4
- package/esm/transactions/evm-submission.js.map +1 -1
- package/esm/transactions/ledger-signing.js +41 -0
- package/esm/transactions/ledger-signing.js.map +1 -0
- package/esm/transactions/prepared-evm.js +23 -1
- package/esm/transactions/prepared-evm.js.map +1 -1
- package/esm/trezor/connect.js +236 -209
- package/esm/trezor/connect.js.map +1 -1
- package/esm/trezor/host-types.js +16 -0
- package/esm/trezor/host-types.js.map +1 -0
- package/esm/trezor/index.js +74 -22
- package/esm/trezor/index.js.map +1 -1
- package/esm/types.js.map +1 -1
- package/package.json +55 -1
- package/types/hardware-transaction-authority.d.ts +1 -0
- package/types/hardware-wallet-manager.d.ts +6 -22
- package/types/hardware-wallet-types.d.ts +21 -0
- package/types/host-keyring.d.ts +16 -0
- package/types/index.d.ts +1 -0
- package/types/keyring-core.d.ts +12 -4
- package/types/keyring-manager.d.ts +5 -3
- package/types/ledger/dmk-host.d.ts +2 -0
- package/types/ledger/dmk-session.d.ts +9 -0
- package/types/ledger/host-types.d.ts +2 -0
- package/types/ledger/index.d.ts +3 -1
- package/types/ledger-hardware.d.ts +5 -0
- package/types/software.d.ts +2 -16
- package/types/transactions/ethereum.d.ts +11 -1
- package/types/transactions/evm-submission.d.ts +7 -2
- package/types/transactions/ledger-signing.d.ts +13 -0
- package/types/transactions/prepared-evm.d.ts +12 -0
- package/types/trezor/connect.d.ts +11 -9
- package/types/trezor/host-types.d.ts +25 -0
- package/types/trezor/index.d.ts +7 -7
- package/types/trezor/webextension-host.d.ts +7 -0
- package/types/trezor-hardware.d.ts +6 -0
- 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,8 +16,10 @@ 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");
|
|
21
24
|
const derivation_paths_1 = require("../utils/derivation-paths");
|
|
22
25
|
const hardwareSignerUnavailable = (hardware) => Object.assign(new Error(`${hardware} signer is unavailable in this host`), {
|
|
@@ -160,7 +163,7 @@ class EthereumTransactions {
|
|
|
160
163
|
}
|
|
161
164
|
return () => assertSynchronousOriginalValidation(guard(), 'Signing context guard must be synchronous');
|
|
162
165
|
};
|
|
163
|
-
this.
|
|
166
|
+
this.captureEvmAccountContext = (target) => {
|
|
164
167
|
this.assertHardwareSignerAvailable(target);
|
|
165
168
|
const state = this.getState();
|
|
166
169
|
const selectedType = state.activeAccountType;
|
|
@@ -174,7 +177,6 @@ class EthereumTransactions {
|
|
|
174
177
|
const account = { address: selectedAccount.address };
|
|
175
178
|
const network = { ...state.activeNetwork };
|
|
176
179
|
const assertSession = this.captureSessionGuard();
|
|
177
|
-
const provider = this.web3Provider;
|
|
178
180
|
const assertCurrent = () => {
|
|
179
181
|
assertSession();
|
|
180
182
|
const current = this.getState();
|
|
@@ -188,8 +190,7 @@ class EthereumTransactions {
|
|
|
188
190
|
[current.activeNetwork, this.getNetwork()].some((selected) => selected.kind !== network.kind ||
|
|
189
191
|
selected.chainId !== network.chainId ||
|
|
190
192
|
selected.slip44 !== network.slip44 ||
|
|
191
|
-
selected.url !== network.url)
|
|
192
|
-
this.web3Provider !== provider)
|
|
193
|
+
selected.url !== network.url))
|
|
193
194
|
throw new Error('Wallet signing context changed');
|
|
194
195
|
};
|
|
195
196
|
assertCurrent();
|
|
@@ -198,10 +199,20 @@ class EthereumTransactions {
|
|
|
198
199
|
activeAccountType,
|
|
199
200
|
activeAccountId,
|
|
200
201
|
activeNetwork: network,
|
|
201
|
-
provider,
|
|
202
202
|
assertCurrent,
|
|
203
203
|
};
|
|
204
204
|
};
|
|
205
|
+
this.captureEvmSigningContext = (target) => {
|
|
206
|
+
const context = this.captureEvmAccountContext(target);
|
|
207
|
+
const provider = this.web3Provider;
|
|
208
|
+
const assertCurrent = () => {
|
|
209
|
+
context.assertCurrent();
|
|
210
|
+
if (this.web3Provider !== provider)
|
|
211
|
+
throw new Error('Wallet signing context changed');
|
|
212
|
+
};
|
|
213
|
+
assertCurrent();
|
|
214
|
+
return { ...context, provider, assertCurrent };
|
|
215
|
+
};
|
|
205
216
|
this.captureSubmission = (operation, account, type, id, network, assertCurrent, details = {}) => {
|
|
206
217
|
if (!this.captureSubmissionLifecycle)
|
|
207
218
|
throw new TypeError('A durable EVM submission lifecycle is required');
|
|
@@ -302,10 +313,51 @@ class EthereumTransactions {
|
|
|
302
313
|
throw error;
|
|
303
314
|
}
|
|
304
315
|
};
|
|
305
|
-
this.ethSign = async (params) => {
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
316
|
+
this.ethSign = async (params, input) => {
|
|
317
|
+
const selected = this.captureEvmAccountContext();
|
|
318
|
+
if (!Array.isArray(params) || params.length !== 2)
|
|
319
|
+
throw new Error('Invalid digest request');
|
|
320
|
+
const first = Object.getOwnPropertyDescriptor(params, '0');
|
|
321
|
+
const second = Object.getOwnPropertyDescriptor(params, '1');
|
|
322
|
+
if (!first ||
|
|
323
|
+
!second ||
|
|
324
|
+
!('value' in first) ||
|
|
325
|
+
!('value' in second) ||
|
|
326
|
+
typeof first.value !== 'string' ||
|
|
327
|
+
typeof second.value !== 'string')
|
|
328
|
+
throw new Error('Invalid digest request');
|
|
329
|
+
params = [first.value, second.value];
|
|
330
|
+
const options = (0, evm_envelope_1.readEvmOwnData)(input, [
|
|
331
|
+
'selectedAccount',
|
|
332
|
+
'targetAccount',
|
|
333
|
+
'assertCurrent',
|
|
334
|
+
]);
|
|
335
|
+
const selectedAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.selectedAccount);
|
|
336
|
+
const targetAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.targetAccount);
|
|
337
|
+
const hostGuard = (0, prepared_evm_1.preparedEvmGuard)({
|
|
338
|
+
assertCurrent: options.assertCurrent,
|
|
339
|
+
});
|
|
340
|
+
const target = {
|
|
341
|
+
id: targetAccount.id,
|
|
342
|
+
type: targetAccount.type,
|
|
343
|
+
};
|
|
344
|
+
const context = this.captureEvmAccountContext(target);
|
|
345
|
+
const assertCurrent = () => {
|
|
346
|
+
hostGuard();
|
|
347
|
+
selected.assertCurrent();
|
|
348
|
+
context.assertCurrent();
|
|
349
|
+
if (selected.activeAccountId !== selectedAccount.id ||
|
|
350
|
+
selected.activeAccountType !== selectedAccount.type ||
|
|
351
|
+
(0, address_1.getAddress)(selected.activeAccount.address) !==
|
|
352
|
+
selectedAccount.expectedAddress ||
|
|
353
|
+
(0, address_1.getAddress)(context.activeAccount.address) !==
|
|
354
|
+
targetAccount.expectedAddress ||
|
|
355
|
+
targetAccount.type === 'SmartAccount')
|
|
356
|
+
throw new Error('EVM digest signing context changed');
|
|
357
|
+
};
|
|
358
|
+
assertCurrent();
|
|
359
|
+
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(target);
|
|
360
|
+
const { activeAccountId, activeAccountType, activeNetwork, activeAccount } = context;
|
|
309
361
|
// Validate that the derived address matches the active account to prevent race conditions
|
|
310
362
|
if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
|
|
311
363
|
throw {
|
|
@@ -374,14 +426,19 @@ class EthereumTransactions {
|
|
|
374
426
|
throw error;
|
|
375
427
|
}
|
|
376
428
|
};
|
|
429
|
+
let signature;
|
|
377
430
|
switch (activeAccountType) {
|
|
378
431
|
case types_1.KeyringAccountType.Trezor:
|
|
379
|
-
|
|
432
|
+
signature = await signWithTrezor();
|
|
433
|
+
break;
|
|
380
434
|
case types_1.KeyringAccountType.Ledger:
|
|
381
|
-
|
|
435
|
+
signature = await signWithLedger();
|
|
436
|
+
break;
|
|
382
437
|
default:
|
|
383
|
-
|
|
438
|
+
signature = sign();
|
|
384
439
|
}
|
|
440
|
+
assertCurrent();
|
|
441
|
+
return signature;
|
|
385
442
|
};
|
|
386
443
|
this.signPersonalMessage = async (params) => {
|
|
387
444
|
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
|
|
@@ -951,33 +1008,18 @@ class EthereumTransactions {
|
|
|
951
1008
|
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
952
1009
|
if (retained)
|
|
953
1010
|
assertCancellationEnvelope(rawTx);
|
|
954
|
-
const
|
|
955
|
-
|
|
1011
|
+
const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
|
|
1012
|
+
unsignedTransaction: rawTx,
|
|
956
1013
|
accountIndex: activeAccountId,
|
|
957
1014
|
expectedAddress: activeAccount.address,
|
|
958
1015
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
959
1016
|
assertCurrent();
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1017
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1018
|
+
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
1019
|
+
return {
|
|
1020
|
+
isCanceled: true,
|
|
1021
|
+
transaction: transactionResponse,
|
|
964
1022
|
};
|
|
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
1023
|
}
|
|
982
1024
|
catch (error) {
|
|
983
1025
|
return {
|
|
@@ -1108,12 +1150,21 @@ class EthereumTransactions {
|
|
|
1108
1150
|
typeof options !== 'object' ||
|
|
1109
1151
|
Array.isArray(options) ||
|
|
1110
1152
|
(options.mode !== 'reviewed-native' &&
|
|
1153
|
+
options.mode !== 'reviewed-generic' &&
|
|
1111
1154
|
options.mode !== 'specialized') ||
|
|
1112
1155
|
typeof options.assertCurrent !== 'function')
|
|
1113
1156
|
throw new Error('Explicit transaction approval is required');
|
|
1114
1157
|
// Capture once; later caller mutations cannot replace this invocation's
|
|
1115
1158
|
// admission decision while chain checks or device approval are pending.
|
|
1116
1159
|
const { assertCurrent: assertHostCurrent, mode, walletNonce } = options;
|
|
1160
|
+
const reviewId = mode === 'reviewed-generic' ? options.reviewId : undefined;
|
|
1161
|
+
if (mode === 'reviewed-generic' &&
|
|
1162
|
+
(typeof reviewId !== 'string' ||
|
|
1163
|
+
!/^[A-Za-z0-9_-]{1,128}$/.test(reviewId) ||
|
|
1164
|
+
walletNonce === undefined))
|
|
1165
|
+
throw new Error('An issued fee review and approved nonce are required');
|
|
1166
|
+
const selectedAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.selectedAccount);
|
|
1167
|
+
const targetAccount = (0, prepared_evm_1.snapshotEvmSigningIdentity)(options.targetAccount);
|
|
1117
1168
|
const nonceApproval = walletNonce === undefined ? undefined : { ...walletNonce };
|
|
1118
1169
|
const assertApproved = () => {
|
|
1119
1170
|
const result = assertHostCurrent();
|
|
@@ -1125,14 +1176,14 @@ class EthereumTransactions {
|
|
|
1125
1176
|
assertApproved();
|
|
1126
1177
|
return await this.sendFormattedTransactionInternal(params, isLegacy, () => {
|
|
1127
1178
|
broadcastAttempted = true;
|
|
1128
|
-
}, assertApproved, mode, nonceApproval);
|
|
1179
|
+
}, assertApproved, mode, nonceApproval, selectedAccount, targetAccount, reviewId);
|
|
1129
1180
|
}
|
|
1130
1181
|
catch (error) {
|
|
1131
1182
|
// A broadcast transport error may mean the node accepted the signed
|
|
1132
1183
|
// transaction. Derive this marker from this invocation, never RPC data.
|
|
1133
1184
|
const submissionError = Object.assign(new Error(error instanceof Error ? error.message : String(error)), error, {
|
|
1134
1185
|
transactionNotBroadcast: !broadcastAttempted ||
|
|
1135
|
-
(0, evm_submission_1.evmSubmissionFailure)(error)
|
|
1186
|
+
(0, evm_submission_1.evmSubmissionFailure)(error)?.transactionNotBroadcast === true,
|
|
1136
1187
|
});
|
|
1137
1188
|
if (error instanceof Error) {
|
|
1138
1189
|
submissionError.name = error.name;
|
|
@@ -1142,19 +1193,60 @@ class EthereumTransactions {
|
|
|
1142
1193
|
throw submissionError;
|
|
1143
1194
|
}
|
|
1144
1195
|
};
|
|
1145
|
-
this.sendFormattedTransactionInternal = async (input, isLegacy, beforeBroadcast, assertHostCurrent, mode, walletNonce) => {
|
|
1196
|
+
this.sendFormattedTransactionInternal = async (input, isLegacy, beforeBroadcast, assertHostCurrent, mode, walletNonce, selectedIdentity, targetIdentity, reviewId) => {
|
|
1146
1197
|
// Hardware approval may outlive the selected account, network or unlocked
|
|
1147
1198
|
// session. Keep immutable identities and one provider for this invocation.
|
|
1148
|
-
const
|
|
1199
|
+
const selectedContext = this.captureEvmAccountContext();
|
|
1200
|
+
const targetAccount = {
|
|
1201
|
+
id: targetIdentity.id,
|
|
1202
|
+
type: targetIdentity.type,
|
|
1203
|
+
};
|
|
1204
|
+
if (targetAccount.type === types_1.KeyringAccountType.SmartAccount)
|
|
1205
|
+
throw new Error('Invalid EVM payer');
|
|
1206
|
+
const { activeAccount, activeAccountType, activeAccountId, activeNetwork, provider, assertCurrent: assertKeyringCurrent, } = this.captureEvmSigningContext(targetAccount);
|
|
1149
1207
|
const assertSigningCurrent = () => {
|
|
1150
1208
|
assertHostCurrent();
|
|
1209
|
+
selectedContext.assertCurrent();
|
|
1151
1210
|
assertKeyringCurrent();
|
|
1211
|
+
if (selectedContext.activeAccountId !== selectedIdentity.id ||
|
|
1212
|
+
selectedContext.activeAccountType !== selectedIdentity.type ||
|
|
1213
|
+
(0, address_1.getAddress)(selectedContext.activeAccount.address) !==
|
|
1214
|
+
selectedIdentity.expectedAddress ||
|
|
1215
|
+
(0, address_1.getAddress)(activeAccount.address) !== targetIdentity.expectedAddress)
|
|
1216
|
+
throw new Error('EVM payer approval context changed');
|
|
1152
1217
|
};
|
|
1218
|
+
assertSigningCurrent();
|
|
1219
|
+
// Generic reviewed calls keep the exact prepared envelope, including
|
|
1220
|
+
// contract creation, calldata and access lists, through existing signers.
|
|
1221
|
+
const reviewed = mode === 'reviewed-generic'
|
|
1222
|
+
? (0, evm_envelope_1.snapshotPreparedEvmTransaction)(input)
|
|
1223
|
+
: undefined;
|
|
1224
|
+
if (reviewed) {
|
|
1225
|
+
if (reviewed.from !== targetIdentity.expectedAddress ||
|
|
1226
|
+
reviewed.chainId !== String(activeNetwork.chainId) ||
|
|
1227
|
+
reviewed.nonce !== String(walletNonce?.nonce) ||
|
|
1228
|
+
(isLegacy !== undefined && isLegacy !== (reviewed.type === 0)) ||
|
|
1229
|
+
(this.gasOverrides.minGasLimit &&
|
|
1230
|
+
BigInt(reviewed.gasLimit) < this.gasOverrides.minGasLimit.toBigInt()))
|
|
1231
|
+
throw new Error('Reviewed EVM transaction does not match its approval');
|
|
1232
|
+
input = reviewed;
|
|
1233
|
+
isLegacy = reviewed.type === 0;
|
|
1234
|
+
}
|
|
1153
1235
|
const assertBeforeBroadcast = () => {
|
|
1154
1236
|
assertCurrent();
|
|
1155
1237
|
beforeBroadcast();
|
|
1156
1238
|
};
|
|
1157
|
-
const submission = this.captureSubmission('send', activeAccount, activeAccountType, activeAccountId, activeNetwork, assertSigningCurrent, {
|
|
1239
|
+
const submission = this.captureSubmission('send', activeAccount, activeAccountType, activeAccountId, activeNetwork, assertSigningCurrent, {
|
|
1240
|
+
walletNonce,
|
|
1241
|
+
...(reviewed
|
|
1242
|
+
? {
|
|
1243
|
+
review: {
|
|
1244
|
+
id: reviewId,
|
|
1245
|
+
unsignedHash: transaction_1.Transaction.from((0, evm_envelope_1.serializePreparedEvmTransaction)(reviewed)).unsignedHash,
|
|
1246
|
+
},
|
|
1247
|
+
}
|
|
1248
|
+
: {}),
|
|
1249
|
+
});
|
|
1158
1250
|
const assertCurrent = submission.assertCurrent;
|
|
1159
1251
|
const approvedNonce = submission.context.walletNonce?.nonce;
|
|
1160
1252
|
const assertApprovedNonce = (nonce) => {
|
|
@@ -1163,6 +1255,7 @@ class EthereumTransactions {
|
|
|
1163
1255
|
};
|
|
1164
1256
|
if (mode === 'reviewed-native') {
|
|
1165
1257
|
const { transaction } = (0, prepared_evm_1.snapshotPreparedEvmRequest)({
|
|
1258
|
+
selectedAccount: selectedIdentity,
|
|
1166
1259
|
account: {
|
|
1167
1260
|
id: activeAccountId,
|
|
1168
1261
|
type: activeAccountType,
|
|
@@ -1193,7 +1286,7 @@ class EthereumTransactions {
|
|
|
1193
1286
|
assertCurrent();
|
|
1194
1287
|
if (this.gasOverrides.minGasLimit !== minimum)
|
|
1195
1288
|
throw new Error('Reviewed native gas policy changed');
|
|
1196
|
-
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
|
|
1289
|
+
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(targetAccount);
|
|
1197
1290
|
if (address.toLowerCase() !== transaction.from.toLowerCase())
|
|
1198
1291
|
throw new Error('Reviewed native signer does not match the approved account');
|
|
1199
1292
|
assertCurrent();
|
|
@@ -1206,6 +1299,9 @@ class EthereumTransactions {
|
|
|
1206
1299
|
if (!params || typeof params !== 'object' || Array.isArray(params))
|
|
1207
1300
|
throw new TypeError('Invalid EVM transaction request');
|
|
1208
1301
|
const supplied = { ...params };
|
|
1302
|
+
if (supplied.from !== undefined &&
|
|
1303
|
+
(0, address_1.getAddress)(supplied.from) !== targetIdentity.expectedAddress)
|
|
1304
|
+
throw new Error('EVM transaction sender does not match the approved payer');
|
|
1209
1305
|
// Validate original scalar spellings before conversion. Normalization's
|
|
1210
1306
|
// permissive zero coercion must not bypass the bounded wire parser.
|
|
1211
1307
|
for (const field of [
|
|
@@ -1258,7 +1354,8 @@ class EthereumTransactions {
|
|
|
1258
1354
|
const validateEip1559Fees = () => {
|
|
1259
1355
|
const maximum = nonNegativeFeeQuantity(params.maxFeePerGas, 'maximum fee');
|
|
1260
1356
|
const priority = nonNegativeFeeQuantity(params.maxPriorityFeePerGas, 'priority fee');
|
|
1261
|
-
if (maximum.isZero() ||
|
|
1357
|
+
if ((mode !== 'reviewed-generic' && maximum.isZero()) ||
|
|
1358
|
+
priority.gt(maximum))
|
|
1262
1359
|
throw new Error('Invalid EIP-1559 fees');
|
|
1263
1360
|
params.maxFeePerGas = maximum;
|
|
1264
1361
|
params.maxPriorityFeePerGas = priority;
|
|
@@ -1269,7 +1366,9 @@ class EthereumTransactions {
|
|
|
1269
1366
|
validateEip1559Fees();
|
|
1270
1367
|
// Only apply a minimum gas limit when a network-specific override is set.
|
|
1271
1368
|
// Otherwise keep the user/dapp-approved gas limit unchanged.
|
|
1272
|
-
if (
|
|
1369
|
+
if (mode !== 'reviewed-generic' &&
|
|
1370
|
+
params.gasLimit != null &&
|
|
1371
|
+
this.gasOverrides.minGasLimit) {
|
|
1273
1372
|
const minGasLimit = this.gasOverrides.minGasLimit;
|
|
1274
1373
|
const currentGasLimit = ethers_v6_1.BigNumber.from(params.gasLimit);
|
|
1275
1374
|
if (currentGasLimit.lt(minGasLimit)) {
|
|
@@ -1340,31 +1439,15 @@ class EthereumTransactions {
|
|
|
1340
1439
|
type: 2, // Need explicit type for hardware wallet serialization
|
|
1341
1440
|
};
|
|
1342
1441
|
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
1343
|
-
const
|
|
1344
|
-
|
|
1442
|
+
const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
|
|
1443
|
+
unsignedTransaction: rawTx,
|
|
1345
1444
|
accountIndex: activeAccountId,
|
|
1346
1445
|
expectedAddress: activeAccount.address,
|
|
1347
1446
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
1348
1447
|
assertCurrent();
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
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
|
-
}
|
|
1448
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1449
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
|
|
1450
|
+
return finalTx;
|
|
1368
1451
|
};
|
|
1369
1452
|
const sendEVMTrezorTransaction = async () => {
|
|
1370
1453
|
assertCurrent();
|
|
@@ -1458,7 +1541,7 @@ class EthereumTransactions {
|
|
|
1458
1541
|
};
|
|
1459
1542
|
const sendEVMTransaction = async () => {
|
|
1460
1543
|
assertCurrent();
|
|
1461
|
-
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
|
|
1544
|
+
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(targetAccount);
|
|
1462
1545
|
// Validate that we have the correct private key for the active account to prevent race conditions
|
|
1463
1546
|
// This is critical for transaction security during account switches
|
|
1464
1547
|
if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
|
|
@@ -1715,32 +1798,18 @@ class EthereumTransactions {
|
|
|
1715
1798
|
};
|
|
1716
1799
|
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
1717
1800
|
assertCurrent();
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1801
|
+
const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
|
|
1802
|
+
unsignedTransaction: rawTx,
|
|
1720
1803
|
accountIndex: activeAccountId,
|
|
1721
1804
|
expectedAddress: activeAccount.address,
|
|
1722
1805
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1806
|
+
assertSignedSender(signedTx);
|
|
1807
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1808
|
+
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
|
|
1809
|
+
return {
|
|
1810
|
+
isSpeedUp: true,
|
|
1811
|
+
transaction: transactionResponse,
|
|
1727
1812
|
};
|
|
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
1813
|
}
|
|
1745
1814
|
catch (error) {
|
|
1746
1815
|
console.error('[SpeedUp] Failed to send replacement transaction with Ledger:', error);
|
|
@@ -1953,73 +2022,51 @@ class EthereumTransactions {
|
|
|
1953
2022
|
};
|
|
1954
2023
|
const sendERC20TokenOnLedger = async () => {
|
|
1955
2024
|
assertCurrent();
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
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),
|
|
2025
|
+
const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc20Abi)(), provider);
|
|
2026
|
+
const txData = _contract.interface.encodeFunctionData('transfer', [
|
|
2027
|
+
receiver,
|
|
2028
|
+
exactTokenAmount,
|
|
2029
|
+
]);
|
|
2030
|
+
let txFormattedForEthers;
|
|
2031
|
+
if (isLegacy) {
|
|
2032
|
+
txFormattedForEthers = {
|
|
2033
|
+
to: tokenAddress,
|
|
2034
|
+
value: '0x0',
|
|
2035
|
+
gasLimit: gasLimit,
|
|
2036
|
+
gasPrice,
|
|
2037
|
+
data: txData,
|
|
2038
|
+
nonce,
|
|
2039
|
+
chainId: activeNetwork.chainId,
|
|
2040
|
+
type: 0,
|
|
1999
2041
|
};
|
|
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
2042
|
}
|
|
2020
|
-
|
|
2021
|
-
|
|
2043
|
+
else {
|
|
2044
|
+
txFormattedForEthers = {
|
|
2045
|
+
to: tokenAddress,
|
|
2046
|
+
value: '0x0',
|
|
2047
|
+
gasLimit: gasLimit,
|
|
2048
|
+
maxFeePerGas,
|
|
2049
|
+
maxPriorityFeePerGas,
|
|
2050
|
+
data: txData,
|
|
2051
|
+
nonce,
|
|
2052
|
+
chainId: activeNetwork.chainId,
|
|
2053
|
+
type: 2, // Need explicit type for hardware wallet serialization
|
|
2054
|
+
};
|
|
2022
2055
|
}
|
|
2056
|
+
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
2057
|
+
const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
|
|
2058
|
+
unsignedTransaction: rawTx,
|
|
2059
|
+
accountIndex: activeAccountId,
|
|
2060
|
+
expectedAddress: activeAccount.address,
|
|
2061
|
+
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2062
|
+
assertCurrent();
|
|
2063
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2064
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
|
|
2065
|
+
const response = await admit(() => provider.sendTransaction(rawTransaction));
|
|
2066
|
+
saveTrezorTx && saveTrezorTx(response);
|
|
2067
|
+
return response;
|
|
2068
|
+
}, submission, undefined, rawTx);
|
|
2069
|
+
return finalTx;
|
|
2023
2070
|
};
|
|
2024
2071
|
const sendERC20TokenOnTrezor = async () => {
|
|
2025
2072
|
assertCurrent();
|
|
@@ -2180,70 +2227,48 @@ class EthereumTransactions {
|
|
|
2180
2227
|
};
|
|
2181
2228
|
const sendERC721TokenOnLedger = async () => {
|
|
2182
2229
|
assertCurrent();
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
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),
|
|
2230
|
+
const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc21Abi)(), provider);
|
|
2231
|
+
const txData = _contract.interface.encodeFunctionData('transferFrom', [
|
|
2232
|
+
activeAccountAddress,
|
|
2233
|
+
receiver,
|
|
2234
|
+
normalizedTokenId,
|
|
2235
|
+
]);
|
|
2236
|
+
let txFormattedForEthers;
|
|
2237
|
+
if (isLegacy) {
|
|
2238
|
+
txFormattedForEthers = {
|
|
2239
|
+
to: tokenAddress,
|
|
2240
|
+
value: '0x0',
|
|
2241
|
+
gasLimit,
|
|
2242
|
+
gasPrice,
|
|
2243
|
+
data: txData,
|
|
2244
|
+
nonce,
|
|
2245
|
+
chainId: activeNetwork.chainId,
|
|
2246
|
+
type: 0,
|
|
2227
2247
|
};
|
|
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
2248
|
}
|
|
2244
|
-
|
|
2245
|
-
|
|
2249
|
+
else {
|
|
2250
|
+
txFormattedForEthers = {
|
|
2251
|
+
to: tokenAddress,
|
|
2252
|
+
value: '0x0',
|
|
2253
|
+
gasLimit,
|
|
2254
|
+
maxFeePerGas,
|
|
2255
|
+
maxPriorityFeePerGas,
|
|
2256
|
+
data: txData,
|
|
2257
|
+
nonce,
|
|
2258
|
+
chainId: activeNetwork.chainId,
|
|
2259
|
+
type: 2, // Need explicit type for hardware wallet serialization
|
|
2260
|
+
};
|
|
2246
2261
|
}
|
|
2262
|
+
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
2263
|
+
const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
|
|
2264
|
+
unsignedTransaction: rawTx,
|
|
2265
|
+
accountIndex: activeAccountId,
|
|
2266
|
+
expectedAddress: activeAccount.address,
|
|
2267
|
+
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2268
|
+
assertCurrent();
|
|
2269
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2270
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
2271
|
+
return finalTx;
|
|
2247
2272
|
};
|
|
2248
2273
|
const sendERC721TokenOnTrezor = async () => {
|
|
2249
2274
|
assertCurrent();
|
|
@@ -2410,66 +2435,44 @@ class EthereumTransactions {
|
|
|
2410
2435
|
};
|
|
2411
2436
|
const sendERC1155TokenOnLedger = async () => {
|
|
2412
2437
|
assertCurrent();
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
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),
|
|
2438
|
+
const _contract = new ethers_v6_1.Contract(tokenAddress, (0, sysweb3_utils_1.getErc55Abi)(), provider);
|
|
2439
|
+
const txData = _contract.interface.encodeFunctionData('safeTransferFrom', [activeAccountAddress, receiver, normalizedTokenId, amount, '0x']);
|
|
2440
|
+
let txFormattedForEthers;
|
|
2441
|
+
if (isLegacy) {
|
|
2442
|
+
txFormattedForEthers = {
|
|
2443
|
+
to: tokenAddress,
|
|
2444
|
+
value: '0x0',
|
|
2445
|
+
gasLimit,
|
|
2446
|
+
gasPrice,
|
|
2447
|
+
data: txData,
|
|
2448
|
+
nonce,
|
|
2449
|
+
chainId: activeNetwork.chainId,
|
|
2450
|
+
type: 0,
|
|
2453
2451
|
};
|
|
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
2452
|
}
|
|
2470
|
-
|
|
2471
|
-
|
|
2453
|
+
else {
|
|
2454
|
+
txFormattedForEthers = {
|
|
2455
|
+
to: tokenAddress,
|
|
2456
|
+
value: '0x0',
|
|
2457
|
+
gasLimit,
|
|
2458
|
+
maxFeePerGas,
|
|
2459
|
+
maxPriorityFeePerGas,
|
|
2460
|
+
data: txData,
|
|
2461
|
+
nonce,
|
|
2462
|
+
chainId: activeNetwork.chainId,
|
|
2463
|
+
type: 2, // Need explicit type for hardware wallet serialization
|
|
2464
|
+
};
|
|
2472
2465
|
}
|
|
2466
|
+
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
2467
|
+
const { rawTransaction: signedTx } = await (0, ledger_signing_1.signLedgerEvmTransaction)(this.requireLedgerSigner(), {
|
|
2468
|
+
unsignedTransaction: rawTx,
|
|
2469
|
+
accountIndex: activeAccountId,
|
|
2470
|
+
expectedAddress: activeAccount.address,
|
|
2471
|
+
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2472
|
+
assertCurrent();
|
|
2473
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2474
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
2475
|
+
return finalTx;
|
|
2473
2476
|
};
|
|
2474
2477
|
const sendERC1155TokenOnTrezor = async () => {
|
|
2475
2478
|
assertCurrent();
|
|
@@ -2791,6 +2794,52 @@ class EthereumTransactions {
|
|
|
2791
2794
|
console.log('[EthereumTransactions] Deferring provider initialization:', error?.message || error);
|
|
2792
2795
|
}
|
|
2793
2796
|
}
|
|
2797
|
+
signPreparedEvmTransaction(input, options) {
|
|
2798
|
+
const selected = this.captureEvmAccountContext();
|
|
2799
|
+
const request = (0, prepared_evm_1.snapshotPreparedEvmRequest)(input);
|
|
2800
|
+
const target = {
|
|
2801
|
+
id: request.account.id,
|
|
2802
|
+
type: request.account.type,
|
|
2803
|
+
};
|
|
2804
|
+
const context = this.captureEvmAccountContext(target);
|
|
2805
|
+
const hostGuard = (0, prepared_evm_1.preparedEvmGuard)(options);
|
|
2806
|
+
const targetRecord = this.getState().accounts[target.type]?.[target.id];
|
|
2807
|
+
const encryptedKey = targetRecord?.xprv;
|
|
2808
|
+
const assertCurrent = () => {
|
|
2809
|
+
selected.assertCurrent();
|
|
2810
|
+
context.assertCurrent();
|
|
2811
|
+
const live = this.getState().accounts[target.type]?.[target.id];
|
|
2812
|
+
if (!live ||
|
|
2813
|
+
live.id !== target.id ||
|
|
2814
|
+
live.isSmartAccount ||
|
|
2815
|
+
live.isLedgerWallet ||
|
|
2816
|
+
live.isTrezorWallet ||
|
|
2817
|
+
typeof encryptedKey !== 'string' ||
|
|
2818
|
+
!encryptedKey ||
|
|
2819
|
+
live.xprv !== encryptedKey ||
|
|
2820
|
+
selected.activeAccountId !== request.selectedAccount.id ||
|
|
2821
|
+
selected.activeAccountType !== request.selectedAccount.type ||
|
|
2822
|
+
(0, address_1.getAddress)(selected.activeAccount.address) !==
|
|
2823
|
+
request.selectedAccount.expectedAddress ||
|
|
2824
|
+
(0, address_1.getAddress)(context.activeAccount.address) !==
|
|
2825
|
+
request.account.expectedAddress ||
|
|
2826
|
+
context.activeNetwork.kind !== 'ethereum' ||
|
|
2827
|
+
context.activeNetwork.slip44 !== 60 ||
|
|
2828
|
+
String(context.activeNetwork.chainId) !== request.network.chainId ||
|
|
2829
|
+
context.activeNetwork.url !== request.network.url)
|
|
2830
|
+
throw new Error('Prepared EVM signing context changed or is unsupported');
|
|
2831
|
+
};
|
|
2832
|
+
assertCurrent();
|
|
2833
|
+
hostGuard();
|
|
2834
|
+
assertCurrent();
|
|
2835
|
+
const key = this.getDecryptedPrivateKey(target);
|
|
2836
|
+
if ((0, address_1.getAddress)(key.address) !== request.account.expectedAddress)
|
|
2837
|
+
throw new Error('Prepared EVM signer address mismatch');
|
|
2838
|
+
const { signed } = (0, prepared_evm_1.signPreparedEvmEnvelope)(request.transaction, key.decryptedPrivateKey);
|
|
2839
|
+
hostGuard();
|
|
2840
|
+
assertCurrent();
|
|
2841
|
+
return signed;
|
|
2842
|
+
}
|
|
2794
2843
|
setWeb3Provider(network) {
|
|
2795
2844
|
this.abortController.abort();
|
|
2796
2845
|
this.abortController = new AbortController();
|