@pioneer-platform/eth-network 8.5.7 → 8.6.1

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.
package/lib/index.js DELETED
@@ -1,1717 +0,0 @@
1
- "use strict";
2
- /*
3
- ETH Network tools
4
-
5
-
6
- Goals:
7
-
8
- *
9
-
10
-
11
- */
12
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
- if (k2 === undefined) k2 = k;
14
- var desc = Object.getOwnPropertyDescriptor(m, k);
15
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
- desc = { enumerable: true, get: function() { return m[k]; } };
17
- }
18
- Object.defineProperty(o, k2, desc);
19
- }) : (function(o, m, k, k2) {
20
- if (k2 === undefined) k2 = k;
21
- o[k2] = m[k];
22
- }));
23
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
- Object.defineProperty(o, "default", { enumerable: true, value: v });
25
- }) : function(o, v) {
26
- o["default"] = v;
27
- });
28
- var __importStar = (this && this.__importStar) || (function () {
29
- var ownKeys = function(o) {
30
- ownKeys = Object.getOwnPropertyNames || function (o) {
31
- var ar = [];
32
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
- return ar;
34
- };
35
- return ownKeys(o);
36
- };
37
- return function (mod) {
38
- if (mod && mod.__esModule) return mod;
39
- var result = {};
40
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
- __setModuleDefault(result, mod);
42
- return result;
43
- };
44
- })();
45
- var __importDefault = (this && this.__importDefault) || function (mod) {
46
- return (mod && mod.__esModule) ? mod : { "default": mod };
47
- };
48
- Object.defineProperty(exports, "__esModule", { value: true });
49
- const TAG = " | eth-network | ";
50
- let Web3 = require('web3');
51
- // @ts-ignore
52
- const ethers = __importStar(require("ethers"));
53
- // @ts-ignore
54
- const BigNumber = require('bignumber.js');
55
- //
56
- const Axios = require('axios');
57
- const https = require('https');
58
- const axios = Axios.create({
59
- httpsAgent: new https.Agent({
60
- rejectUnauthorized: false
61
- })
62
- });
63
- const request = require("request-promise");
64
- //blockbook
65
- let blockbook = require("@pioneer-platform/blockbook");
66
- const Web3Utils = require('web3-utils');
67
- const providers_1 = require("@ethersproject/providers");
68
- const abi_1 = require("@ethersproject/abi");
69
- const utils_1 = require("./utils");
70
- const xchain_util_1 = require("@xchainjs/xchain-util");
71
- const etherscanAPI = __importStar(require("./etherscan-api"));
72
- const log = require('@pioneer-platform/loggerdog')();
73
- let ETHPLORER_API_KEY = process.env['ETHPLORER_API_KEY'] || 'freekey';
74
- const nodes_1 = __importDefault(require("@pioneer-platform/nodes"));
75
- let wait = require('wait-promise');
76
- let sleep = wait.sleep;
77
- //
78
- let web3;
79
- let web3Base;
80
- let ETHERSCAN;
81
- let ETHPLORER;
82
- let PROVIDER;
83
- let NODE_URL;
84
- //TODO precision module
85
- let BASE = 1000000000000000000;
86
- // Remove deprecated import
87
- // import { Interface } from '@ethersproject/abi'
88
- const constant_1 = require("./constant"); // Replace with your actual module file path
89
- const BASE_NODE = 'https://base.llamarpc.com';
90
- const NODES = [];
91
- module.exports = {
92
- init: function (settings) {
93
- //blockbook.init()
94
- //log.debug("node: ",process.env['PARITY_ARCHIVE_NODE'])
95
- //load
96
- // @ts-ignore
97
- let web3nodes = nodes_1.default.getWeb3Nodes();
98
- for (let i = 0; i < web3nodes.length; i++) {
99
- let node = web3nodes[i];
100
- if (!node.networkId)
101
- throw Error('missing networkId');
102
- if (!node.service)
103
- throw Error('missing networkId');
104
- NODES.push(node);
105
- }
106
- if (!settings) {
107
- //use default
108
- web3 = new Web3(process.env['PARITY_ARCHIVE_NODE']);
109
- web3Base = new Web3(process.env['BASE_NODE'] || 'https://base.llamarpc.com');
110
- ETHERSCAN = new providers_1.EtherscanProvider('mainnet', process.env['ETHERSCAN_API_KEY']);
111
- PROVIDER = new ethers.providers.InfuraProvider('mainnet', process.env['INFURA_API_KEY']);
112
- NODE_URL = process.env['PARITY_ARCHIVE_NODE'];
113
- }
114
- else if (settings.testnet) {
115
- if (!process.env['INFURA_TESTNET_ROPSTEN'])
116
- throw Error("Missing INFURA_TESTNET_ROPSTEN");
117
- if (!process.env['ETHERSCAN_API_KEY'])
118
- throw Error("Missing ETHERSCAN_API_KEY");
119
- //if testnet
120
- web3 = new Web3(process.env['INFURA_TESTNET_ROPSTEN']);
121
- NODE_URL = process.env['INFURA_TESTNET_ROPSTEN'];
122
- ETHERSCAN = new providers_1.EtherscanProvider('ropsten', process.env['ETHERSCAN_API_KEY']);
123
- PROVIDER = new ethers.providers.InfuraProvider('ropsten', process.env['INFURA_API_KEY']);
124
- }
125
- else if (settings.network) {
126
- //force a network setting
127
- //TODO
128
- }
129
- else {
130
- //TODO if custom
131
- web3 = new Web3(process.env['PARITY_ARCHIVE_NODE']);
132
- }
133
- },
134
- getNodes: function () {
135
- return NODES;
136
- },
137
- addNode: function (node) {
138
- if (!node.networkId)
139
- throw Error('missing networkId');
140
- if (!node.service)
141
- throw Error('missing networkId');
142
- return NODES.push(node);
143
- },
144
- addNodes: function (nodes) {
145
- for (let i = 0; i < nodes.length; i++) {
146
- let node = nodes[i];
147
- if (!node.networkId)
148
- throw Error('missing networkId');
149
- if (!node.service)
150
- throw Error('missing networkId');
151
- return NODES.push(node);
152
- }
153
- },
154
- decodeTx: function (tx) {
155
- return decode_tx(tx);
156
- },
157
- getInfo: function () {
158
- return check_online_status();
159
- },
160
- getAllowance: function (token, spender, sender) {
161
- return get_allowance(token, spender, sender);
162
- },
163
- getNonce: function (address) {
164
- return web3.eth.getTransactionCount(address, 'pending');
165
- },
166
- getTxCount: function (address, options) {
167
- return get_tx_count(address, options);
168
- },
169
- getFees: function (params) {
170
- return get_fees(params);
171
- },
172
- estimateFee: async function (asset, params) {
173
- if (!params)
174
- throw Error("params required");
175
- if (!params.asset && !asset)
176
- throw Error("Asset or params.asset required");
177
- //create asset locally with correct types
178
- let assetForEstimate = asset ? asset : params.asset;
179
- const { average: averageGP, fast: fastGP, fastest: fastestGP } = (0, utils_1.getDefaultGasPrices)();
180
- let assetAddress;
181
- // @ts-ignore
182
- if (assetForEstimate && (0, xchain_util_1.assetToString)(assetForEstimate) !== (0, xchain_util_1.assetToString)(xchain_util_1.AssetETH)) {
183
- // @ts-ignore
184
- assetAddress = (0, utils_1.getTokenAddress)(assetForEstimate);
185
- }
186
- let gasLimit;
187
- if (assetAddress && assetAddress !== utils_1.ETHAddress) {
188
- if (!params.sender || !params.recipient)
189
- throw Error("missing params! need sender and recipient on token tx!");
190
- let contract = new ethers.Contract(assetAddress, constant_1.ERC20ABI, PROVIDER);
191
- gasLimit = params.data
192
- ? await contract.estimateGas.transfer(params.recipient, params.data, { from: params.sender })
193
- : await contract.estimateGas.transfer(params.recipient, 1, { from: params.sender }); // amount = 1 as a dummy value
194
- }
195
- else {
196
- // ETH transfer
197
- if (!params.sender || !params.recipient)
198
- throw Error("missing params! need sender and recipient");
199
- const gasEstimate = await PROVIDER.estimateGas({
200
- from: params.sender,
201
- to: params.recipient,
202
- value: ethers.utils.parseEther('0.000001') // using dummy ETH amount for gas calculation
203
- });
204
- gasLimit = gasEstimate.add(0); // Add extra gas as buffer
205
- console.log("ETH gasEstimate: ", gasEstimate.toString());
206
- console.log("ETH gasEstimate + buffer: ", gasLimit.toString());
207
- }
208
- return {
209
- gasPrices: {
210
- average: averageGP,
211
- fast: fastGP,
212
- fastest: fastestGP
213
- },
214
- gasLimit,
215
- fees: {
216
- type: 'byte',
217
- average: (0, utils_1.getFee)({ gasPrice: averageGP, gasLimit }),
218
- fast: (0, utils_1.getFee)({ gasPrice: fastGP, gasLimit }),
219
- fastest: (0, utils_1.getFee)({ gasPrice: fastestGP, gasLimit })
220
- }
221
- };
222
- },
223
- getMemoEncoded: function (params) {
224
- return get_memo_data(params);
225
- },
226
- getStreamInfo: function (streamId) {
227
- return get_stream(streamId);
228
- },
229
- getSymbolFromContract: function (contract) {
230
- return get_symbol_from_contract(contract);
231
- },
232
- getTransferData: function (toAddress, amount, contract) {
233
- return get_token_transfer_data(toAddress, amount, contract);
234
- },
235
- getPoolPositions: function (address) {
236
- return get_pool_positions(address);
237
- },
238
- getAllPioneers: function () {
239
- return get_all_pioneers();
240
- },
241
- getAllPioneersBase: function () {
242
- return get_all_pioneers_base();
243
- },
244
- getAllTokensEth: function (address) {
245
- return get_all_tokens_blockbook(address);
246
- },
247
- getPercentPool: function (amountFox, amountEth, poolAddress) {
248
- return get_pool_percent(amountFox, amountEth, poolAddress);
249
- },
250
- checkAirdropClaim: function (address) {
251
- return check_airdrop_claim(address);
252
- },
253
- buildAirdropClaim: function (address) {
254
- return build_airdrop_claim(address);
255
- },
256
- // getFees: function (params: XFeesParams & FeesParams): Promise<Fees> {
257
- // return get_fees()
258
- // },
259
- // estimateGasNormalTx: function (address:string): Promise<BaseAmount> {
260
- // return get_balance_tokens(address)
261
- // },
262
- // estimateGasERC20Tx: function (address:string): Promise<BaseAmount> {
263
- // return get_balance_tokens(address)
264
- // },
265
- getGasPrice: function () {
266
- return web3.eth.getGasPrice();
267
- },
268
- getTransaction: function (txid) {
269
- return get_transaction(txid);
270
- },
271
- getTransactions: function (address, options) {
272
- return get_transactions(address, options);
273
- },
274
- getBalance: function (address) {
275
- return get_balance(address);
276
- },
277
- getBalances: function (addresses) {
278
- return get_balances(addresses);
279
- },
280
- getBalanceAddress: function (address) {
281
- return get_balance(address);
282
- },
283
- getBalanceToken: function (address, token) {
284
- return get_balance_token(address, token);
285
- },
286
- getBalanceTokens: function (address) {
287
- return get_balance_tokens(address);
288
- },
289
- //gasPrice by network
290
- getGasPriceByNetwork: function (networkId) {
291
- return get_gas_price_by_network(networkId);
292
- },
293
- // Nonce by network
294
- getNonceByNetwork: function (networkId, address) {
295
- return get_nonce_by_network(networkId, address);
296
- },
297
- // Estimate Gas by network
298
- estimateGasByNetwork: function (networkId, transaction) {
299
- return estimate_gas_by_network(networkId, transaction);
300
- },
301
- getTransactionByNetwork: function (networkId, transaction) {
302
- return get_transaction_by_network(networkId, transaction);
303
- },
304
- getTransactionsByNetwork: function (networkId, address, options) {
305
- return get_transactions_by_network(networkId, address, options);
306
- },
307
- //
308
- getBalanceAddressByNetwork: function (networkId, address) {
309
- return get_balance_by_network(networkId, address);
310
- },
311
- getBalanceTokenByNetwork: function (networkId, address, token) {
312
- return get_balance_token_by_network(networkId, address, token);
313
- },
314
- getBalanceTokensByNetwork: function (networkId, address) {
315
- return get_balance_tokens_by_network(networkId, address);
316
- },
317
- broadcastByNetwork: function (networkId, tx) {
318
- return broadcast_transaction_by_network(networkId, tx);
319
- },
320
- broadcast: function (tx) {
321
- return broadcast_transaction(tx);
322
- }
323
- };
324
- const get_transactions_by_network = async function (networkId, address, options = { fromBlock: 'latest', toBlock: 'latest' }) {
325
- let tag = TAG + " | get_transactions_by_network | ";
326
- try {
327
- // Find the node in the NODES array
328
- let node = NODES.find((n) => n.networkId === networkId);
329
- if (!node)
330
- throw new Error("101: Missing node for network " + networkId);
331
- // Initialize a new web3 instance
332
- let web3 = new Web3(node.service);
333
- const checksumAddress = web3.utils.toChecksumAddress(address);
334
- // Get the current block height
335
- const currentBlockHeight = await web3.eth.getBlockNumber();
336
- // Define the block range
337
- let fromBlock = options?.fromBlock || 0;
338
- let toBlock = options?.toBlock || "latest";
339
- if (toBlock === "latest") {
340
- toBlock = currentBlockHeight;
341
- }
342
- if (fromBlock === "latest") {
343
- fromBlock = currentBlockHeight;
344
- }
345
- // Adjust the range to ensure it scans only the last 100 blocks if the range is too large
346
- if (fromBlock < toBlock - 100) {
347
- fromBlock = toBlock - 100;
348
- }
349
- log.info(tag, `Scanning from block ${fromBlock} to block ${toBlock}`);
350
- let transactions = [];
351
- // Loop through each block in the range
352
- for (let blockNumber = fromBlock; blockNumber <= toBlock; blockNumber++) {
353
- let block = await web3.eth.getBlock(blockNumber, true); // Retrieve block with full transactions
354
- log.info(tag, "block ", block.transactions.length);
355
- if (block && block.transactions) {
356
- for (let tx of block.transactions) {
357
- // Check if the transaction is initiated by the specified address
358
- if (tx.from?.toLowerCase() === checksumAddress.toLowerCase()) {
359
- // Collect detailed transaction info
360
- let receipt = await web3.eth.getTransactionReceipt(tx.hash);
361
- transactions.push({
362
- txHash: tx.hash,
363
- from: tx.from,
364
- to: tx.to,
365
- value: tx.value,
366
- gas: tx.gas,
367
- gasPrice: tx.gasPrice,
368
- blockNumber: tx.blockNumber,
369
- receipt,
370
- });
371
- }
372
- }
373
- }
374
- }
375
- // Fetch current and pending nonces for the address
376
- let currentNonce = await web3.eth.getTransactionCount(checksumAddress, "pending");
377
- let confirmedNonce = await web3.eth.getTransactionCount(checksumAddress, "latest");
378
- log.info(tag, `Current Nonce: ${currentNonce}, Confirmed Nonce: ${confirmedNonce}`);
379
- // Determine if there are pending transactions
380
- const hasPendingTransactions = currentNonce > confirmedNonce;
381
- if (hasPendingTransactions) {
382
- log.info(tag, "Pending transactions detected");
383
- // Fetch the pending transactions from the transaction pool
384
- // Note: This requires access to the node's txpool, which may not be available on all nodes
385
- let pendingBlock = await web3.eth.getBlock("pending", true);
386
- if (pendingBlock && pendingBlock.transactions) {
387
- for (let tx of pendingBlock.transactions) {
388
- if (tx.from?.toLowerCase() === checksumAddress.toLowerCase()) {
389
- // Collect detailed transaction info
390
- transactions.push({
391
- txHash: tx.hash,
392
- from: tx.from,
393
- to: tx.to,
394
- value: tx.value,
395
- gas: tx.gas,
396
- gasPrice: tx.gasPrice,
397
- blockNumber: tx.blockNumber, // This will be null for pending transactions
398
- receipt: null, // Receipt is not available for pending transactions
399
- pending: true,
400
- });
401
- }
402
- }
403
- }
404
- }
405
- else {
406
- log.info(tag, "No pending transactions detected");
407
- }
408
- return {
409
- address,
410
- networkId,
411
- fromBlock,
412
- toBlock,
413
- currentBlockHeight,
414
- currentNonce,
415
- hasPendingTransactions,
416
- transactions,
417
- };
418
- }
419
- catch (e) {
420
- console.error(tag, e);
421
- throw e; // Rethrow the error to handle it upstream
422
- }
423
- };
424
- // Broadcast transaction by network
425
- const broadcast_transaction_by_network = async function (networkId, tx) {
426
- let tag = TAG + " | broadcast_transaction_by_network | ";
427
- try {
428
- if (!tx)
429
- throw Error("Transaction data required!");
430
- let nodes = NODES.filter((n) => n.networkId === networkId);
431
- if (!nodes || nodes.length === 0)
432
- throw Error("101: missing nodes for network " + networkId);
433
- log.info(tag, `Found ${nodes.length} nodes for network ${networkId}`);
434
- let lastError;
435
- for (let i = 0; i < nodes.length && i < 5; i++) {
436
- let node = nodes[i];
437
- try {
438
- log.info(tag, `Attempt ${i + 1}/${Math.min(nodes.length, 5)}: Trying node ${node.service}`);
439
- // Test if node is alive first with a quick health check
440
- let web3 = new Web3(node.service);
441
- web3.eth.transactionBlockTimeout = 5;
442
- try {
443
- await web3.eth.getChainId();
444
- }
445
- catch (healthError) {
446
- log.warn(tag, `Node ${node.service} health check failed: ${healthError.message}`);
447
- continue;
448
- }
449
- // Broadcast transaction and return txid immediately
450
- // Don't wait for receipt as it can timeout and cause "Failed to check for transaction receipt" errors
451
- let txHash = null;
452
- let broadcastPromise = new Promise((resolve, reject) => {
453
- web3.eth.sendSignedTransaction(tx)
454
- .on('transactionHash', function (hash) {
455
- log.info(tag, "Transaction Hash received:", hash);
456
- txHash = hash;
457
- // Return immediately with the txid - don't wait for receipt
458
- resolve({ transactionHash: hash });
459
- })
460
- .on('receipt', function (receipt) {
461
- log.info(tag, "Receipt (not waiting for this):", receipt);
462
- })
463
- .on('confirmation', function (confirmationNumber, receipt) {
464
- log.debug(tag, "Confirmation Number:", confirmationNumber, "Receipt:", receipt);
465
- })
466
- .on('error', function (error) {
467
- log.error(tag, "Broadcast Error:", error);
468
- // Check if we already have a txid - if so, the broadcast succeeded
469
- if (txHash) {
470
- log.warn(tag, "Transaction was broadcast (txid: " + txHash + ") but receipt check failed");
471
- resolve({ transactionHash: txHash, warning: "Transaction broadcast but receipt not confirmed" });
472
- }
473
- else {
474
- reject(error);
475
- }
476
- });
477
- // Set a timeout to return txid if we have it, even if no receipt
478
- setTimeout(() => {
479
- if (txHash) {
480
- log.info(tag, "Timeout waiting for receipt, but we have txid:", txHash);
481
- resolve({ transactionHash: txHash, warning: "Receipt timeout" });
482
- }
483
- }, 5000); // 5 second timeout
484
- });
485
- let result = await broadcastPromise;
486
- log.info(tag, "Success with node:", node.service);
487
- // Return in the format the SDK expects
488
- return {
489
- txid: result.transactionHash,
490
- success: true,
491
- warning: result.warning
492
- };
493
- }
494
- catch (nodeError) {
495
- lastError = nodeError;
496
- // Check if error indicates transaction was already broadcast successfully
497
- if (nodeError.message && (
498
- nodeError.message.includes('already mined') ||
499
- nodeError.message.includes('nonce too low') ||
500
- nodeError.message.includes('already known')
501
- )) {
502
- log.info(tag, "Transaction was already broadcast successfully:", nodeError.message);
503
- // Try to extract txid from reused/duplicate transaction
504
- // For now, return success without txid since transaction is already on chain
505
- return {
506
- success: true,
507
- warning: "Transaction was already broadcast: " + nodeError.message,
508
- note: "Check blockchain explorer for transaction details"
509
- };
510
- }
511
-
512
- log.warn(tag, `Node ${i + 1} failed: ${node.service}, Error: ${nodeError.message}`);
513
- // Wait a bit before trying next node
514
- if (i < nodes.length - 1 && i < 4) {
515
- await new Promise(resolve => setTimeout(resolve, 500));
516
- }
517
- }
518
- }
519
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + (lastError?.message || "Unknown error"));
520
- }
521
- catch (e) {
522
- console.error(tag, e);
523
- throw e;
524
- }
525
- };
526
- const get_transaction_by_network = async function (networkId, txid) {
527
- let tag = TAG + " | get_transaction | ";
528
- try {
529
- let nodes = NODES.filter((n) => n.networkId === networkId);
530
- if (!nodes || nodes.length === 0)
531
- throw Error("101: missing nodes for network " + networkId);
532
- let lastError;
533
- for (let i = 0; i < nodes.length && i < 5; i++) {
534
- let node = nodes[i];
535
- try {
536
- log.debug(tag, "Trying node:", node.service);
537
- let web3 = new Web3(node.service);
538
- web3.eth.transactionBlockTimeout = 5;
539
- let output = {};
540
- //normal tx info
541
- output.txInfo = await web3.eth.getTransaction(txid);
542
- //if contract
543
- output.receipt = await web3.eth.getTransactionReceipt(txid);
544
- log.debug(tag, "Success with node:", node.service);
545
- return output;
546
- }
547
- catch (nodeError) {
548
- lastError = nodeError;
549
- log.debug(tag, "Failed with node:", node.service, "Error:", nodeError.message);
550
- }
551
- }
552
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + lastError.message);
553
- }
554
- catch (e) {
555
- console.error(tag, e);
556
- throw e;
557
- }
558
- };
559
- const get_gas_price_by_network = async function (networkId) {
560
- let tag = TAG + " | get_gas_price_by_network | ";
561
- try {
562
- // Find all nodes for this network
563
- let nodes = NODES.filter((n) => n.networkId === networkId);
564
- if (!nodes || nodes.length === 0)
565
- throw Error("101: missing nodes for network " + networkId);
566
- log.info(tag, `Found ${nodes.length} nodes for network ${networkId}`);
567
- let lastError;
568
- // Try each node until one works
569
- for (let i = 0; i < nodes.length && i < 5; i++) { // Try up to 5 nodes
570
- let node = nodes[i];
571
- try {
572
- log.info(tag, `Attempt ${i + 1}/${Math.min(nodes.length, 5)}: Trying node ${node.service}`);
573
- // Initialize new web3 instance
574
- let web3 = new Web3(node.service);
575
- // Set timeout for the request
576
- web3.eth.transactionBlockTimeout = 5; // 5 seconds timeout
577
- // Health check first
578
- try {
579
- await web3.eth.getChainId();
580
- }
581
- catch (healthError) {
582
- log.warn(tag, `Node ${node.service} health check failed: ${healthError.message}`);
583
- continue;
584
- }
585
- // Get gas price
586
- let gasPrice = await web3.eth.getGasPrice();
587
- log.info(tag, `Success with node ${node.service}, gasPrice: ${gasPrice}`);
588
- return gasPrice;
589
- }
590
- catch (nodeError) {
591
- lastError = nodeError;
592
- log.warn(tag, `Node ${i + 1} failed: ${node.service}, Error: ${nodeError.message}`);
593
- // Wait a bit before trying next node
594
- if (i < nodes.length - 1 && i < 4) {
595
- await new Promise(resolve => setTimeout(resolve, 500));
596
- }
597
- }
598
- }
599
- // If all nodes failed, throw the last error
600
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + (lastError?.message || "Unknown error"));
601
- }
602
- catch (e) {
603
- console.error(tag, e);
604
- throw e;
605
- }
606
- };
607
- const get_nonce_by_network = async function (networkId, address) {
608
- let tag = TAG + " | get_nonce_by_network | ";
609
- try {
610
- if (!address)
611
- throw Error("Address required!");
612
- let nodes = NODES.filter((n) => n.networkId === networkId);
613
- if (!nodes || nodes.length === 0)
614
- throw Error("101: missing nodes for network " + networkId);
615
- let lastError;
616
- for (let i = 0; i < nodes.length && i < 5; i++) {
617
- let node = nodes[i];
618
- try {
619
- log.debug(tag, "Trying node:", node.service);
620
- let web3 = new Web3(node.service);
621
- web3.eth.transactionBlockTimeout = 5;
622
- let nonce = await web3.eth.getTransactionCount(address, 'pending');
623
- log.debug(tag, "Success with node:", node.service, "nonce:", nonce);
624
- return nonce;
625
- }
626
- catch (nodeError) {
627
- lastError = nodeError;
628
- log.debug(tag, "Failed with node:", node.service, "Error:", nodeError.message);
629
- }
630
- }
631
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + lastError.message);
632
- }
633
- catch (e) {
634
- console.error(tag, e);
635
- throw e;
636
- }
637
- };
638
- const estimate_gas_by_network = async function (networkId, transaction) {
639
- let tag = TAG + " | estimate_gas_by_network | ";
640
- try {
641
- if (!transaction)
642
- throw Error("Transaction object required!");
643
- let nodes = NODES.filter((n) => n.networkId === networkId);
644
- if (!nodes || nodes.length === 0)
645
- throw Error("101: missing nodes for network " + networkId);
646
- let lastError;
647
- for (let i = 0; i < nodes.length && i < 5; i++) {
648
- let node = nodes[i];
649
- try {
650
- log.debug(tag, "Trying node:", node.service);
651
- let web3 = new Web3(node.service);
652
- web3.eth.transactionBlockTimeout = 5;
653
- let gas = await web3.eth.estimateGas(transaction);
654
- log.debug(tag, "Success with node:", node.service, "gas:", gas);
655
- return gas;
656
- }
657
- catch (nodeError) {
658
- lastError = nodeError;
659
- log.debug(tag, "Failed with node:", node.service, "Error:", nodeError.message);
660
- }
661
- }
662
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + lastError.message);
663
- }
664
- catch (e) {
665
- console.error(tag, e);
666
- throw e;
667
- }
668
- };
669
- const get_all_pioneers = async function () {
670
- let tag = TAG + " | get_all_pioneers | ";
671
- try {
672
- let output = {};
673
- const nftContract = new web3.eth.Contract(constant_1.ERC721_ABI, constant_1.PIONEER_CONTRACT_ADDRESS);
674
- const metadataContract = new web3.eth.Contract(constant_1.METADATA_ABI, constant_1.PIONEER_METADATA_CONTRACT_ADDRESS);
675
- // Fetch the total supply of the NFTs
676
- const totalSupply = await nftContract.methods.totalSupply().call();
677
- log.debug("totalSupply: ", totalSupply);
678
- output['totalSupply'] = totalSupply;
679
- output['owners'] = [];
680
- output['images'] = []; // add an images array to output
681
- for (let i = 0; i < totalSupply; i++) {
682
- //slow down
683
- // await sleep(1000);
684
- try {
685
- const owner = await nftContract.methods.ownerOf(i).call();
686
- log.debug(tag, "owner: ", owner);
687
- output['owners'].push(owner.toLowerCase());
688
- //get images
689
- const imageInfo = await metadataContract.methods.getAttributes(i).call();
690
- //log.debug(tag,"imageInfo: ",imageInfo)
691
- // Parse the JSON string and get the image name
692
- const imageName = JSON.parse(imageInfo['0'])["0-backgrounds"];
693
- // Build the full image URL by replacing the image name in the base URL
694
- const baseImageUrl = "https://ipfs.io/ipfs/bafybeiezdzjofkcpiwy5hlvxwzkgcztxc6xtodh3q7eddfjmqsguqs47aa/0-backgrounds/";
695
- const fullImageUrl = baseImageUrl + imageName + ".png";
696
- // Add this image URL to the images array in output
697
- output['images'].push({ address: owner.toLowerCase(), image: fullImageUrl });
698
- }
699
- catch (e) {
700
- log.debug("no image for: ", i);
701
- }
702
- }
703
- return output;
704
- }
705
- catch (e) {
706
- console.error(tag, e);
707
- }
708
- };
709
- const get_all_pioneers_base = async function () {
710
- let tag = TAG + " | get_all_pioneers_base | ";
711
- try {
712
- let output = {};
713
- log.info(tag, "PIONEER_CONTRACT_ADDRESS_BASE: ", constant_1.PIONEER_CONTRACT_ADDRESS_BASE);
714
- const nftContract = new web3Base.eth.Contract(constant_1.ERC721_ABI, constant_1.PIONEER_CONTRACT_ADDRESS_BASE);
715
- const metadataContract = new web3Base.eth.Contract(constant_1.METADATA_ABI, constant_1.PIONEER_METADATA_CONTRACT_ADDRESS_BASE);
716
- // Fetch the total supply of the NFTs
717
- const totalSupply = await nftContract.methods.totalSupply().call();
718
- log.info("totalSupply: ", totalSupply);
719
- output['totalSupply'] = totalSupply;
720
- output['owners'] = [];
721
- output['images'] = []; // add an images array to output
722
- for (let i = 0; i < totalSupply; i++) {
723
- //slow down
724
- // await sleep(1000);
725
- try {
726
- const owner = await nftContract.methods.ownerOf(i).call();
727
- log.info(tag, "owner: ", owner);
728
- output['owners'].push(owner.toLowerCase());
729
- //get images
730
- const imageInfo = await metadataContract.methods.getAttributes(i).call();
731
- log.info(tag, "imageInfo: ", imageInfo);
732
- // Parse the JSON string and get the image name
733
- const imageName = JSON.parse(imageInfo['0'])["0-backgrounds"];
734
- // Build the full image URL by replacing the image name in the base URL
735
- const baseImageUrl = "https://ipfs.io/ipfs/bafybeiezdzjofkcpiwy5hlvxwzkgcztxc6xtodh3q7eddfjmqsguqs47aa/0-backgrounds/";
736
- const fullImageUrl = baseImageUrl + imageName + ".png";
737
- // Add this image URL to the images array in output
738
- output['images'].push({ address: owner.toLowerCase(), image: fullImageUrl });
739
- }
740
- catch (e) {
741
- log.debug("no image for: ", i);
742
- }
743
- }
744
- return output;
745
- }
746
- catch (e) {
747
- console.error(tag, e);
748
- }
749
- };
750
- const decode_tx = async function (tx) {
751
- let tag = TAG + " | decode_tx | ";
752
- try {
753
- const data = ethers.utils.parseTransaction(tx);
754
- return data;
755
- }
756
- catch (e) {
757
- console.error(tag, e);
758
- }
759
- };
760
- const build_airdrop_claim = async function (address) {
761
- let tag = TAG + " | build_airdrop_claim | ";
762
- try {
763
- const airdropContract = new web3.eth.Contract(constant_1.AIRDROP_ABI, constant_1.AIRDROP_CONTRACT);
764
- let accountInfo = await axios({ method: 'GET', url: constant_1.CLAIM_URL + '/' + address });
765
- //console.log("accountInfo: ",accountInfo)
766
- if (!accountInfo.data.index)
767
- throw Error("Not found in db! ");
768
- //
769
- //console.log("airdropContract: ",accountInfo.data.contract)
770
- const AirDropInterface = new abi_1.Interface(constant_1.AIRDROP_ABI);
771
- // const data = airdropContract.methods.claim(
772
- // accountInfo.data.index,
773
- // address,
774
- // 150,
775
- // accountInfo.data.proof
776
- // )
777
- // console.log("airdropContract: ",[
778
- // accountInfo.data.index as number,
779
- // address,
780
- // '0x0821ab0d4414980000',
781
- // accountInfo.data.proof
782
- // ])
783
- const data = AirDropInterface.encodeFunctionData('claim', [
784
- accountInfo.data.index,
785
- address,
786
- '0x0821ab0d4414980000',
787
- accountInfo.data.proof
788
- ]);
789
- return data;
790
- }
791
- catch (e) {
792
- console.error(tag, e);
793
- }
794
- };
795
- const check_airdrop_claim = async function (address) {
796
- let tag = TAG + " | check_airdrop_claim | ";
797
- try {
798
- //
799
- let accountInfo = await axios({ method: 'GET', url: constant_1.CLAIM_URL + '/' + address });
800
- //console.log("accountInfo: ",accountInfo)
801
- let output = {};
802
- if (accountInfo.data.index) {
803
- output.isElgible = true;
804
- output.contract = accountInfo.data.contractAddress;
805
- //get index?
806
- //check contract
807
- //const AirDropInterface = new Interface(AirDropABI)
808
- const airdropContract = new web3.eth.Contract(constant_1.AIRDROP_ABI, accountInfo.data.contractAddress);
809
- //get index by address?
810
- //log.debug("index: ",accountInfo.data.index)
811
- let isClaimed = await airdropContract.methods.isClaimed(accountInfo.data.index).call();
812
- output.isClaimed = isClaimed;
813
- }
814
- else {
815
- output.isElgible = false;
816
- }
817
- return output;
818
- }
819
- catch (e) {
820
- console.error(tag, e);
821
- }
822
- };
823
- // const get_token_transfer_data = async function(toAddress: string, amount: string, contract: string) {
824
- // const tag = TAG + " | get_token_transfer_data | ";
825
- // try {
826
- // const minABI = [
827
- // // balanceOf
828
- // {
829
- // "constant": true,
830
- // "inputs": [{ "name": "_owner", "type": "address" }],
831
- // "name": "balanceOf",
832
- // "outputs": [{ "name": "balance", "type": "uint256" }],
833
- // "type": "function"
834
- // },
835
- // // decimals
836
- // {
837
- // "constant": true,
838
- // "inputs": [],
839
- // "name": "decimals",
840
- // "outputs": [{ "name": "", "type": "uint8" }],
841
- // "type": "function"
842
- // }
843
- // ];
844
- // const newContract = new web3.eth.Contract(minABI, contract);
845
- // const decimalPlaces = await newContract.methods.decimals().call();
846
- //
847
- // // Convert amount to the appropriate number of decimal places
848
- // const amountInSmallestUnit = web3.utils.toBN(amount).mul(web3.utils.toBN(10).pow(decimalPlaces));
849
- //
850
- // // Convert the amount to a hexadecimal string
851
- // const amountHex = amountInSmallestUnit.toString(16);
852
- //
853
- // // Pad the hexadecimal string with zeros to 64 characters
854
- // const amountHexPadded = amountHex.padStart(64, '0');
855
- //
856
- // // Parse the token data
857
- // const tokenData = web3.eth.abi.encodeFunctionCall({
858
- // name: 'transfer',
859
- // type: 'function',
860
- // inputs: [
861
- // {
862
- // type: 'address',
863
- // name: '_to'
864
- // },
865
- // {
866
- // type: 'uint256',
867
- // name: '_value'
868
- // }
869
- // ]
870
- // }, [toAddress, amountInSmallestUnit.toString()]);
871
- //
872
- // return tokenData;
873
- // } catch (e) {
874
- // console.error(tag, e);
875
- // }
876
- // }
877
- // const get_token_transfer_data = async function(toAddress: string, amount: string, contract: string) {
878
- // const tag = TAG + " | get_token_transfer_data | ";
879
- // try {
880
- // const minABI = [
881
- // // balanceOf
882
- // {
883
- // "constant": true,
884
- // "inputs": [{ "name": "_owner", "type": "address" }],
885
- // "name": "balanceOf",
886
- // "outputs": [{ "name": "balance", "type": "uint256" }],
887
- // "type": "function"
888
- // },
889
- // // decimals
890
- // {
891
- // "constant": true,
892
- // "inputs": [],
893
- // "name": "decimals",
894
- // "outputs": [{ "name": "", "type": "uint8" }],
895
- // "type": "function"
896
- // }
897
- // ];
898
- // const newContract = new web3.eth.Contract(minABI, contract);
899
- // const decimalPlaces = await newContract.methods.decimals().call();
900
- //
901
- // // Convert amount to the appropriate number of decimal places
902
- // const amountInWei = web3.utils.toWei(amount, 'ether');
903
- // const decimals = web3.utils.toBN(decimalPlaces);
904
- // const amountInSmallestUnit = web3.utils.toBN(amountInWei).mul(web3.utils.toBN(10).pow(decimals));
905
- //
906
- // // Convert the amount to a hexadecimal string
907
- // const amountHex = amountInSmallestUnit.toString(16);
908
- //
909
- // // Pad the hexadecimal string with zeros to 64 characters
910
- // const amountHexPadded = amountHex.padStart(64, '0');
911
- //
912
- // // Parse the token data
913
- // const tokenData = web3.eth.abi.encodeFunctionCall({
914
- // name: 'transfer',
915
- // type: 'function',
916
- // inputs: [
917
- // {
918
- // type: 'address',
919
- // name: '_to'
920
- // },
921
- // {
922
- // type: 'uint256',
923
- // name: '_value'
924
- // }
925
- // ]
926
- // }, [toAddress, amountInSmallestUnit.toString()]);
927
- //
928
- // return tokenData;
929
- // } catch (e) {
930
- // console.error(tag, e);
931
- // }
932
- // }
933
- const get_token_transfer_data = async function (toAddress, amount, contract) {
934
- const tag = TAG + " | get_token_transfer_data | ";
935
- try {
936
- const minABI = [
937
- // balanceOf
938
- {
939
- "constant": true,
940
- "inputs": [{ "name": "_owner", "type": "address" }],
941
- "name": "balanceOf",
942
- "outputs": [{ "name": "balance", "type": "uint256" }],
943
- "type": "function"
944
- },
945
- // decimals
946
- {
947
- "constant": true,
948
- "inputs": [],
949
- "name": "decimals",
950
- "outputs": [{ "name": "", "type": "uint8" }],
951
- "type": "function"
952
- }
953
- ];
954
- const newContract = new web3.eth.Contract(minABI, contract);
955
- const decimalPlaces = await newContract.methods.decimals().call();
956
- // Convert amount to the appropriate number of decimal places
957
- // Note: we're assuming 'amount' is a string representing a decimal number
958
- const amountInSmallestUnit = web3.utils.toBN(parseFloat(amount) * Math.pow(10, decimalPlaces));
959
- // Convert the amount to a hexadecimal string
960
- const amountHex = amountInSmallestUnit.toString(16);
961
- // Pad the hexadecimal string with zeros to 64 characters
962
- const amountHexPadded = amountHex.padStart(64, '0');
963
- // Parse the token data
964
- const tokenData = web3.eth.abi.encodeFunctionCall({
965
- name: 'transfer',
966
- type: 'function',
967
- inputs: [
968
- {
969
- type: 'address',
970
- name: '_to'
971
- },
972
- {
973
- type: 'uint256',
974
- name: '_value'
975
- }
976
- ]
977
- }, [toAddress, amountInSmallestUnit.toString()]);
978
- return tokenData;
979
- }
980
- catch (e) {
981
- console.error(tag, e);
982
- }
983
- };
984
- // //get_token_transfer_data
985
- // const get_token_transfer_data = async function(toAddress:string, amount:string, contract:string){
986
- // let tag = TAG + " | get_token_transfer_data | "
987
- // try{
988
- //
989
- // let minABI = [
990
- // // balanceOf
991
- // {
992
- // "constant": true,
993
- // "inputs": [{ "name": "_owner", "type": "address" }],
994
- // "name": "balanceOf",
995
- // "outputs": [{ "name": "balance", "type": "uint256" }],
996
- // "type": "function"
997
- // },
998
- // // decimals
999
- // {
1000
- // "constant": true,
1001
- // "inputs": [],
1002
- // "name": "decimals",
1003
- // "outputs": [{ "name": "", "type": "uint8" }],
1004
- // "type": "function"
1005
- // }
1006
- // ];
1007
- // const newContract = new web3.eth.Contract(minABI, contract);
1008
- // const decimalPlaces = await newContract.methods.decimals().call();
1009
- // //
1010
- // // // @ts-ignore
1011
- // // let value = parseInt(amount/Math.pow(10, decimals))
1012
- // // //const adjustedValue = value.mul(web3.utils.toBN(10).pow(web3.utils.toBN(decimals)));
1013
- // //
1014
- // // log.debug(tag, "adjustedValue: ", value.toString());
1015
- //
1016
- // // Calculate the amount in the token's smallest unit
1017
- // const amountInWei = web3.utils.toWei(amount, 'ether');
1018
- // const decimals = web3.utils.toBN(decimalPlaces);
1019
- // const amountInSmallestUnit = web3.utils.toBN(amountInWei).mul(web3.utils.toBN(10).pow(decimals));
1020
- //
1021
- // // Convert the amount to a hexadecimal string
1022
- // const amountHex = amountInSmallestUnit.toString(16);
1023
- //
1024
- // // Pad the hexadecimal string with zeros to 64 characters
1025
- // const amountHexPadded = amountHex.padStart(64, '0');
1026
- //
1027
- // //parse to prescision?
1028
- // let tokenData = await web3.eth.abi.encodeFunctionCall({
1029
- // name: 'transfer',
1030
- // type: 'function',
1031
- // inputs: [
1032
- // {
1033
- // type: 'address',
1034
- // name: '_to'
1035
- // },
1036
- // {
1037
- // type: 'uint256',
1038
- // name: '_value'
1039
- // }
1040
- // ]
1041
- // }, [toAddress, amountInSmallestUnit]);
1042
- //
1043
- // return tokenData
1044
- // }catch(e){
1045
- // console.error(tag,e)
1046
- // }
1047
- // }
1048
- const get_symbol_from_contract = async function (address) {
1049
- let tag = TAG + " | get_symbol_from_contract | ";
1050
- try {
1051
- //get total LP tokens
1052
- //LP token
1053
- const contract = new web3.eth.Contract(constant_1.ERC20ABI, address);
1054
- //log.debug(tag,"contract: ",contract)
1055
- let tokenName = await contract.methods.name().call();
1056
- //log.debug(tag,"tokenName: ",tokenName)
1057
- return tokenName;
1058
- }
1059
- catch (e) {
1060
- console.error(tag, e);
1061
- }
1062
- };
1063
- const get_stream = async function (streamId) {
1064
- let tag = TAG + " | get_stream | ";
1065
- try {
1066
- //get total LP tokens
1067
- //LP token
1068
- const sablierContract = new web3.eth.Contract(constant_1.SABLIER_ABI, constant_1.PROXY_CONTRACT_SABLIER);
1069
- //log.debug(tag,"sablierContract: ",sablierContract)
1070
- //log.debug(tag,"streamId: ",streamId)
1071
- streamId = parseInt(streamId);
1072
- let totalFox = await sablierContract.methods.getSalary(streamId).call();
1073
- //log.debug(tag,"totalFox: ",totalFox)
1074
- return totalFox;
1075
- }
1076
- catch (e) {
1077
- console.error(tag, e);
1078
- }
1079
- };
1080
- const get_tx_count = async function (address, options) {
1081
- let tag = TAG + " | get_tx_count | ";
1082
- try {
1083
- log.debug(tag, "address: ", address);
1084
- if (!address)
1085
- throw Error("102: address required!");
1086
- //confirmed
1087
- let txsConfirmed = await web3.eth.getTransactionCount(address);
1088
- //pending
1089
- let txsWithPending = await web3.eth.getTransactionCount(address, 'pending');
1090
- //count pending
1091
- let pending = txsConfirmed - txsWithPending;
1092
- return {
1093
- confirmed: txsConfirmed,
1094
- total: txsWithPending,
1095
- pending
1096
- };
1097
- }
1098
- catch (e) {
1099
- console.error(tag, e);
1100
- }
1101
- };
1102
- const get_pool_percent = async function (amountFox, amountEth, poolAddress) {
1103
- let tag = TAG + " | get_pool_percent | ";
1104
- try {
1105
- //get total LP tokens
1106
- //LP token
1107
- const lpContract = new web3.eth.Contract(constant_1.ERC20ABI, constant_1.UNISWAP_V2_WETH_FOX_POOL_ADDRESS);
1108
- const foxContract = new web3.eth.Contract(constant_1.ERC20ABI, constant_1.FOX_TOKEN_CONTRACT_ADDRESS);
1109
- const wethContract = new web3.eth.Contract(constant_1.ERC20ABI, constant_1.WETH_TOKEN_CONTRACT_ADDRESS);
1110
- //log.debug("lpContract: ",lpContract)
1111
- let totalSupply = await lpContract.methods.totalSupply().call();
1112
- totalSupply = totalSupply / BASE;
1113
- log.debug("LP totalSupply: ", totalSupply);
1114
- //get total fox in pool
1115
- let totalFox = await foxContract.methods.balanceOf(constant_1.UNISWAP_V2_WETH_FOX_POOL_ADDRESS).call();
1116
- totalFox = totalFox / BASE;
1117
- log.debug("totalFox: ", totalFox / BASE);
1118
- //get total eth in pool
1119
- let totalEth = await wethContract.methods.balanceOf(constant_1.UNISWAP_V2_WETH_FOX_POOL_ADDRESS).call();
1120
- totalEth = totalEth / BASE;
1121
- log.debug("totalEth: ", totalEth);
1122
- //token math
1123
- let result = totalFox / totalEth;
1124
- log.debug("result: ", result);
1125
- //balance
1126
- let lpTokens = (amountFox * totalSupply) / totalFox;
1127
- log.debug("lpTokens: ", lpTokens);
1128
- //total LP tokens
1129
- //liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
1130
- let percent = (lpTokens / totalSupply) * 100;
1131
- log.debug("percent: ", percent);
1132
- return percent;
1133
- }
1134
- catch (e) {
1135
- console.error(tag, e);
1136
- }
1137
- };
1138
- const get_balances = async function (addresses) {
1139
- let tag = TAG + " | get_balances | ";
1140
- try {
1141
- let actions = [];
1142
- for (let i = 0; i < addresses.length; i++) {
1143
- let address = addresses[i];
1144
- let action = {
1145
- method: "eth_getBalance",
1146
- params: [address]
1147
- };
1148
- actions.push(action);
1149
- }
1150
- let result = await rpcCallBatch(actions);
1151
- //covert
1152
- let output = [];
1153
- for (let i = 0; i < result.length; i++) {
1154
- let entry = result[i];
1155
- let balance = entry.result;
1156
- balance = Web3Utils.hexToNumberString(balance);
1157
- balance = balance / BASE;
1158
- output.push(balance);
1159
- }
1160
- return output;
1161
- }
1162
- catch (e) {
1163
- console.error(tag, e);
1164
- }
1165
- };
1166
- const rpcCallBatch = async (actions) => {
1167
- let tag = TAG + " | post_request | ";
1168
- try {
1169
- let body = [];
1170
- for (let i = 0; i < actions.length; i++) {
1171
- let action = actions[i];
1172
- let req = {
1173
- "jsonrpc": "2.0",
1174
- "method": action.method,
1175
- "params": action.params,
1176
- "id": 1
1177
- };
1178
- body.push(req);
1179
- }
1180
- let options = {
1181
- method: "POST",
1182
- url: NODE_URL,
1183
- headers: { 'content-type': 'application/json' },
1184
- body: JSON.stringify(body)
1185
- };
1186
- //console.log("options: ",options)
1187
- let result = await request(options);
1188
- //console.log("result: ",result)
1189
- result = JSON.parse(result);
1190
- if (result.error)
1191
- throw JSON.stringify(result.error);
1192
- return result;
1193
- }
1194
- catch (err) {
1195
- throw new Error(err);
1196
- }
1197
- };
1198
- //get_approval_status
1199
- const get_allowance = async function (tokenAddress, spender, sender) {
1200
- let tag = TAG + " | get_allowance | ";
1201
- try {
1202
- let contract = new web3.eth.Contract(constant_1.ERC20ABI, tokenAddress);
1203
- let allowance = await contract.methods.allowance(spender, sender).call();
1204
- return allowance;
1205
- }
1206
- catch (e) {
1207
- console.error(tag, e);
1208
- }
1209
- };
1210
- const get_all_tokens_blockbook = async function (address) {
1211
- let tag = TAG + " | get_all_tokens_blockbook | ";
1212
- try {
1213
- //
1214
- let ethInto = await blockbook.getEthInfo(address);
1215
- log.debug(tag, "ethInto: ", ethInto);
1216
- return true;
1217
- }
1218
- catch (e) {
1219
- console.error(tag, e);
1220
- }
1221
- };
1222
- const get_nfts = async function (address) {
1223
- let tag = TAG + " | get_nfts | ";
1224
- try {
1225
- //get nfts from etherscan (v3 uniswap)
1226
- //
1227
- let ethInfo = await blockbook.getAddressInfo('ETH', address);
1228
- //TODO filter by LP contracts
1229
- log.debug(tag, "ethInfo: ", ethInfo);
1230
- return ethInfo;
1231
- }
1232
- catch (e) {
1233
- console.error(tag, e);
1234
- }
1235
- };
1236
- const get_pool_positions = async function (address) {
1237
- let tag = TAG + " | get_pool_positions | ";
1238
- try {
1239
- //get nfts from etherscan (v3 uniswap)
1240
- //
1241
- let ethInfo = await blockbook.getAddressInfo('ETH', address);
1242
- //TODO filter by LP contracts
1243
- log.debug(tag, "ethInfo: ", ethInfo);
1244
- return ethInfo;
1245
- }
1246
- catch (e) {
1247
- console.error(tag, e);
1248
- }
1249
- };
1250
- /*
1251
- let swap = {
1252
- inboundAddress: {
1253
- chain: 'ETH',
1254
- pub_key: 'tthorpub1addwnpepqvuy8vh6yj4h28xp6gfpjsztpj6p46y2rs0763t6uw9f6lkky0ly5uvwla6',
1255
- address: '0x36286e570c412531aad366154eea9867b0e71755',
1256
- router: '0x9d496De78837f5a2bA64Cb40E62c19FBcB67f55a',
1257
- halted: false
1258
- },
1259
- asset: {
1260
- chain: 'ETH',
1261
- symbol: 'ETH',
1262
- ticker: 'ETH',
1263
- iconPath: 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/binance/assets/ETH-1C9/logo.png'
1264
- },
1265
- memo: '=:THOR.RUNE:tthor1veu9u5h4mtdq34fjgu982s8pympp6w87ag58nh',
1266
- amount: "0.1"
1267
- }
1268
- */
1269
- let get_memo_data = async function (swap) {
1270
- let tag = TAG + " | get_memo_data | ";
1271
- try {
1272
- const web3 = new Web3();
1273
- if (!swap.inboundAddress.router)
1274
- throw Error("Router required!");
1275
- const routerContract = new web3.eth.Contract(constant_1.TCRopstenAbi, swap.inboundAddress.router);
1276
- const memo = swap.memo;
1277
- //TODO support tokens?
1278
- const data = routerContract.methods
1279
- .deposit(swap.inboundAddress.address, '0x0000000000000000000000000000000000000000', // 0 = ETH
1280
- web3.utils.toBN(swap.amount * BASE), memo)
1281
- .encodeABI();
1282
- return data;
1283
- }
1284
- catch (e) {
1285
- log.error(tag, e);
1286
- throw e;
1287
- }
1288
- };
1289
- /*
1290
- X-chain compatible call
1291
- */
1292
- let estimate_fee = async function (sourceAsset, params) {
1293
- let tag = TAG + " | estimate_fee | ";
1294
- try {
1295
- let checkSummedAddress;
1296
- let decimal;
1297
- if (sourceAsset.symbol === 'ETH') {
1298
- checkSummedAddress = '0x0000000000000000000000000000000000000000';
1299
- decimal = utils_1.ETH_DECIMAL;
1300
- }
1301
- else {
1302
- throw Error("TODO");
1303
- // const assetAddress = sourceAsset.symbol.slice(sourceAsset.ticker.length + 1);
1304
- // const strip0x = assetAddress.substr(2);
1305
- // checkSummedAddress = ethers.utils.getAddress(strip0x);
1306
- //
1307
- // const tokenContract = new ethers.Contract(checkSummedAddress, erc20ABI, wallet);
1308
- // const tokenDecimals = await tokenContract.decimals();
1309
- // decimal = tokenDecimals.toNumber();
1310
- }
1311
- // Connect to the network
1312
- let provider = PROVIDER;
1313
- // Get the current block
1314
- let block = await provider.getBlockNumber();
1315
- log.debug(tag, "block: ", block);
1316
- const { average: averageGP, fast: fastGP, fastest: fastestGP } = (0, utils_1.getDefaultGasPrices)();
1317
- let assetAddress;
1318
- // @ts-ignore
1319
- if (sourceAsset && (0, xchain_util_1.assetToString)(sourceAsset) !== (0, xchain_util_1.assetToString)(xchain_util_1.AssetETH)) {
1320
- // @ts-ignore
1321
- assetAddress = (0, utils_1.getTokenAddress)(sourceAsset);
1322
- }
1323
- let gasLimit;
1324
- if (assetAddress && assetAddress !== utils_1.ETHAddress) {
1325
- if (!params.sender || !params.recipient)
1326
- throw Error("missing params! need sender and recipient on token tx!");
1327
- let contract = new ethers.Contract(assetAddress, constant_1.ERC20ABI, provider);
1328
- gasLimit = params.data
1329
- ? await contract.estimateGas.transfer(params.recipient, params.data, { from: params.sender })
1330
- : await contract.estimateGas.transfer(params.recipient, 1, { from: params.sender }); // amount = 1 as a dummy value
1331
- }
1332
- else {
1333
- // ETH transfer
1334
- if (!params.sender || !params.recipient)
1335
- throw Error("missing params! need sender and recipient");
1336
- const gasEstimate = await provider.estimateGas({
1337
- from: params.sender,
1338
- to: params.recipient,
1339
- value: ethers.utils.parseEther('0.000001') // using dummy ETH amount for gas calculation
1340
- });
1341
- gasLimit = gasEstimate.add(0); // Add extra gas as buffer
1342
- console.log("ETH gasEstimate: ", gasEstimate.toString());
1343
- console.log("ETH gasEstimate + buffer: ", gasLimit.toString());
1344
- }
1345
- return {
1346
- gasPrices: {
1347
- average: averageGP,
1348
- fast: fastGP,
1349
- fastest: fastestGP
1350
- },
1351
- gasLimit,
1352
- fees: {
1353
- type: 'byte',
1354
- average: (0, utils_1.getFee)({ gasPrice: averageGP, gasLimit }),
1355
- fast: (0, utils_1.getFee)({ gasPrice: fastGP, gasLimit }),
1356
- fastest: (0, utils_1.getFee)({ gasPrice: fastestGP, gasLimit })
1357
- }
1358
- };
1359
- }
1360
- catch (e) {
1361
- console.error(tag, "Error: ", e);
1362
- throw e;
1363
- }
1364
- };
1365
- let get_gas_limit = async function ({ asset, recipient, amount, memo }) {
1366
- let tag = TAG + " | get_gas_limit | ";
1367
- try {
1368
- log.debug(tag, "input: ", { asset, recipient, amount, memo });
1369
- const txAmount = BigNumber.from(amount?.amount().toFixed());
1370
- let assetAddress;
1371
- // @ts-ignore
1372
- if (asset && (0, xchain_util_1.assetToString)(asset) !== (0, xchain_util_1.assetToString)(xchain_util_1.AssetETH)) {
1373
- // @ts-ignore
1374
- assetAddress = (0, utils_1.getTokenAddress)(asset);
1375
- }
1376
- let estimate;
1377
- //NOTE: I changed the from to recipient because this module has no context to address of the sender.
1378
- // I hope I dont skrew the pooch and the differnce +-1 byte between addresses actually matter
1379
- if (assetAddress && assetAddress !== utils_1.ETHAddress) {
1380
- // ERC20 gas estimate
1381
- const contract = new ethers.Contract(assetAddress, utils_1.erc20ABI, PROVIDER);
1382
- estimate = await contract.estimateGas.transfer(recipient, txAmount, {
1383
- from: recipient,
1384
- });
1385
- }
1386
- else {
1387
- // ETH gas estimate
1388
- const transactionRequest = {
1389
- from: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", //address with lots of eth
1390
- to: recipient,
1391
- value: txAmount,
1392
- data: memo ? toUtf8Bytes(memo) : undefined,
1393
- };
1394
- estimate = await PROVIDER.estimateGas(transactionRequest);
1395
- }
1396
- return estimate;
1397
- }
1398
- catch (e) {
1399
- log.error(tag, e);
1400
- throw e;
1401
- }
1402
- };
1403
- let get_fees = async function (params) {
1404
- let tag = TAG + " | get_fees | ";
1405
- try {
1406
- const response = await etherscanAPI.getGasOracle(ETHERSCAN.baseUrl, ETHERSCAN.apiKey);
1407
- // Convert result of gas prices: `Gwei` -> `Wei`
1408
- const averageWei = parseUnits(response.SafeGasPrice, 'gwei');
1409
- const fastWei = parseUnits(response.ProposeGasPrice, 'gwei');
1410
- const fastestWei = parseUnits(response.FastGasPrice, 'gwei');
1411
- let gasPrices = {
1412
- average: (0, xchain_util_1.baseAmount)(averageWei.toString(), utils_1.ETH_DECIMAL),
1413
- fast: (0, xchain_util_1.baseAmount)(fastWei.toString(), utils_1.ETH_DECIMAL),
1414
- fastest: (0, xchain_util_1.baseAmount)(fastestWei.toString(), utils_1.ETH_DECIMAL),
1415
- };
1416
- const { fast: fastGP, fastest: fastestGP, average: averageGP } = gasPrices;
1417
- if (!params.amount || !params?.amount?.amount) {
1418
- // @ts-ignore
1419
- params.amount = {
1420
- // @ts-ignore
1421
- amount: function () { return .98; }
1422
- };
1423
- }
1424
- log.debug(tag, "get_gas_limit: ", {
1425
- asset: params.asset,
1426
- amount: params.amount,
1427
- recipient: params.recipient,
1428
- memo: params.memo,
1429
- });
1430
- const gasLimit = await get_gas_limit({
1431
- asset: params.asset,
1432
- amount: params.amount,
1433
- recipient: params.recipient,
1434
- memo: params.memo,
1435
- });
1436
- let output = {
1437
- gasPrices,
1438
- fees: {
1439
- type: 'byte',
1440
- average: (0, utils_1.getFee)({ gasPrice: averageGP, gasLimit }).amount().toString(),
1441
- fast: (0, utils_1.getFee)({ gasPrice: fastGP, gasLimit }).amount().toString(),
1442
- fastest: (0, utils_1.getFee)({ gasPrice: fastestGP, gasLimit }).amount().toString(),
1443
- },
1444
- gasLimit,
1445
- };
1446
- return output;
1447
- }
1448
- catch (e) {
1449
- log.error(tag, e);
1450
- throw e;
1451
- }
1452
- };
1453
- let broadcast_transaction = async function (tx) {
1454
- let tag = TAG + " | broadcast_transaction | ";
1455
- try {
1456
- let output = {};
1457
- output.success = false;
1458
- log.debug(tag, "tx: ", tx);
1459
- if (!tx)
1460
- throw Error("101: missing tx!");
1461
- //push node
1462
- // web3.eth.sendSignedTransaction(tx)
1463
- //push etherscan
1464
- //https://api.etherscan.io/api?module=proxy&action=eth_sendRawTransaction&hex=0xf904808000831cfde080&apikey=YourApiKeyToken
1465
- let resp = await axios({
1466
- method: 'GET',
1467
- url: 'https://api.etherscan.io/api?module=proxy&action=eth_sendRawTransaction&hex=' + tx + '&apikey=' + process.env['ETHERSCAN_API_KEY']
1468
- });
1469
- resp = resp.data;
1470
- console.log(resp);
1471
- //push blockbook
1472
- //TODO lifecycle hook?
1473
- // let resp2 = await web3.eth.sendSignedTransaction(tx)
1474
- // .on('transactionHash', function(hash:any){
1475
- // console.log("hash: ",hash)
1476
- // })
1477
- // .on('receipt', function(receipt:any){
1478
- // console.log("receipt: ",receipt)
1479
- // })
1480
- // .on('confirmation', function(confirmationNumber:any, receipt:any){
1481
- // console.log(confirmationNumber,receipt)
1482
- // })
1483
- // .on('error', console.error);
1484
- //console.log("resp: ",resp)
1485
- if (!resp.error)
1486
- output.success = true;
1487
- if (resp.error)
1488
- output.error = resp;
1489
- if (resp.result)
1490
- output.txid = resp.result;
1491
- return output;
1492
- }
1493
- catch (e) {
1494
- log.error(tag, e);
1495
- throw e;
1496
- }
1497
- };
1498
- const get_balance_tokens_by_network = async function (networkId, address) {
1499
- let tag = TAG + " | get_balance_tokens_by_network | ";
1500
- try {
1501
- let output = {};
1502
- //@TODO zapper? covalent?
1503
- return "";
1504
- }
1505
- catch (e) {
1506
- console.error(tag, e);
1507
- }
1508
- };
1509
- const get_balance_tokens = async function (address) {
1510
- let tag = TAG + " | get_balance_tokens | ";
1511
- try {
1512
- let balances = {};
1513
- let valueUsds = {};
1514
- let coinInfo = {};
1515
- //TODO other? backup?
1516
- //ethpolorer.io
1517
- let resp = await axios({
1518
- method: 'GET',
1519
- url: 'http://api.ethplorer.io/getAddressInfo/' + address + '?apiKey=' + ETHPLORER_API_KEY
1520
- });
1521
- log.debug(tag, "resp: ", resp.data);
1522
- balances['ETH'] = resp.data.ETH.balance;
1523
- valueUsds['ETH'] = parseFloat(resp.data.ETH.balance) * parseFloat(resp.data.ETH.price.rate);
1524
- //infura
1525
- let tokenInfo = resp.data.tokens;
1526
- log.debug(tag, "tokenInfo: ", tokenInfo);
1527
- //
1528
- if (tokenInfo && Object.keys(tokenInfo).length > 0) {
1529
- for (let i = 0; i < tokenInfo.length; i++) {
1530
- let info = tokenInfo[i];
1531
- if (info) {
1532
- log.debug(tag, "info: ", info);
1533
- //let symbol
1534
- let symbol = info.tokenInfo.symbol;
1535
- log.debug(tag, "symbol: ", symbol);
1536
- //rate
1537
- let rate = 0;
1538
- if (info.tokenInfo.price && info.tokenInfo.price.rate) {
1539
- log.debug(tag, "rate: ", info.tokenInfo.price.rate);
1540
- rate = info.tokenInfo.price.rate;
1541
- }
1542
- // @ts-ignore
1543
- let balance = info.balance / parseInt(Math.pow(10, info.tokenInfo.decimals));
1544
- log.debug({ rate, symbol, balance });
1545
- balances[symbol] = balance;
1546
- valueUsds[symbol] = balance * rate;
1547
- coinInfo[symbol] = info.tokenInfo;
1548
- }
1549
- }
1550
- }
1551
- return { balances, valueUsds, coinInfo };
1552
- }
1553
- catch (e) {
1554
- console.error(tag, e);
1555
- }
1556
- };
1557
- const get_balance_token_by_network = async function (networkId, address, token) {
1558
- let tag = TAG + " | get_balance_token_by_network | ";
1559
- try {
1560
- let output = {};
1561
- //find in node array node by networkId
1562
- let node = NODES.find((n) => { return n.networkId == networkId; });
1563
- if (!node)
1564
- throw Error("101: missing node! for network " + networkId);
1565
- //init new web3
1566
- let web3 = new Web3(node.service);
1567
- //decimals
1568
- let contract = new web3.eth.Contract(constant_1.ERC20ABI, token);
1569
- let decimals = await contract.methods.decimals().call();
1570
- //log.debug(tag,"decimals: ",decimals)
1571
- let balance = await contract.methods.balanceOf(address).call();
1572
- //log.debug(tag,"balance: ",balance)
1573
- return balance / Math.pow(10, decimals);
1574
- }
1575
- catch (e) {
1576
- console.error(tag, e);
1577
- }
1578
- };
1579
- const get_balance_token = async function (address, token) {
1580
- let tag = TAG + " | get_balance | ";
1581
- try {
1582
- //decimals
1583
- let contract = new web3.eth.Contract(constant_1.ERC20ABI, token);
1584
- let decimals = await contract.methods.decimals().call();
1585
- //log.debug(tag,"decimals: ",decimals)
1586
- let balance = await contract.methods.balanceOf(address).call();
1587
- //log.debug(tag,"balance: ",balance)
1588
- return balance / Math.pow(10, decimals);
1589
- }
1590
- catch (e) {
1591
- console.error(tag, e);
1592
- }
1593
- };
1594
- const get_balance_by_network = async function (networkId, address) {
1595
- let tag = TAG + " | get_balance_by_network | ";
1596
- try {
1597
- let output = {};
1598
- // Find all nodes for this network
1599
- let nodes = NODES.filter((n) => n.networkId === networkId);
1600
- if (!nodes || nodes.length === 0)
1601
- throw Error("101: missing node! for network " + networkId);
1602
- // Try each node until one works
1603
- let lastError = null;
1604
- for (let i = 0; i < nodes.length && i < 5; i++) {
1605
- try {
1606
- let node = nodes[i];
1607
- log.info(tag, `Attempting to get balance from node ${i + 1}/${nodes.length}: ${node.service}`);
1608
- //init new web3
1609
- let web3 = new Web3(node.service);
1610
- //normal tx info
1611
- output = (await web3.eth.getBalance(address)) / BASE;
1612
- log.info(tag, `Successfully got balance: ${output}`);
1613
- return output;
1614
- }
1615
- catch (nodeError) {
1616
- lastError = nodeError;
1617
- log.warn(tag, `Node ${i + 1} failed: ${nodeError.message}`);
1618
- continue;
1619
- }
1620
- }
1621
- // If all nodes failed, throw the last error
1622
- throw lastError || new Error("All nodes failed to get balance");
1623
- }
1624
- catch (e) {
1625
- console.error(tag, e);
1626
- throw e; // Re-throw the error instead of swallowing it
1627
- }
1628
- };
1629
- const get_balance = async function (address) {
1630
- let tag = TAG + " | get_balance | ";
1631
- try {
1632
- let output = {};
1633
- //normal tx info
1634
- output = (await web3.eth.getBalance(address)) / BASE;
1635
- return output;
1636
- }
1637
- catch (e) {
1638
- console.error(tag, e);
1639
- }
1640
- };
1641
- const get_transactions = async function (address, options) {
1642
- let tag = TAG + " | get_transactions | ";
1643
- try {
1644
- let output = {};
1645
- let ethInfo = await blockbook.getAddressInfo('ETH', address);
1646
- return ethInfo;
1647
- }
1648
- catch (e) {
1649
- console.error(tag, e);
1650
- }
1651
- };
1652
- const get_transaction = async function (txid) {
1653
- let tag = TAG + " | get_transaction | ";
1654
- try {
1655
- let output = {};
1656
- //normal tx info
1657
- output.txInfo = await web3.eth.getTransaction(txid);
1658
- //if contract
1659
- output.receipt = await web3.eth.getTransactionReceipt(txid);
1660
- return output;
1661
- }
1662
- catch (e) {
1663
- console.error(tag, e);
1664
- }
1665
- };
1666
- let check_online_status = async function () {
1667
- let tag = TAG + " | check_online_status | ";
1668
- try {
1669
- let output = {};
1670
- //isTestnet
1671
- output.version = await web3.eth.getNodeInfo();
1672
- output.chainId = await web3.eth.getChainId();
1673
- output.height = await web3.eth.getBlockNumber();
1674
- //TODO get peer count
1675
- output.peers = await web3.eth.net.getPeerCount();
1676
- let networkName;
1677
- switch (output.chainId.toString()) {
1678
- case "1":
1679
- networkName = "Main";
1680
- break;
1681
- case "2":
1682
- networkName = "Morden";
1683
- break;
1684
- case "3":
1685
- networkName = "Ropsten";
1686
- break;
1687
- case "4":
1688
- networkName = "Rinkeby";
1689
- break;
1690
- case "42":
1691
- networkName = "Kovan";
1692
- break;
1693
- default:
1694
- networkName = "Unknown";
1695
- }
1696
- output.networkName = networkName;
1697
- //
1698
- output.gasPrice = await web3.eth.getGasPrice();
1699
- //
1700
- output.syncing = await web3.eth.isSyncing();
1701
- return output;
1702
- }
1703
- catch (e) {
1704
- console.error(tag, e);
1705
- }
1706
- };
1707
- // Helper functions for ethers v5 compatibility
1708
- const parseUnits = (value, unit) => ethers.utils.parseUnits(value, unit);
1709
- const toUtf8Bytes = (text) => ethers.utils.toUtf8Bytes(text);
1710
- // Define our own FeeOption enum
1711
- var FeeOption;
1712
- (function (FeeOption) {
1713
- FeeOption["Average"] = "average";
1714
- FeeOption["Fast"] = "fast";
1715
- FeeOption["Fastest"] = "fastest";
1716
- })(FeeOption || (FeeOption = {}));
1717
- //# sourceMappingURL=index.js.map