@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.
- package/CHANGELOG.md +12 -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 +371 -494
- package/cjs/transactions/ethereum.js.map +1 -1
- package/cjs/transactions/evm-submission-failure.js +73 -0
- package/cjs/transactions/evm-submission-failure.js.map +1 -0
- package/cjs/transactions/evm-submission.js +35 -61
- package/cjs/transactions/evm-submission.js.map +1 -1
- package/cjs/transactions/ledger-signing.js +52 -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/transactions/trezor-signing.js +90 -0
- package/cjs/transactions/trezor-signing.js.map +1 -0
- 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 +372 -495
- package/esm/transactions/ethereum.js.map +1 -1
- package/esm/transactions/evm-submission-failure.js +68 -0
- package/esm/transactions/evm-submission-failure.js.map +1 -0
- package/esm/transactions/evm-submission.js +32 -59
- package/esm/transactions/evm-submission.js.map +1 -1
- package/esm/transactions/ledger-signing.js +49 -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/transactions/trezor-signing.js +87 -0
- package/esm/transactions/trezor-signing.js.map +1 -0
- 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 +61 -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-failure.d.ts +11 -0
- package/types/transactions/evm-submission.d.ts +6 -8
- package/types/transactions/ledger-signing.d.ts +13 -0
- package/types/transactions/prepared-evm.d.ts +12 -0
- package/types/transactions/trezor-signing.d.ts +13 -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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { decrypt, signTypedData as signTypedDataUtil, getEncryptionPublicKey, recoverPersonalSignature, recoverTypedSignature, } from '@metamask/eth-sig-util';
|
|
2
2
|
import { INetworkType } from '@sidhujag/sysweb3-network';
|
|
3
3
|
import { createContractUsingAbi, getErc20Abi, getErc21Abi, getErc55Abi, } from '@sidhujag/sysweb3-utils';
|
|
4
|
+
import { getAddress } from 'ethers/address';
|
|
4
5
|
import { accessListify, Transaction } from 'ethers/transaction';
|
|
5
6
|
import { hexlify } from 'ethers/utils';
|
|
6
7
|
import omit from 'lodash/omit';
|
|
@@ -9,9 +10,12 @@ import { assertEvmGasLimit, bufferedEvmGasLimit, EvmGasLimitError, getEvmFeeData
|
|
|
9
10
|
import { CustomJsonRpcProvider, wrapTransactionResponse } from '../providers';
|
|
10
11
|
import { KeyringAccountType, } from '../types';
|
|
11
12
|
import { assertEvmCancellationEnvelope, authenticateRetainedCancellation, } from './evm-cancellation';
|
|
13
|
+
import { readEvmOwnData, serializePreparedEvmTransaction, snapshotPreparedEvmTransaction, } from './evm-envelope';
|
|
12
14
|
import { deriveEvmAccountFromMnemonic, parsePersonalMessage as parseLocalPersonalMessage, privateKeyToAccount, normalizeGasLimitedTransaction, sendLocalEvmTransaction, signDigestHex, signPersonalMessage as signLocalPersonalMessage, } from './evm-local-signer';
|
|
13
15
|
import { captureEvmSubmission, submitSignedEvmTransaction, submitSignedHardwareEvmTransaction, evmSubmissionFailure, copyEvmSubmissionFailure, } from './evm-submission';
|
|
14
|
-
import {
|
|
16
|
+
import { signLedgerEvmTransaction } from './ledger-signing';
|
|
17
|
+
import { signPreparedEvmEnvelope, snapshotPreparedEvmRequest, snapshotEvmSigningIdentity, preparedEvmGuard, } from './prepared-evm';
|
|
18
|
+
import { signTrezorEvmTransaction } from './trezor-signing';
|
|
15
19
|
import { getAddressDerivationPath } from '../utils/derivation-paths';
|
|
16
20
|
const hardwareSignerUnavailable = (hardware) => Object.assign(new Error(`${hardware} signer is unavailable in this host`), {
|
|
17
21
|
code: 'HARDWARE_SIGNER_UNAVAILABLE',
|
|
@@ -29,26 +33,6 @@ const stripHexPrefix = (value) => {
|
|
|
29
33
|
? value.slice(2)
|
|
30
34
|
: value;
|
|
31
35
|
};
|
|
32
|
-
// Connect returns hexadecimal signature fields; normalize their encoding
|
|
33
|
-
// without mutating the response or reparsing an already numeric recovery v.
|
|
34
|
-
const trezorSignature = (signature) => {
|
|
35
|
-
const { r, s, v } = signature;
|
|
36
|
-
if (![r, s].every((value) => /^(?:0x)?[0-9a-f]{64}$/i.test(value))) {
|
|
37
|
-
throw new Error('Invalid Trezor signature scalar encoding');
|
|
38
|
-
}
|
|
39
|
-
if (typeof v === 'string' && !/^(?:0x)?[0-9a-f]+$/i.test(v)) {
|
|
40
|
-
throw new Error('Invalid Trezor signature recovery value');
|
|
41
|
-
}
|
|
42
|
-
const recovery = typeof v === 'number' ? v : Number.parseInt(v, 16);
|
|
43
|
-
if (!Number.isSafeInteger(recovery) || recovery < 0) {
|
|
44
|
-
throw new Error('Invalid Trezor signature recovery value');
|
|
45
|
-
}
|
|
46
|
-
return {
|
|
47
|
-
r: `0x${stripHexPrefix(r)}`,
|
|
48
|
-
s: `0x${stripHexPrefix(s)}`,
|
|
49
|
-
v: recovery,
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
36
|
const normalizeEthersOverrideValue = (value) => normalizeTxValue(value);
|
|
53
37
|
// The same protocol bound applies to software and external-device envelopes.
|
|
54
38
|
// Keep this at serialization as well as before handing a request to a device.
|
|
@@ -154,7 +138,7 @@ export class EthereumTransactions {
|
|
|
154
138
|
}
|
|
155
139
|
return () => assertSynchronousOriginalValidation(guard(), 'Signing context guard must be synchronous');
|
|
156
140
|
};
|
|
157
|
-
this.
|
|
141
|
+
this.captureEvmAccountContext = (target) => {
|
|
158
142
|
this.assertHardwareSignerAvailable(target);
|
|
159
143
|
const state = this.getState();
|
|
160
144
|
const selectedType = state.activeAccountType;
|
|
@@ -168,7 +152,6 @@ export class EthereumTransactions {
|
|
|
168
152
|
const account = { address: selectedAccount.address };
|
|
169
153
|
const network = { ...state.activeNetwork };
|
|
170
154
|
const assertSession = this.captureSessionGuard();
|
|
171
|
-
const provider = this.web3Provider;
|
|
172
155
|
const assertCurrent = () => {
|
|
173
156
|
assertSession();
|
|
174
157
|
const current = this.getState();
|
|
@@ -182,8 +165,7 @@ export class EthereumTransactions {
|
|
|
182
165
|
[current.activeNetwork, this.getNetwork()].some((selected) => selected.kind !== network.kind ||
|
|
183
166
|
selected.chainId !== network.chainId ||
|
|
184
167
|
selected.slip44 !== network.slip44 ||
|
|
185
|
-
selected.url !== network.url)
|
|
186
|
-
this.web3Provider !== provider)
|
|
168
|
+
selected.url !== network.url))
|
|
187
169
|
throw new Error('Wallet signing context changed');
|
|
188
170
|
};
|
|
189
171
|
assertCurrent();
|
|
@@ -192,10 +174,20 @@ export class EthereumTransactions {
|
|
|
192
174
|
activeAccountType,
|
|
193
175
|
activeAccountId,
|
|
194
176
|
activeNetwork: network,
|
|
195
|
-
provider,
|
|
196
177
|
assertCurrent,
|
|
197
178
|
};
|
|
198
179
|
};
|
|
180
|
+
this.captureEvmSigningContext = (target) => {
|
|
181
|
+
const context = this.captureEvmAccountContext(target);
|
|
182
|
+
const provider = this.web3Provider;
|
|
183
|
+
const assertCurrent = () => {
|
|
184
|
+
context.assertCurrent();
|
|
185
|
+
if (this.web3Provider !== provider)
|
|
186
|
+
throw new Error('Wallet signing context changed');
|
|
187
|
+
};
|
|
188
|
+
assertCurrent();
|
|
189
|
+
return { ...context, provider, assertCurrent };
|
|
190
|
+
};
|
|
199
191
|
this.captureSubmission = (operation, account, type, id, network, assertCurrent, details = {}) => {
|
|
200
192
|
if (!this.captureSubmissionLifecycle)
|
|
201
193
|
throw new TypeError('A durable EVM submission lifecycle is required');
|
|
@@ -296,10 +288,51 @@ export class EthereumTransactions {
|
|
|
296
288
|
throw error;
|
|
297
289
|
}
|
|
298
290
|
};
|
|
299
|
-
this.ethSign = async (params) => {
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
291
|
+
this.ethSign = async (params, input) => {
|
|
292
|
+
const selected = this.captureEvmAccountContext();
|
|
293
|
+
if (!Array.isArray(params) || params.length !== 2)
|
|
294
|
+
throw new Error('Invalid digest request');
|
|
295
|
+
const first = Object.getOwnPropertyDescriptor(params, '0');
|
|
296
|
+
const second = Object.getOwnPropertyDescriptor(params, '1');
|
|
297
|
+
if (!first ||
|
|
298
|
+
!second ||
|
|
299
|
+
!('value' in first) ||
|
|
300
|
+
!('value' in second) ||
|
|
301
|
+
typeof first.value !== 'string' ||
|
|
302
|
+
typeof second.value !== 'string')
|
|
303
|
+
throw new Error('Invalid digest request');
|
|
304
|
+
params = [first.value, second.value];
|
|
305
|
+
const options = readEvmOwnData(input, [
|
|
306
|
+
'selectedAccount',
|
|
307
|
+
'targetAccount',
|
|
308
|
+
'assertCurrent',
|
|
309
|
+
]);
|
|
310
|
+
const selectedAccount = snapshotEvmSigningIdentity(options.selectedAccount);
|
|
311
|
+
const targetAccount = snapshotEvmSigningIdentity(options.targetAccount);
|
|
312
|
+
const hostGuard = preparedEvmGuard({
|
|
313
|
+
assertCurrent: options.assertCurrent,
|
|
314
|
+
});
|
|
315
|
+
const target = {
|
|
316
|
+
id: targetAccount.id,
|
|
317
|
+
type: targetAccount.type,
|
|
318
|
+
};
|
|
319
|
+
const context = this.captureEvmAccountContext(target);
|
|
320
|
+
const assertCurrent = () => {
|
|
321
|
+
hostGuard();
|
|
322
|
+
selected.assertCurrent();
|
|
323
|
+
context.assertCurrent();
|
|
324
|
+
if (selected.activeAccountId !== selectedAccount.id ||
|
|
325
|
+
selected.activeAccountType !== selectedAccount.type ||
|
|
326
|
+
getAddress(selected.activeAccount.address) !==
|
|
327
|
+
selectedAccount.expectedAddress ||
|
|
328
|
+
getAddress(context.activeAccount.address) !==
|
|
329
|
+
targetAccount.expectedAddress ||
|
|
330
|
+
targetAccount.type === 'SmartAccount')
|
|
331
|
+
throw new Error('EVM digest signing context changed');
|
|
332
|
+
};
|
|
333
|
+
assertCurrent();
|
|
334
|
+
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(target);
|
|
335
|
+
const { activeAccountId, activeAccountType, activeNetwork, activeAccount } = context;
|
|
303
336
|
// Validate that the derived address matches the active account to prevent race conditions
|
|
304
337
|
if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
|
|
305
338
|
throw {
|
|
@@ -368,14 +401,19 @@ export class EthereumTransactions {
|
|
|
368
401
|
throw error;
|
|
369
402
|
}
|
|
370
403
|
};
|
|
404
|
+
let signature;
|
|
371
405
|
switch (activeAccountType) {
|
|
372
406
|
case KeyringAccountType.Trezor:
|
|
373
|
-
|
|
407
|
+
signature = await signWithTrezor();
|
|
408
|
+
break;
|
|
374
409
|
case KeyringAccountType.Ledger:
|
|
375
|
-
|
|
410
|
+
signature = await signWithLedger();
|
|
411
|
+
break;
|
|
376
412
|
default:
|
|
377
|
-
|
|
413
|
+
signature = sign();
|
|
378
414
|
}
|
|
415
|
+
assertCurrent();
|
|
416
|
+
return signature;
|
|
379
417
|
};
|
|
380
418
|
this.signPersonalMessage = async (params) => {
|
|
381
419
|
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
|
|
@@ -945,33 +983,18 @@ export class EthereumTransactions {
|
|
|
945
983
|
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
946
984
|
if (retained)
|
|
947
985
|
assertCancellationEnvelope(rawTx);
|
|
948
|
-
const
|
|
949
|
-
|
|
986
|
+
const { rawTransaction: signedTx } = await signLedgerEvmTransaction(this.requireLedgerSigner(), {
|
|
987
|
+
unsignedTransaction: rawTx,
|
|
950
988
|
accountIndex: activeAccountId,
|
|
951
989
|
expectedAddress: activeAccount.address,
|
|
952
990
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
953
991
|
assertCurrent();
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
992
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
993
|
+
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
994
|
+
return {
|
|
995
|
+
isCanceled: true,
|
|
996
|
+
transaction: transactionResponse,
|
|
958
997
|
};
|
|
959
|
-
if (signature) {
|
|
960
|
-
const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
|
|
961
|
-
assertCurrent();
|
|
962
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
963
|
-
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
964
|
-
return {
|
|
965
|
-
isCanceled: true,
|
|
966
|
-
transaction: transactionResponse,
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
else {
|
|
970
|
-
return {
|
|
971
|
-
isCanceled: false,
|
|
972
|
-
error: true,
|
|
973
|
-
};
|
|
974
|
-
}
|
|
975
998
|
}
|
|
976
999
|
catch (error) {
|
|
977
1000
|
return {
|
|
@@ -1019,29 +1042,20 @@ export class EthereumTransactions {
|
|
|
1019
1042
|
const expectedUnsignedTransaction = serializeTransaction(txFormattedForTrezor);
|
|
1020
1043
|
if (retained)
|
|
1021
1044
|
assertCancellationEnvelope(expectedUnsignedTransaction);
|
|
1022
|
-
const
|
|
1045
|
+
const { rawTransaction: signedTx } = await signTrezorEvmTransaction(this.requireTrezorSigner(), {
|
|
1046
|
+
accountIndex: activeAccountId,
|
|
1023
1047
|
coin: trezorCoin,
|
|
1024
|
-
|
|
1025
|
-
index: activeAccountId.toString(),
|
|
1048
|
+
expectedAddress: activeAccount.address,
|
|
1026
1049
|
slip44: activeNetwork.slip44,
|
|
1050
|
+
unsignedTransaction: expectedUnsignedTransaction,
|
|
1027
1051
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
1028
1052
|
assertCurrent();
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
isCanceled: true,
|
|
1036
|
-
transaction: transactionResponse,
|
|
1037
|
-
};
|
|
1038
|
-
}
|
|
1039
|
-
else {
|
|
1040
|
-
return {
|
|
1041
|
-
isCanceled: false,
|
|
1042
|
-
error: true,
|
|
1043
|
-
};
|
|
1044
|
-
}
|
|
1053
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1054
|
+
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
|
|
1055
|
+
return {
|
|
1056
|
+
isCanceled: true,
|
|
1057
|
+
transaction: transactionResponse,
|
|
1058
|
+
};
|
|
1045
1059
|
}
|
|
1046
1060
|
catch (error) {
|
|
1047
1061
|
return {
|
|
@@ -1102,12 +1116,21 @@ export class EthereumTransactions {
|
|
|
1102
1116
|
typeof options !== 'object' ||
|
|
1103
1117
|
Array.isArray(options) ||
|
|
1104
1118
|
(options.mode !== 'reviewed-native' &&
|
|
1119
|
+
options.mode !== 'reviewed-generic' &&
|
|
1105
1120
|
options.mode !== 'specialized') ||
|
|
1106
1121
|
typeof options.assertCurrent !== 'function')
|
|
1107
1122
|
throw new Error('Explicit transaction approval is required');
|
|
1108
1123
|
// Capture once; later caller mutations cannot replace this invocation's
|
|
1109
1124
|
// admission decision while chain checks or device approval are pending.
|
|
1110
1125
|
const { assertCurrent: assertHostCurrent, mode, walletNonce } = options;
|
|
1126
|
+
const reviewId = mode === 'reviewed-generic' ? options.reviewId : undefined;
|
|
1127
|
+
if (mode === 'reviewed-generic' &&
|
|
1128
|
+
(typeof reviewId !== 'string' ||
|
|
1129
|
+
!/^[A-Za-z0-9_-]{1,128}$/.test(reviewId) ||
|
|
1130
|
+
walletNonce === undefined))
|
|
1131
|
+
throw new Error('An issued fee review and approved nonce are required');
|
|
1132
|
+
const selectedAccount = snapshotEvmSigningIdentity(options.selectedAccount);
|
|
1133
|
+
const targetAccount = snapshotEvmSigningIdentity(options.targetAccount);
|
|
1111
1134
|
const nonceApproval = walletNonce === undefined ? undefined : { ...walletNonce };
|
|
1112
1135
|
const assertApproved = () => {
|
|
1113
1136
|
const result = assertHostCurrent();
|
|
@@ -1119,14 +1142,14 @@ export class EthereumTransactions {
|
|
|
1119
1142
|
assertApproved();
|
|
1120
1143
|
return await this.sendFormattedTransactionInternal(params, isLegacy, () => {
|
|
1121
1144
|
broadcastAttempted = true;
|
|
1122
|
-
}, assertApproved, mode, nonceApproval);
|
|
1145
|
+
}, assertApproved, mode, nonceApproval, selectedAccount, targetAccount, reviewId);
|
|
1123
1146
|
}
|
|
1124
1147
|
catch (error) {
|
|
1125
1148
|
// A broadcast transport error may mean the node accepted the signed
|
|
1126
1149
|
// transaction. Derive this marker from this invocation, never RPC data.
|
|
1127
1150
|
const submissionError = Object.assign(new Error(error instanceof Error ? error.message : String(error)), error, {
|
|
1128
1151
|
transactionNotBroadcast: !broadcastAttempted ||
|
|
1129
|
-
evmSubmissionFailure(error)
|
|
1152
|
+
evmSubmissionFailure(error)?.transactionNotBroadcast === true,
|
|
1130
1153
|
});
|
|
1131
1154
|
if (error instanceof Error) {
|
|
1132
1155
|
submissionError.name = error.name;
|
|
@@ -1136,19 +1159,60 @@ export class EthereumTransactions {
|
|
|
1136
1159
|
throw submissionError;
|
|
1137
1160
|
}
|
|
1138
1161
|
};
|
|
1139
|
-
this.sendFormattedTransactionInternal = async (input, isLegacy, beforeBroadcast, assertHostCurrent, mode, walletNonce) => {
|
|
1162
|
+
this.sendFormattedTransactionInternal = async (input, isLegacy, beforeBroadcast, assertHostCurrent, mode, walletNonce, selectedIdentity, targetIdentity, reviewId) => {
|
|
1140
1163
|
// Hardware approval may outlive the selected account, network or unlocked
|
|
1141
1164
|
// session. Keep immutable identities and one provider for this invocation.
|
|
1142
|
-
const
|
|
1165
|
+
const selectedContext = this.captureEvmAccountContext();
|
|
1166
|
+
const targetAccount = {
|
|
1167
|
+
id: targetIdentity.id,
|
|
1168
|
+
type: targetIdentity.type,
|
|
1169
|
+
};
|
|
1170
|
+
if (targetAccount.type === KeyringAccountType.SmartAccount)
|
|
1171
|
+
throw new Error('Invalid EVM payer');
|
|
1172
|
+
const { activeAccount, activeAccountType, activeAccountId, activeNetwork, provider, assertCurrent: assertKeyringCurrent, } = this.captureEvmSigningContext(targetAccount);
|
|
1143
1173
|
const assertSigningCurrent = () => {
|
|
1144
1174
|
assertHostCurrent();
|
|
1175
|
+
selectedContext.assertCurrent();
|
|
1145
1176
|
assertKeyringCurrent();
|
|
1177
|
+
if (selectedContext.activeAccountId !== selectedIdentity.id ||
|
|
1178
|
+
selectedContext.activeAccountType !== selectedIdentity.type ||
|
|
1179
|
+
getAddress(selectedContext.activeAccount.address) !==
|
|
1180
|
+
selectedIdentity.expectedAddress ||
|
|
1181
|
+
getAddress(activeAccount.address) !== targetIdentity.expectedAddress)
|
|
1182
|
+
throw new Error('EVM payer approval context changed');
|
|
1146
1183
|
};
|
|
1184
|
+
assertSigningCurrent();
|
|
1185
|
+
// Generic reviewed calls keep the exact prepared envelope, including
|
|
1186
|
+
// contract creation, calldata and access lists, through existing signers.
|
|
1187
|
+
const reviewed = mode === 'reviewed-generic'
|
|
1188
|
+
? snapshotPreparedEvmTransaction(input)
|
|
1189
|
+
: undefined;
|
|
1190
|
+
if (reviewed) {
|
|
1191
|
+
if (reviewed.from !== targetIdentity.expectedAddress ||
|
|
1192
|
+
reviewed.chainId !== String(activeNetwork.chainId) ||
|
|
1193
|
+
reviewed.nonce !== String(walletNonce?.nonce) ||
|
|
1194
|
+
(isLegacy !== undefined && isLegacy !== (reviewed.type === 0)) ||
|
|
1195
|
+
(this.gasOverrides.minGasLimit &&
|
|
1196
|
+
BigInt(reviewed.gasLimit) < this.gasOverrides.minGasLimit.toBigInt()))
|
|
1197
|
+
throw new Error('Reviewed EVM transaction does not match its approval');
|
|
1198
|
+
input = reviewed;
|
|
1199
|
+
isLegacy = reviewed.type === 0;
|
|
1200
|
+
}
|
|
1147
1201
|
const assertBeforeBroadcast = () => {
|
|
1148
1202
|
assertCurrent();
|
|
1149
1203
|
beforeBroadcast();
|
|
1150
1204
|
};
|
|
1151
|
-
const submission = this.captureSubmission('send', activeAccount, activeAccountType, activeAccountId, activeNetwork, assertSigningCurrent, {
|
|
1205
|
+
const submission = this.captureSubmission('send', activeAccount, activeAccountType, activeAccountId, activeNetwork, assertSigningCurrent, {
|
|
1206
|
+
walletNonce,
|
|
1207
|
+
...(reviewed
|
|
1208
|
+
? {
|
|
1209
|
+
review: {
|
|
1210
|
+
id: reviewId,
|
|
1211
|
+
unsignedHash: Transaction.from(serializePreparedEvmTransaction(reviewed)).unsignedHash,
|
|
1212
|
+
},
|
|
1213
|
+
}
|
|
1214
|
+
: {}),
|
|
1215
|
+
});
|
|
1152
1216
|
const assertCurrent = submission.assertCurrent;
|
|
1153
1217
|
const approvedNonce = submission.context.walletNonce?.nonce;
|
|
1154
1218
|
const assertApprovedNonce = (nonce) => {
|
|
@@ -1157,6 +1221,7 @@ export class EthereumTransactions {
|
|
|
1157
1221
|
};
|
|
1158
1222
|
if (mode === 'reviewed-native') {
|
|
1159
1223
|
const { transaction } = snapshotPreparedEvmRequest({
|
|
1224
|
+
selectedAccount: selectedIdentity,
|
|
1160
1225
|
account: {
|
|
1161
1226
|
id: activeAccountId,
|
|
1162
1227
|
type: activeAccountType,
|
|
@@ -1187,7 +1252,7 @@ export class EthereumTransactions {
|
|
|
1187
1252
|
assertCurrent();
|
|
1188
1253
|
if (this.gasOverrides.minGasLimit !== minimum)
|
|
1189
1254
|
throw new Error('Reviewed native gas policy changed');
|
|
1190
|
-
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
|
|
1255
|
+
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(targetAccount);
|
|
1191
1256
|
if (address.toLowerCase() !== transaction.from.toLowerCase())
|
|
1192
1257
|
throw new Error('Reviewed native signer does not match the approved account');
|
|
1193
1258
|
assertCurrent();
|
|
@@ -1200,6 +1265,9 @@ export class EthereumTransactions {
|
|
|
1200
1265
|
if (!params || typeof params !== 'object' || Array.isArray(params))
|
|
1201
1266
|
throw new TypeError('Invalid EVM transaction request');
|
|
1202
1267
|
const supplied = { ...params };
|
|
1268
|
+
if (supplied.from !== undefined &&
|
|
1269
|
+
getAddress(supplied.from) !== targetIdentity.expectedAddress)
|
|
1270
|
+
throw new Error('EVM transaction sender does not match the approved payer');
|
|
1203
1271
|
// Validate original scalar spellings before conversion. Normalization's
|
|
1204
1272
|
// permissive zero coercion must not bypass the bounded wire parser.
|
|
1205
1273
|
for (const field of [
|
|
@@ -1252,7 +1320,8 @@ export class EthereumTransactions {
|
|
|
1252
1320
|
const validateEip1559Fees = () => {
|
|
1253
1321
|
const maximum = nonNegativeFeeQuantity(params.maxFeePerGas, 'maximum fee');
|
|
1254
1322
|
const priority = nonNegativeFeeQuantity(params.maxPriorityFeePerGas, 'priority fee');
|
|
1255
|
-
if (maximum.isZero() ||
|
|
1323
|
+
if ((mode !== 'reviewed-generic' && maximum.isZero()) ||
|
|
1324
|
+
priority.gt(maximum))
|
|
1256
1325
|
throw new Error('Invalid EIP-1559 fees');
|
|
1257
1326
|
params.maxFeePerGas = maximum;
|
|
1258
1327
|
params.maxPriorityFeePerGas = priority;
|
|
@@ -1263,7 +1332,9 @@ export class EthereumTransactions {
|
|
|
1263
1332
|
validateEip1559Fees();
|
|
1264
1333
|
// Only apply a minimum gas limit when a network-specific override is set.
|
|
1265
1334
|
// Otherwise keep the user/dapp-approved gas limit unchanged.
|
|
1266
|
-
if (
|
|
1335
|
+
if (mode !== 'reviewed-generic' &&
|
|
1336
|
+
params.gasLimit != null &&
|
|
1337
|
+
this.gasOverrides.minGasLimit) {
|
|
1267
1338
|
const minGasLimit = this.gasOverrides.minGasLimit;
|
|
1268
1339
|
const currentGasLimit = BigNumber.from(params.gasLimit);
|
|
1269
1340
|
if (currentGasLimit.lt(minGasLimit)) {
|
|
@@ -1334,31 +1405,15 @@ export class EthereumTransactions {
|
|
|
1334
1405
|
type: 2, // Need explicit type for hardware wallet serialization
|
|
1335
1406
|
};
|
|
1336
1407
|
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1408
|
+
const { rawTransaction: signedTx } = await signLedgerEvmTransaction(this.requireLedgerSigner(), {
|
|
1409
|
+
unsignedTransaction: rawTx,
|
|
1339
1410
|
accountIndex: activeAccountId,
|
|
1340
1411
|
expectedAddress: activeAccount.address,
|
|
1341
1412
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
1342
1413
|
assertCurrent();
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
v: parseInt(signature.v, 16),
|
|
1347
|
-
};
|
|
1348
|
-
if (signature) {
|
|
1349
|
-
try {
|
|
1350
|
-
const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
|
|
1351
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1352
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
|
|
1353
|
-
return finalTx;
|
|
1354
|
-
}
|
|
1355
|
-
catch (error) {
|
|
1356
|
-
throw error;
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
else {
|
|
1360
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
1361
|
-
}
|
|
1414
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1415
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
|
|
1416
|
+
return finalTx;
|
|
1362
1417
|
};
|
|
1363
1418
|
const sendEVMTrezorTransaction = async () => {
|
|
1364
1419
|
assertCurrent();
|
|
@@ -1415,44 +1470,21 @@ export class EthereumTransactions {
|
|
|
1415
1470
|
...txFormattedForTrezor,
|
|
1416
1471
|
type: isLegacy ? 0 : 2,
|
|
1417
1472
|
});
|
|
1418
|
-
const
|
|
1419
|
-
|
|
1420
|
-
tx: txFormattedForTrezor,
|
|
1473
|
+
const { rawTransaction: signedTx } = await signTrezorEvmTransaction(this.requireTrezorSigner(), {
|
|
1474
|
+
accountIndex: activeAccountId,
|
|
1421
1475
|
coin: activeNetwork.currency,
|
|
1476
|
+
expectedAddress: activeAccount.address,
|
|
1422
1477
|
slip44: activeNetwork.slip44,
|
|
1478
|
+
unsignedTransaction: expectedUnsignedTransaction,
|
|
1423
1479
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
1424
1480
|
assertCurrent();
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
? {
|
|
1429
|
-
...formatParams,
|
|
1430
|
-
nonce: transactionNonce,
|
|
1431
|
-
chainId: activeNetwork.chainId,
|
|
1432
|
-
type: 0, // Force Type 0 for legacy
|
|
1433
|
-
}
|
|
1434
|
-
: {
|
|
1435
|
-
...formatParams,
|
|
1436
|
-
nonce: transactionNonce,
|
|
1437
|
-
chainId: activeNetwork.chainId,
|
|
1438
|
-
type: 2, // Need explicit type for hardware wallet serialization
|
|
1439
|
-
};
|
|
1440
|
-
const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
|
|
1441
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1442
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, expectedUnsignedTransaction);
|
|
1443
|
-
return finalTx;
|
|
1444
|
-
}
|
|
1445
|
-
catch (error) {
|
|
1446
|
-
throw error;
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
else {
|
|
1450
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
1451
|
-
}
|
|
1481
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1482
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, expectedUnsignedTransaction);
|
|
1483
|
+
return finalTx;
|
|
1452
1484
|
};
|
|
1453
1485
|
const sendEVMTransaction = async () => {
|
|
1454
1486
|
assertCurrent();
|
|
1455
|
-
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
|
|
1487
|
+
const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey(targetAccount);
|
|
1456
1488
|
// Validate that we have the correct private key for the active account to prevent race conditions
|
|
1457
1489
|
// This is critical for transaction security during account switches
|
|
1458
1490
|
if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
|
|
@@ -1709,32 +1741,18 @@ export class EthereumTransactions {
|
|
|
1709
1741
|
};
|
|
1710
1742
|
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
1711
1743
|
assertCurrent();
|
|
1712
|
-
const
|
|
1713
|
-
|
|
1744
|
+
const { rawTransaction: signedTx } = await signLedgerEvmTransaction(this.requireLedgerSigner(), {
|
|
1745
|
+
unsignedTransaction: rawTx,
|
|
1714
1746
|
accountIndex: activeAccountId,
|
|
1715
1747
|
expectedAddress: activeAccount.address,
|
|
1716
1748
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1749
|
+
assertSignedSender(signedTx);
|
|
1750
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1751
|
+
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
|
|
1752
|
+
return {
|
|
1753
|
+
isSpeedUp: true,
|
|
1754
|
+
transaction: transactionResponse,
|
|
1721
1755
|
};
|
|
1722
|
-
if (signature) {
|
|
1723
|
-
const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
|
|
1724
|
-
assertSignedSender(signedTx);
|
|
1725
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1726
|
-
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, rawTx);
|
|
1727
|
-
return {
|
|
1728
|
-
isSpeedUp: true,
|
|
1729
|
-
transaction: transactionResponse,
|
|
1730
|
-
};
|
|
1731
|
-
}
|
|
1732
|
-
else {
|
|
1733
|
-
return {
|
|
1734
|
-
isSpeedUp: false,
|
|
1735
|
-
error: true,
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
1756
|
}
|
|
1739
1757
|
catch (error) {
|
|
1740
1758
|
console.error('[SpeedUp] Failed to send replacement transaction with Ledger:', error);
|
|
@@ -1794,28 +1812,20 @@ export class EthereumTransactions {
|
|
|
1794
1812
|
assertCurrent();
|
|
1795
1813
|
assertTransactionGasLimit(txFormattedForTrezor);
|
|
1796
1814
|
const expectedUnsignedTransaction = serializeTransaction(txFormattedForTrezor);
|
|
1797
|
-
const
|
|
1815
|
+
const { rawTransaction: signedTx } = await signTrezorEvmTransaction(this.requireTrezorSigner(), {
|
|
1816
|
+
accountIndex: activeAccountId,
|
|
1798
1817
|
coin: trezorCoin,
|
|
1799
|
-
|
|
1800
|
-
index: activeAccountId.toString(),
|
|
1818
|
+
expectedAddress: activeAccount.address,
|
|
1801
1819
|
slip44: activeNetwork.slip44,
|
|
1820
|
+
unsignedTransaction: expectedUnsignedTransaction,
|
|
1802
1821
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent));
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
transaction: transactionResponse,
|
|
1811
|
-
};
|
|
1812
|
-
}
|
|
1813
|
-
else {
|
|
1814
|
-
return {
|
|
1815
|
-
isSpeedUp: false,
|
|
1816
|
-
error: true,
|
|
1817
|
-
};
|
|
1818
|
-
}
|
|
1822
|
+
assertSignedSender(signedTx);
|
|
1823
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1824
|
+
const transactionResponse = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, assertBeforeBroadcast, expectedUnsignedTransaction);
|
|
1825
|
+
return {
|
|
1826
|
+
isSpeedUp: true,
|
|
1827
|
+
transaction: transactionResponse,
|
|
1828
|
+
};
|
|
1819
1829
|
}
|
|
1820
1830
|
catch (error) {
|
|
1821
1831
|
console.error('[SpeedUp] Failed to send replacement transaction with Trezor:', error);
|
|
@@ -1947,73 +1957,51 @@ export class EthereumTransactions {
|
|
|
1947
1957
|
};
|
|
1948
1958
|
const sendERC20TokenOnLedger = async () => {
|
|
1949
1959
|
assertCurrent();
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
type: 0,
|
|
1967
|
-
};
|
|
1968
|
-
}
|
|
1969
|
-
else {
|
|
1970
|
-
txFormattedForEthers = {
|
|
1971
|
-
to: tokenAddress,
|
|
1972
|
-
value: '0x0',
|
|
1973
|
-
gasLimit: gasLimit,
|
|
1974
|
-
maxFeePerGas,
|
|
1975
|
-
maxPriorityFeePerGas,
|
|
1976
|
-
data: txData,
|
|
1977
|
-
nonce,
|
|
1978
|
-
chainId: activeNetwork.chainId,
|
|
1979
|
-
type: 2, // Need explicit type for hardware wallet serialization
|
|
1980
|
-
};
|
|
1981
|
-
}
|
|
1982
|
-
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
1983
|
-
const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
|
|
1984
|
-
rawTx: rawTx.replace('0x', ''),
|
|
1985
|
-
accountIndex: activeAccountId,
|
|
1986
|
-
expectedAddress: activeAccount.address,
|
|
1987
|
-
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
1988
|
-
assertCurrent();
|
|
1989
|
-
const formattedSignature = {
|
|
1990
|
-
r: `0x${signature.r}`,
|
|
1991
|
-
s: `0x${signature.s}`,
|
|
1992
|
-
v: parseInt(signature.v, 16),
|
|
1960
|
+
const _contract = new Contract(tokenAddress, getErc20Abi(), provider);
|
|
1961
|
+
const txData = _contract.interface.encodeFunctionData('transfer', [
|
|
1962
|
+
receiver,
|
|
1963
|
+
exactTokenAmount,
|
|
1964
|
+
]);
|
|
1965
|
+
let txFormattedForEthers;
|
|
1966
|
+
if (isLegacy) {
|
|
1967
|
+
txFormattedForEthers = {
|
|
1968
|
+
to: tokenAddress,
|
|
1969
|
+
value: '0x0',
|
|
1970
|
+
gasLimit: gasLimit,
|
|
1971
|
+
gasPrice,
|
|
1972
|
+
data: txData,
|
|
1973
|
+
nonce,
|
|
1974
|
+
chainId: activeNetwork.chainId,
|
|
1975
|
+
type: 0,
|
|
1993
1976
|
};
|
|
1994
|
-
if (signature) {
|
|
1995
|
-
try {
|
|
1996
|
-
const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
|
|
1997
|
-
assertCurrent();
|
|
1998
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1999
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
|
|
2000
|
-
const response = await admit(() => provider.sendTransaction(rawTransaction));
|
|
2001
|
-
saveTrezorTx && saveTrezorTx(response);
|
|
2002
|
-
return response;
|
|
2003
|
-
}, submission, undefined, rawTx);
|
|
2004
|
-
return finalTx;
|
|
2005
|
-
}
|
|
2006
|
-
catch (error) {
|
|
2007
|
-
throw error;
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
2010
|
-
else {
|
|
2011
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
2012
|
-
}
|
|
2013
1977
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
1978
|
+
else {
|
|
1979
|
+
txFormattedForEthers = {
|
|
1980
|
+
to: tokenAddress,
|
|
1981
|
+
value: '0x0',
|
|
1982
|
+
gasLimit: gasLimit,
|
|
1983
|
+
maxFeePerGas,
|
|
1984
|
+
maxPriorityFeePerGas,
|
|
1985
|
+
data: txData,
|
|
1986
|
+
nonce,
|
|
1987
|
+
chainId: activeNetwork.chainId,
|
|
1988
|
+
type: 2, // Need explicit type for hardware wallet serialization
|
|
1989
|
+
};
|
|
2016
1990
|
}
|
|
1991
|
+
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
1992
|
+
const { rawTransaction: signedTx } = await signLedgerEvmTransaction(this.requireLedgerSigner(), {
|
|
1993
|
+
unsignedTransaction: rawTx,
|
|
1994
|
+
accountIndex: activeAccountId,
|
|
1995
|
+
expectedAddress: activeAccount.address,
|
|
1996
|
+
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
1997
|
+
assertCurrent();
|
|
1998
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
1999
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
|
|
2000
|
+
const response = await admit(() => provider.sendTransaction(rawTransaction));
|
|
2001
|
+
saveTrezorTx && saveTrezorTx(response);
|
|
2002
|
+
return response;
|
|
2003
|
+
}, submission, undefined, rawTx);
|
|
2004
|
+
return finalTx;
|
|
2017
2005
|
};
|
|
2018
2006
|
const sendERC20TokenOnTrezor = async () => {
|
|
2019
2007
|
assertCurrent();
|
|
@@ -2052,58 +2040,21 @@ export class EthereumTransactions {
|
|
|
2052
2040
|
...txToBeSignedByTrezor,
|
|
2053
2041
|
type: isLegacy ? 0 : 2,
|
|
2054
2042
|
});
|
|
2055
|
-
const
|
|
2056
|
-
|
|
2057
|
-
tx: txToBeSignedByTrezor,
|
|
2043
|
+
const { rawTransaction: signedTx } = await signTrezorEvmTransaction(this.requireTrezorSigner(), {
|
|
2044
|
+
accountIndex: activeAccountId,
|
|
2058
2045
|
coin: activeNetwork.currency,
|
|
2046
|
+
expectedAddress: activeAccount.address,
|
|
2059
2047
|
slip44: activeNetwork.slip44,
|
|
2048
|
+
unsignedTransaction: expectedUnsignedTransaction,
|
|
2060
2049
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2061
2050
|
assertCurrent();
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
gasLimit: gasLimit,
|
|
2070
|
-
gasPrice,
|
|
2071
|
-
data: txData,
|
|
2072
|
-
nonce,
|
|
2073
|
-
chainId: activeNetwork.chainId,
|
|
2074
|
-
type: 0,
|
|
2075
|
-
};
|
|
2076
|
-
}
|
|
2077
|
-
else {
|
|
2078
|
-
txFormattedForEthers = {
|
|
2079
|
-
to: tokenAddress,
|
|
2080
|
-
value: '0x0',
|
|
2081
|
-
gasLimit: gasLimit,
|
|
2082
|
-
maxFeePerGas,
|
|
2083
|
-
maxPriorityFeePerGas,
|
|
2084
|
-
data: txData,
|
|
2085
|
-
nonce,
|
|
2086
|
-
chainId: activeNetwork.chainId,
|
|
2087
|
-
type: 2, // Need explicit type for hardware wallet serialization
|
|
2088
|
-
};
|
|
2089
|
-
}
|
|
2090
|
-
const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
|
|
2091
|
-
assertCurrent();
|
|
2092
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2093
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
|
|
2094
|
-
const response = await admit(() => provider.sendTransaction(rawTransaction));
|
|
2095
|
-
saveTrezorTx && saveTrezorTx(response);
|
|
2096
|
-
return response;
|
|
2097
|
-
}, submission, undefined, expectedUnsignedTransaction);
|
|
2098
|
-
return finalTx;
|
|
2099
|
-
}
|
|
2100
|
-
catch (error) {
|
|
2101
|
-
throw error;
|
|
2102
|
-
}
|
|
2103
|
-
}
|
|
2104
|
-
else {
|
|
2105
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
2106
|
-
}
|
|
2051
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2052
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, async ({ rawTransaction, admit }) => {
|
|
2053
|
+
const response = await admit(() => provider.sendTransaction(rawTransaction));
|
|
2054
|
+
saveTrezorTx && saveTrezorTx(response);
|
|
2055
|
+
return response;
|
|
2056
|
+
}, submission, undefined, expectedUnsignedTransaction);
|
|
2057
|
+
return finalTx;
|
|
2107
2058
|
}
|
|
2108
2059
|
catch (error) {
|
|
2109
2060
|
throw error;
|
|
@@ -2174,70 +2125,48 @@ export class EthereumTransactions {
|
|
|
2174
2125
|
};
|
|
2175
2126
|
const sendERC721TokenOnLedger = async () => {
|
|
2176
2127
|
assertCurrent();
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
type: 0,
|
|
2195
|
-
};
|
|
2196
|
-
}
|
|
2197
|
-
else {
|
|
2198
|
-
txFormattedForEthers = {
|
|
2199
|
-
to: tokenAddress,
|
|
2200
|
-
value: '0x0',
|
|
2201
|
-
gasLimit,
|
|
2202
|
-
maxFeePerGas,
|
|
2203
|
-
maxPriorityFeePerGas,
|
|
2204
|
-
data: txData,
|
|
2205
|
-
nonce,
|
|
2206
|
-
chainId: activeNetwork.chainId,
|
|
2207
|
-
type: 2, // Need explicit type for hardware wallet serialization
|
|
2208
|
-
};
|
|
2209
|
-
}
|
|
2210
|
-
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
2211
|
-
const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
|
|
2212
|
-
rawTx: rawTx.replace('0x', ''),
|
|
2213
|
-
accountIndex: activeAccountId,
|
|
2214
|
-
expectedAddress: activeAccount.address,
|
|
2215
|
-
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2216
|
-
assertCurrent();
|
|
2217
|
-
const formattedSignature = {
|
|
2218
|
-
r: `0x${signature.r}`,
|
|
2219
|
-
s: `0x${signature.s}`,
|
|
2220
|
-
v: parseInt(signature.v, 16),
|
|
2128
|
+
const _contract = new Contract(tokenAddress, getErc21Abi(), provider);
|
|
2129
|
+
const txData = _contract.interface.encodeFunctionData('transferFrom', [
|
|
2130
|
+
activeAccountAddress,
|
|
2131
|
+
receiver,
|
|
2132
|
+
normalizedTokenId,
|
|
2133
|
+
]);
|
|
2134
|
+
let txFormattedForEthers;
|
|
2135
|
+
if (isLegacy) {
|
|
2136
|
+
txFormattedForEthers = {
|
|
2137
|
+
to: tokenAddress,
|
|
2138
|
+
value: '0x0',
|
|
2139
|
+
gasLimit,
|
|
2140
|
+
gasPrice,
|
|
2141
|
+
data: txData,
|
|
2142
|
+
nonce,
|
|
2143
|
+
chainId: activeNetwork.chainId,
|
|
2144
|
+
type: 0,
|
|
2221
2145
|
};
|
|
2222
|
-
if (signature) {
|
|
2223
|
-
try {
|
|
2224
|
-
const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
|
|
2225
|
-
assertCurrent();
|
|
2226
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2227
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
2228
|
-
return finalTx;
|
|
2229
|
-
}
|
|
2230
|
-
catch (error) {
|
|
2231
|
-
throw error;
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
else {
|
|
2235
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
2236
|
-
}
|
|
2237
2146
|
}
|
|
2238
|
-
|
|
2239
|
-
|
|
2147
|
+
else {
|
|
2148
|
+
txFormattedForEthers = {
|
|
2149
|
+
to: tokenAddress,
|
|
2150
|
+
value: '0x0',
|
|
2151
|
+
gasLimit,
|
|
2152
|
+
maxFeePerGas,
|
|
2153
|
+
maxPriorityFeePerGas,
|
|
2154
|
+
data: txData,
|
|
2155
|
+
nonce,
|
|
2156
|
+
chainId: activeNetwork.chainId,
|
|
2157
|
+
type: 2, // Need explicit type for hardware wallet serialization
|
|
2158
|
+
};
|
|
2240
2159
|
}
|
|
2160
|
+
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
2161
|
+
const { rawTransaction: signedTx } = await signLedgerEvmTransaction(this.requireLedgerSigner(), {
|
|
2162
|
+
unsignedTransaction: rawTx,
|
|
2163
|
+
accountIndex: activeAccountId,
|
|
2164
|
+
expectedAddress: activeAccount.address,
|
|
2165
|
+
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2166
|
+
assertCurrent();
|
|
2167
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2168
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
2169
|
+
return finalTx;
|
|
2241
2170
|
};
|
|
2242
2171
|
const sendERC721TokenOnTrezor = async () => {
|
|
2243
2172
|
assertCurrent();
|
|
@@ -2280,55 +2209,17 @@ export class EthereumTransactions {
|
|
|
2280
2209
|
...txToBeSignedByTrezor,
|
|
2281
2210
|
type: isLegacy ? 0 : 2,
|
|
2282
2211
|
});
|
|
2283
|
-
const
|
|
2284
|
-
|
|
2285
|
-
tx: txToBeSignedByTrezor,
|
|
2212
|
+
const { rawTransaction: signedTx } = await signTrezorEvmTransaction(this.requireTrezorSigner(), {
|
|
2213
|
+
accountIndex: activeAccountId,
|
|
2286
2214
|
coin: trezorCoin,
|
|
2215
|
+
expectedAddress: activeAccount.address,
|
|
2287
2216
|
slip44: activeNetwork.slip44,
|
|
2217
|
+
unsignedTransaction: expectedUnsignedTransaction,
|
|
2288
2218
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2289
2219
|
assertCurrent();
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
if (isLegacy) {
|
|
2294
|
-
txFormattedForEthers = {
|
|
2295
|
-
to: tokenAddress,
|
|
2296
|
-
value: '0x0',
|
|
2297
|
-
gasLimit,
|
|
2298
|
-
gasPrice,
|
|
2299
|
-
data: txData,
|
|
2300
|
-
nonce,
|
|
2301
|
-
chainId: activeNetwork.chainId,
|
|
2302
|
-
type: 0,
|
|
2303
|
-
};
|
|
2304
|
-
}
|
|
2305
|
-
else {
|
|
2306
|
-
txFormattedForEthers = {
|
|
2307
|
-
to: tokenAddress,
|
|
2308
|
-
value: '0x0',
|
|
2309
|
-
gasLimit,
|
|
2310
|
-
maxFeePerGas,
|
|
2311
|
-
maxPriorityFeePerGas,
|
|
2312
|
-
data: txData,
|
|
2313
|
-
nonce,
|
|
2314
|
-
chainId: activeNetwork.chainId,
|
|
2315
|
-
type: 2, // Need explicit type for hardware wallet serialization
|
|
2316
|
-
};
|
|
2317
|
-
}
|
|
2318
|
-
const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
|
|
2319
|
-
assertCurrent();
|
|
2320
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2321
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
|
|
2322
|
-
return finalTx;
|
|
2323
|
-
}
|
|
2324
|
-
catch (error) {
|
|
2325
|
-
console.log({ error });
|
|
2326
|
-
throw error;
|
|
2327
|
-
}
|
|
2328
|
-
}
|
|
2329
|
-
else {
|
|
2330
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
2331
|
-
}
|
|
2220
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2221
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
|
|
2222
|
+
return finalTx;
|
|
2332
2223
|
}
|
|
2333
2224
|
catch (error) {
|
|
2334
2225
|
console.log({ errorDois: error });
|
|
@@ -2404,66 +2295,44 @@ export class EthereumTransactions {
|
|
|
2404
2295
|
};
|
|
2405
2296
|
const sendERC1155TokenOnLedger = async () => {
|
|
2406
2297
|
assertCurrent();
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
type: 0,
|
|
2421
|
-
};
|
|
2422
|
-
}
|
|
2423
|
-
else {
|
|
2424
|
-
txFormattedForEthers = {
|
|
2425
|
-
to: tokenAddress,
|
|
2426
|
-
value: '0x0',
|
|
2427
|
-
gasLimit,
|
|
2428
|
-
maxFeePerGas,
|
|
2429
|
-
maxPriorityFeePerGas,
|
|
2430
|
-
data: txData,
|
|
2431
|
-
nonce,
|
|
2432
|
-
chainId: activeNetwork.chainId,
|
|
2433
|
-
type: 2, // Need explicit type for hardware wallet serialization
|
|
2434
|
-
};
|
|
2435
|
-
}
|
|
2436
|
-
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
2437
|
-
const signature = await this.requireLedgerSigner().evm.signEVMTransaction({
|
|
2438
|
-
rawTx: rawTx.replace('0x', ''),
|
|
2439
|
-
accountIndex: activeAccountId,
|
|
2440
|
-
expectedAddress: activeAccount.address,
|
|
2441
|
-
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2442
|
-
assertCurrent();
|
|
2443
|
-
const formattedSignature = {
|
|
2444
|
-
r: `0x${signature.r}`,
|
|
2445
|
-
s: `0x${signature.s}`,
|
|
2446
|
-
v: parseInt(signature.v, 16),
|
|
2298
|
+
const _contract = new Contract(tokenAddress, getErc55Abi(), provider);
|
|
2299
|
+
const txData = _contract.interface.encodeFunctionData('safeTransferFrom', [activeAccountAddress, receiver, normalizedTokenId, amount, '0x']);
|
|
2300
|
+
let txFormattedForEthers;
|
|
2301
|
+
if (isLegacy) {
|
|
2302
|
+
txFormattedForEthers = {
|
|
2303
|
+
to: tokenAddress,
|
|
2304
|
+
value: '0x0',
|
|
2305
|
+
gasLimit,
|
|
2306
|
+
gasPrice,
|
|
2307
|
+
data: txData,
|
|
2308
|
+
nonce,
|
|
2309
|
+
chainId: activeNetwork.chainId,
|
|
2310
|
+
type: 0,
|
|
2447
2311
|
};
|
|
2448
|
-
if (signature) {
|
|
2449
|
-
try {
|
|
2450
|
-
const signedTx = serializeTransaction(txFormattedForEthers, formattedSignature);
|
|
2451
|
-
assertCurrent();
|
|
2452
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2453
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
2454
|
-
return finalTx;
|
|
2455
|
-
}
|
|
2456
|
-
catch (error) {
|
|
2457
|
-
throw error;
|
|
2458
|
-
}
|
|
2459
|
-
}
|
|
2460
|
-
else {
|
|
2461
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
2462
|
-
}
|
|
2463
2312
|
}
|
|
2464
|
-
|
|
2465
|
-
|
|
2313
|
+
else {
|
|
2314
|
+
txFormattedForEthers = {
|
|
2315
|
+
to: tokenAddress,
|
|
2316
|
+
value: '0x0',
|
|
2317
|
+
gasLimit,
|
|
2318
|
+
maxFeePerGas,
|
|
2319
|
+
maxPriorityFeePerGas,
|
|
2320
|
+
data: txData,
|
|
2321
|
+
nonce,
|
|
2322
|
+
chainId: activeNetwork.chainId,
|
|
2323
|
+
type: 2, // Need explicit type for hardware wallet serialization
|
|
2324
|
+
};
|
|
2466
2325
|
}
|
|
2326
|
+
const rawTx = serializeTransaction(txFormattedForEthers);
|
|
2327
|
+
const { rawTransaction: signedTx } = await signLedgerEvmTransaction(this.requireLedgerSigner(), {
|
|
2328
|
+
unsignedTransaction: rawTx,
|
|
2329
|
+
accountIndex: activeAccountId,
|
|
2330
|
+
expectedAddress: activeAccount.address,
|
|
2331
|
+
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2332
|
+
assertCurrent();
|
|
2333
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2334
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, rawTx);
|
|
2335
|
+
return finalTx;
|
|
2467
2336
|
};
|
|
2468
2337
|
const sendERC1155TokenOnTrezor = async () => {
|
|
2469
2338
|
assertCurrent();
|
|
@@ -2499,55 +2368,17 @@ export class EthereumTransactions {
|
|
|
2499
2368
|
...txToBeSignedByTrezor,
|
|
2500
2369
|
type: isLegacy ? 0 : 2,
|
|
2501
2370
|
});
|
|
2502
|
-
const
|
|
2503
|
-
|
|
2504
|
-
tx: txToBeSignedByTrezor,
|
|
2371
|
+
const { rawTransaction: signedTx } = await signTrezorEvmTransaction(this.requireTrezorSigner(), {
|
|
2372
|
+
accountIndex: activeAccountId,
|
|
2505
2373
|
coin: activeNetwork.currency,
|
|
2374
|
+
expectedAddress: activeAccount.address,
|
|
2506
2375
|
slip44: activeNetwork.slip44,
|
|
2376
|
+
unsignedTransaction: expectedUnsignedTransaction,
|
|
2507
2377
|
}, await this.authorizeHardwareTransaction(provider, assertCurrent, signal));
|
|
2508
2378
|
assertCurrent();
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
if (isLegacy) {
|
|
2513
|
-
txFormattedForEthers = {
|
|
2514
|
-
to: tokenAddress,
|
|
2515
|
-
value: '0x0',
|
|
2516
|
-
gasLimit,
|
|
2517
|
-
gasPrice,
|
|
2518
|
-
data: txData,
|
|
2519
|
-
nonce,
|
|
2520
|
-
chainId: activeNetwork.chainId,
|
|
2521
|
-
type: 0,
|
|
2522
|
-
};
|
|
2523
|
-
}
|
|
2524
|
-
else {
|
|
2525
|
-
txFormattedForEthers = {
|
|
2526
|
-
to: tokenAddress,
|
|
2527
|
-
value: '0x0',
|
|
2528
|
-
gasLimit,
|
|
2529
|
-
maxFeePerGas,
|
|
2530
|
-
maxPriorityFeePerGas,
|
|
2531
|
-
data: txData,
|
|
2532
|
-
nonce,
|
|
2533
|
-
chainId: activeNetwork.chainId,
|
|
2534
|
-
type: 2, // Need explicit type for hardware wallet serialization
|
|
2535
|
-
};
|
|
2536
|
-
}
|
|
2537
|
-
const signedTx = serializeTransaction(txFormattedForEthers, trezorSignature(signature.payload));
|
|
2538
|
-
assertCurrent();
|
|
2539
|
-
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2540
|
-
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
|
|
2541
|
-
return finalTx;
|
|
2542
|
-
}
|
|
2543
|
-
catch (error) {
|
|
2544
|
-
console.log({ error });
|
|
2545
|
-
throw error;
|
|
2546
|
-
}
|
|
2547
|
-
}
|
|
2548
|
-
else {
|
|
2549
|
-
throw new Error(`Transaction Signature Failed. Error: ${signature}`);
|
|
2550
|
-
}
|
|
2379
|
+
assertHardwareTransactionSender(signedTx, activeAccount.address);
|
|
2380
|
+
const finalTx = await this.submitSignedHardwareTransaction(provider, signedTx, ({ rawTransaction, admit }) => admit(() => provider.sendTransaction(rawTransaction)), submission, undefined, expectedUnsignedTransaction);
|
|
2381
|
+
return finalTx;
|
|
2551
2382
|
}
|
|
2552
2383
|
catch (error) {
|
|
2553
2384
|
console.log({ error });
|
|
@@ -2785,6 +2616,52 @@ export class EthereumTransactions {
|
|
|
2785
2616
|
console.log('[EthereumTransactions] Deferring provider initialization:', error?.message || error);
|
|
2786
2617
|
}
|
|
2787
2618
|
}
|
|
2619
|
+
signPreparedEvmTransaction(input, options) {
|
|
2620
|
+
const selected = this.captureEvmAccountContext();
|
|
2621
|
+
const request = snapshotPreparedEvmRequest(input);
|
|
2622
|
+
const target = {
|
|
2623
|
+
id: request.account.id,
|
|
2624
|
+
type: request.account.type,
|
|
2625
|
+
};
|
|
2626
|
+
const context = this.captureEvmAccountContext(target);
|
|
2627
|
+
const hostGuard = preparedEvmGuard(options);
|
|
2628
|
+
const targetRecord = this.getState().accounts[target.type]?.[target.id];
|
|
2629
|
+
const encryptedKey = targetRecord?.xprv;
|
|
2630
|
+
const assertCurrent = () => {
|
|
2631
|
+
selected.assertCurrent();
|
|
2632
|
+
context.assertCurrent();
|
|
2633
|
+
const live = this.getState().accounts[target.type]?.[target.id];
|
|
2634
|
+
if (!live ||
|
|
2635
|
+
live.id !== target.id ||
|
|
2636
|
+
live.isSmartAccount ||
|
|
2637
|
+
live.isLedgerWallet ||
|
|
2638
|
+
live.isTrezorWallet ||
|
|
2639
|
+
typeof encryptedKey !== 'string' ||
|
|
2640
|
+
!encryptedKey ||
|
|
2641
|
+
live.xprv !== encryptedKey ||
|
|
2642
|
+
selected.activeAccountId !== request.selectedAccount.id ||
|
|
2643
|
+
selected.activeAccountType !== request.selectedAccount.type ||
|
|
2644
|
+
getAddress(selected.activeAccount.address) !==
|
|
2645
|
+
request.selectedAccount.expectedAddress ||
|
|
2646
|
+
getAddress(context.activeAccount.address) !==
|
|
2647
|
+
request.account.expectedAddress ||
|
|
2648
|
+
context.activeNetwork.kind !== 'ethereum' ||
|
|
2649
|
+
context.activeNetwork.slip44 !== 60 ||
|
|
2650
|
+
String(context.activeNetwork.chainId) !== request.network.chainId ||
|
|
2651
|
+
context.activeNetwork.url !== request.network.url)
|
|
2652
|
+
throw new Error('Prepared EVM signing context changed or is unsupported');
|
|
2653
|
+
};
|
|
2654
|
+
assertCurrent();
|
|
2655
|
+
hostGuard();
|
|
2656
|
+
assertCurrent();
|
|
2657
|
+
const key = this.getDecryptedPrivateKey(target);
|
|
2658
|
+
if (getAddress(key.address) !== request.account.expectedAddress)
|
|
2659
|
+
throw new Error('Prepared EVM signer address mismatch');
|
|
2660
|
+
const { signed } = signPreparedEvmEnvelope(request.transaction, key.decryptedPrivateKey);
|
|
2661
|
+
hostGuard();
|
|
2662
|
+
assertCurrent();
|
|
2663
|
+
return signed;
|
|
2664
|
+
}
|
|
2788
2665
|
setWeb3Provider(network) {
|
|
2789
2666
|
this.abortController.abort();
|
|
2790
2667
|
this.abortController = new AbortController();
|