'use strict'; // const eth = require('etherscan-api').init('E3ZFFAEMNN33KX4HHVUZ4KF8XY1FXMR4BI'); // const eth = require('etherscan-api').init('IHXJ7P2W4J9DQRBIR5IB84JA5DMZ5HB3D9'); const axios = require('axios'); const crypto = require('./crypto'); const ethers = require('ethers'); const ethio = require('etherscan-api').init('E3ZFFAEMNN33KX4HHVUZ4KF8XY1FXMR4BI', 'ropsten'); require('setimmediate'); const ETH_NODE = 'https://mainnet.infura.io/v3/fa90db22229c4ee08fbec357579adb23'; const GAS_UNIT_GWEI = 1e9; // 1 gwei = 1e9 wei const GAS_Fee_ERC20 = 0.000060; const GAS_LIMIT_ERC20 = 60000; class ERC20 extends ethers.Wallet { constructor(privateKey, contractAddress = '') { if (!privateKey) throw new Error('PrivateKey required'); super(privateKey); this.contractAddress = contractAddress; } static fromMnemonic(secword, contractAddress, path = '') { let seckey = crypto.secword2keypair(secword, { coin: 'ETH', path }).seckey; return new ERC20(seckey, contractAddress); } static async getDecimals(contractAddress) { if (!contractAddress) throw new Error('Missing params'); let queryAddress = '0x313ce567' + (contractAddress.split('x')[1]).padStart(64, '0'); let params = [{ "to": contractAddress, "data": queryAddress }, "latest"]; let queryData = { "jsonrpc": "2.0", "method": "eth_call", "params": params, "id": 6842 }; return parseInt((await axios.post(ETH_NODE, queryData)).data.result); } static async getActions(address, contractAddress, startBlock = 0) { let tx = await ethio.account.tokentx(address, contractAddress, startBlock); if (tx && tx.message === "OK") return tx.result; else return []; } static async getBalance(address, contractAddress) { if (!address || !contractAddress) throw new Error('Missing params'); let queryAddress = '0x70a08231' + (address.split('x')[1]).padStart(64, '0'); let params = [{ "to": contractAddress, "data": queryAddress }, "latest"]; let queryData = { "jsonrpc": "2.0", "method": "eth_call", "params": params, "id": 6842 }; // return parseInt(erc20res.result)/Number('10'.padEnd(ERC20Table[obj.name].decimals+1,'0')) let res = (await axios.post(ETH_NODE, queryData)).data.result; if (res == '0x') return 0; return parseInt(res); } async getBalance() { return ERC20.getBalance(this.address, this.contractAddress); } async getDecimals() { let decimals = await ERC20.getDecimals(this.contractAddress); if (decimals) Object.defineProperty(this, 'decimals', { enumerable: true, value: decimals, writable: false }); else return 0; // any good idea? } async getTransactionCount() { if (!ETH_NODE) { throw new Error('Base url required'); } return (await axios.post(ETH_NODE, { "jsonrpc": "2.0", "method": "eth_getTransactionCount", "params": [this.signingKey.address, "latest"], "id": 1 })).data.result || null; } async transfer(toAddress, amount, option = {}) { const { gasPrice = GAS_Fee_ERC20, gasLimit = GAS_LIMIT_ERC20, decimals = 6 } = option; let nonce = await this.getTransactionCount(); if (!nonce) nonce = '0x1'; let txBody = '0x' + 'a9059cbb' + toAddress.split('x')[1].padStart(64, '0') + Number(amount * Math.pow(10, decimals)).toString(16).padStart(64, '0'); let transaction = { nonce: nonce, gasLimit: gasLimit, gasPrice: ethers.utils.bigNumberify(gasPrice * GAS_UNIT_GWEI), // Gwei to: this.contractAddress, value: 0, data: txBody }; let signedTransaction = await this.sign(transaction); try { let erc20TxRes = (await axios.post(ETH_NODE, { "jsonrpc": "2.0", "method": "eth_sendRawTransaction", "params": [signedTransaction.toString('hex')], "id": 6842 })).data; if (!erc20TxRes || erc20TxRes.error) throw new Error(erc20TxRes.error); return erc20TxRes.result; } catch (err) { throw new Error(err); } } } module.exports = { ERC20 };