@pioneer-platform/eth-network 8.6.0 → 8.7.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.
package/lib/index.js DELETED
@@ -1,1701 +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
- log.warn(tag, `Node ${i + 1} failed: ${node.service}, Error: ${nodeError.message}`);
497
- // Wait a bit before trying next node
498
- if (i < nodes.length - 1 && i < 4) {
499
- await new Promise(resolve => setTimeout(resolve, 500));
500
- }
501
- }
502
- }
503
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + (lastError?.message || "Unknown error"));
504
- }
505
- catch (e) {
506
- console.error(tag, e);
507
- throw e;
508
- }
509
- };
510
- const get_transaction_by_network = async function (networkId, txid) {
511
- let tag = TAG + " | get_transaction | ";
512
- try {
513
- let nodes = NODES.filter((n) => n.networkId === networkId);
514
- if (!nodes || nodes.length === 0)
515
- throw Error("101: missing nodes for network " + networkId);
516
- let lastError;
517
- for (let i = 0; i < nodes.length && i < 5; i++) {
518
- let node = nodes[i];
519
- try {
520
- log.debug(tag, "Trying node:", node.service);
521
- let web3 = new Web3(node.service);
522
- web3.eth.transactionBlockTimeout = 5;
523
- let output = {};
524
- //normal tx info
525
- output.txInfo = await web3.eth.getTransaction(txid);
526
- //if contract
527
- output.receipt = await web3.eth.getTransactionReceipt(txid);
528
- log.debug(tag, "Success with node:", node.service);
529
- return output;
530
- }
531
- catch (nodeError) {
532
- lastError = nodeError;
533
- log.debug(tag, "Failed with node:", node.service, "Error:", nodeError.message);
534
- }
535
- }
536
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + lastError.message);
537
- }
538
- catch (e) {
539
- console.error(tag, e);
540
- throw e;
541
- }
542
- };
543
- const get_gas_price_by_network = async function (networkId) {
544
- let tag = TAG + " | get_gas_price_by_network | ";
545
- try {
546
- // Find all nodes for this network
547
- let nodes = NODES.filter((n) => n.networkId === networkId);
548
- if (!nodes || nodes.length === 0)
549
- throw Error("101: missing nodes for network " + networkId);
550
- log.info(tag, `Found ${nodes.length} nodes for network ${networkId}`);
551
- let lastError;
552
- // Try each node until one works
553
- for (let i = 0; i < nodes.length && i < 5; i++) { // Try up to 5 nodes
554
- let node = nodes[i];
555
- try {
556
- log.info(tag, `Attempt ${i + 1}/${Math.min(nodes.length, 5)}: Trying node ${node.service}`);
557
- // Initialize new web3 instance
558
- let web3 = new Web3(node.service);
559
- // Set timeout for the request
560
- web3.eth.transactionBlockTimeout = 5; // 5 seconds timeout
561
- // Health check first
562
- try {
563
- await web3.eth.getChainId();
564
- }
565
- catch (healthError) {
566
- log.warn(tag, `Node ${node.service} health check failed: ${healthError.message}`);
567
- continue;
568
- }
569
- // Get gas price
570
- let gasPrice = await web3.eth.getGasPrice();
571
- log.info(tag, `Success with node ${node.service}, gasPrice: ${gasPrice}`);
572
- return gasPrice;
573
- }
574
- catch (nodeError) {
575
- lastError = nodeError;
576
- log.warn(tag, `Node ${i + 1} failed: ${node.service}, Error: ${nodeError.message}`);
577
- // Wait a bit before trying next node
578
- if (i < nodes.length - 1 && i < 4) {
579
- await new Promise(resolve => setTimeout(resolve, 500));
580
- }
581
- }
582
- }
583
- // If all nodes failed, throw the last error
584
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + (lastError?.message || "Unknown error"));
585
- }
586
- catch (e) {
587
- console.error(tag, e);
588
- throw e;
589
- }
590
- };
591
- const get_nonce_by_network = async function (networkId, address) {
592
- let tag = TAG + " | get_nonce_by_network | ";
593
- try {
594
- if (!address)
595
- throw Error("Address required!");
596
- let nodes = NODES.filter((n) => n.networkId === networkId);
597
- if (!nodes || nodes.length === 0)
598
- throw Error("101: missing nodes for network " + networkId);
599
- let lastError;
600
- for (let i = 0; i < nodes.length && i < 5; i++) {
601
- let node = nodes[i];
602
- try {
603
- log.debug(tag, "Trying node:", node.service);
604
- let web3 = new Web3(node.service);
605
- web3.eth.transactionBlockTimeout = 5;
606
- let nonce = await web3.eth.getTransactionCount(address, 'pending');
607
- log.debug(tag, "Success with node:", node.service, "nonce:", nonce);
608
- return nonce;
609
- }
610
- catch (nodeError) {
611
- lastError = nodeError;
612
- log.debug(tag, "Failed with node:", node.service, "Error:", nodeError.message);
613
- }
614
- }
615
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + lastError.message);
616
- }
617
- catch (e) {
618
- console.error(tag, e);
619
- throw e;
620
- }
621
- };
622
- const estimate_gas_by_network = async function (networkId, transaction) {
623
- let tag = TAG + " | estimate_gas_by_network | ";
624
- try {
625
- if (!transaction)
626
- throw Error("Transaction object required!");
627
- let nodes = NODES.filter((n) => n.networkId === networkId);
628
- if (!nodes || nodes.length === 0)
629
- throw Error("101: missing nodes for network " + networkId);
630
- let lastError;
631
- for (let i = 0; i < nodes.length && i < 5; i++) {
632
- let node = nodes[i];
633
- try {
634
- log.debug(tag, "Trying node:", node.service);
635
- let web3 = new Web3(node.service);
636
- web3.eth.transactionBlockTimeout = 5;
637
- let gas = await web3.eth.estimateGas(transaction);
638
- log.debug(tag, "Success with node:", node.service, "gas:", gas);
639
- return gas;
640
- }
641
- catch (nodeError) {
642
- lastError = nodeError;
643
- log.debug(tag, "Failed with node:", node.service, "Error:", nodeError.message);
644
- }
645
- }
646
- throw new Error("All nodes failed for network " + networkId + ". Last error: " + lastError.message);
647
- }
648
- catch (e) {
649
- console.error(tag, e);
650
- throw e;
651
- }
652
- };
653
- const get_all_pioneers = async function () {
654
- let tag = TAG + " | get_all_pioneers | ";
655
- try {
656
- let output = {};
657
- const nftContract = new web3.eth.Contract(constant_1.ERC721_ABI, constant_1.PIONEER_CONTRACT_ADDRESS);
658
- const metadataContract = new web3.eth.Contract(constant_1.METADATA_ABI, constant_1.PIONEER_METADATA_CONTRACT_ADDRESS);
659
- // Fetch the total supply of the NFTs
660
- const totalSupply = await nftContract.methods.totalSupply().call();
661
- log.debug("totalSupply: ", totalSupply);
662
- output['totalSupply'] = totalSupply;
663
- output['owners'] = [];
664
- output['images'] = []; // add an images array to output
665
- for (let i = 0; i < totalSupply; i++) {
666
- //slow down
667
- // await sleep(1000);
668
- try {
669
- const owner = await nftContract.methods.ownerOf(i).call();
670
- log.debug(tag, "owner: ", owner);
671
- output['owners'].push(owner.toLowerCase());
672
- //get images
673
- const imageInfo = await metadataContract.methods.getAttributes(i).call();
674
- //log.debug(tag,"imageInfo: ",imageInfo)
675
- // Parse the JSON string and get the image name
676
- const imageName = JSON.parse(imageInfo['0'])["0-backgrounds"];
677
- // Build the full image URL by replacing the image name in the base URL
678
- const baseImageUrl = "https://ipfs.io/ipfs/bafybeiezdzjofkcpiwy5hlvxwzkgcztxc6xtodh3q7eddfjmqsguqs47aa/0-backgrounds/";
679
- const fullImageUrl = baseImageUrl + imageName + ".png";
680
- // Add this image URL to the images array in output
681
- output['images'].push({ address: owner.toLowerCase(), image: fullImageUrl });
682
- }
683
- catch (e) {
684
- log.debug("no image for: ", i);
685
- }
686
- }
687
- return output;
688
- }
689
- catch (e) {
690
- console.error(tag, e);
691
- }
692
- };
693
- const get_all_pioneers_base = async function () {
694
- let tag = TAG + " | get_all_pioneers_base | ";
695
- try {
696
- let output = {};
697
- log.info(tag, "PIONEER_CONTRACT_ADDRESS_BASE: ", constant_1.PIONEER_CONTRACT_ADDRESS_BASE);
698
- const nftContract = new web3Base.eth.Contract(constant_1.ERC721_ABI, constant_1.PIONEER_CONTRACT_ADDRESS_BASE);
699
- const metadataContract = new web3Base.eth.Contract(constant_1.METADATA_ABI, constant_1.PIONEER_METADATA_CONTRACT_ADDRESS_BASE);
700
- // Fetch the total supply of the NFTs
701
- const totalSupply = await nftContract.methods.totalSupply().call();
702
- log.info("totalSupply: ", totalSupply);
703
- output['totalSupply'] = totalSupply;
704
- output['owners'] = [];
705
- output['images'] = []; // add an images array to output
706
- for (let i = 0; i < totalSupply; i++) {
707
- //slow down
708
- // await sleep(1000);
709
- try {
710
- const owner = await nftContract.methods.ownerOf(i).call();
711
- log.info(tag, "owner: ", owner);
712
- output['owners'].push(owner.toLowerCase());
713
- //get images
714
- const imageInfo = await metadataContract.methods.getAttributes(i).call();
715
- log.info(tag, "imageInfo: ", imageInfo);
716
- // Parse the JSON string and get the image name
717
- const imageName = JSON.parse(imageInfo['0'])["0-backgrounds"];
718
- // Build the full image URL by replacing the image name in the base URL
719
- const baseImageUrl = "https://ipfs.io/ipfs/bafybeiezdzjofkcpiwy5hlvxwzkgcztxc6xtodh3q7eddfjmqsguqs47aa/0-backgrounds/";
720
- const fullImageUrl = baseImageUrl + imageName + ".png";
721
- // Add this image URL to the images array in output
722
- output['images'].push({ address: owner.toLowerCase(), image: fullImageUrl });
723
- }
724
- catch (e) {
725
- log.debug("no image for: ", i);
726
- }
727
- }
728
- return output;
729
- }
730
- catch (e) {
731
- console.error(tag, e);
732
- }
733
- };
734
- const decode_tx = async function (tx) {
735
- let tag = TAG + " | decode_tx | ";
736
- try {
737
- const data = ethers.utils.parseTransaction(tx);
738
- return data;
739
- }
740
- catch (e) {
741
- console.error(tag, e);
742
- }
743
- };
744
- const build_airdrop_claim = async function (address) {
745
- let tag = TAG + " | build_airdrop_claim | ";
746
- try {
747
- const airdropContract = new web3.eth.Contract(constant_1.AIRDROP_ABI, constant_1.AIRDROP_CONTRACT);
748
- let accountInfo = await axios({ method: 'GET', url: constant_1.CLAIM_URL + '/' + address });
749
- //console.log("accountInfo: ",accountInfo)
750
- if (!accountInfo.data.index)
751
- throw Error("Not found in db! ");
752
- //
753
- //console.log("airdropContract: ",accountInfo.data.contract)
754
- const AirDropInterface = new abi_1.Interface(constant_1.AIRDROP_ABI);
755
- // const data = airdropContract.methods.claim(
756
- // accountInfo.data.index,
757
- // address,
758
- // 150,
759
- // accountInfo.data.proof
760
- // )
761
- // console.log("airdropContract: ",[
762
- // accountInfo.data.index as number,
763
- // address,
764
- // '0x0821ab0d4414980000',
765
- // accountInfo.data.proof
766
- // ])
767
- const data = AirDropInterface.encodeFunctionData('claim', [
768
- accountInfo.data.index,
769
- address,
770
- '0x0821ab0d4414980000',
771
- accountInfo.data.proof
772
- ]);
773
- return data;
774
- }
775
- catch (e) {
776
- console.error(tag, e);
777
- }
778
- };
779
- const check_airdrop_claim = async function (address) {
780
- let tag = TAG + " | check_airdrop_claim | ";
781
- try {
782
- //
783
- let accountInfo = await axios({ method: 'GET', url: constant_1.CLAIM_URL + '/' + address });
784
- //console.log("accountInfo: ",accountInfo)
785
- let output = {};
786
- if (accountInfo.data.index) {
787
- output.isElgible = true;
788
- output.contract = accountInfo.data.contractAddress;
789
- //get index?
790
- //check contract
791
- //const AirDropInterface = new Interface(AirDropABI)
792
- const airdropContract = new web3.eth.Contract(constant_1.AIRDROP_ABI, accountInfo.data.contractAddress);
793
- //get index by address?
794
- //log.debug("index: ",accountInfo.data.index)
795
- let isClaimed = await airdropContract.methods.isClaimed(accountInfo.data.index).call();
796
- output.isClaimed = isClaimed;
797
- }
798
- else {
799
- output.isElgible = false;
800
- }
801
- return output;
802
- }
803
- catch (e) {
804
- console.error(tag, e);
805
- }
806
- };
807
- // const get_token_transfer_data = async function(toAddress: string, amount: string, contract: string) {
808
- // const tag = TAG + " | get_token_transfer_data | ";
809
- // try {
810
- // const minABI = [
811
- // // balanceOf
812
- // {
813
- // "constant": true,
814
- // "inputs": [{ "name": "_owner", "type": "address" }],
815
- // "name": "balanceOf",
816
- // "outputs": [{ "name": "balance", "type": "uint256" }],
817
- // "type": "function"
818
- // },
819
- // // decimals
820
- // {
821
- // "constant": true,
822
- // "inputs": [],
823
- // "name": "decimals",
824
- // "outputs": [{ "name": "", "type": "uint8" }],
825
- // "type": "function"
826
- // }
827
- // ];
828
- // const newContract = new web3.eth.Contract(minABI, contract);
829
- // const decimalPlaces = await newContract.methods.decimals().call();
830
- //
831
- // // Convert amount to the appropriate number of decimal places
832
- // const amountInSmallestUnit = web3.utils.toBN(amount).mul(web3.utils.toBN(10).pow(decimalPlaces));
833
- //
834
- // // Convert the amount to a hexadecimal string
835
- // const amountHex = amountInSmallestUnit.toString(16);
836
- //
837
- // // Pad the hexadecimal string with zeros to 64 characters
838
- // const amountHexPadded = amountHex.padStart(64, '0');
839
- //
840
- // // Parse the token data
841
- // const tokenData = web3.eth.abi.encodeFunctionCall({
842
- // name: 'transfer',
843
- // type: 'function',
844
- // inputs: [
845
- // {
846
- // type: 'address',
847
- // name: '_to'
848
- // },
849
- // {
850
- // type: 'uint256',
851
- // name: '_value'
852
- // }
853
- // ]
854
- // }, [toAddress, amountInSmallestUnit.toString()]);
855
- //
856
- // return tokenData;
857
- // } catch (e) {
858
- // console.error(tag, e);
859
- // }
860
- // }
861
- // const get_token_transfer_data = async function(toAddress: string, amount: string, contract: string) {
862
- // const tag = TAG + " | get_token_transfer_data | ";
863
- // try {
864
- // const minABI = [
865
- // // balanceOf
866
- // {
867
- // "constant": true,
868
- // "inputs": [{ "name": "_owner", "type": "address" }],
869
- // "name": "balanceOf",
870
- // "outputs": [{ "name": "balance", "type": "uint256" }],
871
- // "type": "function"
872
- // },
873
- // // decimals
874
- // {
875
- // "constant": true,
876
- // "inputs": [],
877
- // "name": "decimals",
878
- // "outputs": [{ "name": "", "type": "uint8" }],
879
- // "type": "function"
880
- // }
881
- // ];
882
- // const newContract = new web3.eth.Contract(minABI, contract);
883
- // const decimalPlaces = await newContract.methods.decimals().call();
884
- //
885
- // // Convert amount to the appropriate number of decimal places
886
- // const amountInWei = web3.utils.toWei(amount, 'ether');
887
- // const decimals = web3.utils.toBN(decimalPlaces);
888
- // const amountInSmallestUnit = web3.utils.toBN(amountInWei).mul(web3.utils.toBN(10).pow(decimals));
889
- //
890
- // // Convert the amount to a hexadecimal string
891
- // const amountHex = amountInSmallestUnit.toString(16);
892
- //
893
- // // Pad the hexadecimal string with zeros to 64 characters
894
- // const amountHexPadded = amountHex.padStart(64, '0');
895
- //
896
- // // Parse the token data
897
- // const tokenData = web3.eth.abi.encodeFunctionCall({
898
- // name: 'transfer',
899
- // type: 'function',
900
- // inputs: [
901
- // {
902
- // type: 'address',
903
- // name: '_to'
904
- // },
905
- // {
906
- // type: 'uint256',
907
- // name: '_value'
908
- // }
909
- // ]
910
- // }, [toAddress, amountInSmallestUnit.toString()]);
911
- //
912
- // return tokenData;
913
- // } catch (e) {
914
- // console.error(tag, e);
915
- // }
916
- // }
917
- const get_token_transfer_data = async function (toAddress, amount, contract) {
918
- const tag = TAG + " | get_token_transfer_data | ";
919
- try {
920
- const minABI = [
921
- // balanceOf
922
- {
923
- "constant": true,
924
- "inputs": [{ "name": "_owner", "type": "address" }],
925
- "name": "balanceOf",
926
- "outputs": [{ "name": "balance", "type": "uint256" }],
927
- "type": "function"
928
- },
929
- // decimals
930
- {
931
- "constant": true,
932
- "inputs": [],
933
- "name": "decimals",
934
- "outputs": [{ "name": "", "type": "uint8" }],
935
- "type": "function"
936
- }
937
- ];
938
- const newContract = new web3.eth.Contract(minABI, contract);
939
- const decimalPlaces = await newContract.methods.decimals().call();
940
- // Convert amount to the appropriate number of decimal places
941
- // Note: we're assuming 'amount' is a string representing a decimal number
942
- const amountInSmallestUnit = web3.utils.toBN(parseFloat(amount) * Math.pow(10, decimalPlaces));
943
- // Convert the amount to a hexadecimal string
944
- const amountHex = amountInSmallestUnit.toString(16);
945
- // Pad the hexadecimal string with zeros to 64 characters
946
- const amountHexPadded = amountHex.padStart(64, '0');
947
- // Parse the token data
948
- const tokenData = web3.eth.abi.encodeFunctionCall({
949
- name: 'transfer',
950
- type: 'function',
951
- inputs: [
952
- {
953
- type: 'address',
954
- name: '_to'
955
- },
956
- {
957
- type: 'uint256',
958
- name: '_value'
959
- }
960
- ]
961
- }, [toAddress, amountInSmallestUnit.toString()]);
962
- return tokenData;
963
- }
964
- catch (e) {
965
- console.error(tag, e);
966
- }
967
- };
968
- // //get_token_transfer_data
969
- // const get_token_transfer_data = async function(toAddress:string, amount:string, contract:string){
970
- // let tag = TAG + " | get_token_transfer_data | "
971
- // try{
972
- //
973
- // let minABI = [
974
- // // balanceOf
975
- // {
976
- // "constant": true,
977
- // "inputs": [{ "name": "_owner", "type": "address" }],
978
- // "name": "balanceOf",
979
- // "outputs": [{ "name": "balance", "type": "uint256" }],
980
- // "type": "function"
981
- // },
982
- // // decimals
983
- // {
984
- // "constant": true,
985
- // "inputs": [],
986
- // "name": "decimals",
987
- // "outputs": [{ "name": "", "type": "uint8" }],
988
- // "type": "function"
989
- // }
990
- // ];
991
- // const newContract = new web3.eth.Contract(minABI, contract);
992
- // const decimalPlaces = await newContract.methods.decimals().call();
993
- // //
994
- // // // @ts-ignore
995
- // // let value = parseInt(amount/Math.pow(10, decimals))
996
- // // //const adjustedValue = value.mul(web3.utils.toBN(10).pow(web3.utils.toBN(decimals)));
997
- // //
998
- // // log.debug(tag, "adjustedValue: ", value.toString());
999
- //
1000
- // // Calculate the amount in the token's smallest unit
1001
- // const amountInWei = web3.utils.toWei(amount, 'ether');
1002
- // const decimals = web3.utils.toBN(decimalPlaces);
1003
- // const amountInSmallestUnit = web3.utils.toBN(amountInWei).mul(web3.utils.toBN(10).pow(decimals));
1004
- //
1005
- // // Convert the amount to a hexadecimal string
1006
- // const amountHex = amountInSmallestUnit.toString(16);
1007
- //
1008
- // // Pad the hexadecimal string with zeros to 64 characters
1009
- // const amountHexPadded = amountHex.padStart(64, '0');
1010
- //
1011
- // //parse to prescision?
1012
- // let tokenData = await web3.eth.abi.encodeFunctionCall({
1013
- // name: 'transfer',
1014
- // type: 'function',
1015
- // inputs: [
1016
- // {
1017
- // type: 'address',
1018
- // name: '_to'
1019
- // },
1020
- // {
1021
- // type: 'uint256',
1022
- // name: '_value'
1023
- // }
1024
- // ]
1025
- // }, [toAddress, amountInSmallestUnit]);
1026
- //
1027
- // return tokenData
1028
- // }catch(e){
1029
- // console.error(tag,e)
1030
- // }
1031
- // }
1032
- const get_symbol_from_contract = async function (address) {
1033
- let tag = TAG + " | get_symbol_from_contract | ";
1034
- try {
1035
- //get total LP tokens
1036
- //LP token
1037
- const contract = new web3.eth.Contract(constant_1.ERC20ABI, address);
1038
- //log.debug(tag,"contract: ",contract)
1039
- let tokenName = await contract.methods.name().call();
1040
- //log.debug(tag,"tokenName: ",tokenName)
1041
- return tokenName;
1042
- }
1043
- catch (e) {
1044
- console.error(tag, e);
1045
- }
1046
- };
1047
- const get_stream = async function (streamId) {
1048
- let tag = TAG + " | get_stream | ";
1049
- try {
1050
- //get total LP tokens
1051
- //LP token
1052
- const sablierContract = new web3.eth.Contract(constant_1.SABLIER_ABI, constant_1.PROXY_CONTRACT_SABLIER);
1053
- //log.debug(tag,"sablierContract: ",sablierContract)
1054
- //log.debug(tag,"streamId: ",streamId)
1055
- streamId = parseInt(streamId);
1056
- let totalFox = await sablierContract.methods.getSalary(streamId).call();
1057
- //log.debug(tag,"totalFox: ",totalFox)
1058
- return totalFox;
1059
- }
1060
- catch (e) {
1061
- console.error(tag, e);
1062
- }
1063
- };
1064
- const get_tx_count = async function (address, options) {
1065
- let tag = TAG + " | get_tx_count | ";
1066
- try {
1067
- log.debug(tag, "address: ", address);
1068
- if (!address)
1069
- throw Error("102: address required!");
1070
- //confirmed
1071
- let txsConfirmed = await web3.eth.getTransactionCount(address);
1072
- //pending
1073
- let txsWithPending = await web3.eth.getTransactionCount(address, 'pending');
1074
- //count pending
1075
- let pending = txsConfirmed - txsWithPending;
1076
- return {
1077
- confirmed: txsConfirmed,
1078
- total: txsWithPending,
1079
- pending
1080
- };
1081
- }
1082
- catch (e) {
1083
- console.error(tag, e);
1084
- }
1085
- };
1086
- const get_pool_percent = async function (amountFox, amountEth, poolAddress) {
1087
- let tag = TAG + " | get_pool_percent | ";
1088
- try {
1089
- //get total LP tokens
1090
- //LP token
1091
- const lpContract = new web3.eth.Contract(constant_1.ERC20ABI, constant_1.UNISWAP_V2_WETH_FOX_POOL_ADDRESS);
1092
- const foxContract = new web3.eth.Contract(constant_1.ERC20ABI, constant_1.FOX_TOKEN_CONTRACT_ADDRESS);
1093
- const wethContract = new web3.eth.Contract(constant_1.ERC20ABI, constant_1.WETH_TOKEN_CONTRACT_ADDRESS);
1094
- //log.debug("lpContract: ",lpContract)
1095
- let totalSupply = await lpContract.methods.totalSupply().call();
1096
- totalSupply = totalSupply / BASE;
1097
- log.debug("LP totalSupply: ", totalSupply);
1098
- //get total fox in pool
1099
- let totalFox = await foxContract.methods.balanceOf(constant_1.UNISWAP_V2_WETH_FOX_POOL_ADDRESS).call();
1100
- totalFox = totalFox / BASE;
1101
- log.debug("totalFox: ", totalFox / BASE);
1102
- //get total eth in pool
1103
- let totalEth = await wethContract.methods.balanceOf(constant_1.UNISWAP_V2_WETH_FOX_POOL_ADDRESS).call();
1104
- totalEth = totalEth / BASE;
1105
- log.debug("totalEth: ", totalEth);
1106
- //token math
1107
- let result = totalFox / totalEth;
1108
- log.debug("result: ", result);
1109
- //balance
1110
- let lpTokens = (amountFox * totalSupply) / totalFox;
1111
- log.debug("lpTokens: ", lpTokens);
1112
- //total LP tokens
1113
- //liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
1114
- let percent = (lpTokens / totalSupply) * 100;
1115
- log.debug("percent: ", percent);
1116
- return percent;
1117
- }
1118
- catch (e) {
1119
- console.error(tag, e);
1120
- }
1121
- };
1122
- const get_balances = async function (addresses) {
1123
- let tag = TAG + " | get_balances | ";
1124
- try {
1125
- let actions = [];
1126
- for (let i = 0; i < addresses.length; i++) {
1127
- let address = addresses[i];
1128
- let action = {
1129
- method: "eth_getBalance",
1130
- params: [address]
1131
- };
1132
- actions.push(action);
1133
- }
1134
- let result = await rpcCallBatch(actions);
1135
- //covert
1136
- let output = [];
1137
- for (let i = 0; i < result.length; i++) {
1138
- let entry = result[i];
1139
- let balance = entry.result;
1140
- balance = Web3Utils.hexToNumberString(balance);
1141
- balance = balance / BASE;
1142
- output.push(balance);
1143
- }
1144
- return output;
1145
- }
1146
- catch (e) {
1147
- console.error(tag, e);
1148
- }
1149
- };
1150
- const rpcCallBatch = async (actions) => {
1151
- let tag = TAG + " | post_request | ";
1152
- try {
1153
- let body = [];
1154
- for (let i = 0; i < actions.length; i++) {
1155
- let action = actions[i];
1156
- let req = {
1157
- "jsonrpc": "2.0",
1158
- "method": action.method,
1159
- "params": action.params,
1160
- "id": 1
1161
- };
1162
- body.push(req);
1163
- }
1164
- let options = {
1165
- method: "POST",
1166
- url: NODE_URL,
1167
- headers: { 'content-type': 'application/json' },
1168
- body: JSON.stringify(body)
1169
- };
1170
- //console.log("options: ",options)
1171
- let result = await request(options);
1172
- //console.log("result: ",result)
1173
- result = JSON.parse(result);
1174
- if (result.error)
1175
- throw JSON.stringify(result.error);
1176
- return result;
1177
- }
1178
- catch (err) {
1179
- throw new Error(err);
1180
- }
1181
- };
1182
- //get_approval_status
1183
- const get_allowance = async function (tokenAddress, spender, sender) {
1184
- let tag = TAG + " | get_allowance | ";
1185
- try {
1186
- let contract = new web3.eth.Contract(constant_1.ERC20ABI, tokenAddress);
1187
- let allowance = await contract.methods.allowance(spender, sender).call();
1188
- return allowance;
1189
- }
1190
- catch (e) {
1191
- console.error(tag, e);
1192
- }
1193
- };
1194
- const get_all_tokens_blockbook = async function (address) {
1195
- let tag = TAG + " | get_all_tokens_blockbook | ";
1196
- try {
1197
- //
1198
- let ethInto = await blockbook.getEthInfo(address);
1199
- log.debug(tag, "ethInto: ", ethInto);
1200
- return true;
1201
- }
1202
- catch (e) {
1203
- console.error(tag, e);
1204
- }
1205
- };
1206
- const get_nfts = async function (address) {
1207
- let tag = TAG + " | get_nfts | ";
1208
- try {
1209
- //get nfts from etherscan (v3 uniswap)
1210
- //
1211
- let ethInfo = await blockbook.getAddressInfo('ETH', address);
1212
- //TODO filter by LP contracts
1213
- log.debug(tag, "ethInfo: ", ethInfo);
1214
- return ethInfo;
1215
- }
1216
- catch (e) {
1217
- console.error(tag, e);
1218
- }
1219
- };
1220
- const get_pool_positions = async function (address) {
1221
- let tag = TAG + " | get_pool_positions | ";
1222
- try {
1223
- //get nfts from etherscan (v3 uniswap)
1224
- //
1225
- let ethInfo = await blockbook.getAddressInfo('ETH', address);
1226
- //TODO filter by LP contracts
1227
- log.debug(tag, "ethInfo: ", ethInfo);
1228
- return ethInfo;
1229
- }
1230
- catch (e) {
1231
- console.error(tag, e);
1232
- }
1233
- };
1234
- /*
1235
- let swap = {
1236
- inboundAddress: {
1237
- chain: 'ETH',
1238
- pub_key: 'tthorpub1addwnpepqvuy8vh6yj4h28xp6gfpjsztpj6p46y2rs0763t6uw9f6lkky0ly5uvwla6',
1239
- address: '0x36286e570c412531aad366154eea9867b0e71755',
1240
- router: '0x9d496De78837f5a2bA64Cb40E62c19FBcB67f55a',
1241
- halted: false
1242
- },
1243
- asset: {
1244
- chain: 'ETH',
1245
- symbol: 'ETH',
1246
- ticker: 'ETH',
1247
- iconPath: 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/binance/assets/ETH-1C9/logo.png'
1248
- },
1249
- memo: '=:THOR.RUNE:tthor1veu9u5h4mtdq34fjgu982s8pympp6w87ag58nh',
1250
- amount: "0.1"
1251
- }
1252
- */
1253
- let get_memo_data = async function (swap) {
1254
- let tag = TAG + " | get_memo_data | ";
1255
- try {
1256
- const web3 = new Web3();
1257
- if (!swap.inboundAddress.router)
1258
- throw Error("Router required!");
1259
- const routerContract = new web3.eth.Contract(constant_1.TCRopstenAbi, swap.inboundAddress.router);
1260
- const memo = swap.memo;
1261
- //TODO support tokens?
1262
- const data = routerContract.methods
1263
- .deposit(swap.inboundAddress.address, '0x0000000000000000000000000000000000000000', // 0 = ETH
1264
- web3.utils.toBN(swap.amount * BASE), memo)
1265
- .encodeABI();
1266
- return data;
1267
- }
1268
- catch (e) {
1269
- log.error(tag, e);
1270
- throw e;
1271
- }
1272
- };
1273
- /*
1274
- X-chain compatible call
1275
- */
1276
- let estimate_fee = async function (sourceAsset, params) {
1277
- let tag = TAG + " | estimate_fee | ";
1278
- try {
1279
- let checkSummedAddress;
1280
- let decimal;
1281
- if (sourceAsset.symbol === 'ETH') {
1282
- checkSummedAddress = '0x0000000000000000000000000000000000000000';
1283
- decimal = utils_1.ETH_DECIMAL;
1284
- }
1285
- else {
1286
- throw Error("TODO");
1287
- // const assetAddress = sourceAsset.symbol.slice(sourceAsset.ticker.length + 1);
1288
- // const strip0x = assetAddress.substr(2);
1289
- // checkSummedAddress = ethers.utils.getAddress(strip0x);
1290
- //
1291
- // const tokenContract = new ethers.Contract(checkSummedAddress, erc20ABI, wallet);
1292
- // const tokenDecimals = await tokenContract.decimals();
1293
- // decimal = tokenDecimals.toNumber();
1294
- }
1295
- // Connect to the network
1296
- let provider = PROVIDER;
1297
- // Get the current block
1298
- let block = await provider.getBlockNumber();
1299
- log.debug(tag, "block: ", block);
1300
- const { average: averageGP, fast: fastGP, fastest: fastestGP } = (0, utils_1.getDefaultGasPrices)();
1301
- let assetAddress;
1302
- // @ts-ignore
1303
- if (sourceAsset && (0, xchain_util_1.assetToString)(sourceAsset) !== (0, xchain_util_1.assetToString)(xchain_util_1.AssetETH)) {
1304
- // @ts-ignore
1305
- assetAddress = (0, utils_1.getTokenAddress)(sourceAsset);
1306
- }
1307
- let gasLimit;
1308
- if (assetAddress && assetAddress !== utils_1.ETHAddress) {
1309
- if (!params.sender || !params.recipient)
1310
- throw Error("missing params! need sender and recipient on token tx!");
1311
- let contract = new ethers.Contract(assetAddress, constant_1.ERC20ABI, provider);
1312
- gasLimit = params.data
1313
- ? await contract.estimateGas.transfer(params.recipient, params.data, { from: params.sender })
1314
- : await contract.estimateGas.transfer(params.recipient, 1, { from: params.sender }); // amount = 1 as a dummy value
1315
- }
1316
- else {
1317
- // ETH transfer
1318
- if (!params.sender || !params.recipient)
1319
- throw Error("missing params! need sender and recipient");
1320
- const gasEstimate = await provider.estimateGas({
1321
- from: params.sender,
1322
- to: params.recipient,
1323
- value: ethers.utils.parseEther('0.000001') // using dummy ETH amount for gas calculation
1324
- });
1325
- gasLimit = gasEstimate.add(0); // Add extra gas as buffer
1326
- console.log("ETH gasEstimate: ", gasEstimate.toString());
1327
- console.log("ETH gasEstimate + buffer: ", gasLimit.toString());
1328
- }
1329
- return {
1330
- gasPrices: {
1331
- average: averageGP,
1332
- fast: fastGP,
1333
- fastest: fastestGP
1334
- },
1335
- gasLimit,
1336
- fees: {
1337
- type: 'byte',
1338
- average: (0, utils_1.getFee)({ gasPrice: averageGP, gasLimit }),
1339
- fast: (0, utils_1.getFee)({ gasPrice: fastGP, gasLimit }),
1340
- fastest: (0, utils_1.getFee)({ gasPrice: fastestGP, gasLimit })
1341
- }
1342
- };
1343
- }
1344
- catch (e) {
1345
- console.error(tag, "Error: ", e);
1346
- throw e;
1347
- }
1348
- };
1349
- let get_gas_limit = async function ({ asset, recipient, amount, memo }) {
1350
- let tag = TAG + " | get_gas_limit | ";
1351
- try {
1352
- log.debug(tag, "input: ", { asset, recipient, amount, memo });
1353
- const txAmount = BigNumber.from(amount?.amount().toFixed());
1354
- let assetAddress;
1355
- // @ts-ignore
1356
- if (asset && (0, xchain_util_1.assetToString)(asset) !== (0, xchain_util_1.assetToString)(xchain_util_1.AssetETH)) {
1357
- // @ts-ignore
1358
- assetAddress = (0, utils_1.getTokenAddress)(asset);
1359
- }
1360
- let estimate;
1361
- //NOTE: I changed the from to recipient because this module has no context to address of the sender.
1362
- // I hope I dont skrew the pooch and the differnce +-1 byte between addresses actually matter
1363
- if (assetAddress && assetAddress !== utils_1.ETHAddress) {
1364
- // ERC20 gas estimate
1365
- const contract = new ethers.Contract(assetAddress, utils_1.erc20ABI, PROVIDER);
1366
- estimate = await contract.estimateGas.transfer(recipient, txAmount, {
1367
- from: recipient,
1368
- });
1369
- }
1370
- else {
1371
- // ETH gas estimate
1372
- const transactionRequest = {
1373
- from: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", //address with lots of eth
1374
- to: recipient,
1375
- value: txAmount,
1376
- data: memo ? toUtf8Bytes(memo) : undefined,
1377
- };
1378
- estimate = await PROVIDER.estimateGas(transactionRequest);
1379
- }
1380
- return estimate;
1381
- }
1382
- catch (e) {
1383
- log.error(tag, e);
1384
- throw e;
1385
- }
1386
- };
1387
- let get_fees = async function (params) {
1388
- let tag = TAG + " | get_fees | ";
1389
- try {
1390
- const response = await etherscanAPI.getGasOracle(ETHERSCAN.baseUrl, ETHERSCAN.apiKey);
1391
- // Convert result of gas prices: `Gwei` -> `Wei`
1392
- const averageWei = parseUnits(response.SafeGasPrice, 'gwei');
1393
- const fastWei = parseUnits(response.ProposeGasPrice, 'gwei');
1394
- const fastestWei = parseUnits(response.FastGasPrice, 'gwei');
1395
- let gasPrices = {
1396
- average: (0, xchain_util_1.baseAmount)(averageWei.toString(), utils_1.ETH_DECIMAL),
1397
- fast: (0, xchain_util_1.baseAmount)(fastWei.toString(), utils_1.ETH_DECIMAL),
1398
- fastest: (0, xchain_util_1.baseAmount)(fastestWei.toString(), utils_1.ETH_DECIMAL),
1399
- };
1400
- const { fast: fastGP, fastest: fastestGP, average: averageGP } = gasPrices;
1401
- if (!params.amount || !params?.amount?.amount) {
1402
- // @ts-ignore
1403
- params.amount = {
1404
- // @ts-ignore
1405
- amount: function () { return .98; }
1406
- };
1407
- }
1408
- log.debug(tag, "get_gas_limit: ", {
1409
- asset: params.asset,
1410
- amount: params.amount,
1411
- recipient: params.recipient,
1412
- memo: params.memo,
1413
- });
1414
- const gasLimit = await get_gas_limit({
1415
- asset: params.asset,
1416
- amount: params.amount,
1417
- recipient: params.recipient,
1418
- memo: params.memo,
1419
- });
1420
- let output = {
1421
- gasPrices,
1422
- fees: {
1423
- type: 'byte',
1424
- average: (0, utils_1.getFee)({ gasPrice: averageGP, gasLimit }).amount().toString(),
1425
- fast: (0, utils_1.getFee)({ gasPrice: fastGP, gasLimit }).amount().toString(),
1426
- fastest: (0, utils_1.getFee)({ gasPrice: fastestGP, gasLimit }).amount().toString(),
1427
- },
1428
- gasLimit,
1429
- };
1430
- return output;
1431
- }
1432
- catch (e) {
1433
- log.error(tag, e);
1434
- throw e;
1435
- }
1436
- };
1437
- let broadcast_transaction = async function (tx) {
1438
- let tag = TAG + " | broadcast_transaction | ";
1439
- try {
1440
- let output = {};
1441
- output.success = false;
1442
- log.debug(tag, "tx: ", tx);
1443
- if (!tx)
1444
- throw Error("101: missing tx!");
1445
- //push node
1446
- // web3.eth.sendSignedTransaction(tx)
1447
- //push etherscan
1448
- //https://api.etherscan.io/api?module=proxy&action=eth_sendRawTransaction&hex=0xf904808000831cfde080&apikey=YourApiKeyToken
1449
- let resp = await axios({
1450
- method: 'GET',
1451
- url: 'https://api.etherscan.io/api?module=proxy&action=eth_sendRawTransaction&hex=' + tx + '&apikey=' + process.env['ETHERSCAN_API_KEY']
1452
- });
1453
- resp = resp.data;
1454
- console.log(resp);
1455
- //push blockbook
1456
- //TODO lifecycle hook?
1457
- // let resp2 = await web3.eth.sendSignedTransaction(tx)
1458
- // .on('transactionHash', function(hash:any){
1459
- // console.log("hash: ",hash)
1460
- // })
1461
- // .on('receipt', function(receipt:any){
1462
- // console.log("receipt: ",receipt)
1463
- // })
1464
- // .on('confirmation', function(confirmationNumber:any, receipt:any){
1465
- // console.log(confirmationNumber,receipt)
1466
- // })
1467
- // .on('error', console.error);
1468
- //console.log("resp: ",resp)
1469
- if (!resp.error)
1470
- output.success = true;
1471
- if (resp.error)
1472
- output.error = resp;
1473
- if (resp.result)
1474
- output.txid = resp.result;
1475
- return output;
1476
- }
1477
- catch (e) {
1478
- log.error(tag, e);
1479
- throw e;
1480
- }
1481
- };
1482
- const get_balance_tokens_by_network = async function (networkId, address) {
1483
- let tag = TAG + " | get_balance_tokens_by_network | ";
1484
- try {
1485
- let output = {};
1486
- //@TODO zapper? covalent?
1487
- return "";
1488
- }
1489
- catch (e) {
1490
- console.error(tag, e);
1491
- }
1492
- };
1493
- const get_balance_tokens = async function (address) {
1494
- let tag = TAG + " | get_balance_tokens | ";
1495
- try {
1496
- let balances = {};
1497
- let valueUsds = {};
1498
- let coinInfo = {};
1499
- //TODO other? backup?
1500
- //ethpolorer.io
1501
- let resp = await axios({
1502
- method: 'GET',
1503
- url: 'http://api.ethplorer.io/getAddressInfo/' + address + '?apiKey=' + ETHPLORER_API_KEY
1504
- });
1505
- log.debug(tag, "resp: ", resp.data);
1506
- balances['ETH'] = resp.data.ETH.balance;
1507
- valueUsds['ETH'] = parseFloat(resp.data.ETH.balance) * parseFloat(resp.data.ETH.price.rate);
1508
- //infura
1509
- let tokenInfo = resp.data.tokens;
1510
- log.debug(tag, "tokenInfo: ", tokenInfo);
1511
- //
1512
- if (tokenInfo && Object.keys(tokenInfo).length > 0) {
1513
- for (let i = 0; i < tokenInfo.length; i++) {
1514
- let info = tokenInfo[i];
1515
- if (info) {
1516
- log.debug(tag, "info: ", info);
1517
- //let symbol
1518
- let symbol = info.tokenInfo.symbol;
1519
- log.debug(tag, "symbol: ", symbol);
1520
- //rate
1521
- let rate = 0;
1522
- if (info.tokenInfo.price && info.tokenInfo.price.rate) {
1523
- log.debug(tag, "rate: ", info.tokenInfo.price.rate);
1524
- rate = info.tokenInfo.price.rate;
1525
- }
1526
- // @ts-ignore
1527
- let balance = info.balance / parseInt(Math.pow(10, info.tokenInfo.decimals));
1528
- log.debug({ rate, symbol, balance });
1529
- balances[symbol] = balance;
1530
- valueUsds[symbol] = balance * rate;
1531
- coinInfo[symbol] = info.tokenInfo;
1532
- }
1533
- }
1534
- }
1535
- return { balances, valueUsds, coinInfo };
1536
- }
1537
- catch (e) {
1538
- console.error(tag, e);
1539
- }
1540
- };
1541
- const get_balance_token_by_network = async function (networkId, address, token) {
1542
- let tag = TAG + " | get_balance_token_by_network | ";
1543
- try {
1544
- let output = {};
1545
- //find in node array node by networkId
1546
- let node = NODES.find((n) => { return n.networkId == networkId; });
1547
- if (!node)
1548
- throw Error("101: missing node! for network " + networkId);
1549
- //init new web3
1550
- let web3 = new Web3(node.service);
1551
- //decimals
1552
- let contract = new web3.eth.Contract(constant_1.ERC20ABI, token);
1553
- let decimals = await contract.methods.decimals().call();
1554
- //log.debug(tag,"decimals: ",decimals)
1555
- let balance = await contract.methods.balanceOf(address).call();
1556
- //log.debug(tag,"balance: ",balance)
1557
- return balance / Math.pow(10, decimals);
1558
- }
1559
- catch (e) {
1560
- console.error(tag, e);
1561
- }
1562
- };
1563
- const get_balance_token = async function (address, token) {
1564
- let tag = TAG + " | get_balance | ";
1565
- try {
1566
- //decimals
1567
- let contract = new web3.eth.Contract(constant_1.ERC20ABI, token);
1568
- let decimals = await contract.methods.decimals().call();
1569
- //log.debug(tag,"decimals: ",decimals)
1570
- let balance = await contract.methods.balanceOf(address).call();
1571
- //log.debug(tag,"balance: ",balance)
1572
- return balance / Math.pow(10, decimals);
1573
- }
1574
- catch (e) {
1575
- console.error(tag, e);
1576
- }
1577
- };
1578
- const get_balance_by_network = async function (networkId, address) {
1579
- let tag = TAG + " | get_balance_by_network | ";
1580
- try {
1581
- let output = {};
1582
- // Find all nodes for this network
1583
- let nodes = NODES.filter((n) => n.networkId === networkId);
1584
- if (!nodes || nodes.length === 0)
1585
- throw Error("101: missing node! for network " + networkId);
1586
- // Try each node until one works
1587
- let lastError = null;
1588
- for (let i = 0; i < nodes.length && i < 5; i++) {
1589
- try {
1590
- let node = nodes[i];
1591
- log.info(tag, `Attempting to get balance from node ${i + 1}/${nodes.length}: ${node.service}`);
1592
- //init new web3
1593
- let web3 = new Web3(node.service);
1594
- //normal tx info
1595
- output = (await web3.eth.getBalance(address)) / BASE;
1596
- log.info(tag, `Successfully got balance: ${output}`);
1597
- return output;
1598
- }
1599
- catch (nodeError) {
1600
- lastError = nodeError;
1601
- log.warn(tag, `Node ${i + 1} failed: ${nodeError.message}`);
1602
- continue;
1603
- }
1604
- }
1605
- // If all nodes failed, throw the last error
1606
- throw lastError || new Error("All nodes failed to get balance");
1607
- }
1608
- catch (e) {
1609
- console.error(tag, e);
1610
- throw e; // Re-throw the error instead of swallowing it
1611
- }
1612
- };
1613
- const get_balance = async function (address) {
1614
- let tag = TAG + " | get_balance | ";
1615
- try {
1616
- let output = {};
1617
- //normal tx info
1618
- output = (await web3.eth.getBalance(address)) / BASE;
1619
- return output;
1620
- }
1621
- catch (e) {
1622
- console.error(tag, e);
1623
- }
1624
- };
1625
- const get_transactions = async function (address, options) {
1626
- let tag = TAG + " | get_transactions | ";
1627
- try {
1628
- let output = {};
1629
- let ethInfo = await blockbook.getAddressInfo('ETH', address);
1630
- return ethInfo;
1631
- }
1632
- catch (e) {
1633
- console.error(tag, e);
1634
- }
1635
- };
1636
- const get_transaction = async function (txid) {
1637
- let tag = TAG + " | get_transaction | ";
1638
- try {
1639
- let output = {};
1640
- //normal tx info
1641
- output.txInfo = await web3.eth.getTransaction(txid);
1642
- //if contract
1643
- output.receipt = await web3.eth.getTransactionReceipt(txid);
1644
- return output;
1645
- }
1646
- catch (e) {
1647
- console.error(tag, e);
1648
- }
1649
- };
1650
- let check_online_status = async function () {
1651
- let tag = TAG + " | check_online_status | ";
1652
- try {
1653
- let output = {};
1654
- //isTestnet
1655
- output.version = await web3.eth.getNodeInfo();
1656
- output.chainId = await web3.eth.getChainId();
1657
- output.height = await web3.eth.getBlockNumber();
1658
- //TODO get peer count
1659
- output.peers = await web3.eth.net.getPeerCount();
1660
- let networkName;
1661
- switch (output.chainId.toString()) {
1662
- case "1":
1663
- networkName = "Main";
1664
- break;
1665
- case "2":
1666
- networkName = "Morden";
1667
- break;
1668
- case "3":
1669
- networkName = "Ropsten";
1670
- break;
1671
- case "4":
1672
- networkName = "Rinkeby";
1673
- break;
1674
- case "42":
1675
- networkName = "Kovan";
1676
- break;
1677
- default:
1678
- networkName = "Unknown";
1679
- }
1680
- output.networkName = networkName;
1681
- //
1682
- output.gasPrice = await web3.eth.getGasPrice();
1683
- //
1684
- output.syncing = await web3.eth.isSyncing();
1685
- return output;
1686
- }
1687
- catch (e) {
1688
- console.error(tag, e);
1689
- }
1690
- };
1691
- // Helper functions for ethers v5 compatibility
1692
- const parseUnits = (value, unit) => ethers.utils.parseUnits(value, unit);
1693
- const toUtf8Bytes = (text) => ethers.utils.toUtf8Bytes(text);
1694
- // Define our own FeeOption enum
1695
- var FeeOption;
1696
- (function (FeeOption) {
1697
- FeeOption["Average"] = "average";
1698
- FeeOption["Fast"] = "fast";
1699
- FeeOption["Fastest"] = "fastest";
1700
- })(FeeOption || (FeeOption = {}));
1701
- //# sourceMappingURL=index.js.map