@ledgerhq/coin-tester-evm 1.6.0-nightly.5 → 1.6.0-nightly.6

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 (56) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +69 -43
  3. package/lib/src/helpers.d.ts +6 -6
  4. package/lib/src/helpers.d.ts.map +1 -1
  5. package/lib/src/helpers.js +12 -11
  6. package/lib/src/helpers.js.map +1 -1
  7. package/lib/src/indexer.d.ts.map +1 -1
  8. package/lib/src/indexer.js +193 -184
  9. package/lib/src/indexer.js.map +1 -1
  10. package/lib/src/scenarii/blast.d.ts.map +1 -1
  11. package/lib/src/scenarii/blast.js +8 -8
  12. package/lib/src/scenarii/blast.js.map +1 -1
  13. package/lib/src/scenarii/ethereum.d.ts.map +1 -1
  14. package/lib/src/scenarii/ethereum.js +10 -10
  15. package/lib/src/scenarii/ethereum.js.map +1 -1
  16. package/lib/src/scenarii/polygon.d.ts.map +1 -1
  17. package/lib/src/scenarii/polygon.js +11 -11
  18. package/lib/src/scenarii/polygon.js.map +1 -1
  19. package/lib/src/scenarii/scroll.d.ts.map +1 -1
  20. package/lib/src/scenarii/scroll.js +8 -8
  21. package/lib/src/scenarii/scroll.js.map +1 -1
  22. package/lib/src/scenarii/sonic.d.ts.map +1 -1
  23. package/lib/src/scenarii/sonic.js +8 -8
  24. package/lib/src/scenarii/sonic.js.map +1 -1
  25. package/lib/tsconfig.tsbuildinfo +1 -1
  26. package/lib-es/src/helpers.d.ts +6 -6
  27. package/lib-es/src/helpers.d.ts.map +1 -1
  28. package/lib-es/src/helpers.js +12 -11
  29. package/lib-es/src/helpers.js.map +1 -1
  30. package/lib-es/src/indexer.d.ts.map +1 -1
  31. package/lib-es/src/indexer.js +194 -185
  32. package/lib-es/src/indexer.js.map +1 -1
  33. package/lib-es/src/scenarii/blast.d.ts.map +1 -1
  34. package/lib-es/src/scenarii/blast.js +9 -9
  35. package/lib-es/src/scenarii/blast.js.map +1 -1
  36. package/lib-es/src/scenarii/ethereum.d.ts.map +1 -1
  37. package/lib-es/src/scenarii/ethereum.js +11 -11
  38. package/lib-es/src/scenarii/ethereum.js.map +1 -1
  39. package/lib-es/src/scenarii/polygon.d.ts.map +1 -1
  40. package/lib-es/src/scenarii/polygon.js +12 -12
  41. package/lib-es/src/scenarii/polygon.js.map +1 -1
  42. package/lib-es/src/scenarii/scroll.d.ts.map +1 -1
  43. package/lib-es/src/scenarii/scroll.js +9 -9
  44. package/lib-es/src/scenarii/scroll.js.map +1 -1
  45. package/lib-es/src/scenarii/sonic.d.ts.map +1 -1
  46. package/lib-es/src/scenarii/sonic.js +9 -9
  47. package/lib-es/src/scenarii/sonic.js.map +1 -1
  48. package/lib-es/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +10 -10
  50. package/src/helpers.ts +15 -14
  51. package/src/indexer.ts +200 -205
  52. package/src/scenarii/blast.ts +9 -11
  53. package/src/scenarii/ethereum.ts +11 -13
  54. package/src/scenarii/polygon.ts +12 -14
  55. package/src/scenarii/scroll.ts +9 -11
  56. package/src/scenarii/sonic.ts +9 -11
package/src/indexer.ts CHANGED
@@ -2,7 +2,7 @@ import BigNumber from "bignumber.js";
2
2
  import { SetupServerApi, setupServer } from "msw/node";
3
3
  import BlueBirdPromise from "bluebird";
4
4
  import { http, HttpResponse, bypass } from "msw";
5
- import { utils, providers, ethers } from "ethers";
5
+ import { AbiCoder, ethers } from "ethers";
6
6
  import { ERC20_ABI, ERC721_ABI, ERC1155_ABI } from "@ledgerhq/coin-evm/abis/index";
7
7
  import { safeEncodeEIP55 } from "@ledgerhq/coin-evm/utils";
8
8
  import { EvmConfigInfo } from "@ledgerhq/coin-evm/config";
@@ -41,16 +41,18 @@ type TraceTransaction = {
41
41
 
42
42
  const MAX_BLOCK_RANGE = 1024;
43
43
 
44
- const ERC20Interface = new utils.Interface(ERC20_ABI);
45
- const ERC721Interface = new utils.Interface(ERC721_ABI);
46
- const ERC1155Interface = new utils.Interface(ERC1155_ABI);
44
+ const ERC20Interface = new ethers.Interface(ERC20_ABI);
45
+ const ERC721Interface = new ethers.Interface(ERC721_ABI);
46
+ const ERC1155Interface = new ethers.Interface(ERC1155_ABI);
47
47
 
48
48
  const TRANSFER_EVENTS_TOPICS = {
49
- ERC20: ERC20Interface.getEventTopic("Transfer"),
50
- ERC721: ERC721Interface.getEventTopic("Transfer"),
51
- ERC1155: ERC1155Interface.getEventTopic("TransferSingle"),
49
+ ERC20: ERC20Interface.getEvent("Transfer")?.topicHash || "",
50
+ ERC721: ERC721Interface.getEvent("Transfer")?.topicHash || "",
51
+ ERC1155: ERC1155Interface.getEvent("TransferSingle")?.topicHash || "",
52
52
  };
53
53
 
54
+ const abiCoder = new AbiCoder();
55
+
54
56
  const explorerEtherscanOperationByAddress: Record<string, Map<string, EtherscanOperation> | null> =
55
57
  {};
56
58
  const explorerEtherscanERC20EventsByAddress: Record<
@@ -98,13 +100,23 @@ export const resetIndexer = () => {
98
100
  }
99
101
  };
100
102
 
101
- const handleLog = async (log: providers.Log, provider: ethers.providers.StaticJsonRpcProvider) => {
102
- const contractDecimals = await provider
103
- .call({ to: log.address, data: ERC20Interface.encodeFunctionData("decimals") })
104
- .then(res => (!res || res === "0x" ? false : true));
103
+ const handleLog = async (log: ethers.Log, provider: ethers.JsonRpcProvider) => {
104
+ let hasDecimals = false;
105
+
106
+ try {
107
+ const res = await provider.call({
108
+ to: log.address,
109
+ data: ERC20Interface.encodeFunctionData("decimals"),
110
+ });
111
+ // if call didn’t revert and returned something valid
112
+ hasDecimals = !!(res && res !== "0x");
113
+ } catch {
114
+ // execution reverted → no decimals()
115
+ hasDecimals = false;
116
+ }
105
117
 
106
- const isERC20 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC20 && contractDecimals;
107
- const isERC721 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC721 && !contractDecimals;
118
+ const isERC20 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC20 && hasDecimals;
119
+ const isERC721 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC721 && !hasDecimals;
108
120
  const isERC1155 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC1155;
109
121
 
110
122
  if (isERC20) {
@@ -116,17 +128,14 @@ const handleLog = async (log: providers.Log, provider: ethers.providers.StaticJs
116
128
  }
117
129
  };
118
130
 
119
- const handleERC20Log = async (
120
- log: providers.Log,
121
- provider: ethers.providers.StaticJsonRpcProvider,
122
- ) => {
131
+ const handleERC20Log = async (log: ethers.Log, provider: ethers.JsonRpcProvider) => {
123
132
  const [name, ticker, decimals, block, tx, receipt] = await Promise.all([
124
133
  provider
125
134
  .call({ to: log.address, data: ERC20Interface.encodeFunctionData("name") })
126
- .then(res => ethers.utils.defaultAbiCoder.decode(["string"], res)[0]),
135
+ .then(res => abiCoder.decode(["string"], res)[0]),
127
136
  provider
128
137
  .call({ to: log.address, data: ERC20Interface.encodeFunctionData("symbol") })
129
- .then(res => ethers.utils.defaultAbiCoder.decode(["string"], res)[0]),
138
+ .then(res => abiCoder.decode(["string"], res)[0]),
130
139
  provider
131
140
  .call({ to: log.address, data: ERC20Interface.encodeFunctionData("decimals") })
132
141
  .then(res => new BigNumber(res).toString()),
@@ -135,30 +144,30 @@ const handleERC20Log = async (
135
144
  provider.getTransactionReceipt(log.transactionHash),
136
145
  ]);
137
146
 
138
- const from = safeEncodeEIP55(ethers.utils.defaultAbiCoder.decode(["address"], log.topics[1])[0]);
139
- const to = safeEncodeEIP55(ethers.utils.defaultAbiCoder.decode(["address"], log.topics[2])[0]);
140
- const amount = ethers.BigNumber.from(log.data === "0x" ? 0 : log.data).toString();
147
+ const from = safeEncodeEIP55(abiCoder.decode(["address"], log.topics[1])[0]);
148
+ const to = safeEncodeEIP55(abiCoder.decode(["address"], log.topics[2])[0]);
149
+ const amount = BigInt(log.data === "0x" ? 0 : log.data).toString();
141
150
 
142
151
  const etherscanErc20Event: EtherscanERC20Event = {
143
- blockNumber: block.number.toString(),
144
- timeStamp: block.timestamp.toString(),
152
+ blockNumber: block?.number.toString() || "0",
153
+ timeStamp: block?.timestamp.toString() || "0",
145
154
  hash: log.transactionHash,
146
- nonce: tx.nonce.toString(),
147
- blockHash: block.hash,
155
+ nonce: tx?.nonce.toString() || "0",
156
+ blockHash: block?.hash || "",
148
157
  from,
149
158
  to,
150
159
  value: amount,
151
160
  tokenName: name,
152
161
  tokenSymbol: ticker,
153
162
  tokenDecimal: decimals,
154
- transactionIndex: block.transactions.indexOf(log.transactionHash).toString(),
155
- gas: tx.gasLimit.toString(),
156
- gasPrice: tx.gasPrice?.toString() || "",
157
- cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
163
+ transactionIndex: block?.transactions.indexOf(log.transactionHash).toString() || "0",
164
+ gas: tx?.gasLimit.toString() || "0",
165
+ gasPrice: tx?.gasPrice?.toString() || "",
166
+ cumulativeGasUsed: receipt?.cumulativeGasUsed.toString() || "0",
158
167
  gasUsed: receipt?.gasUsed?.toString() || "0",
159
- input: tx.data,
160
- confirmations: tx.confirmations.toString(),
161
- contractAddress: tx.to!.toLowerCase(),
168
+ input: tx?.data || "0x",
169
+ confirmations: tx?.confirmations.toString() || "0",
170
+ contractAddress: tx?.to!.toLowerCase() || "",
162
171
  };
163
172
 
164
173
  if (!explorerEtherscanERC20EventsByAddress[from]) {
@@ -176,9 +185,10 @@ const handleERC20Log = async (
176
185
  if (!explorerLedgerOperationByAddress[to]) {
177
186
  explorerLedgerOperationByAddress[to] = new Map<string, LedgerExplorerOperation>();
178
187
  }
188
+ const txHash = tx?.hash;
179
189
  const alreadyExistingOperation =
180
- explorerLedgerOperationByAddress[from]!.get(tx.hash) ||
181
- explorerLedgerOperationByAddress[to]!.get(tx.hash);
190
+ (txHash && explorerLedgerOperationByAddress[from]!.get(txHash)) ||
191
+ (txHash && explorerLedgerOperationByAddress[to]!.get(txHash));
182
192
  const ledgerOperation: LedgerExplorerOperation = alreadyExistingOperation
183
193
  ? {
184
194
  ...alreadyExistingOperation,
@@ -193,16 +203,16 @@ const handleERC20Log = async (
193
203
  }
194
204
  : {
195
205
  hash: log.transactionHash,
196
- transaction_type: receipt.type,
206
+ transaction_type: receipt?.type ?? 0,
197
207
  nonce: "",
198
208
  nonce_value: -1,
199
- value: tx.value.toString(),
200
- gas: tx.gasLimit.toString(),
201
- gas_price: receipt.effectiveGasPrice.toString(),
202
- max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas!.toString() : null,
203
- max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas!.toString() : null,
204
- from: tx.from,
205
- to: tx.to!,
209
+ value: tx?.value.toString() ?? "0",
210
+ gas: tx?.gasLimit.toString() ?? "0",
211
+ gas_price: receipt?.gasPrice.toString() ?? "0",
212
+ max_fee_per_gas: tx?.type === 2 ? tx.maxFeePerGas!.toString() : null,
213
+ max_priority_fee_per_gas: tx?.type === 2 ? tx.maxPriorityFeePerGas!.toString() : null,
214
+ from: tx?.from ?? "0x",
215
+ to: tx?.to ?? "0x0000000000000000000000000000000000000000",
206
216
  transfer_events: [
207
217
  {
208
218
  contract: log.address,
@@ -215,52 +225,49 @@ const handleERC20Log = async (
215
225
  erc1155_transfer_events: [],
216
226
  approval_events: [],
217
227
  actions: [],
218
- confirmations: tx.confirmations,
228
+ confirmations: tx?.confirmations ? await tx.confirmations() : 0,
219
229
  input: null,
220
- gas_used: receipt.gasUsed.toString(),
221
- cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
222
- status: receipt.status!,
223
- received_at: new Date(block.timestamp * 1000).toISOString(),
230
+ gas_used: receipt?.gasUsed.toString() ?? "0",
231
+ cumulative_gas_used: receipt?.cumulativeGasUsed.toString() ?? "0",
232
+ status: receipt?.status ?? 0,
233
+ received_at: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
224
234
  block: {
225
235
  hash: log.blockHash,
226
236
  height: log.blockNumber,
227
- time: new Date(block.timestamp * 1000).toISOString(),
237
+ time: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
228
238
  },
229
239
  };
230
240
  explorerLedgerOperationByAddress[from]!.set(ledgerOperation.hash, ledgerOperation);
231
241
  explorerLedgerOperationByAddress[to]!.set(ledgerOperation.hash, ledgerOperation);
232
242
  };
233
243
 
234
- const handleERC721Log = async (
235
- log: providers.Log,
236
- provider: ethers.providers.StaticJsonRpcProvider,
237
- ) => {
244
+ const handleERC721Log = async (log: ethers.Log, provider: ethers.JsonRpcProvider) => {
238
245
  const [block, tx, receipt] = await Promise.all([
239
246
  provider.getBlock(log.blockHash),
240
247
  provider.getTransaction(log.transactionHash),
241
248
  provider.getTransactionReceipt(log.transactionHash),
242
249
  ]);
243
250
 
244
- const from = safeEncodeEIP55(ethers.utils.defaultAbiCoder.decode(["address"], log.topics[1])[0]);
245
- const to = safeEncodeEIP55(ethers.utils.defaultAbiCoder.decode(["address"], log.topics[2])[0]);
246
- const tokenID = ethers.utils.defaultAbiCoder.decode(["uint256"], log.topics[3])[0].toString();
251
+ const from = safeEncodeEIP55(abiCoder.decode(["address"], log.topics[1])[0]);
252
+ const to = safeEncodeEIP55(abiCoder.decode(["address"], log.topics[2])[0]);
253
+ const tokenID = abiCoder.decode(["uint256"], log.topics[3])[0].toString();
247
254
 
248
255
  const erc721Event: EtherscanERC721Event = {
249
- blockNumber: block.number.toString(),
250
- timeStamp: block.timestamp.toString(),
251
- hash: tx.hash,
252
- nonce: tx.nonce.toString(),
253
- blockHash: block.hash,
256
+ blockNumber: block?.number.toString() || "0",
257
+ timeStamp: block?.timestamp.toString() || "0",
258
+ hash: tx?.hash || "",
259
+ nonce: tx?.nonce.toString() || "0",
260
+ blockHash: block?.hash || "",
254
261
  from,
255
262
  to,
256
- transactionIndex: block.transactions.indexOf(log.transactionHash).toString(),
257
- gas: tx.gasLimit.toString(),
258
- gasPrice: tx.gasPrice?.toString() || "",
259
- cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
263
+ transactionIndex: block?.transactions.indexOf(log.transactionHash).toString() || "0",
264
+ gas: tx?.gasLimit.toString() || "0",
265
+ gasPrice: tx?.gasPrice?.toString() || "",
266
+ cumulativeGasUsed: receipt?.cumulativeGasUsed.toString() || "0",
260
267
  gasUsed: receipt?.gasUsed?.toString() || "0",
261
- input: tx.data,
262
- confirmations: tx.confirmations.toString(),
263
- contractAddress: tx.to!,
268
+ input: tx?.data || "0x",
269
+ confirmations: tx?.confirmations.toString() || "0",
270
+ contractAddress: tx?.to ?? "0x0000000000000000000000000000000000000000",
264
271
  tokenID,
265
272
  tokenName: "tokenName",
266
273
  tokenSymbol: "tokenSymbol",
@@ -282,9 +289,10 @@ const handleERC721Log = async (
282
289
  if (!explorerLedgerOperationByAddress[to]) {
283
290
  explorerLedgerOperationByAddress[to] = new Map<string, LedgerExplorerOperation>();
284
291
  }
292
+ const txHash = tx?.hash;
285
293
  const alreadyExistingOperation =
286
- explorerLedgerOperationByAddress[from]!.get(tx.hash) ||
287
- explorerLedgerOperationByAddress[to]!.get(tx.hash);
294
+ (txHash && explorerLedgerOperationByAddress[from]!.get(txHash)) ||
295
+ (txHash && explorerLedgerOperationByAddress[to]!.get(txHash));
288
296
  const ledgerOperation: LedgerExplorerOperation = alreadyExistingOperation
289
297
  ? {
290
298
  ...alreadyExistingOperation,
@@ -299,16 +307,16 @@ const handleERC721Log = async (
299
307
  }
300
308
  : {
301
309
  hash: log.transactionHash,
302
- transaction_type: receipt.type,
310
+ transaction_type: receipt?.type ?? 0,
303
311
  nonce: "",
304
312
  nonce_value: -1,
305
- value: tx.value.toString(),
306
- gas: tx.gasLimit.toString(),
307
- gas_price: receipt.effectiveGasPrice.toString(),
308
- max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas!.toString() : null,
309
- max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas!.toString() : null,
310
- from: tx.from,
311
- to: tx.to!,
313
+ value: tx?.value.toString() ?? "0",
314
+ gas: tx?.gasLimit.toString() ?? "0",
315
+ gas_price: receipt?.gasPrice.toString() ?? "0",
316
+ max_fee_per_gas: tx?.type === 2 ? tx?.maxFeePerGas!.toString() : null,
317
+ max_priority_fee_per_gas: tx?.type === 2 ? tx?.maxPriorityFeePerGas!.toString() : null,
318
+ from: tx?.from ?? "0x",
319
+ to: tx?.to ?? "0x0000000000000000000000000000000000000000",
312
320
  transfer_events: [],
313
321
  erc721_transfer_events: [
314
322
  {
@@ -321,16 +329,16 @@ const handleERC721Log = async (
321
329
  erc1155_transfer_events: [],
322
330
  approval_events: [],
323
331
  actions: [],
324
- confirmations: tx.confirmations,
332
+ confirmations: tx?.confirmations ? await tx.confirmations() : 0,
325
333
  input: null,
326
- gas_used: receipt.gasUsed.toString(),
327
- cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
328
- status: receipt.status!,
329
- received_at: new Date(block.timestamp * 1000).toISOString(),
334
+ gas_used: receipt?.gasUsed.toString() ?? "0",
335
+ cumulative_gas_used: receipt?.cumulativeGasUsed.toString() ?? "0",
336
+ status: receipt?.status ?? 0,
337
+ received_at: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
330
338
  block: {
331
339
  hash: log.blockHash,
332
340
  height: log.blockNumber,
333
- time: new Date(block.timestamp * 1000).toISOString(),
341
+ time: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
334
342
  },
335
343
  };
336
344
 
@@ -338,42 +346,37 @@ const handleERC721Log = async (
338
346
  explorerLedgerOperationByAddress[to]!.set(ledgerOperation.hash, ledgerOperation);
339
347
  };
340
348
 
341
- const handleERC1155Log = async (
342
- log: providers.Log,
343
- provider: ethers.providers.StaticJsonRpcProvider,
344
- ) => {
349
+ const handleERC1155Log = async (log: ethers.Log, provider: ethers.JsonRpcProvider) => {
345
350
  const [block, tx, receipt] = await Promise.all([
346
351
  provider.getBlock(log.blockHash),
347
352
  provider.getTransaction(log.transactionHash),
348
353
  provider.getTransactionReceipt(log.transactionHash),
349
354
  ]);
350
355
 
351
- const from = safeEncodeEIP55(ethers.utils.defaultAbiCoder.decode(["address"], log.topics[2])[0]);
352
- const to = safeEncodeEIP55(ethers.utils.defaultAbiCoder.decode(["address"], log.topics[3])[0]);
353
- const operator = safeEncodeEIP55(
354
- ethers.utils.defaultAbiCoder.decode(["address"], log.topics[1])[0],
355
- );
356
+ const from = safeEncodeEIP55(abiCoder.decode(["address"], log.topics[2])[0]);
357
+ const to = safeEncodeEIP55(abiCoder.decode(["address"], log.topics[3])[0]);
358
+ const operator = safeEncodeEIP55(abiCoder.decode(["address"], log.topics[1])[0]);
356
359
 
357
- const transfersMap: [string, string][] = ethers.utils.defaultAbiCoder
360
+ const transfersMap: [string, string][] = abiCoder
358
361
  .decode(["uint256", "uint256"], log.data)
359
362
  .map((value, index) => [index === 0 ? "id" : "value", value.toString()]);
360
363
 
361
364
  const etherscanERC1155Events: EtherscanERC1155Event[] = transfersMap.map(([id, value]) => ({
362
- blockNumber: block.number.toString(),
363
- timeStamp: block.timestamp.toString(),
364
- hash: tx.hash,
365
- nonce: tx.nonce.toString(),
366
- blockHash: block.hash,
365
+ blockNumber: block?.number.toString() || "0",
366
+ timeStamp: block?.timestamp.toString() || "0",
367
+ hash: tx?.hash || "",
368
+ nonce: tx?.nonce.toString() || "0",
369
+ blockHash: block?.hash || "",
367
370
  from,
368
371
  to,
369
- transactionIndex: block.transactions.indexOf(log.transactionHash).toString(),
370
- gas: tx.gasLimit.toString(),
371
- gasPrice: tx.gasPrice?.toString() || "",
372
- cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
372
+ transactionIndex: block?.transactions.indexOf(log.transactionHash).toString() || "0",
373
+ gas: tx?.gasLimit.toString() || "0",
374
+ gasPrice: tx?.gasPrice?.toString() || "",
375
+ cumulativeGasUsed: receipt?.cumulativeGasUsed.toString() || "0",
373
376
  gasUsed: receipt?.gasUsed?.toString() || "0",
374
- input: tx.data,
375
- confirmations: tx.confirmations.toString(),
376
- contractAddress: tx.to!,
377
+ input: tx?.data || "0x",
378
+ confirmations: tx?.confirmations.toString() || "0",
379
+ contractAddress: tx?.to ?? "0x0000000000000000000000000000000000000000",
377
380
  tokenID: id,
378
381
  tokenValue: value,
379
382
  tokenName: "tokenName",
@@ -398,9 +401,10 @@ const handleERC1155Log = async (
398
401
  if (!explorerLedgerOperationByAddress[to]) {
399
402
  explorerLedgerOperationByAddress[to] = new Map<string, LedgerExplorerOperation>();
400
403
  }
404
+ const txHash = tx?.hash;
401
405
  const alreadyExistingOperation =
402
- explorerLedgerOperationByAddress[from]!.get(tx.hash) ||
403
- explorerLedgerOperationByAddress[to]!.get(tx.hash);
406
+ (txHash && explorerLedgerOperationByAddress[from]!.get(txHash)) ||
407
+ (txHash && explorerLedgerOperationByAddress[to]!.get(txHash));
404
408
  const ledgerOperation: LedgerExplorerOperation = alreadyExistingOperation
405
409
  ? {
406
410
  ...alreadyExistingOperation,
@@ -415,17 +419,17 @@ const handleERC1155Log = async (
415
419
  ],
416
420
  }
417
421
  : {
418
- hash: log.transactionHash,
419
- transaction_type: receipt.type,
422
+ hash: log.transactionHash || "",
423
+ transaction_type: receipt?.type ?? 0,
420
424
  nonce: "",
421
425
  nonce_value: -1,
422
- value: tx.value.toString(),
423
- gas: tx.gasLimit.toString(),
424
- gas_price: receipt.effectiveGasPrice.toString(),
425
- max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas!.toString() : null,
426
- max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas!.toString() : null,
427
- from: tx.from,
428
- to: tx.to!,
426
+ value: tx?.value.toString() || "0",
427
+ gas: tx?.gasLimit.toString() || "0",
428
+ gas_price: receipt?.gasPrice.toString() || "0",
429
+ max_fee_per_gas: tx?.type === 2 ? tx?.maxFeePerGas!.toString() : null,
430
+ max_priority_fee_per_gas: tx?.type === 2 ? tx?.maxPriorityFeePerGas!.toString() : null,
431
+ from: tx?.from ?? "0x",
432
+ to: tx?.to ?? "0x0000000000000000000000000000000000000000",
429
433
  transfer_events: [],
430
434
  erc721_transfer_events: [],
431
435
  erc1155_transfer_events: [
@@ -439,16 +443,16 @@ const handleERC1155Log = async (
439
443
  ],
440
444
  approval_events: [],
441
445
  actions: [],
442
- confirmations: tx.confirmations,
446
+ confirmations: tx?.confirmations ? await tx.confirmations() : 0,
443
447
  input: null,
444
- gas_used: receipt.gasUsed.toString(),
445
- cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
446
- status: receipt.status!,
447
- received_at: new Date(block.timestamp * 1000).toISOString(),
448
+ gas_used: receipt?.gasUsed.toString() || "0",
449
+ cumulative_gas_used: receipt?.cumulativeGasUsed.toString() || "0",
450
+ status: receipt?.status ?? 0,
451
+ received_at: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
448
452
  block: {
449
453
  hash: log.blockHash,
450
454
  height: log.blockNumber,
451
- time: new Date(block.timestamp * 1000).toISOString(),
455
+ time: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
452
456
  },
453
457
  };
454
458
 
@@ -456,44 +460,41 @@ const handleERC1155Log = async (
456
460
  explorerLedgerOperationByAddress[to]!.set(ledgerOperation.hash, ledgerOperation);
457
461
  };
458
462
 
459
- const handleBlock = async (
460
- blockNumber: number,
461
- provider: ethers.providers.StaticJsonRpcProvider,
462
- ) => {
463
- const block = await provider.getBlockWithTransactions(blockNumber);
463
+ const handleBlock = async (blockNumber: number, provider: ethers.JsonRpcProvider) => {
464
+ const block = await provider.getBlock(blockNumber, true);
464
465
 
465
466
  for (const transaction of block?.transactions || []) {
466
467
  const [tx, receipt, traces] = await Promise.all([
467
- provider.getTransaction(transaction.hash),
468
- provider.getTransactionReceipt(transaction.hash),
469
- provider.send("trace_transaction", [transaction.hash]).catch(() => []) as Promise<
468
+ provider.getTransaction(transaction),
469
+ provider.getTransactionReceipt(transaction),
470
+ provider.send("trace_transaction", [transaction]).catch(() => []) as Promise<
470
471
  TraceTransaction[]
471
472
  >,
472
473
  ]);
473
474
 
474
- const code = transaction.to ? await provider.getCode(transaction.to) : false;
475
- const from = safeEncodeEIP55(transaction.from);
476
- const to = safeEncodeEIP55(transaction.to || "");
475
+ const code = tx?.to ? await provider.getCode(tx?.to) : false;
476
+ const from = safeEncodeEIP55(tx?.from || "");
477
+ const to = safeEncodeEIP55(tx?.to || "");
477
478
  const etherscanOperation: EtherscanOperation = {
478
- blockNumber: block.number.toString(),
479
- timeStamp: block.timestamp.toString(),
480
- hash: transaction.hash,
481
- nonce: transaction.nonce.toString(),
482
- blockHash: block.hash,
483
- transactionIndex: block.transactions.indexOf(transaction).toString(),
479
+ blockNumber: block?.number.toString() || "0",
480
+ timeStamp: block?.timestamp.toString() || "0",
481
+ hash: tx?.hash || "",
482
+ nonce: tx?.nonce.toString() || "0",
483
+ blockHash: block?.hash || "",
484
+ transactionIndex: block?.transactions.indexOf(transaction).toString() || "0",
484
485
  from,
485
486
  to,
486
- value: transaction.value.toBigInt().toString(),
487
- gas: transaction.gasLimit.toString(),
488
- gasPrice: transaction.gasPrice?.toString() || "",
489
- isError: receipt.status === 1 ? "0" : "1",
490
- txreceipt_status: receipt.status!.toString(),
491
- input: transaction.data,
492
- contractAddress: code === "0x" ? "" : transaction.to!,
493
- cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
487
+ value: tx?.value.toString() || "0",
488
+ gas: tx?.gasLimit.toString() || "0",
489
+ gasPrice: tx?.gasPrice?.toString() || "",
490
+ isError: receipt?.status === 1 ? "0" : "1",
491
+ txreceipt_status: receipt?.status!.toString() || "0",
492
+ input: tx?.data,
493
+ contractAddress: code === "0x" ? "" : tx?.to ?? "0x0000000000000000000000000000000000000000",
494
+ cumulativeGasUsed: receipt?.cumulativeGasUsed.toString() || "0",
494
495
  gasUsed: receipt?.gasUsed?.toString() || "0",
495
- confirmations: transaction.confirmations.toString(),
496
- methodId: transaction.data?.length > 10 ? transaction.data.slice(0, 10) : "",
496
+ confirmations: tx?.confirmations.toString() || "0",
497
+ methodId: tx?.data && tx.data.length > 10 ? tx.data.slice(0, 10) : "",
497
498
  functionName: "",
498
499
  };
499
500
 
@@ -513,32 +514,32 @@ const handleBlock = async (
513
514
  explorerLedgerOperationByAddress[to] = new Map<string, LedgerExplorerOperation>();
514
515
  }
515
516
  const ledgerOperation: LedgerExplorerOperation = {
516
- hash: receipt.transactionHash,
517
- transaction_type: receipt.type,
517
+ hash: receipt?.hash || "",
518
+ transaction_type: receipt?.type || 0,
518
519
  nonce: "",
519
520
  nonce_value: -1,
520
- value: tx.value.toString(),
521
- gas: tx.gasLimit.toString(),
522
- gas_price: receipt.effectiveGasPrice.toString(),
523
- max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas!.toString() : null,
524
- max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas!.toString() : null,
525
- from: tx.from,
526
- to: tx.to!,
521
+ value: tx?.value.toString() || "0",
522
+ gas: tx?.gasLimit.toString() || "0",
523
+ gas_price: receipt?.gasPrice.toString() || "",
524
+ max_fee_per_gas: tx?.type === 2 ? tx?.maxFeePerGas!.toString() : null,
525
+ max_priority_fee_per_gas: tx?.type === 2 ? tx?.maxPriorityFeePerGas!.toString() : null,
526
+ from: tx?.from || "",
527
+ to: tx?.to ?? "0x0000000000000000000000000000000000000000",
527
528
  transfer_events: [],
528
529
  erc721_transfer_events: [],
529
530
  erc1155_transfer_events: [],
530
531
  approval_events: [],
531
532
  actions: [],
532
- confirmations: tx.confirmations,
533
+ confirmations: tx?.confirmations ? await tx.confirmations() : 0,
533
534
  input: null,
534
- gas_used: receipt.gasUsed.toString(),
535
- cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
536
- status: receipt.status!,
537
- received_at: new Date(block.timestamp * 1000).toISOString(),
535
+ gas_used: receipt?.gasUsed.toString() || "0",
536
+ cumulative_gas_used: receipt?.cumulativeGasUsed.toString() || "0",
537
+ status: receipt?.status ?? 0,
538
+ received_at: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
538
539
  block: {
539
- hash: receipt.blockHash,
540
- height: receipt.blockNumber,
541
- time: new Date(block.timestamp * 1000).toISOString(),
540
+ hash: receipt?.blockHash || "",
541
+ height: receipt?.blockNumber || 0,
542
+ time: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
542
543
  },
543
544
  };
544
545
  explorerLedgerOperationByAddress[from]!.set(ledgerOperation.hash, ledgerOperation);
@@ -553,20 +554,18 @@ const handleBlock = async (
553
554
  const to = safeEncodeEIP55(action.to || "");
554
555
  const etherscanInternalTransaction: EtherscanInternalTransaction = {
555
556
  blockNumber: blockNumber.toString(),
556
- timeStamp: block.timestamp.toString(),
557
+ timeStamp: block?.timestamp.toString() || "0",
557
558
  hash: transactionHash,
558
559
  from,
559
560
  to,
560
- value: ethers.BigNumber.from(action.value).toBigInt().toString(),
561
+ value: BigInt(action.value).toString() || "0",
561
562
  contractAddress: code === "0x" ? "" : action.to!,
562
563
  input: action.input || "0x",
563
564
  type,
564
- gas: ethers.BigNumber.from(action.gas).toBigInt().toString(),
565
- gasUsed: ethers.BigNumber.from(result?.gasUsed || "0")
566
- .toBigInt()
567
- .toString(),
565
+ gas: BigInt(action.gas).toString(),
566
+ gasUsed: BigInt(result?.gasUsed || "0").toString(),
568
567
  traceId: transactionPosition.toString(),
569
- isError: receipt.status === 1 ? "0" : "1",
568
+ isError: receipt?.status === 1 ? "0" : "1",
570
569
  errCode: "",
571
570
  };
572
571
 
@@ -591,9 +590,10 @@ const handleBlock = async (
591
590
  if (!explorerLedgerOperationByAddress[to]) {
592
591
  explorerLedgerOperationByAddress[to] = new Map();
593
592
  }
593
+ const txHash = tx?.hash;
594
594
  const alreadyExistingOperation =
595
- explorerLedgerOperationByAddress[from]!.get(tx.hash) ||
596
- explorerLedgerOperationByAddress[to]!.get(tx.hash);
595
+ (txHash && explorerLedgerOperationByAddress[from]!.get(txHash)) ||
596
+ (txHash && explorerLedgerOperationByAddress[to]!.get(txHash));
597
597
  const ledgerOperation: LedgerExplorerOperation = alreadyExistingOperation
598
598
  ? {
599
599
  ...alreadyExistingOperation,
@@ -603,27 +603,25 @@ const handleBlock = async (
603
603
  from,
604
604
  to,
605
605
  input: null,
606
- value: ethers.BigNumber.from(action.value).toBigInt().toString(),
607
- gas: ethers.BigNumber.from(action.gas).toBigInt().toString(),
608
- gas_used: ethers.BigNumber.from(result?.gasUsed || "0")
609
- .toBigInt()
610
- .toString(),
606
+ value: BigInt(action.value).toString(),
607
+ gas: BigInt(action.gas).toString(),
608
+ gas_used: BigInt(result?.gasUsed || "0").toString(),
611
609
  error: null,
612
610
  },
613
611
  ],
614
612
  }
615
613
  : {
616
- hash: receipt.transactionHash,
617
- transaction_type: receipt.type,
614
+ hash: receipt?.hash || "",
615
+ transaction_type: receipt?.type ?? 0,
618
616
  nonce: "",
619
617
  nonce_value: -1,
620
- value: tx.value.toString(),
621
- gas: tx.gasLimit.toString(),
622
- gas_price: receipt.effectiveGasPrice.toString(),
623
- max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas!.toString() : null,
624
- max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas!.toString() : null,
625
- from: tx.from,
626
- to: tx.to!,
618
+ value: tx?.value.toString() || "0",
619
+ gas: tx?.gasLimit.toString() || "0",
620
+ gas_price: receipt?.gasPrice.toString() || "0",
621
+ max_fee_per_gas: tx?.type === 2 ? tx?.maxFeePerGas!.toString() : null,
622
+ max_priority_fee_per_gas: tx?.type === 2 ? tx?.maxPriorityFeePerGas!.toString() : null,
623
+ from: tx?.from || "0x",
624
+ to: tx?.to ?? "0x0000000000000000000000000000000000000000",
627
625
  transfer_events: [],
628
626
  erc721_transfer_events: [],
629
627
  erc1155_transfer_events: [],
@@ -633,24 +631,22 @@ const handleBlock = async (
633
631
  from,
634
632
  to,
635
633
  input: null,
636
- value: ethers.BigNumber.from(action.value).toBigInt().toString(),
637
- gas: ethers.BigNumber.from(action.gas).toBigInt().toString(),
638
- gas_used: ethers.BigNumber.from(result?.gasUsed || "0")
639
- .toBigInt()
640
- .toString(),
634
+ value: BigInt(action.value).toString(),
635
+ gas: BigInt(action.gas).toString(),
636
+ gas_used: BigInt(result?.gasUsed || "0").toString(),
641
637
  error: null,
642
638
  },
643
639
  ],
644
- confirmations: tx.confirmations,
640
+ confirmations: tx?.confirmations ? await tx.confirmations() : 0,
645
641
  input: null,
646
- gas_used: receipt.gasUsed.toString(),
647
- cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
648
- status: receipt.status!,
649
- received_at: new Date(block.timestamp * 1000).toISOString(),
642
+ gas_used: receipt?.gasUsed.toString() || "0",
643
+ cumulative_gas_used: receipt?.cumulativeGasUsed.toString() || "0",
644
+ status: receipt?.status ?? 0,
645
+ received_at: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
650
646
  block: {
651
- hash: receipt.blockHash,
652
- height: receipt.blockNumber,
653
- time: new Date(block.timestamp * 1000).toISOString(),
647
+ hash: receipt?.blockHash || "",
648
+ height: receipt?.blockNumber || 0,
649
+ time: new Date((block?.timestamp ?? 0) * 1000).toISOString(),
654
650
  },
655
651
  };
656
652
  explorerLedgerOperationByAddress[from]!.set(ledgerOperation.hash, ledgerOperation);
@@ -668,7 +664,7 @@ export const indexBlocks = async () => {
668
664
  throw new Error("fromBlock is not set");
669
665
  }
670
666
 
671
- const provider = new providers.StaticJsonRpcProvider(process.env.RPC);
667
+ const provider = new ethers.JsonRpcProvider(process.env.RPC);
672
668
  let latestBlockNumber = await provider.getBlockNumber();
673
669
  const toBlock = Math.min(fromBlock + MAX_BLOCK_RANGE, latestBlockNumber);
674
670
  const rangeSize = toBlock - fromBlock + 1;
@@ -687,7 +683,6 @@ export const indexBlocks = async () => {
687
683
  [TRANSFER_EVENTS_TOPICS.ERC20, TRANSFER_EVENTS_TOPICS.ERC721, TRANSFER_EVENTS_TOPICS.ERC1155],
688
684
  ],
689
685
  });
690
-
691
686
  await BlueBirdPromise.map(
692
687
  blocks,
693
688
  async blockNumber =>