rename seckey to prikey
This commit is contained in:
@@ -1,42 +1,45 @@
|
||||
'use strict';
|
||||
'use strict'
|
||||
// 该脚本只用于系统账户对用户进行提现转账
|
||||
const { ERC20 } = require('../utils/erc20');
|
||||
const { inject } = require('./Provider');
|
||||
const { ERC20 } = require('../utils/erc20')
|
||||
const { inject } = require('./Provider')
|
||||
// const { USDTAddr } = require('./constant');
|
||||
const crypto = require('../utils/crypto');
|
||||
const crypto = require('../utils/crypto')
|
||||
|
||||
const ROOTSECWORD = inject(function (SysConfig) {
|
||||
const { ROOTSECWORD } = SysConfig;
|
||||
return ROOTSECWORD;
|
||||
});
|
||||
const { ROOTSECWORD } = SysConfig
|
||||
return ROOTSECWORD
|
||||
})
|
||||
const VICCONTRACTADDR = inject(function (SysConfig) {
|
||||
const { VICCONTRACTADDR } = SysConfig;
|
||||
return VICCONTRACTADDR;
|
||||
});
|
||||
const { VICCONTRACTADDR } = SysConfig
|
||||
return VICCONTRACTADDR
|
||||
})
|
||||
const VICSECWORD = inject(function (SysConfig) {
|
||||
const { VICSECWORD } = SysConfig;
|
||||
return VICSECWORD;
|
||||
});
|
||||
const { VICSECWORD } = SysConfig
|
||||
return VICSECWORD
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
async sendUSDT2User (toAddress, amount, option = {}) {
|
||||
const { path } = option;
|
||||
const kp = crypto.secword2keypair(ROOTSECWORD, { path });
|
||||
const account = new ERC20(kp.seckey);
|
||||
return await account.transfer(toAddress, amount, option);
|
||||
const { path } = option
|
||||
const kp = crypto.secword2keypair(ROOTSECWORD, { path })
|
||||
const account = new ERC20(kp.prikey)
|
||||
return await account.transfer(toAddress, amount, option)
|
||||
},
|
||||
async sendVIC2User (toAddress, amount, option = {}) {
|
||||
const account = ERC20.fromMnemonic(VICSECWORD, VICCONTRACTADDR);
|
||||
return await account.transfer(toAddress, amount, Object.assign(option, { decimals: 18 })).then(res => {
|
||||
const account = ERC20.fromMnemonic(VICSECWORD, VICCONTRACTADDR)
|
||||
return await account
|
||||
.transfer(toAddress, amount, Object.assign(option, { decimals: 18 }))
|
||||
.then(res => {
|
||||
return {
|
||||
success: true,
|
||||
res
|
||||
};
|
||||
}).catch(err => {
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
return {
|
||||
error: err,
|
||||
res: null
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,15 +135,15 @@ module.exports = {
|
||||
}
|
||||
return null
|
||||
},
|
||||
sign: function (data, seckey, option) {
|
||||
sign: function (data, prikey, option) {
|
||||
// data can be string or buffer or object, results are the same
|
||||
if (this.isHashable(data) && this.isSeckey(seckey)) {
|
||||
if (this.isHashable(data) && this.isSeckey(prikey)) {
|
||||
option = option || {}
|
||||
|
||||
// 使用nacl的签名算法。注意,nacl.sign需要的seckey是64字节=512位,而比特币/以太坊的seckey是32字节。因此本方法只能用于 TIC 币的 keypair。
|
||||
option.output = 'buf' // 哈希必须输出为 buffer
|
||||
var hashBuf = this.hash(data, option)
|
||||
var signature = nacl.sign.detached(hashBuf, Buffer.from(seckey, 'hex'))
|
||||
var signature = nacl.sign.detached(hashBuf, Buffer.from(prikey, 'hex'))
|
||||
return Buffer.from(signature).toString('hex') // 返回128个hex字符,64字节
|
||||
|
||||
// 方案2:尚未彻底实现。
|
||||
@@ -151,7 +151,7 @@ module.exports = {
|
||||
// let inputEncoding=my.INPUT_LIST.indexOf(option.input)>=0?option.input:my.INPUT // 'utf8', 'ascii' or 'latin1' for string data, default to utf8 if not specified; ignored for Buffer, TypedArray, or DataView.
|
||||
// let outputEncoding=(option.output==='buf')?undefined:(my.OUTPUT_LIST.indexOf(option.output)>=0?option.output:my.OUTPUT)
|
||||
// let signer=crypto.createSign(hasher)
|
||||
// return signer.update(data, inputEncoding).sign(seckey, outputEncoding) // todo: crypto的sign要求的seckey必须是PEM格式,因此这样写是不能用的。
|
||||
// return signer.update(data, inputEncoding).sign(prikey, outputEncoding) // todo: crypto的sign要求的seckey必须是PEM格式,因此这样写是不能用的。
|
||||
}
|
||||
return null
|
||||
},
|
||||
@@ -189,7 +189,7 @@ module.exports = {
|
||||
return {
|
||||
hash: hashBuf.toString('hex'),
|
||||
pubkey: Buffer.from(keypair.publicKey).toString('hex'), // 测试过 不能直接keypair.publicKey.toString('hex'),不是buffer类型
|
||||
seckey: Buffer.from(keypair.secretKey).toString('hex')
|
||||
prikey: Buffer.from(keypair.secretKey).toString('hex')
|
||||
}
|
||||
}
|
||||
return null
|
||||
@@ -226,24 +226,24 @@ module.exports = {
|
||||
return {
|
||||
coin,
|
||||
path,
|
||||
seckey: key.privateKey.toString('hex'), // 或者 key.toJSON().privateKey。或者 key.privateKey.slice(2) 删除开头的'0x'如果是ethers.HDNode.fromMnemonic(secword)的结果
|
||||
prikey: key.privateKey.toString('hex'), // 或者 key.toJSON().privateKey。或者 key.privateKey.slice(2) 删除开头的'0x'如果是ethers.HDNode.fromMnemonic(secword)的结果
|
||||
pubkey: key.publicKey.toString('hex')
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
seckey2pubkey: function (seckey, option = {}) {
|
||||
if (this.isSeckey(seckey) && seckey.length === 64) {
|
||||
seckey2pubkey: function (prikey, option = {}) {
|
||||
if (this.isSeckey(prikey) && prikey.length === 64) {
|
||||
// 只能用于32字节的私钥(BTC, ETH)。也就是不能用于 TIC 的私钥。
|
||||
const { curve = my.CURVE, compress = 'compressed' } = option
|
||||
return new crypto.ECDH(curve)
|
||||
.setPrivateKey(seckey, 'hex')
|
||||
.setPrivateKey(prikey, 'hex')
|
||||
.getPublicKey('hex', compress)
|
||||
.toString('hex') // ecdh.getPublicKey(不加参数) 默认为 'uncompressed'
|
||||
// 从 nodejs 10.0 开始,还有 crypto.ECDH.convertKey 方法,更直接。
|
||||
// 或者 require('secp256k1').publicKeyCreate(Buffer.from(seckey, 'hex'),compress).toString('hex')
|
||||
// 或者 require('bitcore-lib').PublicKey.fromPrivateKey(new Btc.PrivateKey(seckey)).toString('hex')
|
||||
// 注意,Buffer.from(nacl.box.keyPair.fromSecretKey(Buffer.from(seckey,'hex')).publicKey).toString('hex') 得到的公钥与上面的不同
|
||||
// 或者 require('secp256k1').publicKeyCreate(Buffer.from(prikey, 'hex'),compress).toString('hex')
|
||||
// 或者 require('bitcore-lib').PublicKey.fromPrivateKey(new Btc.PrivateKey(prikey)).toString('hex')
|
||||
// 注意,Buffer.from(nacl.box.keyPair.fromSecretKey(Buffer.from(prikey,'hex')).publicKey).toString('hex') 得到的公钥与上面的不同
|
||||
}
|
||||
return null
|
||||
},
|
||||
@@ -270,10 +270,10 @@ module.exports = {
|
||||
isSecword: function (secword) {
|
||||
return Secword.isValid(secword)
|
||||
},
|
||||
isSeckey: function (seckey) {
|
||||
isSeckey: function (prikey) {
|
||||
// 比特币、以太坊的私钥:64 hex
|
||||
// nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex
|
||||
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(seckey)
|
||||
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(prikey)
|
||||
},
|
||||
isPubkey: function (pubkey) {
|
||||
// 比特币的公钥:压缩型 '02|03' + 64 hex 或 无压缩型 '04' + 128 hex
|
||||
@@ -350,10 +350,10 @@ module.exports = {
|
||||
randomKeypair: function () {
|
||||
// 此函数有错!!
|
||||
let kp = nacl.box.keyPair()
|
||||
const seckey = Buffer.from(kp.secretKey).toString('hex')
|
||||
const pubkey = this.seckey2pubkey(seckey)
|
||||
const prikey = Buffer.from(kp.secretKey).toString('hex')
|
||||
const pubkey = this.seckey2pubkey(prikey)
|
||||
return {
|
||||
seckey,
|
||||
prikey,
|
||||
pubkey
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,88 +1,107 @@
|
||||
'use strict';
|
||||
'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');
|
||||
const axios = require('axios')
|
||||
const crypto = require('./crypto')
|
||||
const ethers = require('ethers')
|
||||
const ethio = require('etherscan-api').init(
|
||||
'E3ZFFAEMNN33KX4HHVUZ4KF8XY1FXMR4BI'
|
||||
)
|
||||
|
||||
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;
|
||||
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.00006
|
||||
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;
|
||||
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 fromMnemonic (secword, contractAddress, path = '') {
|
||||
let prikey = crypto.secword2keypair(secword, { coin: 'ETH', path }).prikey
|
||||
return new ERC20(prikey, 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"];
|
||||
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);
|
||||
jsonrpc: '2.0',
|
||||
method: 'eth_call',
|
||||
params: params,
|
||||
id: 6842
|
||||
}
|
||||
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 [];
|
||||
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"];
|
||||
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
|
||||
};
|
||||
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);
|
||||
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 getBalance () {
|
||||
return ERC20.getBalance(this.address, this.contractAddress)
|
||||
}
|
||||
async getDecimals() {
|
||||
let decimals = await ERC20.getDecimals(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?
|
||||
})
|
||||
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 getTransactionCount () {
|
||||
if (!ETH_NODE) {
|
||||
throw new Error('Base url required')
|
||||
}
|
||||
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');
|
||||
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,
|
||||
@@ -90,26 +109,25 @@ class ERC20 extends ethers.Wallet {
|
||||
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);
|
||||
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