@sidhujag/sysweb3-keyring 1.0.491

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +201 -0
  2. package/cjs/errorUtils.js +75 -0
  3. package/cjs/errorUtils.js.map +1 -0
  4. package/cjs/hardware-wallet-manager.js +462 -0
  5. package/cjs/hardware-wallet-manager.js.map +1 -0
  6. package/cjs/index.js +31 -0
  7. package/cjs/index.js.map +1 -0
  8. package/cjs/initial-state.js +105 -0
  9. package/cjs/initial-state.js.map +1 -0
  10. package/cjs/keyring-manager.js +1687 -0
  11. package/cjs/keyring-manager.js.map +1 -0
  12. package/cjs/ledger/bitcoin_client/index.js +47 -0
  13. package/cjs/ledger/bitcoin_client/index.js.map +1 -0
  14. package/cjs/ledger/bitcoin_client/lib/appClient.js +408 -0
  15. package/cjs/ledger/bitcoin_client/lib/appClient.js.map +1 -0
  16. package/cjs/ledger/bitcoin_client/lib/bip32.js +61 -0
  17. package/cjs/ledger/bitcoin_client/lib/bip32.js.map +1 -0
  18. package/cjs/ledger/bitcoin_client/lib/buffertools.js +126 -0
  19. package/cjs/ledger/bitcoin_client/lib/buffertools.js.map +1 -0
  20. package/cjs/ledger/bitcoin_client/lib/clientCommands.js +270 -0
  21. package/cjs/ledger/bitcoin_client/lib/clientCommands.js.map +1 -0
  22. package/cjs/ledger/bitcoin_client/lib/constants.js +16 -0
  23. package/cjs/ledger/bitcoin_client/lib/constants.js.map +1 -0
  24. package/cjs/ledger/bitcoin_client/lib/merkelizedPsbt.js +54 -0
  25. package/cjs/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +1 -0
  26. package/cjs/ledger/bitcoin_client/lib/merkle.js +109 -0
  27. package/cjs/ledger/bitcoin_client/lib/merkle.js.map +1 -0
  28. package/cjs/ledger/bitcoin_client/lib/merkleMap.js +46 -0
  29. package/cjs/ledger/bitcoin_client/lib/merkleMap.js.map +1 -0
  30. package/cjs/ledger/bitcoin_client/lib/policy.js +66 -0
  31. package/cjs/ledger/bitcoin_client/lib/policy.js.map +1 -0
  32. package/cjs/ledger/bitcoin_client/lib/psbtv2.js +640 -0
  33. package/cjs/ledger/bitcoin_client/lib/psbtv2.js.map +1 -0
  34. package/cjs/ledger/bitcoin_client/lib/varint.js +113 -0
  35. package/cjs/ledger/bitcoin_client/lib/varint.js.map +1 -0
  36. package/cjs/ledger/consts.js +7 -0
  37. package/cjs/ledger/consts.js.map +1 -0
  38. package/cjs/ledger/index.js +319 -0
  39. package/cjs/ledger/index.js.map +1 -0
  40. package/cjs/ledger/types.js +3 -0
  41. package/cjs/ledger/types.js.map +1 -0
  42. package/cjs/network-utils.js +76 -0
  43. package/cjs/network-utils.js.map +1 -0
  44. package/cjs/providers.js +270 -0
  45. package/cjs/providers.js.map +1 -0
  46. package/cjs/signers.js +64 -0
  47. package/cjs/signers.js.map +1 -0
  48. package/cjs/storage.js +30 -0
  49. package/cjs/storage.js.map +1 -0
  50. package/cjs/transactions/__tests__/integration.test.js +237 -0
  51. package/cjs/transactions/__tests__/integration.test.js.map +1 -0
  52. package/cjs/transactions/__tests__/syscoin.test.js +361 -0
  53. package/cjs/transactions/__tests__/syscoin.test.js.map +1 -0
  54. package/cjs/transactions/ethereum.js +1577 -0
  55. package/cjs/transactions/ethereum.js.map +1 -0
  56. package/cjs/transactions/index.js +19 -0
  57. package/cjs/transactions/index.js.map +1 -0
  58. package/cjs/transactions/syscoin.js +328 -0
  59. package/cjs/transactions/syscoin.js.map +1 -0
  60. package/cjs/trezor/index.js +718 -0
  61. package/cjs/trezor/index.js.map +1 -0
  62. package/cjs/types.js +12 -0
  63. package/cjs/types.js.map +1 -0
  64. package/cjs/utils/derivation-paths.js +99 -0
  65. package/cjs/utils/derivation-paths.js.map +1 -0
  66. package/cjs/utils/psbt.js +60 -0
  67. package/cjs/utils/psbt.js.map +1 -0
  68. package/cjs/utils.js +130 -0
  69. package/cjs/utils.js.map +1 -0
  70. package/package.json +46 -0
  71. package/types/errorUtils.d.ts +1 -0
  72. package/types/hardware-wallet-manager.d.ts +110 -0
  73. package/types/index.d.ts +12 -0
  74. package/types/initial-state.d.ts +79 -0
  75. package/types/keyring-manager.d.ts +184 -0
  76. package/types/ledger/bitcoin_client/index.d.ts +5 -0
  77. package/types/ledger/bitcoin_client/lib/appClient.d.ts +106 -0
  78. package/types/ledger/bitcoin_client/lib/bip32.d.ts +11 -0
  79. package/types/ledger/bitcoin_client/lib/buffertools.d.ts +28 -0
  80. package/types/ledger/bitcoin_client/lib/clientCommands.d.ts +77 -0
  81. package/types/ledger/bitcoin_client/lib/constants.d.ts +12 -0
  82. package/types/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +24 -0
  83. package/types/ledger/bitcoin_client/lib/merkle.d.ts +32 -0
  84. package/types/ledger/bitcoin_client/lib/merkleMap.d.ts +23 -0
  85. package/types/ledger/bitcoin_client/lib/policy.d.ts +36 -0
  86. package/types/ledger/bitcoin_client/lib/psbtv2.d.ts +167 -0
  87. package/types/ledger/bitcoin_client/lib/varint.d.ts +23 -0
  88. package/types/ledger/consts.d.ts +3 -0
  89. package/types/ledger/index.d.ts +51 -0
  90. package/types/ledger/types.d.ts +48 -0
  91. package/types/network-utils.d.ts +14 -0
  92. package/types/providers.d.ts +47 -0
  93. package/types/signers.d.ts +95 -0
  94. package/types/storage.d.ts +2 -0
  95. package/types/transactions/__tests__/integration.test.d.ts +1 -0
  96. package/types/transactions/__tests__/syscoin.test.d.ts +1 -0
  97. package/types/transactions/ethereum.d.ts +80 -0
  98. package/types/transactions/index.d.ts +2 -0
  99. package/types/transactions/syscoin.d.ts +61 -0
  100. package/types/trezor/index.d.ts +170 -0
  101. package/types/types.d.ts +294 -0
  102. package/types/utils/derivation-paths.d.ts +35 -0
  103. package/types/utils/psbt.d.ts +17 -0
  104. package/types/utils.d.ts +4 -0
@@ -0,0 +1,1577 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EthereumTransactions = void 0;
7
+ const sysweb3_network_1 = require("@sidhujag/sysweb3-network");
8
+ const sysweb3_utils_1 = require("@sidhujag/sysweb3-utils");
9
+ const eth_sig_util_1 = require("eth-sig-util");
10
+ const ethereumjs_util_1 = require("ethereumjs-util");
11
+ const ethers_1 = require("ethers");
12
+ const floor_1 = __importDefault(require("lodash/floor"));
13
+ const omit_1 = __importDefault(require("lodash/omit"));
14
+ const providers_1 = require("../providers");
15
+ const types_1 = require("../types");
16
+ /**
17
+ * Chain IDs for zkSync Era networks that require specialized L2 provider functionality.
18
+ * These networks use CustomL2JsonRpcProvider (which extends zksync-ethers.Provider)
19
+ * instead of CustomJsonRpcProvider.
20
+ *
21
+ * zkSync Era networks:
22
+ * - 324: zkSync Era Mainnet
23
+ * - 300: zkSync Era Sepolia Testnet
24
+ */
25
+ const L2_NETWORK_CHAIN_IDS = [324, 300];
26
+ class EthereumTransactions {
27
+ constructor(getNetwork, getDecryptedPrivateKey, getState, ledgerSigner, trezorSigner) {
28
+ this.signTypedData = async (addr, typedData, version) => {
29
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
30
+ const { activeAccountType, accounts, activeAccountId } = this.getState();
31
+ const activeAccount = accounts[activeAccountType][activeAccountId];
32
+ // Validate that the derived address matches the active account to prevent race conditions
33
+ if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
34
+ throw {
35
+ message: `Account state mismatch detected. Expected ${activeAccount.address} but got ${address}. Please try again after account switching completes.`,
36
+ };
37
+ }
38
+ const signTypedData = () => {
39
+ if (addr.toLowerCase() !== address.toLowerCase())
40
+ throw {
41
+ message: 'Decrypting for wrong address, change activeAccount maybe',
42
+ };
43
+ const privKey = Buffer.from((0, ethereumjs_util_1.stripHexPrefix)(decryptedPrivateKey), 'hex');
44
+ return (0, eth_sig_util_1.signTypedMessage)(privKey, { data: typedData }, version);
45
+ };
46
+ const signTypedDataWithLedger = async () => {
47
+ if (addr.toLowerCase() !== activeAccount.address.toLowerCase())
48
+ throw {
49
+ message: 'Decrypting for wrong address, change activeAccount maybe',
50
+ };
51
+ return await this.ledgerSigner.evm.signTypedData({
52
+ version,
53
+ accountIndex: activeAccountId,
54
+ data: typedData,
55
+ });
56
+ };
57
+ const signTypedDataWithTrezor = async () => {
58
+ if (addr.toLowerCase() !== activeAccount.address.toLowerCase())
59
+ throw {
60
+ message: 'Decrypting for wrong address, change activeAccount maybe',
61
+ };
62
+ return await this.trezorSigner.signTypedData({
63
+ version,
64
+ address: addr,
65
+ data: typedData,
66
+ index: activeAccountId,
67
+ });
68
+ };
69
+ switch (activeAccountType) {
70
+ case types_1.KeyringAccountType.Trezor:
71
+ return await signTypedDataWithTrezor();
72
+ case types_1.KeyringAccountType.Ledger:
73
+ return await signTypedDataWithLedger();
74
+ default:
75
+ return signTypedData();
76
+ }
77
+ };
78
+ this.verifyTypedSignature = (data, signature, version) => {
79
+ try {
80
+ const msgParams = {
81
+ data,
82
+ sig: signature,
83
+ };
84
+ return (0, eth_sig_util_1.recoverTypedMessage)(msgParams, version);
85
+ }
86
+ catch (error) {
87
+ throw error;
88
+ }
89
+ };
90
+ this.ethSign = async (params) => {
91
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
92
+ const { accounts, activeAccountId, activeAccountType, activeNetwork } = this.getState();
93
+ const activeAccount = accounts[activeAccountType][activeAccountId];
94
+ // Validate that the derived address matches the active account to prevent race conditions
95
+ if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
96
+ throw {
97
+ message: `Account state mismatch detected. Expected ${activeAccount.address} but got ${address}. Please try again after account switching completes.`,
98
+ };
99
+ }
100
+ let msg = '';
101
+ //Comparisions do not need to care for checksum address
102
+ if (params[0].toLowerCase() === address.toLowerCase()) {
103
+ msg = (0, ethereumjs_util_1.stripHexPrefix)(params[1]);
104
+ }
105
+ else if (params[1].toLowerCase() === address.toLowerCase()) {
106
+ msg = (0, ethereumjs_util_1.stripHexPrefix)(params[0]);
107
+ }
108
+ else {
109
+ throw new Error('Signing for wrong address');
110
+ }
111
+ const sign = () => {
112
+ try {
113
+ const bufPriv = (0, ethereumjs_util_1.toBuffer)(decryptedPrivateKey);
114
+ // Validate and prepare the message for eth_sign
115
+ let msgHash;
116
+ // Check if message is a valid 32-byte hex string
117
+ if (msg.length === 64 && /^[0-9a-fA-F]+$/.test(msg)) {
118
+ // Message is already a 32-byte hex string
119
+ msgHash = Buffer.from(msg, 'hex');
120
+ }
121
+ else {
122
+ // Message is not a proper hash - provide helpful error
123
+ throw new Error(`Expected message to be an Uint8Array with length 32. ` +
124
+ `Got message of length ${msg.length}: "${msg.substring(0, 50)}${msg.length > 50 ? '...' : ''}". ` +
125
+ `For signing arbitrary text, use personal_sign instead of eth_sign.`);
126
+ }
127
+ const sig = (0, ethereumjs_util_1.ecsign)(msgHash, bufPriv);
128
+ const resp = (0, eth_sig_util_1.concatSig)((0, ethereumjs_util_1.toBuffer)(sig.v), sig.r, sig.s);
129
+ return resp;
130
+ }
131
+ catch (error) {
132
+ throw error;
133
+ }
134
+ };
135
+ const signWithLedger = async () => {
136
+ try {
137
+ const response = await this.ledgerSigner.evm.signPersonalMessage({
138
+ accountIndex: activeAccountId,
139
+ message: msg,
140
+ });
141
+ return response;
142
+ }
143
+ catch (error) {
144
+ throw error;
145
+ }
146
+ };
147
+ const signWithTrezor = async () => {
148
+ try {
149
+ // For EVM networks, Trezor expects 'eth' regardless of the network's currency
150
+ const trezorCoin = activeNetwork.slip44 === 60 ? 'eth' : activeNetwork.currency;
151
+ const response = await this.trezorSigner.signMessage({
152
+ coin: trezorCoin,
153
+ address: activeAccount.address,
154
+ index: activeAccountId,
155
+ message: msg,
156
+ slip44: activeNetwork.slip44,
157
+ });
158
+ return response.signature;
159
+ }
160
+ catch (error) {
161
+ throw error;
162
+ }
163
+ };
164
+ switch (activeAccountType) {
165
+ case types_1.KeyringAccountType.Trezor:
166
+ return await signWithTrezor();
167
+ case types_1.KeyringAccountType.Ledger:
168
+ return await signWithLedger();
169
+ default:
170
+ return sign();
171
+ }
172
+ };
173
+ this.signPersonalMessage = async (params) => {
174
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
175
+ const { accounts, activeAccountId, activeAccountType, activeNetwork } = this.getState();
176
+ const activeAccount = accounts[activeAccountType][activeAccountId];
177
+ // Validate that the derived address matches the active account to prevent race conditions
178
+ if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
179
+ throw {
180
+ message: `Account state mismatch detected. Expected ${activeAccount.address} but got ${address}. Please try again after account switching completes.`,
181
+ };
182
+ }
183
+ let msg = '';
184
+ if (params[0].toLowerCase() === address.toLowerCase()) {
185
+ msg = params[1];
186
+ }
187
+ else if (params[1].toLowerCase() === address.toLowerCase()) {
188
+ msg = params[0];
189
+ }
190
+ else {
191
+ throw new Error('Signing for wrong address');
192
+ }
193
+ const signPersonalMessageWithDefaultWallet = () => {
194
+ try {
195
+ const privateKey = (0, ethereumjs_util_1.toBuffer)(decryptedPrivateKey);
196
+ // Handle both hex-encoded and plain text messages for personal_sign
197
+ let message;
198
+ if (msg.startsWith('0x')) {
199
+ // Message is hex-encoded
200
+ try {
201
+ message = (0, ethereumjs_util_1.toBuffer)(msg);
202
+ }
203
+ catch (error) {
204
+ // If hex parsing fails, treat as plain text
205
+ message = Buffer.from(msg, 'utf8');
206
+ }
207
+ }
208
+ else {
209
+ // Message is plain text
210
+ message = Buffer.from(msg, 'utf8');
211
+ }
212
+ const msgHash = (0, ethereumjs_util_1.hashPersonalMessage)(message);
213
+ const sig = (0, ethereumjs_util_1.ecsign)(msgHash, privateKey);
214
+ const serialized = (0, eth_sig_util_1.concatSig)((0, ethereumjs_util_1.toBuffer)(sig.v), sig.r, sig.s);
215
+ return serialized;
216
+ }
217
+ catch (error) {
218
+ throw error;
219
+ }
220
+ };
221
+ const signPersonalMessageWithLedger = async () => {
222
+ try {
223
+ // Handle both hex-encoded and plain text messages for personal_sign
224
+ let messageForLedger;
225
+ if (msg.startsWith('0x')) {
226
+ // Message is hex-encoded, remove 0x prefix
227
+ messageForLedger = msg.replace('0x', '');
228
+ }
229
+ else {
230
+ // Message is plain text, convert to hex
231
+ messageForLedger = Buffer.from(msg, 'utf8').toString('hex');
232
+ }
233
+ const response = await this.ledgerSigner.evm.signPersonalMessage({
234
+ accountIndex: activeAccountId,
235
+ message: messageForLedger,
236
+ });
237
+ return response;
238
+ }
239
+ catch (error) {
240
+ throw error;
241
+ }
242
+ };
243
+ const signPersonalMessageWithTrezor = async () => {
244
+ try {
245
+ // Handle both hex-encoded and plain text messages for personal_sign
246
+ let messageForTrezor;
247
+ if (msg.startsWith('0x')) {
248
+ // Message is hex-encoded, keep as is
249
+ messageForTrezor = msg;
250
+ }
251
+ else {
252
+ // Message is plain text, convert to hex with 0x prefix
253
+ messageForTrezor = '0x' + Buffer.from(msg, 'utf8').toString('hex');
254
+ }
255
+ // For EVM networks, Trezor expects 'eth' regardless of the network's currency
256
+ const trezorCoin = activeNetwork.slip44 === 60 ? 'eth' : activeNetwork.currency;
257
+ const response = await this.trezorSigner.signMessage({
258
+ coin: trezorCoin,
259
+ address: activeAccount.address,
260
+ index: activeAccountId,
261
+ message: messageForTrezor,
262
+ slip44: activeNetwork.slip44,
263
+ });
264
+ return response.signature;
265
+ }
266
+ catch (error) {
267
+ throw error;
268
+ }
269
+ };
270
+ switch (activeAccountType) {
271
+ case types_1.KeyringAccountType.Trezor:
272
+ return await signPersonalMessageWithTrezor();
273
+ case types_1.KeyringAccountType.Ledger:
274
+ return await signPersonalMessageWithLedger();
275
+ default:
276
+ return signPersonalMessageWithDefaultWallet();
277
+ }
278
+ };
279
+ this.parsePersonalMessage = (hexMsg) => {
280
+ try {
281
+ return (0, ethereumjs_util_1.toAscii)(hexMsg);
282
+ }
283
+ catch (error) {
284
+ throw error;
285
+ }
286
+ };
287
+ this.verifyPersonalMessage = (message, sign) => {
288
+ try {
289
+ const msgParams = {
290
+ data: message,
291
+ sig: sign,
292
+ };
293
+ return (0, eth_sig_util_1.recoverPersonalSignature)(msgParams);
294
+ }
295
+ catch (error) {
296
+ throw error;
297
+ }
298
+ };
299
+ this.getEncryptedPubKey = () => {
300
+ const { decryptedPrivateKey } = this.getDecryptedPrivateKey();
301
+ try {
302
+ return (0, eth_sig_util_1.getEncryptionPublicKey)((0, ethereumjs_util_1.stripHexPrefix)(decryptedPrivateKey));
303
+ }
304
+ catch (error) {
305
+ throw error;
306
+ }
307
+ };
308
+ // eth_decryptMessage
309
+ this.decryptMessage = (msgParams) => {
310
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
311
+ let encryptedData = '';
312
+ if (msgParams[0].toLowerCase() === address.toLowerCase()) {
313
+ encryptedData = msgParams[1];
314
+ }
315
+ else if (msgParams[1].toLowerCase() === address.toLowerCase()) {
316
+ encryptedData = msgParams[0];
317
+ }
318
+ else {
319
+ throw new Error('Decrypting for wrong receiver');
320
+ }
321
+ encryptedData = (0, ethereumjs_util_1.stripHexPrefix)(encryptedData);
322
+ try {
323
+ const buff = Buffer.from(encryptedData, 'hex');
324
+ const cleanData = JSON.parse(buff.toString('utf8'));
325
+ const sig = (0, eth_sig_util_1.decrypt)(cleanData, (0, ethereumjs_util_1.stripHexPrefix)(decryptedPrivateKey));
326
+ return sig;
327
+ }
328
+ catch (error) {
329
+ throw error;
330
+ }
331
+ };
332
+ this.toBigNumber = (aBigNumberish) => ethers_1.ethers.BigNumber.from(String(aBigNumberish));
333
+ this.getData = ({ contractAddress, receivingAddress, value, }) => {
334
+ const abi = (0, sysweb3_utils_1.getErc20Abi)();
335
+ try {
336
+ const contract = (0, sysweb3_utils_1.createContractUsingAbi)(abi, contractAddress, this.web3Provider);
337
+ const data = contract.methods
338
+ .transfer(receivingAddress, value)
339
+ .encodeABI();
340
+ return data;
341
+ }
342
+ catch (error) {
343
+ throw error;
344
+ }
345
+ };
346
+ this.getFeeDataWithDynamicMaxPriorityFeePerGas = async () => {
347
+ let maxFeePerGas = this.toBigNumber(0);
348
+ let maxPriorityFeePerGas = this.toBigNumber(0);
349
+ try {
350
+ const block = await this.web3Provider.getBlock('latest');
351
+ if (block && block.baseFeePerGas) {
352
+ try {
353
+ const ethMaxPriorityFee = await this.web3Provider.send('eth_maxPriorityFeePerGas', []);
354
+ maxPriorityFeePerGas = ethers_1.ethers.BigNumber.from(ethMaxPriorityFee);
355
+ maxFeePerGas = block.baseFeePerGas.mul(2).add(maxPriorityFeePerGas);
356
+ }
357
+ catch (e) {
358
+ maxPriorityFeePerGas = ethers_1.ethers.BigNumber.from('1500000000');
359
+ maxFeePerGas = block.baseFeePerGas.mul(2).add(maxPriorityFeePerGas);
360
+ }
361
+ return { maxFeePerGas, maxPriorityFeePerGas };
362
+ }
363
+ else if (block && !block.baseFeePerGas) {
364
+ console.error('Chain doesnt support EIP1559');
365
+ return { maxFeePerGas, maxPriorityFeePerGas };
366
+ }
367
+ else if (!block)
368
+ throw new Error('Block not found');
369
+ return { maxFeePerGas, maxPriorityFeePerGas };
370
+ }
371
+ catch (error) {
372
+ console.error(error);
373
+ return { maxFeePerGas, maxPriorityFeePerGas };
374
+ }
375
+ };
376
+ this.calculateNewGasValues = (oldTxsParams, isForCancel, isLegacy) => {
377
+ const newGasValues = {
378
+ maxFeePerGas: undefined,
379
+ maxPriorityFeePerGas: undefined,
380
+ gasPrice: undefined,
381
+ gasLimit: undefined,
382
+ };
383
+ const { maxFeePerGas, maxPriorityFeePerGas, gasLimit, gasPrice } = oldTxsParams;
384
+ const calculateAndConvertNewValue = (feeValue) => {
385
+ const calculateValue = String(feeValue * multiplierToUse);
386
+ const convertValueToHex = '0x' + parseInt(calculateValue, 10).toString(16);
387
+ return ethers_1.ethers.BigNumber.from(convertValueToHex);
388
+ };
389
+ const maxFeePerGasToNumber = maxFeePerGas?.toNumber();
390
+ const maxPriorityFeePerGasToNumber = maxPriorityFeePerGas?.toNumber();
391
+ const gasLimitToNumber = gasLimit?.toNumber();
392
+ const gasPriceToNumber = gasPrice?.toNumber();
393
+ const multiplierToUse = 1.2; //The same calculation we used in the edit fee modal, always using the 0.2 multiplier
394
+ if (!isLegacy) {
395
+ newGasValues.maxFeePerGas = calculateAndConvertNewValue(maxFeePerGasToNumber);
396
+ newGasValues.maxPriorityFeePerGas = calculateAndConvertNewValue(maxPriorityFeePerGasToNumber);
397
+ }
398
+ if (isLegacy) {
399
+ newGasValues.gasPrice = calculateAndConvertNewValue(gasPriceToNumber);
400
+ }
401
+ if (isForCancel) {
402
+ const DEFAULT_GAS_LIMIT_VALUE = '21000';
403
+ const convertToHex = '0x' + parseInt(DEFAULT_GAS_LIMIT_VALUE, 10).toString(16);
404
+ newGasValues.gasLimit = ethers_1.ethers.BigNumber.from(convertToHex);
405
+ }
406
+ if (!isForCancel) {
407
+ newGasValues.gasLimit = calculateAndConvertNewValue(gasLimitToNumber);
408
+ }
409
+ return newGasValues;
410
+ };
411
+ this.cancelSentTransaction = async (txHash, isLegacy) => {
412
+ const tx = (await this.web3Provider.getTransaction(txHash));
413
+ if (!tx) {
414
+ //If we don't find the TX or is already confirmed we send as error true to show this message
415
+ //in the alert at Pali
416
+ return {
417
+ isCanceled: false,
418
+ error: true,
419
+ };
420
+ }
421
+ const { decryptedPrivateKey } = this.getDecryptedPrivateKey();
422
+ const wallet = new ethers_1.ethers.Wallet(decryptedPrivateKey, this.web3Provider);
423
+ let changedTxToCancel;
424
+ const oldTxsGasValues = {
425
+ maxFeePerGas: tx.maxFeePerGas,
426
+ maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
427
+ gasPrice: tx.gasPrice,
428
+ gasLimit: tx.gasLimit,
429
+ };
430
+ if (!isLegacy) {
431
+ const newGasValues = this.calculateNewGasValues(oldTxsGasValues, true, false);
432
+ //We have to send another TX using the same nonce but we can use the From and To for the same address and also
433
+ //the value as 0
434
+ changedTxToCancel = {
435
+ nonce: tx.nonce,
436
+ from: wallet.address,
437
+ to: wallet.address,
438
+ value: ethers_1.ethers.constants.Zero,
439
+ maxFeePerGas: newGasValues.maxFeePerGas,
440
+ maxPriorityFeePerGas: newGasValues.maxPriorityFeePerGas,
441
+ gasLimit: newGasValues.gasLimit,
442
+ };
443
+ }
444
+ else {
445
+ const newGasValues = this.calculateNewGasValues(oldTxsGasValues, true, true);
446
+ //We have to send another TX using the same nonce but we can use the From and To for the same address and also
447
+ //the value as 0
448
+ changedTxToCancel = {
449
+ nonce: tx.nonce,
450
+ from: wallet.address,
451
+ to: wallet.address,
452
+ value: ethers_1.ethers.constants.Zero,
453
+ gasLimit: newGasValues.gasLimit,
454
+ gasPrice: newGasValues.gasPrice,
455
+ };
456
+ }
457
+ const cancelTransaction = async () => {
458
+ try {
459
+ const transactionResponse = await wallet.sendTransaction(changedTxToCancel);
460
+ if (transactionResponse) {
461
+ return {
462
+ isCanceled: true,
463
+ transaction: transactionResponse,
464
+ };
465
+ }
466
+ else {
467
+ return {
468
+ isCanceled: false,
469
+ };
470
+ }
471
+ }
472
+ catch (error) {
473
+ //If we don't find the TX or is already confirmed we send as error true to show this message
474
+ //in the alert at Pali
475
+ return {
476
+ isCanceled: false,
477
+ error: true,
478
+ };
479
+ }
480
+ };
481
+ return await cancelTransaction();
482
+ };
483
+ //TODO: This function needs to be refactored
484
+ this.sendFormattedTransaction = async (params, isLegacy) => {
485
+ const { activeAccountType, activeAccountId, accounts, activeNetwork } = this.getState();
486
+ const activeAccount = accounts[activeAccountType][activeAccountId];
487
+ const sendEVMLedgerTransaction = async () => {
488
+ const transactionNonce = await this.getRecommendedNonce(activeAccount.address);
489
+ const formatParams = (0, omit_1.default)(params, 'from'); //From is not needed we're already passing in the HD derivation path so it can be inferred
490
+ const txFormattedForEthers = isLegacy
491
+ ? {
492
+ ...formatParams,
493
+ nonce: transactionNonce,
494
+ chainId: activeNetwork.chainId,
495
+ }
496
+ : {
497
+ ...formatParams,
498
+ nonce: transactionNonce,
499
+ chainId: activeNetwork.chainId,
500
+ type: 2,
501
+ };
502
+ const rawTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers);
503
+ const signature = await this.ledgerSigner.evm.signEVMTransaction({
504
+ rawTx: rawTx.replace('0x', ''),
505
+ accountIndex: activeAccountId,
506
+ });
507
+ const formattedSignature = {
508
+ r: `0x${signature.r}`,
509
+ s: `0x${signature.s}`,
510
+ v: parseInt(signature.v, 16),
511
+ };
512
+ if (signature) {
513
+ try {
514
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, formattedSignature);
515
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
516
+ return finalTx;
517
+ }
518
+ catch (error) {
519
+ throw error;
520
+ }
521
+ }
522
+ else {
523
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
524
+ }
525
+ };
526
+ const sendEVMTrezorTransaction = async () => {
527
+ const transactionNonce = await this.getRecommendedNonce(activeAccount.address);
528
+ let txFormattedForTrezor = {};
529
+ const formatParams = (0, omit_1.default)(params, 'from'); //From is not needed we're already passing in the HD derivation path so it can be inferred
530
+ switch (isLegacy) {
531
+ case true:
532
+ txFormattedForTrezor = {
533
+ ...formatParams,
534
+ gasLimit: typeof formatParams.gasLimit === 'string'
535
+ ? formatParams.gasLimit
536
+ : // @ts-ignore
537
+ `${params.gasLimit.hex}`,
538
+ value: typeof formatParams.value === 'string' ||
539
+ typeof formatParams.value === 'number'
540
+ ? `${formatParams.value}`
541
+ : // @ts-ignore
542
+ `${params.value.hex}`,
543
+ nonce: this.toBigNumber(transactionNonce)._hex,
544
+ chainId: activeNetwork.chainId,
545
+ };
546
+ break;
547
+ case false:
548
+ txFormattedForTrezor = {
549
+ ...formatParams,
550
+ gasLimit: typeof formatParams.gasLimit === 'string'
551
+ ? formatParams.gasLimit
552
+ : // @ts-ignore
553
+ `${params.gasLimit.hex}`,
554
+ maxFeePerGas: typeof formatParams.maxFeePerGas === 'string'
555
+ ? formatParams.maxFeePerGas
556
+ : // @ts-ignore
557
+ `${params.maxFeePerGas.hex}`,
558
+ maxPriorityFeePerGas: typeof formatParams.maxPriorityFeePerGas === 'string'
559
+ ? formatParams.maxPriorityFeePerGas
560
+ : // @ts-ignore
561
+ `${params.maxPriorityFeePerGas.hex}`,
562
+ value: typeof formatParams.value === 'string' ||
563
+ typeof formatParams.value === 'number'
564
+ ? `${formatParams.value}`
565
+ : // @ts-ignore
566
+ `${params.value.hex}`,
567
+ nonce: this.toBigNumber(transactionNonce)._hex,
568
+ chainId: activeNetwork.chainId,
569
+ };
570
+ break;
571
+ default:
572
+ txFormattedForTrezor = {
573
+ ...formatParams,
574
+ gasLimit: typeof formatParams.gasLimit === 'string'
575
+ ? formatParams.gasLimit
576
+ : // @ts-ignore
577
+ `${params.gasLimit.hex}`,
578
+ maxFeePerGas: typeof formatParams.maxFeePerGas === 'string'
579
+ ? formatParams.maxFeePerGas
580
+ : // @ts-ignore
581
+ `${params.maxFeePerGas.hex}`,
582
+ maxPriorityFeePerGas: typeof formatParams.maxPriorityFeePerGas === 'string'
583
+ ? formatParams.maxPriorityFeePerGas
584
+ : // @ts-ignore
585
+ `${params.maxPriorityFeePerGas.hex}`,
586
+ value: typeof formatParams.value === 'string' ||
587
+ typeof formatParams.value === 'number'
588
+ ? `${formatParams.value}`
589
+ : // @ts-ignore
590
+ `${params.value.hex}`,
591
+ nonce: this.toBigNumber(transactionNonce)._hex,
592
+ chainId: activeNetwork.chainId,
593
+ };
594
+ break;
595
+ }
596
+ const signature = await this.trezorSigner.signEthTransaction({
597
+ index: `${activeAccountId}`,
598
+ tx: txFormattedForTrezor,
599
+ coin: activeNetwork.currency,
600
+ slip44: activeNetwork.slip44,
601
+ });
602
+ if (signature.success) {
603
+ try {
604
+ const txFormattedForEthers = isLegacy
605
+ ? {
606
+ ...formatParams,
607
+ nonce: transactionNonce,
608
+ chainId: activeNetwork.chainId,
609
+ }
610
+ : {
611
+ ...formatParams,
612
+ nonce: transactionNonce,
613
+ chainId: activeNetwork.chainId,
614
+ type: 2,
615
+ };
616
+ signature.payload.v = parseInt(signature.payload.v, 16); //v parameter must be a number by ethers standards
617
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, signature.payload);
618
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
619
+ return finalTx;
620
+ }
621
+ catch (error) {
622
+ throw error;
623
+ }
624
+ }
625
+ else {
626
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
627
+ }
628
+ };
629
+ const sendEVMTransaction = async () => {
630
+ const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
631
+ // Validate that we have the correct private key for the active account to prevent race conditions
632
+ // This is critical for transaction security during account switches
633
+ if (address.toLowerCase() !== activeAccount.address.toLowerCase()) {
634
+ throw new Error(`Account state mismatch detected during transaction. Expected ${activeAccount.address} but got ${address}. Please wait for account switching to complete and try again.`);
635
+ }
636
+ const tx = params;
637
+ const wallet = new ethers_1.ethers.Wallet(decryptedPrivateKey, this.web3Provider);
638
+ try {
639
+ const transaction = await wallet.sendTransaction(tx);
640
+ const response = await this.web3Provider.getTransaction(transaction.hash);
641
+ //TODO: more precisely on this lines
642
+ if (!response) {
643
+ return await this.getTransactionTimestamp(transaction);
644
+ }
645
+ else {
646
+ return await this.getTransactionTimestamp(response);
647
+ }
648
+ }
649
+ catch (error) {
650
+ throw error;
651
+ }
652
+ };
653
+ switch (activeAccountType) {
654
+ case types_1.KeyringAccountType.Trezor:
655
+ return await sendEVMTrezorTransaction();
656
+ case types_1.KeyringAccountType.Ledger:
657
+ return await sendEVMLedgerTransaction();
658
+ default:
659
+ return await sendEVMTransaction();
660
+ }
661
+ };
662
+ this.sendTransactionWithEditedFee = async (txHash, isLegacy) => {
663
+ const tx = (await this.web3Provider.getTransaction(txHash));
664
+ if (!tx) {
665
+ return {
666
+ isSpeedUp: false,
667
+ error: true,
668
+ };
669
+ }
670
+ const { decryptedPrivateKey, address } = this.getDecryptedPrivateKey();
671
+ const wallet = new ethers_1.ethers.Wallet(decryptedPrivateKey, this.web3Provider);
672
+ // Check if this might be a max send transaction by comparing total cost to balance
673
+ const currentBalance = await this.web3Provider.getBalance(address);
674
+ // Ensure all transaction values are resolved from promises
675
+ const gasLimit = await Promise.resolve(tx.gasLimit);
676
+ const gasPrice = await Promise.resolve(tx.gasPrice || 0);
677
+ const maxFeePerGas = await Promise.resolve(tx.maxFeePerGas || 0);
678
+ const maxPriorityFeePerGas = await Promise.resolve(tx.maxPriorityFeePerGas || 0);
679
+ const txValue = await Promise.resolve(tx.value);
680
+ const txData = await Promise.resolve(tx.data || '0x');
681
+ // Check if this is a contract call (has data)
682
+ const isContractCall = txData && txData !== '0x' && txData.length > 2;
683
+ const originalGasCost = isLegacy
684
+ ? gasLimit.mul(gasPrice || 0)
685
+ : gasLimit.mul(maxFeePerGas || 0);
686
+ const originalTotalCost = txValue.add(originalGasCost);
687
+ // If original transaction used >95% of balance, it's likely a max send
688
+ const balanceThreshold = currentBalance.mul(95).div(100);
689
+ const isLikelyMaxSend = originalTotalCost.gt(balanceThreshold);
690
+ let txWithEditedFee;
691
+ const oldTxsGasValues = {
692
+ maxFeePerGas: maxFeePerGas,
693
+ maxPriorityFeePerGas: maxPriorityFeePerGas,
694
+ gasPrice: gasPrice,
695
+ gasLimit: gasLimit,
696
+ };
697
+ if (!isLegacy) {
698
+ const newGasValues = this.calculateNewGasValues(oldTxsGasValues, false, false);
699
+ let adjustedValue = txValue;
700
+ // For likely max sends, check if we need to adjust value
701
+ if (isLikelyMaxSend &&
702
+ newGasValues.gasLimit &&
703
+ newGasValues.maxFeePerGas) {
704
+ const newGasCost = newGasValues.gasLimit.mul(newGasValues.maxFeePerGas);
705
+ const newTotalCost = txValue.add(newGasCost);
706
+ if (newTotalCost.gt(currentBalance)) {
707
+ // If this is a contract call, we cannot adjust the value
708
+ if (isContractCall) {
709
+ console.error('[SpeedUp] Cannot adjust value for contract call - rejecting speedup');
710
+ return {
711
+ isSpeedUp: false,
712
+ error: true,
713
+ };
714
+ }
715
+ // For non-contract calls, reduce value to fit within balance
716
+ adjustedValue = currentBalance.sub(newGasCost);
717
+ // Ensure we don't go below a minimum threshold (0.0001 ETH)
718
+ const minValue = ethers_1.ethers.utils.parseEther('0.0001');
719
+ if (adjustedValue.lt(minValue)) {
720
+ console.warn('[SpeedUp] Adjusted value too low, keeping original');
721
+ adjustedValue = txValue;
722
+ }
723
+ }
724
+ }
725
+ txWithEditedFee = {
726
+ from: tx.from,
727
+ to: tx.to,
728
+ nonce: tx.nonce,
729
+ value: adjustedValue,
730
+ data: txData,
731
+ maxFeePerGas: newGasValues.maxFeePerGas,
732
+ maxPriorityFeePerGas: newGasValues.maxPriorityFeePerGas,
733
+ gasLimit: newGasValues.gasLimit,
734
+ };
735
+ }
736
+ else {
737
+ const newGasValues = this.calculateNewGasValues(oldTxsGasValues, false, true);
738
+ let adjustedValue = txValue;
739
+ // For likely max sends, check if we need to adjust value
740
+ if (isLikelyMaxSend && newGasValues.gasLimit && newGasValues.gasPrice) {
741
+ const newGasCost = newGasValues.gasLimit.mul(newGasValues.gasPrice);
742
+ const newTotalCost = txValue.add(newGasCost);
743
+ if (newTotalCost.gt(currentBalance)) {
744
+ // If this is a contract call, we cannot adjust the value
745
+ if (isContractCall) {
746
+ console.error('[SpeedUp] Cannot adjust value for contract call - rejecting speedup');
747
+ return {
748
+ isSpeedUp: false,
749
+ error: true,
750
+ };
751
+ }
752
+ // For non-contract calls, reduce value to fit within balance
753
+ adjustedValue = currentBalance.sub(newGasCost);
754
+ // Ensure we don't go below a minimum threshold (0.0001 ETH)
755
+ const minValue = ethers_1.ethers.utils.parseEther('0.0001');
756
+ if (adjustedValue.lt(minValue)) {
757
+ console.warn('[SpeedUp] Adjusted value too low, keeping original');
758
+ adjustedValue = txValue;
759
+ }
760
+ }
761
+ }
762
+ txWithEditedFee = {
763
+ from: tx.from,
764
+ to: tx.to,
765
+ nonce: tx.nonce,
766
+ value: adjustedValue,
767
+ data: txData,
768
+ gasLimit: newGasValues.gasLimit,
769
+ gasPrice: newGasValues.gasPrice,
770
+ };
771
+ }
772
+ const sendEditedTransaction = async () => {
773
+ try {
774
+ const transactionResponse = await wallet.sendTransaction(txWithEditedFee);
775
+ if (transactionResponse) {
776
+ return {
777
+ isSpeedUp: true,
778
+ transaction: transactionResponse,
779
+ };
780
+ }
781
+ else {
782
+ return {
783
+ isSpeedUp: false,
784
+ };
785
+ }
786
+ }
787
+ catch (error) {
788
+ console.error('[SpeedUp] Failed to send replacement transaction:', error);
789
+ //If we don't find the TX or is already confirmed we send as error true to show this message
790
+ //in the alert at Pali
791
+ return {
792
+ isSpeedUp: false,
793
+ error: true,
794
+ };
795
+ }
796
+ };
797
+ return await sendEditedTransaction();
798
+ };
799
+ // TODO: refactor this function
800
+ this.sendTransaction = async ({ sender, receivingAddress, amount, gasLimit, token, }) => {
801
+ const tokenDecimals = token && token.decimals ? token.decimals : 18;
802
+ const decimals = this.toBigNumber(tokenDecimals);
803
+ const parsedAmount = ethers_1.ethers.utils.parseEther(String(amount));
804
+ const { decryptedPrivateKey } = this.getDecryptedPrivateKey();
805
+ const wallet = new ethers_1.ethers.Wallet(decryptedPrivateKey, this.web3Provider);
806
+ const value = token && token.contract_address
807
+ ? parsedAmount.mul(this.toBigNumber('10').pow(decimals))
808
+ : parsedAmount;
809
+ const data = token && token.contract_address
810
+ ? this.getData({
811
+ contractAddress: token.contract_address,
812
+ receivingAddress,
813
+ value,
814
+ })
815
+ : null;
816
+ // gas price, gas limit e maxPriorityFeePerGas (tip)
817
+ const { maxFeePerGas, maxPriorityFeePerGas } = await this.getFeeDataWithDynamicMaxPriorityFeePerGas();
818
+ const tx = {
819
+ to: receivingAddress,
820
+ value,
821
+ maxPriorityFeePerGas,
822
+ maxFeePerGas,
823
+ nonce: await this.web3Provider.getTransactionCount(sender, 'latest'),
824
+ type: 2,
825
+ chainId: this.web3Provider.network.chainId,
826
+ gasLimit: this.toBigNumber(0) || gasLimit,
827
+ data,
828
+ };
829
+ tx.gasLimit = await this.web3Provider.estimateGas(tx);
830
+ try {
831
+ const transaction = await wallet.sendTransaction(tx);
832
+ const response = await this.web3Provider.getTransaction(transaction.hash);
833
+ if (!response) {
834
+ return await this.getTransactionTimestamp(transaction);
835
+ }
836
+ else {
837
+ return await this.getTransactionTimestamp(response);
838
+ }
839
+ }
840
+ catch (error) {
841
+ throw error;
842
+ }
843
+ };
844
+ this.sendSignedErc20Transaction = async ({ receiver, tokenAddress, tokenAmount, isLegacy = false, maxPriorityFeePerGas, maxFeePerGas, gasPrice, decimals, gasLimit, saveTrezorTx, }) => {
845
+ const { decryptedPrivateKey } = this.getDecryptedPrivateKey();
846
+ const { accounts, activeAccountType, activeAccountId, activeNetwork } = this.getState();
847
+ const { address: activeAccountAddress } = accounts[activeAccountType][activeAccountId];
848
+ const sendERC20Token = async () => {
849
+ const currentWallet = new ethers_1.ethers.Wallet(decryptedPrivateKey);
850
+ const walletSigned = currentWallet.connect(this.web3Provider);
851
+ try {
852
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc20Abi)(), walletSigned);
853
+ const calculatedTokenAmount = ethers_1.ethers.BigNumber.from(decimals
854
+ ? ethers_1.ethers.utils.parseUnits(tokenAmount, this.toBigNumber(decimals))
855
+ : ethers_1.ethers.utils.parseEther(tokenAmount));
856
+ let transferMethod;
857
+ if (isLegacy) {
858
+ const overrides = {
859
+ nonce: await this.web3Provider.getTransactionCount(walletSigned.address, 'pending'),
860
+ gasPrice,
861
+ ...(gasLimit && { gasLimit }),
862
+ };
863
+ transferMethod = await _contract.transfer(receiver, calculatedTokenAmount, overrides);
864
+ }
865
+ else {
866
+ const overrides = {
867
+ nonce: await this.web3Provider.getTransactionCount(walletSigned.address, 'pending'),
868
+ maxPriorityFeePerGas,
869
+ maxFeePerGas,
870
+ ...(gasLimit && { gasLimit }),
871
+ };
872
+ transferMethod = await _contract.transfer(receiver, calculatedTokenAmount, overrides);
873
+ }
874
+ return transferMethod;
875
+ }
876
+ catch (error) {
877
+ throw error;
878
+ }
879
+ };
880
+ const sendERC20TokenOnLedger = async () => {
881
+ const signer = this.web3Provider.getSigner(activeAccountAddress);
882
+ const transactionNonce = await this.getRecommendedNonce(activeAccountAddress);
883
+ try {
884
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc20Abi)(), signer);
885
+ const calculatedTokenAmount = ethers_1.ethers.BigNumber.from(ethers_1.ethers.utils.parseEther(tokenAmount));
886
+ const txData = _contract.interface.encodeFunctionData('transfer', [
887
+ receiver,
888
+ calculatedTokenAmount,
889
+ ]);
890
+ // Use fallback gas limit if not provided (for auto-estimation)
891
+ const effectiveGasLimit = gasLimit || this.toBigNumber('100000'); // ERC20 fallback
892
+ let txFormattedForEthers;
893
+ if (isLegacy) {
894
+ txFormattedForEthers = {
895
+ to: tokenAddress,
896
+ value: '0x0',
897
+ gasLimit: effectiveGasLimit,
898
+ gasPrice,
899
+ data: txData,
900
+ nonce: transactionNonce,
901
+ chainId: activeNetwork.chainId,
902
+ type: 0,
903
+ };
904
+ }
905
+ else {
906
+ txFormattedForEthers = {
907
+ to: tokenAddress,
908
+ value: '0x0',
909
+ gasLimit: effectiveGasLimit,
910
+ maxFeePerGas,
911
+ maxPriorityFeePerGas,
912
+ data: txData,
913
+ nonce: transactionNonce,
914
+ chainId: activeNetwork.chainId,
915
+ type: 2,
916
+ };
917
+ }
918
+ const rawTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers);
919
+ const signature = await this.ledgerSigner.evm.signEVMTransaction({
920
+ rawTx: rawTx.replace('0x', ''),
921
+ accountIndex: activeAccountId,
922
+ });
923
+ const formattedSignature = {
924
+ r: `0x${signature.r}`,
925
+ s: `0x${signature.s}`,
926
+ v: parseInt(signature.v, 16),
927
+ };
928
+ if (signature) {
929
+ try {
930
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, formattedSignature);
931
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
932
+ saveTrezorTx && saveTrezorTx(finalTx);
933
+ return finalTx;
934
+ }
935
+ catch (error) {
936
+ throw error;
937
+ }
938
+ }
939
+ else {
940
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
941
+ }
942
+ }
943
+ catch (error) {
944
+ throw error;
945
+ }
946
+ };
947
+ const sendERC20TokenOnTrezor = async () => {
948
+ const signer = this.web3Provider.getSigner(activeAccountAddress);
949
+ const transactionNonce = await this.getRecommendedNonce(activeAccountAddress);
950
+ try {
951
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc20Abi)(), signer);
952
+ const calculatedTokenAmount = ethers_1.ethers.BigNumber.from(ethers_1.ethers.utils.parseEther(tokenAmount));
953
+ const txData = _contract.interface.encodeFunctionData('transfer', [
954
+ receiver,
955
+ calculatedTokenAmount,
956
+ ]);
957
+ // Use fallback gas limit if not provided (for auto-estimation)
958
+ const effectiveGasLimit = gasLimit || this.toBigNumber('100000'); // ERC20 fallback
959
+ let txToBeSignedByTrezor;
960
+ if (isLegacy) {
961
+ txToBeSignedByTrezor = {
962
+ to: tokenAddress,
963
+ value: '0x0',
964
+ // @ts-ignore
965
+ gasLimit: `${effectiveGasLimit.hex}`,
966
+ // @ts-ignore
967
+ gasPrice: `${gasPrice}`,
968
+ nonce: this.toBigNumber(transactionNonce)._hex,
969
+ chainId: activeNetwork.chainId,
970
+ data: txData,
971
+ };
972
+ }
973
+ else {
974
+ txToBeSignedByTrezor = {
975
+ to: tokenAddress,
976
+ value: '0x0',
977
+ // @ts-ignore
978
+ gasLimit: `${effectiveGasLimit.hex}`,
979
+ // @ts-ignore
980
+ maxFeePerGas: `${maxFeePerGas.hex}`,
981
+ // @ts-ignore
982
+ maxPriorityFeePerGas: `${maxPriorityFeePerGas.hex}`,
983
+ nonce: this.toBigNumber(transactionNonce)._hex,
984
+ chainId: activeNetwork.chainId,
985
+ data: txData,
986
+ };
987
+ }
988
+ const signature = await this.trezorSigner.signEthTransaction({
989
+ index: `${activeAccountId}`,
990
+ tx: txToBeSignedByTrezor,
991
+ coin: activeNetwork.currency,
992
+ slip44: activeNetwork.slip44,
993
+ });
994
+ if (signature.success) {
995
+ try {
996
+ let txFormattedForEthers;
997
+ if (isLegacy) {
998
+ txFormattedForEthers = {
999
+ to: tokenAddress,
1000
+ value: '0x0',
1001
+ gasLimit: effectiveGasLimit,
1002
+ gasPrice,
1003
+ data: txData,
1004
+ nonce: transactionNonce,
1005
+ chainId: activeNetwork.chainId,
1006
+ type: 0,
1007
+ };
1008
+ }
1009
+ else {
1010
+ txFormattedForEthers = {
1011
+ to: tokenAddress,
1012
+ value: '0x0',
1013
+ gasLimit: effectiveGasLimit,
1014
+ maxFeePerGas,
1015
+ maxPriorityFeePerGas,
1016
+ data: txData,
1017
+ nonce: transactionNonce,
1018
+ chainId: activeNetwork.chainId,
1019
+ type: 2,
1020
+ };
1021
+ }
1022
+ signature.payload.v = parseInt(signature.payload.v, 16); //v parameter must be a number by ethers standards
1023
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, signature.payload);
1024
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
1025
+ saveTrezorTx && saveTrezorTx(finalTx);
1026
+ return finalTx;
1027
+ }
1028
+ catch (error) {
1029
+ throw error;
1030
+ }
1031
+ }
1032
+ else {
1033
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
1034
+ }
1035
+ }
1036
+ catch (error) {
1037
+ throw error;
1038
+ }
1039
+ };
1040
+ switch (activeAccountType) {
1041
+ case types_1.KeyringAccountType.Trezor:
1042
+ return await sendERC20TokenOnTrezor();
1043
+ case types_1.KeyringAccountType.Ledger:
1044
+ return await sendERC20TokenOnLedger();
1045
+ default:
1046
+ return await sendERC20Token();
1047
+ }
1048
+ };
1049
+ this.sendSignedErc721Transaction = async ({ receiver, tokenAddress, tokenId, isLegacy, maxPriorityFeePerGas, maxFeePerGas, gasPrice, gasLimit, }) => {
1050
+ const { decryptedPrivateKey } = this.getDecryptedPrivateKey();
1051
+ const { accounts, activeAccountType, activeAccountId, activeNetwork } = this.getState();
1052
+ const { address: activeAccountAddress } = accounts[activeAccountType][activeAccountId];
1053
+ const sendERC721Token = async () => {
1054
+ const currentWallet = new ethers_1.ethers.Wallet(decryptedPrivateKey);
1055
+ const walletSigned = currentWallet.connect(this.web3Provider);
1056
+ let transferMethod;
1057
+ try {
1058
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc21Abi)(), walletSigned);
1059
+ if (isLegacy) {
1060
+ const overrides = {
1061
+ nonce: await this.web3Provider.getTransactionCount(walletSigned.address, 'pending'),
1062
+ gasPrice,
1063
+ ...(gasLimit && { gasLimit }),
1064
+ };
1065
+ transferMethod = await _contract.transferFrom(walletSigned.address, receiver, tokenId, overrides);
1066
+ }
1067
+ else {
1068
+ const overrides = {
1069
+ nonce: await this.web3Provider.getTransactionCount(walletSigned.address, 'pending'),
1070
+ };
1071
+ transferMethod = await _contract.transferFrom(walletSigned.address, receiver, tokenId, overrides);
1072
+ }
1073
+ return transferMethod;
1074
+ }
1075
+ catch (error) {
1076
+ throw error;
1077
+ }
1078
+ };
1079
+ const sendERC721TokenOnLedger = async () => {
1080
+ const signer = this.web3Provider.getSigner(activeAccountAddress);
1081
+ const transactionNonce = await this.getRecommendedNonce(activeAccountAddress);
1082
+ try {
1083
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc21Abi)(), signer);
1084
+ const txData = _contract.interface.encodeFunctionData('transferFrom', [
1085
+ activeAccountAddress,
1086
+ receiver,
1087
+ tokenId,
1088
+ ]);
1089
+ // Use fallback gas limit if not provided (for auto-estimation)
1090
+ const effectiveGasLimit = gasLimit || this.toBigNumber('150000'); // ERC721 fallback
1091
+ let txFormattedForEthers;
1092
+ if (isLegacy) {
1093
+ txFormattedForEthers = {
1094
+ to: tokenAddress,
1095
+ value: '0x0',
1096
+ gasLimit: effectiveGasLimit,
1097
+ gasPrice,
1098
+ data: txData,
1099
+ nonce: transactionNonce,
1100
+ chainId: activeNetwork.chainId,
1101
+ type: 0,
1102
+ };
1103
+ }
1104
+ else {
1105
+ txFormattedForEthers = {
1106
+ to: tokenAddress,
1107
+ value: '0x0',
1108
+ gasLimit: effectiveGasLimit,
1109
+ maxFeePerGas,
1110
+ maxPriorityFeePerGas,
1111
+ data: txData,
1112
+ nonce: transactionNonce,
1113
+ chainId: activeNetwork.chainId,
1114
+ type: 2,
1115
+ };
1116
+ }
1117
+ const rawTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers);
1118
+ const signature = await this.ledgerSigner.evm.signEVMTransaction({
1119
+ rawTx: rawTx.replace('0x', ''),
1120
+ accountIndex: activeAccountId,
1121
+ });
1122
+ const formattedSignature = {
1123
+ r: `0x${signature.r}`,
1124
+ s: `0x${signature.s}`,
1125
+ v: parseInt(signature.v, 16),
1126
+ };
1127
+ if (signature) {
1128
+ try {
1129
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, formattedSignature);
1130
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
1131
+ return finalTx;
1132
+ }
1133
+ catch (error) {
1134
+ throw error;
1135
+ }
1136
+ }
1137
+ else {
1138
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
1139
+ }
1140
+ }
1141
+ catch (error) {
1142
+ throw error;
1143
+ }
1144
+ };
1145
+ const sendERC721TokenOnTrezor = async () => {
1146
+ const signer = this.web3Provider.getSigner(activeAccountAddress);
1147
+ const transactionNonce = await this.getRecommendedNonce(activeAccountAddress);
1148
+ try {
1149
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc21Abi)(), signer);
1150
+ const txData = _contract.interface.encodeFunctionData('transferFrom', [
1151
+ activeAccountAddress,
1152
+ receiver,
1153
+ tokenId,
1154
+ ]);
1155
+ // Use fallback gas limit if not provided (for auto-estimation)
1156
+ const effectiveGasLimit = gasLimit || this.toBigNumber('150000'); // ERC721 fallback
1157
+ let txToBeSignedByTrezor;
1158
+ if (isLegacy) {
1159
+ txToBeSignedByTrezor = {
1160
+ to: tokenAddress,
1161
+ value: '0x0',
1162
+ // @ts-ignore
1163
+ gasLimit: `${effectiveGasLimit.hex}`,
1164
+ // @ts-ignore
1165
+ gasPrice: `${gasPrice}`,
1166
+ nonce: this.toBigNumber(transactionNonce)._hex,
1167
+ chainId: activeNetwork.chainId,
1168
+ data: txData,
1169
+ };
1170
+ console.log({ txToBeSignedByTrezor });
1171
+ }
1172
+ else {
1173
+ txToBeSignedByTrezor = {
1174
+ to: tokenAddress,
1175
+ value: '0x0',
1176
+ // @ts-ignore
1177
+ gasLimit: `${effectiveGasLimit.hex}`,
1178
+ // @ts-ignore
1179
+ maxFeePerGas: `${maxFeePerGas.hex}`,
1180
+ // @ts-ignore
1181
+ maxPriorityFeePerGas: `${maxPriorityFeePerGas.hex}`,
1182
+ nonce: this.toBigNumber(transactionNonce)._hex,
1183
+ chainId: activeNetwork.chainId,
1184
+ data: txData,
1185
+ };
1186
+ }
1187
+ // For EVM networks, Trezor expects 'eth' regardless of the network's currency
1188
+ const trezorCoin = activeNetwork.slip44 === 60 ? 'eth' : activeNetwork.currency;
1189
+ const signature = await this.trezorSigner.signEthTransaction({
1190
+ index: `${activeAccountId}`,
1191
+ tx: txToBeSignedByTrezor,
1192
+ coin: trezorCoin,
1193
+ slip44: activeNetwork.slip44,
1194
+ });
1195
+ if (signature.success) {
1196
+ try {
1197
+ let txFormattedForEthers;
1198
+ if (isLegacy) {
1199
+ txFormattedForEthers = {
1200
+ to: tokenAddress,
1201
+ value: '0x0',
1202
+ gasLimit: effectiveGasLimit,
1203
+ gasPrice,
1204
+ data: txData,
1205
+ nonce: transactionNonce,
1206
+ chainId: activeNetwork.chainId,
1207
+ type: 0,
1208
+ };
1209
+ }
1210
+ else {
1211
+ txFormattedForEthers = {
1212
+ to: tokenAddress,
1213
+ value: '0x0',
1214
+ gasLimit: effectiveGasLimit,
1215
+ maxFeePerGas,
1216
+ maxPriorityFeePerGas,
1217
+ data: txData,
1218
+ nonce: transactionNonce,
1219
+ chainId: activeNetwork.chainId,
1220
+ type: 2,
1221
+ };
1222
+ }
1223
+ signature.payload.v = parseInt(signature.payload.v, 16); //v parameter must be a number by ethers standards
1224
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, signature.payload);
1225
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
1226
+ return finalTx;
1227
+ }
1228
+ catch (error) {
1229
+ console.log({ error });
1230
+ throw error;
1231
+ }
1232
+ }
1233
+ else {
1234
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
1235
+ }
1236
+ }
1237
+ catch (error) {
1238
+ console.log({ errorDois: error });
1239
+ throw error;
1240
+ }
1241
+ };
1242
+ switch (activeAccountType) {
1243
+ case types_1.KeyringAccountType.Trezor:
1244
+ return await sendERC721TokenOnTrezor();
1245
+ case types_1.KeyringAccountType.Ledger:
1246
+ return await sendERC721TokenOnLedger();
1247
+ default:
1248
+ return await sendERC721Token();
1249
+ }
1250
+ };
1251
+ this.sendSignedErc1155Transaction = async ({ receiver, tokenAddress, tokenId, tokenAmount, isLegacy, maxPriorityFeePerGas, maxFeePerGas, gasPrice, gasLimit, }) => {
1252
+ const { decryptedPrivateKey } = this.getDecryptedPrivateKey();
1253
+ const { accounts, activeAccountType, activeAccountId, activeNetwork } = this.getState();
1254
+ const { address: activeAccountAddress } = accounts[activeAccountType][activeAccountId];
1255
+ const sendERC1155Token = async () => {
1256
+ const currentWallet = new ethers_1.ethers.Wallet(decryptedPrivateKey);
1257
+ const walletSigned = currentWallet.connect(this.web3Provider);
1258
+ let transferMethod;
1259
+ try {
1260
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc55Abi)(), walletSigned);
1261
+ const amount = tokenAmount ? parseInt(tokenAmount) : 1;
1262
+ const overrides = {};
1263
+ transferMethod = await _contract.safeTransferFrom(walletSigned.address, receiver, tokenId, amount, [], overrides);
1264
+ return transferMethod;
1265
+ }
1266
+ catch (error) {
1267
+ throw error;
1268
+ }
1269
+ };
1270
+ const sendERC1155TokenOnLedger = async () => {
1271
+ const signer = this.web3Provider.getSigner(activeAccountAddress);
1272
+ const transactionNonce = await this.getRecommendedNonce(activeAccountAddress);
1273
+ try {
1274
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc55Abi)(), signer);
1275
+ const amount = tokenAmount ? parseInt(tokenAmount) : 1;
1276
+ const txData = _contract.interface.encodeFunctionData('safeTransferFrom', [activeAccountAddress, receiver, tokenId, amount, []]);
1277
+ // Use fallback gas limit if not provided (for auto-estimation)
1278
+ const effectiveGasLimit = gasLimit || this.toBigNumber('200000'); // ERC1155 fallback
1279
+ let txFormattedForEthers;
1280
+ if (isLegacy) {
1281
+ txFormattedForEthers = {
1282
+ to: tokenAddress,
1283
+ value: '0x0',
1284
+ gasLimit: effectiveGasLimit,
1285
+ gasPrice,
1286
+ data: txData,
1287
+ nonce: transactionNonce,
1288
+ chainId: activeNetwork.chainId,
1289
+ type: 0,
1290
+ };
1291
+ }
1292
+ else {
1293
+ txFormattedForEthers = {
1294
+ to: tokenAddress,
1295
+ value: '0x0',
1296
+ gasLimit: effectiveGasLimit,
1297
+ maxFeePerGas,
1298
+ maxPriorityFeePerGas,
1299
+ data: txData,
1300
+ nonce: transactionNonce,
1301
+ chainId: activeNetwork.chainId,
1302
+ type: 2,
1303
+ };
1304
+ }
1305
+ const rawTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers);
1306
+ const signature = await this.ledgerSigner.evm.signEVMTransaction({
1307
+ rawTx: rawTx.replace('0x', ''),
1308
+ accountIndex: activeAccountId,
1309
+ });
1310
+ const formattedSignature = {
1311
+ r: `0x${signature.r}`,
1312
+ s: `0x${signature.s}`,
1313
+ v: parseInt(signature.v, 16),
1314
+ };
1315
+ if (signature) {
1316
+ try {
1317
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, formattedSignature);
1318
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
1319
+ return finalTx;
1320
+ }
1321
+ catch (error) {
1322
+ throw error;
1323
+ }
1324
+ }
1325
+ else {
1326
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
1327
+ }
1328
+ }
1329
+ catch (error) {
1330
+ throw error;
1331
+ }
1332
+ };
1333
+ const sendERC1155TokenOnTrezor = async () => {
1334
+ const signer = this.web3Provider.getSigner(activeAccountAddress);
1335
+ const transactionNonce = await this.getRecommendedNonce(activeAccountAddress);
1336
+ try {
1337
+ const _contract = new ethers_1.ethers.Contract(tokenAddress, (0, sysweb3_utils_1.getErc55Abi)(), signer);
1338
+ const amount = tokenAmount ? parseInt(tokenAmount) : 1;
1339
+ const txData = _contract.interface.encodeFunctionData('safeTransferFrom', [activeAccountAddress, receiver, tokenId, amount, []]);
1340
+ // Use fallback gas limit if not provided (for auto-estimation)
1341
+ const effectiveGasLimit = gasLimit || this.toBigNumber('200000'); // ERC1155 fallback
1342
+ let txToBeSignedByTrezor;
1343
+ if (isLegacy) {
1344
+ txToBeSignedByTrezor = {
1345
+ to: tokenAddress,
1346
+ value: '0x0',
1347
+ // @ts-ignore
1348
+ gasLimit: `${effectiveGasLimit.hex}`,
1349
+ // @ts-ignore
1350
+ gasPrice: `${gasPrice}`,
1351
+ nonce: this.toBigNumber(transactionNonce)._hex,
1352
+ chainId: activeNetwork.chainId,
1353
+ data: txData,
1354
+ };
1355
+ }
1356
+ else {
1357
+ txToBeSignedByTrezor = {
1358
+ to: tokenAddress,
1359
+ value: '0x0',
1360
+ // @ts-ignore
1361
+ gasLimit: `${effectiveGasLimit.hex}`,
1362
+ // @ts-ignore
1363
+ maxFeePerGas: `${maxFeePerGas.hex}`,
1364
+ // @ts-ignore
1365
+ maxPriorityFeePerGas: `${maxPriorityFeePerGas.hex}`,
1366
+ nonce: this.toBigNumber(transactionNonce)._hex,
1367
+ chainId: activeNetwork.chainId,
1368
+ data: txData,
1369
+ };
1370
+ }
1371
+ const signature = await this.trezorSigner.signEthTransaction({
1372
+ index: `${activeAccountId}`,
1373
+ tx: txToBeSignedByTrezor,
1374
+ coin: activeNetwork.currency,
1375
+ slip44: activeNetwork.slip44,
1376
+ });
1377
+ if (signature.success) {
1378
+ try {
1379
+ let txFormattedForEthers;
1380
+ if (isLegacy) {
1381
+ txFormattedForEthers = {
1382
+ to: tokenAddress,
1383
+ value: '0x0',
1384
+ gasLimit: effectiveGasLimit,
1385
+ gasPrice,
1386
+ data: txData,
1387
+ nonce: transactionNonce,
1388
+ chainId: activeNetwork.chainId,
1389
+ type: 0,
1390
+ };
1391
+ }
1392
+ else {
1393
+ txFormattedForEthers = {
1394
+ to: tokenAddress,
1395
+ value: '0x0',
1396
+ gasLimit: effectiveGasLimit,
1397
+ maxFeePerGas,
1398
+ maxPriorityFeePerGas,
1399
+ data: txData,
1400
+ nonce: transactionNonce,
1401
+ chainId: activeNetwork.chainId,
1402
+ type: 2,
1403
+ };
1404
+ }
1405
+ signature.payload.v = parseInt(signature.payload.v, 16); //v parameter must be a number by ethers standards
1406
+ const signedTx = ethers_1.ethers.utils.serializeTransaction(txFormattedForEthers, signature.payload);
1407
+ const finalTx = await this.web3Provider.sendTransaction(signedTx);
1408
+ return finalTx;
1409
+ }
1410
+ catch (error) {
1411
+ console.log({ error });
1412
+ throw error;
1413
+ }
1414
+ }
1415
+ else {
1416
+ throw new Error(`Transaction Signature Failed. Error: ${signature}`);
1417
+ }
1418
+ }
1419
+ catch (error) {
1420
+ console.log({ error });
1421
+ throw error;
1422
+ }
1423
+ };
1424
+ switch (activeAccountType) {
1425
+ case types_1.KeyringAccountType.Trezor:
1426
+ return await sendERC1155TokenOnTrezor();
1427
+ case types_1.KeyringAccountType.Ledger:
1428
+ return await sendERC1155TokenOnLedger();
1429
+ default:
1430
+ return await sendERC1155Token();
1431
+ }
1432
+ };
1433
+ this.getRecommendedNonce = async (address) => {
1434
+ try {
1435
+ return await this.web3Provider.getTransactionCount(address, 'pending');
1436
+ }
1437
+ catch (error) {
1438
+ throw error;
1439
+ }
1440
+ };
1441
+ this.getFeeByType = async (type) => {
1442
+ const gasPrice = (await this.getRecommendedGasPrice(false));
1443
+ const low = this.toBigNumber(gasPrice)
1444
+ .mul(ethers_1.ethers.BigNumber.from('8'))
1445
+ .div(ethers_1.ethers.BigNumber.from('10'))
1446
+ .toString();
1447
+ const high = this.toBigNumber(gasPrice)
1448
+ .mul(ethers_1.ethers.BigNumber.from('11'))
1449
+ .div(ethers_1.ethers.BigNumber.from('10'))
1450
+ .toString();
1451
+ if (type === 'low')
1452
+ return low;
1453
+ if (type === 'high')
1454
+ return high;
1455
+ return gasPrice;
1456
+ };
1457
+ this.getGasLimit = async (toAddress) => {
1458
+ try {
1459
+ const estimated = await this.web3Provider.estimateGas({
1460
+ to: toAddress,
1461
+ });
1462
+ return Number(ethers_1.ethers.utils.formatUnits(estimated, 'gwei'));
1463
+ }
1464
+ catch (error) {
1465
+ throw error;
1466
+ }
1467
+ };
1468
+ this.getTxGasLimit = async (tx) => {
1469
+ try {
1470
+ return this.web3Provider.estimateGas(tx);
1471
+ }
1472
+ catch (error) {
1473
+ throw error;
1474
+ }
1475
+ };
1476
+ this.getRecommendedGasPrice = async (formatted) => {
1477
+ try {
1478
+ const gasPriceBN = await this.web3Provider.getGasPrice();
1479
+ if (formatted) {
1480
+ return {
1481
+ gwei: Number(ethers_1.ethers.utils.formatUnits(gasPriceBN, 'gwei')).toFixed(2),
1482
+ ethers: ethers_1.ethers.utils.formatEther(gasPriceBN),
1483
+ };
1484
+ }
1485
+ return gasPriceBN.toString();
1486
+ }
1487
+ catch (error) {
1488
+ throw error;
1489
+ }
1490
+ };
1491
+ this.getBalance = async (address) => {
1492
+ try {
1493
+ const balance = await this.web3Provider.getBalance(address);
1494
+ const formattedBalance = ethers_1.ethers.utils.formatEther(balance);
1495
+ const roundedBalance = (0, floor_1.default)(parseFloat(formattedBalance), 4);
1496
+ return roundedBalance;
1497
+ }
1498
+ catch (error) {
1499
+ throw error;
1500
+ }
1501
+ };
1502
+ this.getTransactionTimestamp = async (transaction) => {
1503
+ const { timestamp } = await this.web3Provider.getBlock(Number(transaction.blockNumber));
1504
+ return {
1505
+ ...transaction,
1506
+ timestamp,
1507
+ };
1508
+ };
1509
+ this.importAccount = (mnemonicOrPrivKey) => {
1510
+ if (ethers_1.ethers.utils.isHexString(mnemonicOrPrivKey)) {
1511
+ return new ethers_1.ethers.Wallet(mnemonicOrPrivKey);
1512
+ }
1513
+ const { privateKey } = ethers_1.ethers.Wallet.fromMnemonic(mnemonicOrPrivKey);
1514
+ const account = new ethers_1.ethers.Wallet(privateKey);
1515
+ return account;
1516
+ };
1517
+ this.getNetwork = getNetwork;
1518
+ this.getDecryptedPrivateKey = getDecryptedPrivateKey;
1519
+ this.abortController = new AbortController();
1520
+ // NOTE: Defer network access until vault state getter is initialized
1521
+ // The web3Provider will be created lazily when first accessed via getters
1522
+ this.getState = getState;
1523
+ this.trezorSigner = trezorSigner;
1524
+ this.ledgerSigner = ledgerSigner;
1525
+ }
1526
+ // Getter that automatically ensures providers are initialized when accessed
1527
+ get web3Provider() {
1528
+ this.ensureProvidersInitialized();
1529
+ return this._web3Provider;
1530
+ }
1531
+ // Helper method to ensure providers are initialized when first needed
1532
+ ensureProvidersInitialized() {
1533
+ if (!this._web3Provider) {
1534
+ // Providers not initialized yet, initialize them now
1535
+ try {
1536
+ const currentNetwork = this.getNetwork();
1537
+ this.setWeb3Provider(currentNetwork);
1538
+ }
1539
+ catch (error) {
1540
+ // If vault state not available yet, providers will be initialized later
1541
+ // when setWeb3Provider is called explicitly
1542
+ console.log('[EthereumTransactions] Deferring provider initialization:', error.message);
1543
+ }
1544
+ }
1545
+ }
1546
+ // Helper method to detect UTXO networks
1547
+ isUtxoNetwork(network) {
1548
+ // Generic UTXO network detection patterns:
1549
+ // 1. URL contains blockbook or trezor (most reliable)
1550
+ // 2. Network kind is explicitly set to 'syscoin'
1551
+ const hasBlockbookUrl = !!(network.url?.includes('blockbook') || network.url?.includes('trezor'));
1552
+ const hasUtxoKind = network.kind === sysweb3_network_1.INetworkType.Syscoin;
1553
+ return hasBlockbookUrl || hasUtxoKind;
1554
+ }
1555
+ setWeb3Provider(network) {
1556
+ this.abortController.abort();
1557
+ this.abortController = new AbortController();
1558
+ // Check if network is a UTXO network to avoid creating web3 providers for blockbook URLs
1559
+ const isUtxoNetwork = this.isUtxoNetwork(network);
1560
+ if (isUtxoNetwork) {
1561
+ // For UTXO networks, don't create web3 providers at all since they won't be used
1562
+ console.log('[EthereumTransactions] setWeb3Provider: Skipping web3Provider creation for UTXO network:', network.url);
1563
+ // Clear any existing providers for UTXO networks
1564
+ this._web3Provider = undefined;
1565
+ }
1566
+ else {
1567
+ // For EVM networks, create normal providers
1568
+ const isL2Network = L2_NETWORK_CHAIN_IDS.includes(network.chainId);
1569
+ const CurrentProvider = isL2Network
1570
+ ? providers_1.CustomL2JsonRpcProvider
1571
+ : providers_1.CustomJsonRpcProvider;
1572
+ this._web3Provider = new CurrentProvider(this.abortController.signal, network.url);
1573
+ }
1574
+ }
1575
+ }
1576
+ exports.EthereumTransactions = EthereumTransactions;
1577
+ //# sourceMappingURL=ethereum.js.map