@ledgerhq/coin-evm 2.16.0-nightly.2 → 2.16.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 (151) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.unimportedrc.json +1 -2
  3. package/CHANGELOG.md +4 -29
  4. package/jest.config.js +0 -1
  5. package/lib/__tests__/coin-tester/anvil.d.ts +3 -0
  6. package/lib/__tests__/coin-tester/anvil.d.ts.map +1 -0
  7. package/lib/__tests__/coin-tester/anvil.js +83 -0
  8. package/lib/__tests__/coin-tester/anvil.js.map +1 -0
  9. package/lib/__tests__/coin-tester/helpers.d.ts +34 -0
  10. package/lib/__tests__/coin-tester/helpers.d.ts.map +1 -0
  11. package/lib/__tests__/coin-tester/helpers.js +119 -0
  12. package/lib/__tests__/coin-tester/helpers.js.map +1 -0
  13. package/lib/__tests__/coin-tester/indexer.d.ts +6 -0
  14. package/lib/__tests__/coin-tester/indexer.d.ts.map +1 -0
  15. package/lib/__tests__/coin-tester/indexer.js +647 -0
  16. package/lib/__tests__/coin-tester/indexer.js.map +1 -0
  17. package/lib/__tests__/coin-tester/scenarii/blast.d.ts +5 -0
  18. package/lib/__tests__/coin-tester/scenarii/blast.d.ts.map +1 -0
  19. package/lib/__tests__/coin-tester/scenarii/blast.js +130 -0
  20. package/lib/__tests__/coin-tester/scenarii/blast.js.map +1 -0
  21. package/lib/__tests__/coin-tester/scenarii/ethereum.d.ts +5 -0
  22. package/lib/__tests__/coin-tester/scenarii/ethereum.d.ts.map +1 -0
  23. package/lib/__tests__/coin-tester/scenarii/ethereum.js +209 -0
  24. package/lib/__tests__/coin-tester/scenarii/ethereum.js.map +1 -0
  25. package/lib/__tests__/coin-tester/scenarii/polygon.d.ts +5 -0
  26. package/lib/__tests__/coin-tester/scenarii/polygon.d.ts.map +1 -0
  27. package/lib/__tests__/coin-tester/scenarii/polygon.js +203 -0
  28. package/lib/__tests__/coin-tester/scenarii/polygon.js.map +1 -0
  29. package/lib/__tests__/coin-tester/scenarii/scroll.d.ts +5 -0
  30. package/lib/__tests__/coin-tester/scenarii/scroll.d.ts.map +1 -0
  31. package/lib/__tests__/coin-tester/scenarii/scroll.js +130 -0
  32. package/lib/__tests__/coin-tester/scenarii/scroll.js.map +1 -0
  33. package/lib/__tests__/coin-tester/scenarii/sonic.d.ts +5 -0
  34. package/lib/__tests__/coin-tester/scenarii/sonic.d.ts.map +1 -0
  35. package/lib/__tests__/coin-tester/scenarii/sonic.js +124 -0
  36. package/lib/__tests__/coin-tester/scenarii/sonic.js.map +1 -0
  37. package/lib/__tests__/coin-tester/scenarii.test.d.ts +5 -0
  38. package/lib/__tests__/coin-tester/scenarii.test.d.ts.map +1 -0
  39. package/lib/__tests__/coin-tester/scenarii.test.js +77 -0
  40. package/lib/__tests__/coin-tester/scenarii.test.js.map +1 -0
  41. package/lib/__tests__/unit/hw-signMessage.unit.test.js +10 -19
  42. package/lib/__tests__/unit/hw-signMessage.unit.test.js.map +1 -1
  43. package/lib/__tests__/unit/nftResolvers.unit.test.js +32 -3
  44. package/lib/__tests__/unit/nftResolvers.unit.test.js.map +1 -1
  45. package/lib/__tests__/unit/signOperation.unit.test.js +2 -5
  46. package/lib/__tests__/unit/signOperation.unit.test.js.map +1 -1
  47. package/lib/api/nft/index.d.ts +12 -13
  48. package/lib/api/nft/index.d.ts.map +1 -1
  49. package/lib/api/nft/index.js +1 -13
  50. package/lib/api/nft/index.js.map +1 -1
  51. package/lib/hw-signMessage.d.ts.map +1 -1
  52. package/lib/hw-signMessage.js +51 -20
  53. package/lib/hw-signMessage.js.map +1 -1
  54. package/lib/nftResolvers.d.ts +5 -3
  55. package/lib/nftResolvers.d.ts.map +1 -1
  56. package/lib/nftResolvers.js +23 -2
  57. package/lib/nftResolvers.js.map +1 -1
  58. package/lib/signOperation.d.ts +1 -1
  59. package/lib/signOperation.d.ts.map +1 -1
  60. package/lib/signOperation.js +44 -33
  61. package/lib/signOperation.js.map +1 -1
  62. package/lib/types/signer.d.ts +13 -5
  63. package/lib/types/signer.d.ts.map +1 -1
  64. package/lib-es/__tests__/coin-tester/anvil.d.ts +3 -0
  65. package/lib-es/__tests__/coin-tester/anvil.d.ts.map +1 -0
  66. package/lib-es/__tests__/coin-tester/anvil.js +52 -0
  67. package/lib-es/__tests__/coin-tester/anvil.js.map +1 -0
  68. package/lib-es/__tests__/coin-tester/helpers.d.ts +34 -0
  69. package/lib-es/__tests__/coin-tester/helpers.d.ts.map +1 -0
  70. package/lib-es/__tests__/coin-tester/helpers.js +111 -0
  71. package/lib-es/__tests__/coin-tester/helpers.js.map +1 -0
  72. package/lib-es/__tests__/coin-tester/indexer.d.ts +6 -0
  73. package/lib-es/__tests__/coin-tester/indexer.d.ts.map +1 -0
  74. package/lib-es/__tests__/coin-tester/indexer.js +637 -0
  75. package/lib-es/__tests__/coin-tester/indexer.js.map +1 -0
  76. package/lib-es/__tests__/coin-tester/scenarii/blast.d.ts +5 -0
  77. package/lib-es/__tests__/coin-tester/scenarii/blast.d.ts.map +1 -0
  78. package/lib-es/__tests__/coin-tester/scenarii/blast.js +124 -0
  79. package/lib-es/__tests__/coin-tester/scenarii/blast.js.map +1 -0
  80. package/lib-es/__tests__/coin-tester/scenarii/ethereum.d.ts +5 -0
  81. package/lib-es/__tests__/coin-tester/scenarii/ethereum.d.ts.map +1 -0
  82. package/lib-es/__tests__/coin-tester/scenarii/ethereum.js +203 -0
  83. package/lib-es/__tests__/coin-tester/scenarii/ethereum.js.map +1 -0
  84. package/lib-es/__tests__/coin-tester/scenarii/polygon.d.ts +5 -0
  85. package/lib-es/__tests__/coin-tester/scenarii/polygon.d.ts.map +1 -0
  86. package/lib-es/__tests__/coin-tester/scenarii/polygon.js +197 -0
  87. package/lib-es/__tests__/coin-tester/scenarii/polygon.js.map +1 -0
  88. package/lib-es/__tests__/coin-tester/scenarii/scroll.d.ts +5 -0
  89. package/lib-es/__tests__/coin-tester/scenarii/scroll.d.ts.map +1 -0
  90. package/lib-es/__tests__/coin-tester/scenarii/scroll.js +124 -0
  91. package/lib-es/__tests__/coin-tester/scenarii/scroll.js.map +1 -0
  92. package/lib-es/__tests__/coin-tester/scenarii/sonic.d.ts +5 -0
  93. package/lib-es/__tests__/coin-tester/scenarii/sonic.d.ts.map +1 -0
  94. package/lib-es/__tests__/coin-tester/scenarii/sonic.js +118 -0
  95. package/lib-es/__tests__/coin-tester/scenarii/sonic.js.map +1 -0
  96. package/lib-es/__tests__/coin-tester/scenarii.test.d.ts +5 -0
  97. package/lib-es/__tests__/coin-tester/scenarii.test.d.ts.map +1 -0
  98. package/lib-es/__tests__/coin-tester/scenarii.test.js +74 -0
  99. package/lib-es/__tests__/coin-tester/scenarii.test.js.map +1 -0
  100. package/lib-es/__tests__/unit/hw-signMessage.unit.test.js +10 -19
  101. package/lib-es/__tests__/unit/hw-signMessage.unit.test.js.map +1 -1
  102. package/lib-es/__tests__/unit/nftResolvers.unit.test.js +32 -3
  103. package/lib-es/__tests__/unit/nftResolvers.unit.test.js.map +1 -1
  104. package/lib-es/__tests__/unit/signOperation.unit.test.js +2 -5
  105. package/lib-es/__tests__/unit/signOperation.unit.test.js.map +1 -1
  106. package/lib-es/api/nft/index.d.ts +12 -13
  107. package/lib-es/api/nft/index.d.ts.map +1 -1
  108. package/lib-es/api/nft/index.js +0 -11
  109. package/lib-es/api/nft/index.js.map +1 -1
  110. package/lib-es/hw-signMessage.d.ts.map +1 -1
  111. package/lib-es/hw-signMessage.js +51 -20
  112. package/lib-es/hw-signMessage.js.map +1 -1
  113. package/lib-es/nftResolvers.d.ts +5 -3
  114. package/lib-es/nftResolvers.d.ts.map +1 -1
  115. package/lib-es/nftResolvers.js +23 -2
  116. package/lib-es/nftResolvers.js.map +1 -1
  117. package/lib-es/signOperation.d.ts +1 -1
  118. package/lib-es/signOperation.d.ts.map +1 -1
  119. package/lib-es/signOperation.js +45 -34
  120. package/lib-es/signOperation.js.map +1 -1
  121. package/lib-es/types/signer.d.ts +13 -5
  122. package/lib-es/types/signer.d.ts.map +1 -1
  123. package/package.json +14 -13
  124. package/src/__tests__/coin-tester/.env.example +7 -0
  125. package/src/__tests__/coin-tester/anvil.ts +67 -0
  126. package/src/__tests__/coin-tester/docker-compose.yml +8 -0
  127. package/src/__tests__/coin-tester/helpers.ts +151 -0
  128. package/src/__tests__/coin-tester/indexer.ts +776 -0
  129. package/src/__tests__/coin-tester/scenarii/blast.ts +152 -0
  130. package/src/__tests__/coin-tester/scenarii/ethereum.ts +247 -0
  131. package/src/__tests__/coin-tester/scenarii/polygon.ts +232 -0
  132. package/src/__tests__/coin-tester/scenarii/scroll.ts +156 -0
  133. package/src/__tests__/coin-tester/scenarii/sonic.ts +150 -0
  134. package/src/__tests__/coin-tester/scenarii.test.ts +78 -0
  135. package/src/__tests__/unit/hw-signMessage.unit.test.ts +25 -20
  136. package/src/__tests__/unit/nftResolvers.unit.test.ts +39 -6
  137. package/src/__tests__/unit/signOperation.unit.test.ts +5 -5
  138. package/src/api/nft/index.ts +2 -19
  139. package/src/hw-signMessage.ts +59 -28
  140. package/src/nftResolvers.ts +32 -3
  141. package/src/signOperation.ts +69 -56
  142. package/src/types/signer.ts +20 -5
  143. package/lib/abis/index.d.ts +0 -7
  144. package/lib/abis/index.d.ts.map +0 -1
  145. package/lib/abis/index.js +0 -17
  146. package/lib/abis/index.js.map +0 -1
  147. package/lib-es/abis/index.d.ts +0 -7
  148. package/lib-es/abis/index.d.ts.map +0 -1
  149. package/lib-es/abis/index.js +0 -7
  150. package/lib-es/abis/index.js.map +0 -1
  151. package/src/abis/index.ts +0 -13
@@ -0,0 +1,647 @@
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.initMswHandlers = exports.indexBlocks = exports.setBlock = exports.resetIndexer = void 0;
7
+ const bignumber_js_1 = __importDefault(require("bignumber.js"));
8
+ const node_1 = require("msw/node");
9
+ const bluebird_1 = __importDefault(require("bluebird"));
10
+ const msw_1 = require("msw");
11
+ const ethers_1 = require("ethers");
12
+ const erc1155_abi_json_1 = __importDefault(require("../../abis/erc1155.abi.json"));
13
+ const erc721_abi_json_1 = __importDefault(require("../../abis/erc721.abi.json"));
14
+ const erc20_abi_json_1 = __importDefault(require("../../abis/erc20.abi.json"));
15
+ const logic_1 = require("../../logic");
16
+ const MAX_BLOCK_RANGE = 1024;
17
+ const ERC20Interface = new ethers_1.utils.Interface(erc20_abi_json_1.default);
18
+ const ERC721Interface = new ethers_1.utils.Interface(erc721_abi_json_1.default);
19
+ const ERC1155Interface = new ethers_1.utils.Interface(erc1155_abi_json_1.default);
20
+ const TRANSFER_EVENTS_TOPICS = {
21
+ ERC20: ERC20Interface.getEventTopic("Transfer"),
22
+ ERC721: ERC721Interface.getEventTopic("Transfer"),
23
+ ERC1155: ERC1155Interface.getEventTopic("TransferSingle"),
24
+ };
25
+ const explorerEtherscanOperationByAddress = {};
26
+ const explorerEtherscanERC20EventsByAddress = {};
27
+ const explorerEtherscanERC721EventsByAddress = {};
28
+ const explorerEtherscanERC1155EventsByAddress = {};
29
+ const explorerEtherscanInternalByAddress = {};
30
+ const explorerLedgerOperationByAddress = {};
31
+ const resetIndexer = () => {
32
+ (0, exports.setBlock)(0);
33
+ server?.close();
34
+ for (const address in explorerEtherscanOperationByAddress) {
35
+ delete explorerEtherscanOperationByAddress[address];
36
+ }
37
+ for (const address in explorerEtherscanERC20EventsByAddress) {
38
+ delete explorerEtherscanERC20EventsByAddress[address];
39
+ }
40
+ for (const address in explorerEtherscanERC721EventsByAddress) {
41
+ delete explorerEtherscanERC721EventsByAddress[address];
42
+ }
43
+ for (const address in explorerEtherscanERC1155EventsByAddress) {
44
+ delete explorerEtherscanERC1155EventsByAddress[address];
45
+ }
46
+ for (const address in explorerEtherscanInternalByAddress) {
47
+ delete explorerEtherscanInternalByAddress[address];
48
+ }
49
+ for (const address in explorerLedgerOperationByAddress) {
50
+ delete explorerLedgerOperationByAddress[address];
51
+ }
52
+ };
53
+ exports.resetIndexer = resetIndexer;
54
+ const handleLog = async (log, provider) => {
55
+ const contractDecimals = await provider
56
+ .call({ to: log.address, data: ERC20Interface.encodeFunctionData("decimals") })
57
+ .then(res => (!res || res === "0x" ? false : true));
58
+ const isERC20 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC20 && contractDecimals;
59
+ const isERC721 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC721 && !contractDecimals;
60
+ const isERC1155 = log.topics[0] === TRANSFER_EVENTS_TOPICS.ERC1155;
61
+ if (isERC20) {
62
+ return handleERC20Log(log, provider);
63
+ }
64
+ else if (isERC721) {
65
+ return handleERC721Log(log, provider);
66
+ }
67
+ else if (isERC1155) {
68
+ return handleERC1155Log(log, provider);
69
+ }
70
+ };
71
+ const handleERC20Log = async (log, provider) => {
72
+ const [name, ticker, decimals, block, tx, receipt] = await Promise.all([
73
+ provider
74
+ .call({ to: log.address, data: ERC20Interface.encodeFunctionData("name") })
75
+ .then(res => ethers_1.ethers.utils.defaultAbiCoder.decode(["string"], res)[0]),
76
+ provider
77
+ .call({ to: log.address, data: ERC20Interface.encodeFunctionData("symbol") })
78
+ .then(res => ethers_1.ethers.utils.defaultAbiCoder.decode(["string"], res)[0]),
79
+ provider
80
+ .call({ to: log.address, data: ERC20Interface.encodeFunctionData("decimals") })
81
+ .then(res => new bignumber_js_1.default(res).toString()),
82
+ provider.getBlock(log.blockHash),
83
+ provider.getTransaction(log.transactionHash),
84
+ provider.getTransactionReceipt(log.transactionHash),
85
+ ]);
86
+ const from = (0, logic_1.safeEncodeEIP55)(ethers_1.ethers.utils.defaultAbiCoder.decode(["address"], log.topics[1])[0]);
87
+ const to = (0, logic_1.safeEncodeEIP55)(ethers_1.ethers.utils.defaultAbiCoder.decode(["address"], log.topics[2])[0]);
88
+ const amount = ethers_1.ethers.BigNumber.from(log.data === "0x" ? 0 : log.data).toString();
89
+ const etherscanErc20Event = {
90
+ blockNumber: block.number.toString(),
91
+ timeStamp: block.timestamp.toString(),
92
+ hash: log.transactionHash,
93
+ nonce: tx.nonce.toString(),
94
+ blockHash: block.hash,
95
+ from,
96
+ to,
97
+ value: amount,
98
+ tokenName: name,
99
+ tokenSymbol: ticker,
100
+ tokenDecimal: decimals,
101
+ transactionIndex: block.transactions.indexOf(log.transactionHash).toString(),
102
+ gas: tx.gasLimit.toString(),
103
+ gasPrice: tx.gasPrice?.toString() || "",
104
+ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
105
+ gasUsed: receipt?.gasUsed?.toString() || "0",
106
+ input: tx.data,
107
+ confirmations: tx.confirmations.toString(),
108
+ contractAddress: tx.to.toLowerCase(),
109
+ };
110
+ if (!explorerEtherscanERC20EventsByAddress[from]) {
111
+ explorerEtherscanERC20EventsByAddress[from] = new Map();
112
+ }
113
+ if (!explorerEtherscanERC20EventsByAddress[to]) {
114
+ explorerEtherscanERC20EventsByAddress[to] = new Map();
115
+ }
116
+ explorerEtherscanERC20EventsByAddress[from].set(etherscanErc20Event.hash, etherscanErc20Event);
117
+ explorerEtherscanERC20EventsByAddress[to].set(etherscanErc20Event.hash, etherscanErc20Event);
118
+ if (!explorerLedgerOperationByAddress[from]) {
119
+ explorerLedgerOperationByAddress[from] = new Map();
120
+ }
121
+ if (!explorerLedgerOperationByAddress[to]) {
122
+ explorerLedgerOperationByAddress[to] = new Map();
123
+ }
124
+ const alreadyExistingOperation = explorerLedgerOperationByAddress[from].get(tx.hash) ||
125
+ explorerLedgerOperationByAddress[to].get(tx.hash);
126
+ const ledgerOperation = alreadyExistingOperation
127
+ ? {
128
+ ...alreadyExistingOperation,
129
+ transfer_events: [
130
+ {
131
+ contract: log.address,
132
+ count: amount,
133
+ from,
134
+ to,
135
+ },
136
+ ],
137
+ }
138
+ : {
139
+ hash: log.transactionHash,
140
+ transaction_type: receipt.type,
141
+ nonce: "",
142
+ nonce_value: -1,
143
+ value: tx.value.toString(),
144
+ gas: tx.gasLimit.toString(),
145
+ gas_price: receipt.effectiveGasPrice.toString(),
146
+ max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas.toString() : null,
147
+ max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas.toString() : null,
148
+ from: tx.from,
149
+ to: tx.to,
150
+ transfer_events: [
151
+ {
152
+ contract: log.address,
153
+ count: amount,
154
+ from,
155
+ to,
156
+ },
157
+ ],
158
+ erc721_transfer_events: [],
159
+ erc1155_transfer_events: [],
160
+ approval_events: [],
161
+ actions: [],
162
+ confirmations: tx.confirmations,
163
+ input: null,
164
+ gas_used: receipt.gasUsed.toString(),
165
+ cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
166
+ status: receipt.status,
167
+ received_at: new Date(block.timestamp * 1000).toISOString(),
168
+ block: {
169
+ hash: log.blockHash,
170
+ height: log.blockNumber,
171
+ time: new Date(block.timestamp * 1000).toISOString(),
172
+ },
173
+ };
174
+ explorerLedgerOperationByAddress[from].set(ledgerOperation.hash, ledgerOperation);
175
+ explorerLedgerOperationByAddress[to].set(ledgerOperation.hash, ledgerOperation);
176
+ };
177
+ const handleERC721Log = async (log, provider) => {
178
+ const [block, tx, receipt] = await Promise.all([
179
+ provider.getBlock(log.blockHash),
180
+ provider.getTransaction(log.transactionHash),
181
+ provider.getTransactionReceipt(log.transactionHash),
182
+ ]);
183
+ const from = (0, logic_1.safeEncodeEIP55)(ethers_1.ethers.utils.defaultAbiCoder.decode(["address"], log.topics[1])[0]);
184
+ const to = (0, logic_1.safeEncodeEIP55)(ethers_1.ethers.utils.defaultAbiCoder.decode(["address"], log.topics[2])[0]);
185
+ const tokenID = ethers_1.ethers.utils.defaultAbiCoder.decode(["uint256"], log.topics[3])[0].toString();
186
+ const erc721Event = {
187
+ blockNumber: block.number.toString(),
188
+ timeStamp: block.timestamp.toString(),
189
+ hash: tx.hash,
190
+ nonce: tx.nonce.toString(),
191
+ blockHash: block.hash,
192
+ from,
193
+ to,
194
+ transactionIndex: block.transactions.indexOf(log.transactionHash).toString(),
195
+ gas: tx.gasLimit.toString(),
196
+ gasPrice: tx.gasPrice?.toString() || "",
197
+ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
198
+ gasUsed: receipt?.gasUsed?.toString() || "0",
199
+ input: tx.data,
200
+ confirmations: tx.confirmations.toString(),
201
+ contractAddress: tx.to,
202
+ tokenID,
203
+ tokenName: "tokenName",
204
+ tokenSymbol: "tokenSymbol",
205
+ tokenDecimal: "0",
206
+ };
207
+ if (!explorerEtherscanERC721EventsByAddress[from]) {
208
+ explorerEtherscanERC721EventsByAddress[from] = new Map();
209
+ }
210
+ if (!explorerEtherscanERC721EventsByAddress[to]) {
211
+ explorerEtherscanERC721EventsByAddress[to] = new Map();
212
+ }
213
+ explorerEtherscanERC721EventsByAddress[from].set(erc721Event.hash, erc721Event);
214
+ explorerEtherscanERC721EventsByAddress[to].set(erc721Event.hash, erc721Event);
215
+ if (!explorerLedgerOperationByAddress[from]) {
216
+ explorerLedgerOperationByAddress[from] = new Map();
217
+ }
218
+ if (!explorerLedgerOperationByAddress[to]) {
219
+ explorerLedgerOperationByAddress[to] = new Map();
220
+ }
221
+ const alreadyExistingOperation = explorerLedgerOperationByAddress[from].get(tx.hash) ||
222
+ explorerLedgerOperationByAddress[to].get(tx.hash);
223
+ const ledgerOperation = alreadyExistingOperation
224
+ ? {
225
+ ...alreadyExistingOperation,
226
+ erc721_transfer_events: [
227
+ {
228
+ contract: log.address,
229
+ sender: from,
230
+ receiver: to,
231
+ token_id: tokenID,
232
+ },
233
+ ],
234
+ }
235
+ : {
236
+ hash: log.transactionHash,
237
+ transaction_type: receipt.type,
238
+ nonce: "",
239
+ nonce_value: -1,
240
+ value: tx.value.toString(),
241
+ gas: tx.gasLimit.toString(),
242
+ gas_price: receipt.effectiveGasPrice.toString(),
243
+ max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas.toString() : null,
244
+ max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas.toString() : null,
245
+ from: tx.from,
246
+ to: tx.to,
247
+ transfer_events: [],
248
+ erc721_transfer_events: [
249
+ {
250
+ contract: log.address,
251
+ sender: from,
252
+ receiver: to,
253
+ token_id: tokenID,
254
+ },
255
+ ],
256
+ erc1155_transfer_events: [],
257
+ approval_events: [],
258
+ actions: [],
259
+ confirmations: tx.confirmations,
260
+ input: null,
261
+ gas_used: receipt.gasUsed.toString(),
262
+ cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
263
+ status: receipt.status,
264
+ received_at: new Date(block.timestamp * 1000).toISOString(),
265
+ block: {
266
+ hash: log.blockHash,
267
+ height: log.blockNumber,
268
+ time: new Date(block.timestamp * 1000).toISOString(),
269
+ },
270
+ };
271
+ explorerLedgerOperationByAddress[from].set(ledgerOperation.hash, ledgerOperation);
272
+ explorerLedgerOperationByAddress[to].set(ledgerOperation.hash, ledgerOperation);
273
+ };
274
+ const handleERC1155Log = async (log, provider) => {
275
+ const [block, tx, receipt] = await Promise.all([
276
+ provider.getBlock(log.blockHash),
277
+ provider.getTransaction(log.transactionHash),
278
+ provider.getTransactionReceipt(log.transactionHash),
279
+ ]);
280
+ const from = (0, logic_1.safeEncodeEIP55)(ethers_1.ethers.utils.defaultAbiCoder.decode(["address"], log.topics[2])[0]);
281
+ const to = (0, logic_1.safeEncodeEIP55)(ethers_1.ethers.utils.defaultAbiCoder.decode(["address"], log.topics[3])[0]);
282
+ const operator = (0, logic_1.safeEncodeEIP55)(ethers_1.ethers.utils.defaultAbiCoder.decode(["address"], log.topics[1])[0]);
283
+ const transfersMap = ethers_1.ethers.utils.defaultAbiCoder
284
+ .decode(["uint256", "uint256"], log.data)
285
+ .map((value, index) => [index === 0 ? "id" : "value", value.toString()]);
286
+ const etherscanERC1155Events = transfersMap.map(([id, value]) => ({
287
+ blockNumber: block.number.toString(),
288
+ timeStamp: block.timestamp.toString(),
289
+ hash: tx.hash,
290
+ nonce: tx.nonce.toString(),
291
+ blockHash: block.hash,
292
+ from,
293
+ to,
294
+ transactionIndex: block.transactions.indexOf(log.transactionHash).toString(),
295
+ gas: tx.gasLimit.toString(),
296
+ gasPrice: tx.gasPrice?.toString() || "",
297
+ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
298
+ gasUsed: receipt?.gasUsed?.toString() || "0",
299
+ input: tx.data,
300
+ confirmations: tx.confirmations.toString(),
301
+ contractAddress: tx.to,
302
+ tokenID: id,
303
+ tokenValue: value,
304
+ tokenName: "tokenName",
305
+ tokenSymbol: "tokenSymbol",
306
+ }));
307
+ etherscanERC1155Events.forEach(erc1155Event => {
308
+ if (!explorerEtherscanERC1155EventsByAddress[from]) {
309
+ explorerEtherscanERC1155EventsByAddress[from] = new Map();
310
+ }
311
+ if (!explorerEtherscanERC1155EventsByAddress[to]) {
312
+ explorerEtherscanERC1155EventsByAddress[to] = new Map();
313
+ }
314
+ explorerEtherscanERC1155EventsByAddress[from].set(erc1155Event.hash, erc1155Event);
315
+ explorerEtherscanERC1155EventsByAddress[to].set(erc1155Event.hash, erc1155Event);
316
+ });
317
+ if (!explorerLedgerOperationByAddress[from]) {
318
+ explorerLedgerOperationByAddress[from] = new Map();
319
+ }
320
+ if (!explorerLedgerOperationByAddress[to]) {
321
+ explorerLedgerOperationByAddress[to] = new Map();
322
+ }
323
+ const alreadyExistingOperation = explorerLedgerOperationByAddress[from].get(tx.hash) ||
324
+ explorerLedgerOperationByAddress[to].get(tx.hash);
325
+ const ledgerOperation = alreadyExistingOperation
326
+ ? {
327
+ ...alreadyExistingOperation,
328
+ erc1155_transfer_events: [
329
+ {
330
+ contract: log.address,
331
+ sender: from,
332
+ receiver: to,
333
+ operator,
334
+ transfers: [Object.fromEntries(transfersMap)],
335
+ },
336
+ ],
337
+ }
338
+ : {
339
+ hash: log.transactionHash,
340
+ transaction_type: receipt.type,
341
+ nonce: "",
342
+ nonce_value: -1,
343
+ value: tx.value.toString(),
344
+ gas: tx.gasLimit.toString(),
345
+ gas_price: receipt.effectiveGasPrice.toString(),
346
+ max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas.toString() : null,
347
+ max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas.toString() : null,
348
+ from: tx.from,
349
+ to: tx.to,
350
+ transfer_events: [],
351
+ erc721_transfer_events: [],
352
+ erc1155_transfer_events: [
353
+ {
354
+ contract: log.address,
355
+ sender: from,
356
+ receiver: to,
357
+ operator,
358
+ transfers: [Object.fromEntries(transfersMap)],
359
+ },
360
+ ],
361
+ approval_events: [],
362
+ actions: [],
363
+ confirmations: tx.confirmations,
364
+ input: null,
365
+ gas_used: receipt.gasUsed.toString(),
366
+ cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
367
+ status: receipt.status,
368
+ received_at: new Date(block.timestamp * 1000).toISOString(),
369
+ block: {
370
+ hash: log.blockHash,
371
+ height: log.blockNumber,
372
+ time: new Date(block.timestamp * 1000).toISOString(),
373
+ },
374
+ };
375
+ explorerLedgerOperationByAddress[from].set(ledgerOperation.hash, ledgerOperation);
376
+ explorerLedgerOperationByAddress[to].set(ledgerOperation.hash, ledgerOperation);
377
+ };
378
+ const handleBlock = async (blockNumber, provider) => {
379
+ const block = await provider.getBlockWithTransactions(blockNumber);
380
+ for (const transaction of block?.transactions || []) {
381
+ const [tx, receipt, traces] = await Promise.all([
382
+ provider.getTransaction(transaction.hash),
383
+ provider.getTransactionReceipt(transaction.hash),
384
+ provider.send("trace_transaction", [transaction.hash]).catch(() => []),
385
+ ]);
386
+ const code = transaction.to ? await provider.getCode(transaction.to) : false;
387
+ const from = (0, logic_1.safeEncodeEIP55)(transaction.from);
388
+ const to = (0, logic_1.safeEncodeEIP55)(transaction.to || "");
389
+ const etherscanOperation = {
390
+ blockNumber: block.number.toString(),
391
+ timeStamp: block.timestamp.toString(),
392
+ hash: transaction.hash,
393
+ nonce: transaction.nonce.toString(),
394
+ blockHash: block.hash,
395
+ transactionIndex: block.transactions.indexOf(transaction).toString(),
396
+ from,
397
+ to,
398
+ value: transaction.value.toBigInt().toString(),
399
+ gas: transaction.gasLimit.toString(),
400
+ gasPrice: transaction.gasPrice?.toString() || "",
401
+ isError: receipt.status === 1 ? "0" : "1",
402
+ txreceipt_status: receipt.status.toString(),
403
+ input: transaction.data,
404
+ contractAddress: code === "0x" ? "" : transaction.to,
405
+ cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
406
+ gasUsed: receipt?.gasUsed?.toString() || "0",
407
+ confirmations: transaction.confirmations.toString(),
408
+ methodId: transaction.data?.length > 10 ? transaction.data.slice(0, 10) : "",
409
+ functionName: "",
410
+ };
411
+ if (!explorerEtherscanOperationByAddress[from]) {
412
+ explorerEtherscanOperationByAddress[from] = new Map();
413
+ }
414
+ if (!explorerEtherscanOperationByAddress[to]) {
415
+ explorerEtherscanOperationByAddress[to] = new Map();
416
+ }
417
+ explorerEtherscanOperationByAddress[from].set(etherscanOperation.hash, etherscanOperation);
418
+ explorerEtherscanOperationByAddress[to].set(etherscanOperation.hash, etherscanOperation);
419
+ if (!explorerLedgerOperationByAddress[from]) {
420
+ explorerLedgerOperationByAddress[from] = new Map();
421
+ }
422
+ if (!explorerLedgerOperationByAddress[to]) {
423
+ explorerLedgerOperationByAddress[to] = new Map();
424
+ }
425
+ const ledgerOperation = {
426
+ hash: receipt.transactionHash,
427
+ transaction_type: receipt.type,
428
+ nonce: "",
429
+ nonce_value: -1,
430
+ value: tx.value.toString(),
431
+ gas: tx.gasLimit.toString(),
432
+ gas_price: receipt.effectiveGasPrice.toString(),
433
+ max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas.toString() : null,
434
+ max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas.toString() : null,
435
+ from: tx.from,
436
+ to: tx.to,
437
+ transfer_events: [],
438
+ erc721_transfer_events: [],
439
+ erc1155_transfer_events: [],
440
+ approval_events: [],
441
+ actions: [],
442
+ confirmations: tx.confirmations,
443
+ 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
+ block: {
449
+ hash: receipt.blockHash,
450
+ height: receipt.blockNumber,
451
+ time: new Date(block.timestamp * 1000).toISOString(),
452
+ },
453
+ };
454
+ explorerLedgerOperationByAddress[from].set(ledgerOperation.hash, ledgerOperation);
455
+ explorerLedgerOperationByAddress[to].set(ledgerOperation.hash, ledgerOperation);
456
+ for (const { action, result, type, transactionHash, transactionPosition } of traces.filter(trace => trace.type === "call")) {
457
+ if (action?.callType !== "call")
458
+ continue;
459
+ const code = action.to ? await provider.getCode(action.to) : false;
460
+ const from = (0, logic_1.safeEncodeEIP55)(action.from || "");
461
+ const to = (0, logic_1.safeEncodeEIP55)(action.to || "");
462
+ const etherscanInternalTransaction = {
463
+ blockNumber: blockNumber.toString(),
464
+ timeStamp: block.timestamp.toString(),
465
+ hash: transactionHash,
466
+ from,
467
+ to,
468
+ value: ethers_1.ethers.BigNumber.from(action.value).toBigInt().toString(),
469
+ contractAddress: code === "0x" ? "" : action.to,
470
+ input: action.input || "0x",
471
+ type,
472
+ gas: ethers_1.ethers.BigNumber.from(action.gas).toBigInt().toString(),
473
+ gasUsed: ethers_1.ethers.BigNumber.from(result?.gasUsed || "0")
474
+ .toBigInt()
475
+ .toString(),
476
+ traceId: transactionPosition.toString(),
477
+ isError: receipt.status === 1 ? "0" : "1",
478
+ errCode: "",
479
+ };
480
+ if (!explorerEtherscanInternalByAddress[from]) {
481
+ explorerEtherscanInternalByAddress[from] = new Map();
482
+ }
483
+ if (!explorerEtherscanInternalByAddress[to]) {
484
+ explorerEtherscanInternalByAddress[to] = new Map();
485
+ }
486
+ explorerEtherscanInternalByAddress[from].set(etherscanInternalTransaction.hash, etherscanInternalTransaction);
487
+ explorerEtherscanInternalByAddress[to].set(etherscanInternalTransaction.hash, etherscanInternalTransaction);
488
+ if (!explorerLedgerOperationByAddress[from]) {
489
+ explorerLedgerOperationByAddress[from] = new Map();
490
+ }
491
+ if (!explorerLedgerOperationByAddress[to]) {
492
+ explorerLedgerOperationByAddress[to] = new Map();
493
+ }
494
+ const alreadyExistingOperation = explorerLedgerOperationByAddress[from].get(tx.hash) ||
495
+ explorerLedgerOperationByAddress[to].get(tx.hash);
496
+ const ledgerOperation = alreadyExistingOperation
497
+ ? {
498
+ ...alreadyExistingOperation,
499
+ actions: [
500
+ ...alreadyExistingOperation.actions,
501
+ {
502
+ from,
503
+ to,
504
+ input: null,
505
+ value: ethers_1.ethers.BigNumber.from(action.value).toBigInt().toString(),
506
+ gas: ethers_1.ethers.BigNumber.from(action.gas).toBigInt().toString(),
507
+ gas_used: ethers_1.ethers.BigNumber.from(result?.gasUsed || "0")
508
+ .toBigInt()
509
+ .toString(),
510
+ error: null,
511
+ },
512
+ ],
513
+ }
514
+ : {
515
+ hash: receipt.transactionHash,
516
+ transaction_type: receipt.type,
517
+ nonce: "",
518
+ nonce_value: -1,
519
+ value: tx.value.toString(),
520
+ gas: tx.gasLimit.toString(),
521
+ gas_price: receipt.effectiveGasPrice.toString(),
522
+ max_fee_per_gas: tx.type === 2 ? tx.maxFeePerGas.toString() : null,
523
+ max_priority_fee_per_gas: tx.type === 2 ? tx.maxPriorityFeePerGas.toString() : null,
524
+ from: tx.from,
525
+ to: tx.to,
526
+ transfer_events: [],
527
+ erc721_transfer_events: [],
528
+ erc1155_transfer_events: [],
529
+ approval_events: [],
530
+ actions: [
531
+ {
532
+ from,
533
+ to,
534
+ input: null,
535
+ value: ethers_1.ethers.BigNumber.from(action.value).toBigInt().toString(),
536
+ gas: ethers_1.ethers.BigNumber.from(action.gas).toBigInt().toString(),
537
+ gas_used: ethers_1.ethers.BigNumber.from(result?.gasUsed || "0")
538
+ .toBigInt()
539
+ .toString(),
540
+ error: null,
541
+ },
542
+ ],
543
+ confirmations: tx.confirmations,
544
+ input: null,
545
+ gas_used: receipt.gasUsed.toString(),
546
+ cumulative_gas_used: receipt.cumulativeGasUsed.toString(),
547
+ status: receipt.status,
548
+ received_at: new Date(block.timestamp * 1000).toISOString(),
549
+ block: {
550
+ hash: receipt.blockHash,
551
+ height: receipt.blockNumber,
552
+ time: new Date(block.timestamp * 1000).toISOString(),
553
+ },
554
+ };
555
+ explorerLedgerOperationByAddress[from].set(ledgerOperation.hash, ledgerOperation);
556
+ }
557
+ }
558
+ };
559
+ let fromBlock;
560
+ const setBlock = (blockHeight) => {
561
+ fromBlock = blockHeight;
562
+ };
563
+ exports.setBlock = setBlock;
564
+ const indexBlocks = async () => {
565
+ if (!fromBlock) {
566
+ throw new Error("fromBlock is not set");
567
+ }
568
+ const provider = new ethers_1.providers.StaticJsonRpcProvider(process.env.RPC);
569
+ let latestBlockNumber = await provider.getBlockNumber();
570
+ const toBlock = Math.min(fromBlock + MAX_BLOCK_RANGE, latestBlockNumber);
571
+ const rangeSize = toBlock - fromBlock + 1;
572
+ const blocks = rangeSize > 1
573
+ ? Array(rangeSize)
574
+ .fill("")
575
+ .map((_, index) => fromBlock + index)
576
+ .sort((a, b) => a - b)
577
+ : [latestBlockNumber];
578
+ const logs = await provider.getLogs({
579
+ fromBlock,
580
+ toBlock,
581
+ topics: [
582
+ [TRANSFER_EVENTS_TOPICS.ERC20, TRANSFER_EVENTS_TOPICS.ERC721, TRANSFER_EVENTS_TOPICS.ERC1155],
583
+ ],
584
+ });
585
+ await bluebird_1.default.map(blocks, async (blockNumber) => Promise.all([
586
+ handleBlock(blockNumber, provider),
587
+ new Promise(resolve => setTimeout(resolve, 500)),
588
+ ]), { concurrency: 10 });
589
+ await bluebird_1.default.map(logs, async (log) => Promise.all([handleLog(log, provider), new Promise(resolve => setTimeout(resolve, 500))]), { concurrency: 10 });
590
+ latestBlockNumber = await provider.getBlockNumber();
591
+ (0, exports.setBlock)(Math.min(toBlock, latestBlockNumber));
592
+ console.log(`Indexing completed ✓`);
593
+ };
594
+ exports.indexBlocks = indexBlocks;
595
+ let server;
596
+ const initMswHandlers = (currencyConfig) => {
597
+ const handlers = [];
598
+ if (currencyConfig.explorer.type === "ledger") {
599
+ handlers.push(msw_1.http.get("*.ledger.com/blockchain/v4/*/address/*/txs", async ({ request, params }) => {
600
+ const address = params["2"];
601
+ const response = await fetch((0, msw_1.bypass)(request)).then(res => res.json());
602
+ const opsMap = explorerLedgerOperationByAddress[address || ""] || new Map();
603
+ response.data.push(...opsMap.values());
604
+ return msw_1.HttpResponse.json(response);
605
+ }));
606
+ }
607
+ else if (currencyConfig.explorer.type !== "none") {
608
+ handlers.push(msw_1.http.get(currencyConfig.explorer.uri, async ({ request }) => {
609
+ const uri = new URL(request.url).searchParams;
610
+ const address = uri.get("address");
611
+ const action = uri.get("action");
612
+ const response = await fetch((0, msw_1.bypass)(request)).then(res => res.json());
613
+ switch (action) {
614
+ case "txlist": {
615
+ const opsMap = explorerEtherscanOperationByAddress[address || ""] || new Map();
616
+ response.result.push(...opsMap.values());
617
+ break;
618
+ }
619
+ case "tokentx": {
620
+ const erc20EventsMap = explorerEtherscanERC20EventsByAddress[address || ""] || new Map();
621
+ response.result.push(...erc20EventsMap.values());
622
+ break;
623
+ }
624
+ case "tokennfttx": {
625
+ const erc721EventsMap = explorerEtherscanERC721EventsByAddress[address || ""] || new Map();
626
+ response.result.push(...erc721EventsMap.values());
627
+ break;
628
+ }
629
+ case "token1155tx": {
630
+ const erc1155EventsMap = explorerEtherscanERC1155EventsByAddress[address || ""] || new Map();
631
+ response.result.push(...erc1155EventsMap.values());
632
+ break;
633
+ }
634
+ case "txlistinternal": {
635
+ const internalMap = explorerEtherscanInternalByAddress[address || ""] || new Map();
636
+ response.result.push(...internalMap.values());
637
+ break;
638
+ }
639
+ }
640
+ return msw_1.HttpResponse.json(response);
641
+ }));
642
+ }
643
+ server = (0, node_1.setupServer)(...handlers);
644
+ server.listen({ onUnhandledRequest: "bypass" });
645
+ };
646
+ exports.initMswHandlers = initMswHandlers;
647
+ //# sourceMappingURL=indexer.js.map