@ledgerhq/coin-evm 0.2.0-next.0

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 (53) hide show
  1. package/.eslintrc.js +57 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/CHANGELOG.md +18 -0
  4. package/jest.config.js +6 -0
  5. package/package.json +102 -0
  6. package/src/__tests__/adapters.unit.test.ts +527 -0
  7. package/src/__tests__/broadcast.unit.test.ts +181 -0
  8. package/src/__tests__/buildOptimisticOperation.unit.test.ts +182 -0
  9. package/src/__tests__/createTransaction.unit.test.ts +52 -0
  10. package/src/__tests__/deviceTransactionConfig.unit.test.ts +245 -0
  11. package/src/__tests__/estimateMaxSpendable.unit.test.ts +123 -0
  12. package/src/__tests__/getTransactionStatus.unit.test.ts +355 -0
  13. package/src/__tests__/hw-getAddress.unit.test.ts +24 -0
  14. package/src/__tests__/logic.unit.test.ts +406 -0
  15. package/src/__tests__/preload.unit.test.ts +139 -0
  16. package/src/__tests__/prepareTransaction.unit.test.ts +394 -0
  17. package/src/__tests__/rpc.unit.test.ts +532 -0
  18. package/src/__tests__/signOperation.unit.test.ts +157 -0
  19. package/src/__tests__/synchronization.unit.test.ts +832 -0
  20. package/src/__tests__/transaction.unit.test.ts +196 -0
  21. package/src/abis/erc20.abi.json +230 -0
  22. package/src/abis/optimismGasPriceOracle.abi.json +252 -0
  23. package/src/adapters.ts +148 -0
  24. package/src/api/etherscan.ts +124 -0
  25. package/src/api/rpc.common.ts +354 -0
  26. package/src/api/rpc.native.ts +5 -0
  27. package/src/api/rpc.ts +2 -0
  28. package/src/bridge/js.ts +77 -0
  29. package/src/bridge.integration.test.ts +93 -0
  30. package/src/broadcast.ts +40 -0
  31. package/src/buildOptimisticOperation.ts +113 -0
  32. package/src/cli-transaction.ts +11 -0
  33. package/src/createTransaction.ts +25 -0
  34. package/src/datasets/ethereum.scanAccounts.1.ts +48 -0
  35. package/src/datasets/ethereum1.ts +20 -0
  36. package/src/datasets/ethereum2.ts +20 -0
  37. package/src/datasets/ethereum_classic.ts +68 -0
  38. package/src/deviceTransactionConfig.ts +64 -0
  39. package/src/errors.ts +5 -0
  40. package/src/estimateMaxSpendable.ts +19 -0
  41. package/src/getTransactionStatus.ts +186 -0
  42. package/src/hw-getAddress.ts +24 -0
  43. package/src/logic.ts +149 -0
  44. package/src/preload.ts +54 -0
  45. package/src/prepareTransaction.ts +176 -0
  46. package/src/signOperation.ts +127 -0
  47. package/src/specs.ts +344 -0
  48. package/src/speculos-deviceActions.ts +83 -0
  49. package/src/synchronization.ts +317 -0
  50. package/src/testUtils.ts +153 -0
  51. package/src/transaction.ts +193 -0
  52. package/src/types.ts +132 -0
  53. package/tsconfig.json +12 -0
@@ -0,0 +1,527 @@
1
+ import {
2
+ encodeAccountId,
3
+ encodeTokenAccountId,
4
+ } from "@ledgerhq/coin-framework/account/index";
5
+ import { findTokenById } from "@ledgerhq/cryptoassets";
6
+ import { Operation } from "@ledgerhq/types-live";
7
+ import BigNumber from "bignumber.js";
8
+ import { ethers } from "ethers";
9
+ import {
10
+ etherscanERC20EventToOperation,
11
+ etherscanOperationToOperation,
12
+ transactionToEthersTransaction,
13
+ } from "../adapters";
14
+ import {
15
+ EtherscanERC20Event,
16
+ EtherscanOperation,
17
+ EvmTransactionEIP1559,
18
+ EvmTransactionLegacy,
19
+ } from "../types";
20
+
21
+ const testData = Buffer.from("testBufferString").toString("hex");
22
+ const eip1559Tx: EvmTransactionEIP1559 = {
23
+ amount: new BigNumber(100),
24
+ useAllAmount: false,
25
+ subAccountId: "id",
26
+ recipient: "0xkvn",
27
+ feesStrategy: "custom",
28
+ family: "evm",
29
+ mode: "send",
30
+ nonce: 0,
31
+ gasLimit: new BigNumber(21000),
32
+ chainId: 1,
33
+ data: Buffer.from(testData, "hex"),
34
+ maxFeePerGas: new BigNumber(10000),
35
+ maxPriorityFeePerGas: new BigNumber(10000),
36
+ type: 2,
37
+ };
38
+ const legacyTx: EvmTransactionLegacy = {
39
+ amount: new BigNumber(100),
40
+ useAllAmount: false,
41
+ subAccountId: "id",
42
+ recipient: "0xkvn",
43
+ feesStrategy: "custom",
44
+ family: "evm",
45
+ mode: "send",
46
+ nonce: 0,
47
+ gasLimit: new BigNumber(21000),
48
+ chainId: 1,
49
+ data: Buffer.from(testData, "hex"),
50
+ gasPrice: new BigNumber(10000),
51
+ type: 0,
52
+ };
53
+
54
+ describe("EVM Family", () => {
55
+ describe("adapters.ts", () => {
56
+ describe("transactionToEthersTransaction", () => {
57
+ it("should build convert an EIP1559 ledger live transaction to an ethers transaction", () => {
58
+ const ethers1559Tx: ethers.Transaction = {
59
+ to: "0xkvn",
60
+ nonce: 0,
61
+ gasLimit: ethers.BigNumber.from(21000),
62
+ data: "0x" + testData,
63
+ value: ethers.BigNumber.from(100),
64
+ chainId: 1,
65
+ type: 2,
66
+ maxFeePerGas: ethers.BigNumber.from(10000),
67
+ maxPriorityFeePerGas: ethers.BigNumber.from(10000),
68
+ };
69
+
70
+ expect(transactionToEthersTransaction(eip1559Tx)).toEqual(ethers1559Tx);
71
+ });
72
+
73
+ it("should build convert an legacy ledger live transaction to an ethers transaction", () => {
74
+ const legacyEthersTx: ethers.Transaction = {
75
+ to: "0xkvn",
76
+ nonce: 0,
77
+ gasLimit: ethers.BigNumber.from(21000),
78
+ data: "0x" + testData,
79
+ value: ethers.BigNumber.from(100),
80
+ chainId: 1,
81
+ type: 0,
82
+ gasPrice: ethers.BigNumber.from(10000),
83
+ };
84
+
85
+ expect(transactionToEthersTransaction(legacyTx)).toEqual(
86
+ legacyEthersTx
87
+ );
88
+ });
89
+ });
90
+
91
+ describe("etherscanOperationToOperation", () => {
92
+ it("should convert a etherscan-like smart contract operation (from their API) to a Ledger Live Operation", () => {
93
+ const etherscanOp: EtherscanOperation = {
94
+ blockNumber: "14923692",
95
+ timeStamp: "1654646570",
96
+ hash: "0xaa45b4858ba44230a5fce5a29570a5dec2bf1f0ba95bacdec4fe8f2c4fa99338",
97
+ nonce: "7",
98
+ blockHash:
99
+ "0x8df71a12a8c06b36c06c26bf6248857dd2a2b75b6edbb4e33e9477078897b282",
100
+ transactionIndex: "27",
101
+ from: "0x9aa99c23f67c81701c772b106b4f83f6e858dd2e",
102
+ to: "0xc5102fe9359fd9a28f877a67e36b0f050d81a3cc",
103
+ value: "0",
104
+ gas: "6000000",
105
+ gasPrice: "125521409858",
106
+ isError: "0",
107
+ txreceipt_status: "1",
108
+ input:
109
+ "0xa9059cbb000000000000000000000000313143c4088a47c469d06fe3fa5fd4196be6a4d600000000000000000000000000000000000000000003b8e97d229a2d54800000",
110
+ contractAddress: "",
111
+ cumulativeGasUsed: "1977481",
112
+ gasUsed: "57168",
113
+ confirmations: "122471",
114
+ methodId: "0xa9059cbb",
115
+ functionName: "transfer(address _to, uint256 _value)",
116
+ };
117
+
118
+ const accountId = encodeAccountId({
119
+ type: "js",
120
+ version: "2",
121
+ currencyId: "ethereum",
122
+ xpubOrAddress: "0x9aa99c23f67c81701c772b106b4f83f6e858dd2e",
123
+ derivationMode: "",
124
+ });
125
+
126
+ const expectedOperation: Operation = {
127
+ id: "js:2:ethereum:0x9aa99c23f67c81701c772b106b4f83f6e858dd2e:-0xaa45b4858ba44230a5fce5a29570a5dec2bf1f0ba95bacdec4fe8f2c4fa99338-FEES",
128
+ hash: "0xaa45b4858ba44230a5fce5a29570a5dec2bf1f0ba95bacdec4fe8f2c4fa99338",
129
+ accountId,
130
+ blockHash:
131
+ "0x8df71a12a8c06b36c06c26bf6248857dd2a2b75b6edbb4e33e9477078897b282",
132
+ blockHeight: 14923692,
133
+ recipients: ["0xc5102fE9359FD9a28f877a67E36B0F050d81a3CC"],
134
+ senders: ["0x9AA99C23F67c81701C772B106b4F83f6e858dd2E"],
135
+ value: new BigNumber("7175807958762144"),
136
+ fee: new BigNumber("7175807958762144"),
137
+ date: new Date("2022-06-08T00:02:50.000Z"),
138
+ transactionSequenceNumber: 7,
139
+ type: "FEES",
140
+ extra: {},
141
+ };
142
+
143
+ expect(etherscanOperationToOperation(accountId, etherscanOp)).toEqual(
144
+ expectedOperation
145
+ );
146
+ });
147
+
148
+ it("should convert a etherscan-like coin out operation (from their API) to a Ledger Live Operation", () => {
149
+ const etherscanOp: EtherscanOperation = {
150
+ blockNumber: "13807766",
151
+ timeStamp: "1639544926",
152
+ hash: "0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944",
153
+ nonce: "11898499",
154
+ blockHash:
155
+ "0xad04a8ed598c9c270f7ffd9a113224bc16fc285af814a2dc735c261620bad669",
156
+ transactionIndex: "394",
157
+ from: "0x829bd824b016326a401d083b33d092293333a830",
158
+ to: "0x26e3fd2dec89bf645ba7b41c4ddfad8454ee6245",
159
+ value: "143141441418750645",
160
+ gas: "210000",
161
+ gasPrice: "68363841693",
162
+ isError: "0",
163
+ txreceipt_status: "1",
164
+ input: "0x",
165
+ contractAddress: "",
166
+ cumulativeGasUsed: "14788393",
167
+ gasUsed: "21000",
168
+ confirmations: "2582470",
169
+ methodId: "0x",
170
+ functionName: "",
171
+ };
172
+
173
+ const accountId = encodeAccountId({
174
+ type: "js",
175
+ version: "2",
176
+ currencyId: "ethereum",
177
+ xpubOrAddress: "0x829BD824B016326A401d083B33D092293333A830",
178
+ derivationMode: "",
179
+ });
180
+
181
+ const expectedOperation: Operation = {
182
+ id: "js:2:ethereum:0x829BD824B016326A401d083B33D092293333A830:-0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944-OUT",
183
+ hash: "0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944",
184
+ accountId,
185
+ blockHash:
186
+ "0xad04a8ed598c9c270f7ffd9a113224bc16fc285af814a2dc735c261620bad669",
187
+ blockHeight: 13807766,
188
+ recipients: ["0x26E3fd2dEc89bF645BA7b41c4DdFad8454Ee6245"],
189
+ senders: ["0x829BD824B016326A401d083B33D092293333A830"],
190
+ value: new BigNumber("143141441418750645").plus("1435640675553000"),
191
+ fee: new BigNumber("1435640675553000"),
192
+ date: new Date("2021-12-15T05:08:46.000Z"),
193
+ transactionSequenceNumber: 11898499,
194
+ type: "OUT",
195
+ extra: {},
196
+ };
197
+
198
+ expect(etherscanOperationToOperation(accountId, etherscanOp)).toEqual(
199
+ expectedOperation
200
+ );
201
+ });
202
+
203
+ it("should convert a etherscan-like coin in operation (from their API) to a Ledger Live Operation", () => {
204
+ const etherscanOp: EtherscanOperation = {
205
+ blockNumber: "13807766",
206
+ timeStamp: "1639544926",
207
+ hash: "0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944",
208
+ nonce: "11898499",
209
+ blockHash:
210
+ "0xad04a8ed598c9c270f7ffd9a113224bc16fc285af814a2dc735c261620bad669",
211
+ transactionIndex: "394",
212
+ from: "0x26e3fd2dec89bf645ba7b41c4ddfad8454ee6245",
213
+ to: "0x829bd824b016326a401d083b33d092293333a830",
214
+ value: "143141441418750645",
215
+ gas: "210000",
216
+ gasPrice: "68363841693",
217
+ isError: "0",
218
+ txreceipt_status: "1",
219
+ input: "0x",
220
+ contractAddress: "",
221
+ cumulativeGasUsed: "14788393",
222
+ gasUsed: "21000",
223
+ confirmations: "2582470",
224
+ methodId: "0x",
225
+ functionName: "",
226
+ };
227
+
228
+ const accountId = encodeAccountId({
229
+ type: "js",
230
+ version: "2",
231
+ currencyId: "ethereum",
232
+ xpubOrAddress: "0x829BD824B016326A401d083B33D092293333A830",
233
+ derivationMode: "",
234
+ });
235
+
236
+ const expectedOperation: Operation = {
237
+ id: "js:2:ethereum:0x829BD824B016326A401d083B33D092293333A830:-0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944-IN",
238
+ hash: "0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944",
239
+ accountId,
240
+ blockHash:
241
+ "0xad04a8ed598c9c270f7ffd9a113224bc16fc285af814a2dc735c261620bad669",
242
+ blockHeight: 13807766,
243
+ recipients: ["0x829BD824B016326A401d083B33D092293333A830"],
244
+ senders: ["0x26E3fd2dEc89bF645BA7b41c4DdFad8454Ee6245"],
245
+ value: new BigNumber("143141441418750645"),
246
+ fee: new BigNumber("1435640675553000"),
247
+ date: new Date("2021-12-15T05:08:46.000Z"),
248
+ transactionSequenceNumber: 11898499,
249
+ type: "IN",
250
+ extra: {},
251
+ };
252
+
253
+ expect(etherscanOperationToOperation(accountId, etherscanOp)).toEqual(
254
+ expectedOperation
255
+ );
256
+ });
257
+
258
+ it("should convert a etherscan-like coin none operation (from their API) to a Ledger Live Operation", () => {
259
+ const etherscanOp: EtherscanOperation = {
260
+ blockNumber: "13807766",
261
+ timeStamp: "1639544926",
262
+ hash: "0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944",
263
+ nonce: "11898499",
264
+ blockHash:
265
+ "0xad04a8ed598c9c270f7ffd9a113224bc16fc285af814a2dc735c261620bad669",
266
+ transactionIndex: "394",
267
+ from: "0x6bfd74c0996f269bcece59191eff667b3dfd73b9",
268
+ to: "0x02a357476a300c89ce27d7d4c7e57bbd2dd3f006",
269
+ value: "143141441418750645",
270
+ gas: "210000",
271
+ gasPrice: "68363841693",
272
+ isError: "0",
273
+ txreceipt_status: "1",
274
+ input: "0x",
275
+ contractAddress: "",
276
+ cumulativeGasUsed: "14788393",
277
+ gasUsed: "21000",
278
+ confirmations: "2582470",
279
+ methodId: "0x",
280
+ functionName: "",
281
+ };
282
+
283
+ const accountId = encodeAccountId({
284
+ type: "js",
285
+ version: "2",
286
+ currencyId: "ethereum",
287
+ xpubOrAddress: "0x829BD824B016326A401d083B33D092293333A830",
288
+ derivationMode: "",
289
+ });
290
+
291
+ const expectedOperation: Operation = {
292
+ id: "js:2:ethereum:0x829BD824B016326A401d083B33D092293333A830:-0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944-NONE",
293
+ hash: "0x8d3e871469ce549c5a80b8c8beaae0d502ecea85bb43eb84703cebeea7d25944",
294
+ accountId,
295
+ blockHash:
296
+ "0xad04a8ed598c9c270f7ffd9a113224bc16fc285af814a2dc735c261620bad669",
297
+ blockHeight: 13807766,
298
+ recipients: ["0x02a357476A300c89Ce27D7D4C7E57Bbd2DD3f006"],
299
+ senders: ["0x6bfD74C0996F269Bcece59191EFf667b3dFD73b9"],
300
+ value: new BigNumber("143141441418750645"),
301
+ fee: new BigNumber("1435640675553000"),
302
+ date: new Date("2021-12-15T05:08:46.000Z"),
303
+ transactionSequenceNumber: 11898499,
304
+ type: "NONE",
305
+ extra: {},
306
+ };
307
+
308
+ expect(etherscanOperationToOperation(accountId, etherscanOp)).toEqual(
309
+ expectedOperation
310
+ );
311
+ });
312
+ });
313
+
314
+ describe("etherscanERC20EventToOperation", () => {
315
+ it("should return null for an unknown token", () => {
316
+ const etherscanOp: EtherscanERC20Event = {
317
+ blockNumber: "16240731",
318
+ timeStamp: "1671717983",
319
+ hash: "0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf",
320
+ nonce: "53",
321
+ blockHash:
322
+ "0x58ee7556044cd139e569c87c173a6dedbfbeb9ada6693ee6090fd510acee9c21",
323
+ from: "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d",
324
+ contractAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb41",
325
+ to: "0xc2907efcce4011c491bbeda8a0fa63ba7aab596c",
326
+ value: "2000000",
327
+ tokenName: "USD Coin",
328
+ tokenSymbol: "USDC",
329
+ tokenDecimal: "6",
330
+ transactionIndex: "65",
331
+ gas: "79381",
332
+ gasPrice: "24314367325",
333
+ gasUsed: "65613",
334
+ cumulativeGasUsed: "4557746",
335
+ input: "deprecated",
336
+ confirmations: "150032",
337
+ };
338
+
339
+ const accountId = encodeAccountId({
340
+ type: "js",
341
+ version: "2",
342
+ currencyId: "ethereum",
343
+ xpubOrAddress: "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d",
344
+ derivationMode: "",
345
+ });
346
+
347
+ expect(etherscanERC20EventToOperation(accountId, etherscanOp)).toEqual(
348
+ null
349
+ );
350
+ });
351
+
352
+ it("should convert a etherscan-like usdc out event (from their API) to a Ledger Live Operation", () => {
353
+ const etherscanOp: EtherscanERC20Event = {
354
+ blockNumber: "16240731",
355
+ timeStamp: "1671717983",
356
+ hash: "0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf",
357
+ nonce: "53",
358
+ blockHash:
359
+ "0x58ee7556044cd139e569c87c173a6dedbfbeb9ada6693ee6090fd510acee9c21",
360
+ from: "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d",
361
+ contractAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
362
+ to: "0xc2907efcce4011c491bbeda8a0fa63ba7aab596c",
363
+ value: "2000000",
364
+ tokenName: "USD Coin",
365
+ tokenSymbol: "USDC",
366
+ tokenDecimal: "6",
367
+ transactionIndex: "65",
368
+ gas: "79381",
369
+ gasPrice: "24314367325",
370
+ gasUsed: "65613",
371
+ cumulativeGasUsed: "4557746",
372
+ input: "deprecated",
373
+ confirmations: "150032",
374
+ };
375
+
376
+ const accountId = encodeAccountId({
377
+ type: "js",
378
+ version: "2",
379
+ currencyId: "ethereum",
380
+ xpubOrAddress: "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d",
381
+ derivationMode: "",
382
+ });
383
+ const tokenCurrency = findTokenById("ethereum/erc20/usd__coin");
384
+ const tokenAccountId = encodeTokenAccountId(accountId, tokenCurrency!);
385
+
386
+ const expectedOperation: Operation = {
387
+ id: "js:2:ethereum:0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d:+ethereum%2Ferc20%2Fusd__coin-0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf-OUT",
388
+ hash: "0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf",
389
+ accountId: tokenAccountId,
390
+ blockHash:
391
+ "0x58ee7556044cd139e569c87c173a6dedbfbeb9ada6693ee6090fd510acee9c21",
392
+ blockHeight: 16240731,
393
+ senders: ["0x6cBCD73CD8e8a42844662f0A0e76D7F79Afd933d"],
394
+ recipients: ["0xC2907EFccE4011C491BbedA8A0fA63BA7aab596C"],
395
+ value: new BigNumber("2000000"),
396
+ fee: new BigNumber("1595338583295225"),
397
+ contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
398
+ date: new Date("2022-12-22T14:06:23.000Z"),
399
+ transactionSequenceNumber: 53,
400
+ type: "OUT",
401
+ extra: {},
402
+ };
403
+
404
+ expect(etherscanERC20EventToOperation(accountId, etherscanOp)).toEqual({
405
+ operation: expectedOperation,
406
+ tokenCurrency,
407
+ });
408
+ });
409
+
410
+ it("should convert a etherscan-like usdc in event (from their API) to a Ledger Live Operation", () => {
411
+ const etherscanOp: EtherscanERC20Event = {
412
+ blockNumber: "16240731",
413
+ timeStamp: "1671717983",
414
+ hash: "0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf",
415
+ nonce: "53",
416
+ blockHash:
417
+ "0x58ee7556044cd139e569c87c173a6dedbfbeb9ada6693ee6090fd510acee9c21",
418
+ from: "0xc2907efcce4011c491bbeda8a0fa63ba7aab596c",
419
+ contractAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
420
+ to: "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d",
421
+ value: "2000000",
422
+ tokenName: "USD Coin",
423
+ tokenSymbol: "USDC",
424
+ tokenDecimal: "6",
425
+ transactionIndex: "65",
426
+ gas: "79381",
427
+ gasPrice: "24314367325",
428
+ gasUsed: "65613",
429
+ cumulativeGasUsed: "4557746",
430
+ input: "deprecated",
431
+ confirmations: "150032",
432
+ };
433
+
434
+ const accountId = encodeAccountId({
435
+ type: "js",
436
+ version: "2",
437
+ currencyId: "ethereum",
438
+ xpubOrAddress: "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d",
439
+ derivationMode: "",
440
+ });
441
+ const tokenCurrency = findTokenById("ethereum/erc20/usd__coin");
442
+ const tokenAccountId = encodeTokenAccountId(accountId, tokenCurrency!);
443
+
444
+ const expectedOperation: Operation = {
445
+ id: "js:2:ethereum:0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d:+ethereum%2Ferc20%2Fusd__coin-0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf-IN",
446
+ hash: "0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf",
447
+ accountId: tokenAccountId,
448
+ blockHash:
449
+ "0x58ee7556044cd139e569c87c173a6dedbfbeb9ada6693ee6090fd510acee9c21",
450
+ blockHeight: 16240731,
451
+ senders: ["0xC2907EFccE4011C491BbedA8A0fA63BA7aab596C"],
452
+ recipients: ["0x6cBCD73CD8e8a42844662f0A0e76D7F79Afd933d"],
453
+ value: new BigNumber("2000000"),
454
+ fee: new BigNumber("1595338583295225"),
455
+ contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
456
+ date: new Date("2022-12-22T14:06:23.000Z"),
457
+ transactionSequenceNumber: 53,
458
+ type: "IN",
459
+ extra: {},
460
+ };
461
+
462
+ expect(etherscanERC20EventToOperation(accountId, etherscanOp)).toEqual({
463
+ operation: expectedOperation,
464
+ tokenCurrency,
465
+ });
466
+ });
467
+
468
+ it("should convert a etherscan-like usdc none event (from their API) to a Ledger Live Operation", () => {
469
+ const etherscanOp: EtherscanERC20Event = {
470
+ blockNumber: "16240731",
471
+ timeStamp: "1671717983",
472
+ hash: "0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf",
473
+ nonce: "53",
474
+ blockHash:
475
+ "0x58ee7556044cd139e569c87c173a6dedbfbeb9ada6693ee6090fd510acee9c21",
476
+ from: "0x6bfd74c0996f269bcece59191eff667b3dfd73b9",
477
+ contractAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
478
+ to: "0x02a357476a300c89ce27d7d4c7e57bbd2dd3f006",
479
+ value: "2000000",
480
+ tokenName: "USD Coin",
481
+ tokenSymbol: "USDC",
482
+ tokenDecimal: "6",
483
+ transactionIndex: "65",
484
+ gas: "79381",
485
+ gasPrice: "24314367325",
486
+ gasUsed: "65613",
487
+ cumulativeGasUsed: "4557746",
488
+ input: "deprecated",
489
+ confirmations: "150032",
490
+ };
491
+
492
+ const accountId = encodeAccountId({
493
+ type: "js",
494
+ version: "2",
495
+ currencyId: "ethereum",
496
+ xpubOrAddress: "0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d",
497
+ derivationMode: "",
498
+ });
499
+ const tokenCurrency = findTokenById("ethereum/erc20/usd__coin");
500
+ const tokenAccountId = encodeTokenAccountId(accountId, tokenCurrency!);
501
+
502
+ const expectedOperation: Operation = {
503
+ id: "js:2:ethereum:0x6cbcd73cd8e8a42844662f0a0e76d7f79afd933d:+ethereum%2Ferc20%2Fusd__coin-0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf-NONE",
504
+ hash: "0x02b972f304dc24c9bc362e6435c4ad654241f9af916689a4790145c9bcbdf4cf",
505
+ accountId: tokenAccountId,
506
+ blockHash:
507
+ "0x58ee7556044cd139e569c87c173a6dedbfbeb9ada6693ee6090fd510acee9c21",
508
+ blockHeight: 16240731,
509
+ recipients: ["0x02a357476A300c89Ce27D7D4C7E57Bbd2DD3f006"],
510
+ senders: ["0x6bfD74C0996F269Bcece59191EFf667b3dFD73b9"],
511
+ value: new BigNumber("2000000"),
512
+ fee: new BigNumber("1595338583295225"),
513
+ contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
514
+ date: new Date("2022-12-22T14:06:23.000Z"),
515
+ transactionSequenceNumber: 53,
516
+ type: "NONE",
517
+ extra: {},
518
+ };
519
+
520
+ expect(etherscanERC20EventToOperation(accountId, etherscanOp)).toEqual({
521
+ operation: expectedOperation,
522
+ tokenCurrency,
523
+ });
524
+ });
525
+ });
526
+ });
527
+ });