feat: 添加区块链工具
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
"cron": "^1.7.1",
|
"cron": "^1.7.1",
|
||||||
"deepmerge": "^4.0.0",
|
"deepmerge": "^4.0.0",
|
||||||
"errorhandler": "^1.5.0",
|
"errorhandler": "^1.5.0",
|
||||||
|
"ethers": "^4.0.36",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"js-sha3": "^0.8.0",
|
"js-sha3": "^0.8.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
|
|||||||
19
src/common/rootWallet.js
Normal file
19
src/common/rootWallet.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
// 该脚本只用于系统账户对用户进行提现转账
|
||||||
|
const { ERC20 } = require('../utils/erc20');
|
||||||
|
const { inject } = require('./Provider');
|
||||||
|
|
||||||
|
const USDTAddr = '0xdac17f958d2ee523a2206206994597c13d831ec7';
|
||||||
|
const RootAccount = inject(function (SysConfig) {
|
||||||
|
const { ROOTSECWORD } = SysConfig;
|
||||||
|
return ERC20.fromMnemonic(ROOTSECWORD, USDTAddr);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
async sendUSDT2User (toAddress, amount, option = {}) {
|
||||||
|
return await RootAccount.transfer(toAddress, amount, option);
|
||||||
|
},
|
||||||
|
async sendVIC2User (toAddress, amount, option = {}) {
|
||||||
|
return await RootAccount.transfer(toAddress, amount, Object.assign(option, { decimals: 18 }));
|
||||||
|
}
|
||||||
|
};
|
||||||
1
src/utils/abi.js
Normal file
1
src/utils/abi.js
Normal file
File diff suppressed because one or more lines are too long
108
src/utils/erc20.js
Normal file
108
src/utils/erc20.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
'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');
|
||||||
|
|
||||||
|
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 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
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user