Files
vic-server-mongo/src/utils/erc20.js
2019-09-08 17:24:36 +08:00

116 lines
4.4 KiB
JavaScript

'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
};