Line data Source code
1 : import 'dart:typed_data';
2 : import 'package:walletkit_dart/src/common/logger.dart';
3 : import 'package:walletkit_dart/walletkit_dart.dart';
4 :
5 : base class EtherscanTransaction extends EVMTransaction {
6 1 : const EtherscanTransaction({
7 : required super.hash,
8 : required super.block,
9 : required super.confirmations,
10 : required super.timeMilli,
11 : required super.amount,
12 : required super.fee,
13 : required super.sender,
14 : required super.recipient,
15 : required super.transferMethod,
16 : required super.token,
17 : required super.status,
18 : required super.input,
19 : required super.gasPrice,
20 : super.decodedInput,
21 : required super.gas,
22 : required super.gasUsed,
23 : });
24 :
25 1 : factory EtherscanTransaction.fromJson(
26 : Json json, {
27 : required CoinEntity token,
28 : required String address,
29 : }) {
30 : /// Etherscan V2
31 : if (json
32 : case {
33 2 : 'blockNumber': String block_s,
34 2 : 'timeStamp': String timeStamp_s,
35 2 : 'hash': String hash,
36 2 : 'from': String from,
37 2 : 'to': String to,
38 2 : 'value': String value_s,
39 2 : 'gas': String gas_s,
40 2 : 'gasUsed': String gasUsed_s,
41 2 : 'gasPrice': String gasPrice_s,
42 2 : 'txreceipt_status': String txreceipt_status_s,
43 2 : 'isError': String _,
44 2 : 'input': String input_s,
45 2 : 'functionName': String functionName, // V2 only
46 : }) {
47 1 : final block = block_s.toIntOrNull ?? -1;
48 1 : final confirmations = block_s.toIntOrNull ?? -1;
49 :
50 1 : final timeMilli = timeStamp_s.toIntOrNull ?? -1;
51 1 : final amount = Amount(
52 1 : value: BigInt.tryParse(value_s) ?? BigInt.from(-1),
53 1 : decimals: token.decimals,
54 : );
55 :
56 1 : final fee = Amount(
57 3 : value: gasPrice_s.toBigInt * gasUsed_s.toBigInt,
58 1 : decimals: token.decimals,
59 : );
60 :
61 1 : final gasPrice = Amount(
62 1 : value: gasPrice_s.toBigInt,
63 1 : decimals: token.decimals,
64 : );
65 :
66 1 : final transferMethod = TransactionTransferMethod.fromAddress(address, to, from);
67 :
68 1 : final input = input_s.hexToBytesWithPrefixOrNull ?? Uint8List(0);
69 :
70 : final contractFunction = switch (functionName) {
71 1 : "" => null,
72 1 : _ => ContractFunction.fromTextSignature(textSignature: functionName)
73 : };
74 :
75 : ContractFunctionWithValues? decodedInput;
76 : if (contractFunction != null) {
77 : try {
78 1 : decodedInput = ContractFunction.decode(
79 : data: input,
80 : function: contractFunction,
81 : );
82 : } catch (e, s) {
83 0 : Logger.logError(e, s: s, hint: "Failed to decode contract function");
84 : }
85 : }
86 :
87 1 : return EtherscanTransaction(
88 : hash: hash,
89 : block: block,
90 : confirmations: confirmations,
91 1 : timeMilli: timeMilli * 1000,
92 : amount: amount,
93 : fee: fee,
94 : gasPrice: gasPrice,
95 1 : gasUsed: gasUsed_s.toInt,
96 : sender: from,
97 1 : gas: gas_s.toInt,
98 : recipient: to,
99 : transferMethod: transferMethod,
100 : token: token,
101 1 : status: ConfirmationStatus.fromReceiptStatus(
102 1 : txreceipt_status_s.toIntOrNull ?? -1,
103 : ),
104 : input: input,
105 : decodedInput: decodedInput,
106 : );
107 : }
108 :
109 : /// Etherscan V1
110 : if (json
111 : case {
112 2 : 'blockNumber': String block_s,
113 2 : 'timeStamp': String timeStamp_s,
114 2 : 'hash': String hash,
115 2 : 'from': String from,
116 2 : 'to': String to,
117 2 : 'value': String value_s,
118 2 : 'gas': String gas_s,
119 2 : 'gasUsed': String gasUsed_s,
120 2 : 'gasPrice': String gasPrice_s,
121 2 : 'txreceipt_status': String txreceipt_status_s,
122 2 : 'isError': String _,
123 2 : 'input': String input_s,
124 : }) {
125 1 : final block = block_s.toIntOrNull ?? -1;
126 1 : final confirmations = block_s.toIntOrNull ?? -1;
127 :
128 1 : final timeMilli = timeStamp_s.toIntOrNull ?? -1;
129 1 : final amount = Amount(
130 1 : value: BigInt.tryParse(value_s) ?? BigInt.from(-1),
131 1 : decimals: token.decimals,
132 : );
133 :
134 1 : final fee = Amount(
135 3 : value: gasPrice_s.toBigInt * gasUsed_s.toBigInt,
136 1 : decimals: token.decimals,
137 : );
138 :
139 1 : final gasPrice = Amount(
140 1 : value: gasPrice_s.toBigInt,
141 1 : decimals: token.decimals,
142 : );
143 :
144 1 : final transferMethod = TransactionTransferMethod.fromAddress(address, to, from);
145 :
146 1 : final input = input_s.hexToBytesWithPrefixOrNull ?? Uint8List(0);
147 :
148 1 : return EtherscanTransaction(
149 : hash: hash,
150 : block: block,
151 : confirmations: confirmations,
152 1 : timeMilli: timeMilli * 1000,
153 : amount: amount,
154 : fee: fee,
155 : gasPrice: gasPrice,
156 1 : gasUsed: gasUsed_s.toInt,
157 : sender: from,
158 1 : gas: gas_s.toInt,
159 : recipient: to,
160 : transferMethod: transferMethod,
161 : token: token,
162 1 : status: ConfirmationStatus.fromReceiptStatus(
163 1 : txreceipt_status_s.toIntOrNull ?? -1,
164 : ),
165 : input: input,
166 : );
167 : }
168 :
169 0 : throw UnsupportedError("Invalid JSON for EtherscanTransaction");
170 : }
171 :
172 0 : factory EtherscanTransaction.fromJsonErc1155(
173 : Json json, {
174 : required EvmCoinEntity currency,
175 : required String address,
176 : }) {
177 0 : EtherscanTransaction _createTransaction({
178 : required String block_s,
179 : required String timeStamp_s,
180 : required String hash,
181 : required String from,
182 : required String to,
183 : required String gas_s,
184 : required String gasUsed_s,
185 : required String gasPrice_s,
186 : required String contractAddress,
187 : required String? symbol,
188 : required String? name,
189 : required String tokenID_s,
190 : required String input,
191 : String? tokenValue,
192 : }) {
193 0 : final block = block_s.toIntOrNull ?? -1;
194 0 : final confirmations = block_s.toIntOrNull ?? -1;
195 0 : final timeMilli = timeStamp_s.toIntOrNull ?? -1;
196 0 : final token = ERC1155Entity(
197 : name: name ?? "N.Av",
198 : symbol: symbol ?? "N.Av",
199 : contractAddress: contractAddress,
200 0 : chainID: currency.chainID,
201 0 : tokenId: BigInt.tryParse(tokenID_s) ?? BigInt.from(-1),
202 : );
203 0 : final amount = Amount(
204 : value:
205 0 : tokenValue != null ? (BigInt.tryParse(tokenValue) ?? BigInt.from(0)) : BigInt.from(0),
206 : decimals: 0,
207 : );
208 0 : final fee = Amount(
209 0 : value: gasPrice_s.toBigInt * gasUsed_s.toBigInt,
210 0 : decimals: currency.decimals,
211 : );
212 0 : final gasPrice = Amount(
213 0 : value: gasPrice_s.toBigInt,
214 0 : decimals: currency.decimals,
215 : );
216 0 : final transferMethod = TransactionTransferMethod.fromAddress(address, to, from);
217 :
218 0 : return EtherscanTransaction(
219 : hash: hash,
220 : block: block,
221 : confirmations: confirmations,
222 0 : timeMilli: timeMilli * 1000,
223 : amount: amount,
224 : fee: fee,
225 0 : gasUsed: gasUsed_s.toInt,
226 : sender: from,
227 : recipient: to,
228 0 : gas: gas_s.toInt,
229 : gasPrice: gasPrice,
230 : transferMethod: transferMethod,
231 : token: token,
232 0 : status: ConfirmationStatus.fromConfirmations(confirmations),
233 0 : input: input.hexToBytesWithPrefixOrNull ?? Uint8List(0),
234 : );
235 : }
236 :
237 : if (json
238 : case {
239 0 : 'blockNumber': String block_s,
240 0 : 'timeStamp': String timeStamp_s,
241 0 : 'hash': String hash,
242 0 : 'from': String from,
243 0 : 'to': String to,
244 0 : 'tokenValue': String value_s,
245 0 : 'gas': String gas_s,
246 0 : 'gasUsed': String gasUsed_s,
247 0 : 'gasPrice': String gasPrice_s,
248 0 : 'contractAddress': String contractAddress,
249 0 : 'tokenSymbol': String? symbol,
250 0 : 'tokenName': String? name,
251 0 : 'tokenID': String tokenID_s,
252 0 : 'input': String? input,
253 : }) {
254 0 : return _createTransaction(
255 : block_s: block_s,
256 : timeStamp_s: timeStamp_s,
257 : hash: hash,
258 : from: from,
259 : to: to,
260 : gas_s: gas_s,
261 : gasUsed_s: gasUsed_s,
262 : gasPrice_s: gasPrice_s,
263 : contractAddress: contractAddress,
264 : symbol: symbol,
265 : name: name,
266 : tokenID_s: tokenID_s,
267 : input: input ?? "",
268 : tokenValue: value_s,
269 : );
270 : }
271 : if (json
272 : case {
273 0 : 'blockNumber': String block_s,
274 0 : 'timeStamp': String timeStamp_s,
275 0 : 'hash': String hash,
276 0 : 'from': String from,
277 0 : 'to': String to,
278 0 : 'gas': String gas_s,
279 0 : 'gasUsed': String gasUsed_s,
280 0 : 'gasPrice': String gasPrice_s,
281 0 : 'contractAddress': String contractAddress,
282 0 : 'tokenSymbol': String? symbol,
283 0 : 'tokenName': String? name,
284 0 : 'tokenID': String tokenID_s,
285 0 : 'input': String input,
286 : }) {
287 0 : return _createTransaction(
288 : block_s: block_s,
289 : timeStamp_s: timeStamp_s,
290 : hash: hash,
291 : from: from,
292 : to: to,
293 : gas_s: gas_s,
294 : gasUsed_s: gasUsed_s,
295 : gasPrice_s: gasPrice_s,
296 : contractAddress: contractAddress,
297 : symbol: symbol,
298 : name: name,
299 : tokenID_s: tokenID_s,
300 : input: input,
301 : );
302 : }
303 0 : throw UnsupportedError("Invalid JSON for EtherscanTransaction");
304 : }
305 :
306 1 : factory EtherscanTransaction.fromJsonErc20(
307 : Json json, {
308 : required EvmCoinEntity currency,
309 : required String address,
310 : }) {
311 : if (json
312 : case {
313 2 : 'blockNumber': String block_s,
314 2 : 'timeStamp': String timeStamp_s,
315 2 : 'hash': String hash,
316 2 : 'from': String from,
317 2 : 'to': String to,
318 2 : 'value': String value_s,
319 2 : 'gas': String gas_s,
320 2 : 'gasUsed': String gasUsed_s,
321 2 : 'gasPrice': String gasPrice_s,
322 2 : 'input': String input,
323 2 : 'contractAddress': String contractAddress,
324 2 : 'tokenDecimal': String decimals_s,
325 2 : 'tokenSymbol': String symbol,
326 2 : 'tokenName': String name,
327 : }) {
328 1 : final block = block_s.toIntOrNull ?? -1;
329 1 : final confirmations = block_s.toIntOrNull ?? -1;
330 :
331 1 : final timeMilli = timeStamp_s.toIntOrNull ?? -1;
332 :
333 1 : final token = ERC20Entity(
334 : name: name,
335 : symbol: symbol,
336 1 : decimals: decimals_s.toIntOrNull ?? 18,
337 : contractAddress: contractAddress,
338 1 : chainID: currency.chainID,
339 : );
340 :
341 1 : final amount = Amount(
342 1 : value: BigInt.tryParse(value_s) ?? BigInt.from(-1),
343 1 : decimals: token.decimals,
344 : );
345 :
346 1 : final fee = Amount(
347 3 : value: gasPrice_s.toBigInt * gasUsed_s.toBigInt,
348 1 : decimals: currency.decimals,
349 : );
350 :
351 1 : final gasPrice = Amount(
352 1 : value: gasPrice_s.toBigInt,
353 1 : decimals: currency.decimals,
354 : );
355 :
356 1 : final transferMethod = TransactionTransferMethod.fromAddress(address, to, from);
357 :
358 1 : return EtherscanTransaction(
359 : hash: hash,
360 : block: block,
361 : confirmations: confirmations,
362 1 : timeMilli: timeMilli * 1000,
363 : amount: amount,
364 : fee: fee,
365 1 : gasUsed: gasUsed_s.toInt,
366 : sender: from,
367 : recipient: to,
368 1 : gas: gas_s.toInt,
369 : gasPrice: gasPrice,
370 : transferMethod: transferMethod,
371 : token: token,
372 1 : status: ConfirmationStatus.fromConfirmations(confirmations),
373 2 : input: input.hexToBytesWithPrefixOrNull ?? Uint8List(0),
374 : );
375 : }
376 0 : throw UnsupportedError("Invalid JSON for EtherscanTransaction");
377 : }
378 :
379 1 : factory EtherscanTransaction.fromJsonErc721(
380 : Json json, {
381 : required EvmCoinEntity currency,
382 : required String address,
383 : }) {
384 : if (json
385 : case {
386 2 : 'blockNumber': String block_s,
387 2 : 'timeStamp': String timeStamp_s,
388 2 : 'hash': String hash,
389 2 : 'from': String from,
390 2 : 'to': String to,
391 2 : 'gas': String gas_s,
392 2 : 'gasUsed': String gasUsed_s,
393 2 : 'gasPrice': String gasPrice_s,
394 2 : 'contractAddress': String contractAddress,
395 2 : 'tokenID': String tokenID_s,
396 2 : 'tokenName': String name,
397 2 : 'tokenSymbol': String symbol,
398 2 : 'tokenDecimal': String _,
399 : }) {
400 1 : final block = block_s.toIntOrNull ?? -1;
401 1 : final confirmations = block_s.toIntOrNull ?? -1;
402 :
403 1 : final timeMilli = timeStamp_s.toIntOrNull ?? -1;
404 :
405 1 : final tokenId = BigInt.tryParse(tokenID_s) ?? BigInt.from(-1);
406 1 : final token = ERC721Entity(
407 : name: name,
408 : symbol: symbol,
409 : contractAddress: contractAddress,
410 1 : chainID: currency.chainID,
411 : tokenId: tokenId,
412 : );
413 :
414 1 : final amount = Amount(
415 1 : value: BigInt.zero,
416 : decimals: 0,
417 : );
418 :
419 1 : final fee = Amount(
420 3 : value: gasPrice_s.toBigInt * gasUsed_s.toBigInt,
421 1 : decimals: currency.decimals,
422 : );
423 :
424 1 : final gasPrice = Amount(
425 1 : value: gasPrice_s.toBigInt,
426 1 : decimals: currency.decimals,
427 : );
428 :
429 1 : final transferMethod = TransactionTransferMethod.fromAddress(address, to, from);
430 :
431 1 : return EtherscanTransaction(
432 : hash: hash,
433 : block: block,
434 : confirmations: confirmations,
435 1 : timeMilli: timeMilli * 1000,
436 : amount: amount,
437 : fee: fee,
438 : sender: from,
439 : gasPrice: gasPrice,
440 1 : gas: gas_s.toInt,
441 1 : gasUsed: gasUsed_s.toInt,
442 : recipient: to,
443 : transferMethod: transferMethod,
444 : token: token,
445 1 : status: ConfirmationStatus.fromConfirmations(confirmations),
446 1 : input: Uint8List(0),
447 : );
448 : }
449 0 : throw UnsupportedError("Invalid JSON for EtherscanTransaction");
450 : }
451 : }
|