From 07a88d9bc79c8d8cf8a040747db9e35a2991363b Mon Sep 17 00:00:00 2001 From: Luk Lu Date: Sat, 4 Jun 2022 12:08:41 +0800 Subject: [PATCH] rename all libs from xxx.yyy to xxx-yyy --- btc.js | 280 +++++++++-------- eth.js | 875 +++++++++++++++++++++++++++------------------------ index.js | 26 +- package.json | 10 +- tic.js | 165 +++++----- 5 files changed, 717 insertions(+), 639 deletions(-) diff --git a/btc.js b/btc.js index fe8a806..ecb7980 100644 --- a/btc.js +++ b/btc.js @@ -3,148 +3,166 @@ const axios = require('axios') const HDNode = require('./utils/hdnode') const bitcoinjs = require('bitcoinjs-lib') -const Ticrypto = require('tic.crypto') +const Ticrypto = require('tic-crypto') const BTC_NODE = require('./netConfig').BTC_NODE const BTC_NODE2 = require('./netConfig').BTC_NODE2 const BTC_TXFEE = 30 class BTC { - constructor(privateKey){ - if(!Ticrypto.isSeckey(privateKey)) throw new Error('Invalid PrivateKey') - var publicKey = Ticrypto.seckey2pubkey(privateKey) - Object.defineProperties(this,{ - "privateKey" : { - enumerable : true, - writable : false, - value : privateKey - }, - "publicKey": { - enumerable : true, - writable : false, - value : Ticrypto.seckey2pubkey(privateKey,{coin:"BTC"}) - }, - "address" : { - enumerable : true, - writable : false, - value : Ticrypto.pubkey2address(publicKey,{coin:"BTC"}) - }, - "url" : { - enumerable : true, - get: function() { return this._url }, - set: function(url) { - if (typeof(url) !== 'string') { throw new Error('invalid url') } - this._url = url - } - }, - "defaultGas":{ - enumerable: true, - get: function() { return this._defaultGasFee }, - set: function(value) { - if (typeof(value) !== 'number') { throw new Error('invalid defaultGasFee') } - this._defaultGasFee = value - } - } - }) - this._url = BTC_NODE - this._defaultGasFee = BTC_TXFEE - - } - static generateNewAccount(){ - var mnemonic = Ticrypto.randomSecword() - return Object.assign(new BTC(Ticrypto.secword2keypair(mnemonic, {coin:"BTC"}).seckey),{mnemonic : mnemonic}) - } - static fromMnemonic(mnemonic){ - HDNode.isValidMnemonic(mnemonic) - return Object.assign(new BTC(Ticrypto.secword2keypair(mnemonic, {coin:"BTC"}).seckey),{mnemonic:mnemonic}) - } - static async getBalance(address){ - return (await axios.get(`${BTC_NODE}/addrs/${address}/balance`)).data.balance - } - static async getActions(address){ - return (await axios.get(`${BTC_NODE}/addrs/${address}`)).data.txrefs - } - static async getUTXO(address){ - // console.log(`${BTC_NODE2}/unspent?active=${address}`,`${BTC_NODE2}/unspent?active=${address}`) - try { - return (await axios.get(`${BTC_NODE2}/unspent?active=${address}`)).data.unspent_outputs - } catch (error) { - return null + constructor (privateKey) { + if (!Ticrypto.isSeckey(privateKey)) throw new Error('Invalid PrivateKey') + var publicKey = Ticrypto.seckey2pubkey(privateKey) + Object.defineProperties(this, { + privateKey: { + enumerable: true, + writable: false, + value: privateKey + }, + publicKey: { + enumerable: true, + writable: false, + value: Ticrypto.seckey2pubkey(privateKey, { coin: 'BTC' }) + }, + address: { + enumerable: true, + writable: false, + value: Ticrypto.pubkey2address(publicKey, { coin: 'BTC' }) + }, + url: { + enumerable: true, + get: function () { + return this._url + }, + set: function (url) { + if (typeof url !== 'string') { + throw new Error('invalid url') + } + this._url = url } - } - static encrypt(data, key){ - if(!data || !key) throw new Error('Required Params Missing') - return Ticrypto.encrypt(data,key) - } - static decrypt(data, key){ - return Ticrypto.decrypt(data, key, {format:"json"}) //return null for wrong key - } - static isValidAddress(address){ - return address.length == 34 && address[0] == '1' - } - async sendTransaction(toAddress, amount, option = {gasFee : BTC_TXFEE}){ - let set = bitcoinjs.ECPair.fromPrivateKey(Buffer.from(this.privateKey,'hex'))//导入私钥用于签名 - let txb = new bitcoinjs.TransactionBuilder()//初始化交易对象 - let tx = await BTC.getUTXO('1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD') - if(!tx) return null - var tot = 0//用于记录UTXO总量 - amount+=1e4//消费金额是转出金额加上10000的矿工费 - txb.setVersion(1)//设置交易版本号 - for(var i=0;i/0'/0/0 + var mnemonic = Ticrypto.randomSecword() + return Object.assign(ETH.fromMnemonic(mnemonic, option), { + mnemonic, + mnemonic + }) + } + static fromMnemonic (mnemonic, option = { path: defaultPath }) { + HDNode.isValidMnemonic(mnemonic) //check valid mnemonic,will throw Error if not valid + let seed = HDNode.mnemonicToSeed(mnemonic) + return new ETH(HDNode.fromSeed(seed).derivePath(option.path).privateKey) + } + static async getBalance (address) { + if (!address) { + throw new Error('Address is required') + } + let res = ( + await axios.post(ETH_NODE, { + jsonrpc: '2.0', + method: 'eth_getBalance', + params: [address, 'latest'], + id: 1 + }) + ).data + if (res) return parseInt(res.result) / 1e18 + //1000000000000000000 + else return null + } + static async getActions (address) { + let tx = await eth.account.txlist(address, 0, 'latast') + if (tx && tx.message === 'OK') return tx.result + else return [] + } + static fromEncryptedWallet (json, password, progressCallback) { + if (progressCallback && typeof progressCallback !== 'function') { + throw new Error('invalid callback') + } + + return new Promise(function (resolve, reject) { + if (secretStorage.isCrowdsaleWallet(json)) { + try { + var privateKey = secretStorage.decryptCrowdsale(json, password) + resolve(new ETH(privateKey)) + } catch (error) { + reject(error) + } + } else if (secretStorage.isValidWallet(json)) { + secretStorage + .decrypt(json, password, progressCallback) + .then( + function (signingKey) { + var wallet = new ETH(signingKey) + if (signingKey.mnemonic && signingKey.path) { + utils.defineProperty(wallet, 'mnemonic', signingKey.mnemonic) + utils.defineProperty(wallet, 'path', signingKey.path) + } + resolve(wallet) + return null }, - 'address' : { - enumerable : true, - writable : false, - value : signingKey.address, - }, - 'url' : { - enumerable: true, - get: function() { return this._url }, - set: function(url) { - if (typeof(url) !== 'string') { throw new Error('invalid url') } - this._url = url - }, - }, - 'defaultGasFee' : { - enumerable: true, - get: function() { return this._defaultGasFee }, - set: function(value) { - if (typeof(value) !== 'number') { throw new Error('invalid defaultGasFee') } - this._defaultGasFee = value - } + function (error) { + reject(error) } + ) + .catch(function (error) { + reject(error) + }) + } else { + reject('invalid wallet JSON') + } + }) + } + static parseTransaction (rawTransaction) { + rawTransaction = utils.hexlify(rawTransaction, 'rawTransaction') + var signedTransaction = utils.RLP.decode(rawTransaction) + if (signedTransaction.length !== 9) { + throw new Error('invalid transaction') + } + + var raw = [] + + var transaction = {} + transactionFields.forEach(function (fieldInfo, index) { + transaction[fieldInfo.name] = signedTransaction[index] + raw.push(signedTransaction[index]) + }) + + if (transaction.to) { + if (transaction.to == '0x') { + delete transaction.to + } else { + transaction.to = utils.getAddress(transaction.to) + } + } + + ;['gasPrice', 'gasLimit', 'nonce', 'value'].forEach(function (name) { + if (!transaction[name]) { + return + } + if (transaction[name].length === 0) { + transaction[name] = utils.bigNumberify(0) + } else { + transaction[name] = utils.bigNumberify(transaction[name]) + } + }) + + if (transaction.nonce) { + transaction.nonce = transaction.nonce.toNumber() + } else { + transaction.nonce = 0 + } + + var v = utils.arrayify(signedTransaction[6]) + var r = utils.arrayify(signedTransaction[7]) + var s = utils.arrayify(signedTransaction[8]) + + if ( + v.length >= 1 && + r.length >= 1 && + r.length <= 32 && + s.length >= 1 && + s.length <= 32 + ) { + transaction.v = utils.bigNumberify(v).toNumber() + transaction.r = signedTransaction[7] + transaction.s = signedTransaction[8] + + var chainId = (transaction.v - 35) / 2 + if (chainId < 0) { + chainId = 0 + } + chainId = parseInt(chainId) + + transaction.chainId = chainId + + var recoveryParam = transaction.v - 27 + + if (chainId) { + raw.push(utils.hexlify(chainId)) + raw.push('0x') + raw.push('0x') + recoveryParam -= chainId * 2 + 8 + } + + var digest = utils.keccak256(utils.RLP.encode(raw)) + try { + transaction.from = SigningKey.recover(digest, r, s, recoveryParam) + } catch (error) { + console.log(error) + } + } + + return transaction + } + static encrypt (data, key) { + if (!data || !key) throw new Error('Required Params Missing') + return Ticrypto.encrypt(data, key) + } + static decrypt (data, key) { + return Ticrypto.decrypt(data, key, { format: 'json' }) //return null for wrong key + } + static async estimateGasPrice () { + try { + return ( + parseInt( + ( + await axios.post(ETH_NODE, { + method: 'eth_gasPrice', + id: '6842', + jsonrpc: '2.0' + }) + ).data.result + ) / 1e9 + ) + } catch (err) { + return 1 + } + } + + static isValidAddress (address) { + let res = address.match(/^(0x)?[0-9a-fA-F]{40}$/) + return res && res[0].slice(0, 2) === '0x' + } + + async getBalance () { + return ETH.getBalance(this.address) + } + async getActions () { + return ETH.getActions(this.address) + } + async getTransactionCount () { + if (!this._url) { + throw new Error('Base url required') + } + var self = this + return ( + ( + await axios.post(this._url, { + jsonrpc: '2.0', + method: 'eth_getTransactionCount', + params: [self.address, 'latest'], + id: 1 }) - this._defaultGasFee = GAS_Fee - this._url = ETH_NODE + ).data.result || null + ) + } + signTransaction (transaction) { + var chainId = transaction.chainId + if (chainId == null && this.provider) { + chainId = this.provider.chainId } - static generateNewAccount(option = {path:defaultPath}){ - //major path as default path >/0'/0/0 - var mnemonic = Ticrypto.randomSecword() - return Object.assign(ETH.fromMnemonic(mnemonic, option),{mnemonic,mnemonic}) + if (!chainId) { + chainId = 0 } - static fromMnemonic(mnemonic, option = {path:defaultPath}){ - HDNode.isValidMnemonic(mnemonic) //check valid mnemonic,will throw Error if not valid - let seed = HDNode.mnemonicToSeed(mnemonic) - return new ETH(HDNode.fromSeed(seed).derivePath(option.path).privateKey) - } - static async getBalance(address){ - if(!address){ throw new Error('Address is required') } - let res = (await axios.post(ETH_NODE,{ - "jsonrpc":"2.0","method":"eth_getBalance","params":[address, "latest"],"id":1 - })).data - if(res) - return parseInt(res.result)/1e18 //1000000000000000000 - else return null - } - static async getActions(address){ - let tx = await eth.account.txlist(address, 0 ,'latast') - if(tx && tx.message === 'OK') - return tx.result - else return [] - } - static fromEncryptedWallet(json, password, progressCallback) { - if (progressCallback && typeof(progressCallback) !== 'function') { - throw new Error('invalid callback') - } - - return new Promise(function(resolve, reject) { - - if (secretStorage.isCrowdsaleWallet(json)) { - try { - var privateKey = secretStorage.decryptCrowdsale(json, password) - resolve(new ETH(privateKey)) - } catch (error) { - reject(error) - } - - } else if (secretStorage.isValidWallet(json)) { - - secretStorage.decrypt(json, password, progressCallback).then(function(signingKey) { - var wallet = new ETH(signingKey) - if (signingKey.mnemonic && signingKey.path) { - utils.defineProperty(wallet, 'mnemonic', signingKey.mnemonic) - utils.defineProperty(wallet, 'path', signingKey.path) - } - resolve(wallet) - return null - }, function(error) { - reject(error) - }).catch(function(error) { reject(error) }) - - } else { - reject('invalid wallet JSON') - } - }) - } - static parseTransaction(rawTransaction){ - rawTransaction = utils.hexlify(rawTransaction, 'rawTransaction') - var signedTransaction = utils.RLP.decode(rawTransaction) - if (signedTransaction.length !== 9) { throw new Error('invalid transaction') } - - var raw = [] - - var transaction = {} - transactionFields.forEach(function(fieldInfo, index) { - transaction[fieldInfo.name] = signedTransaction[index] - raw.push(signedTransaction[index]) - }) - - if (transaction.to) { - if (transaction.to == '0x') { - delete transaction.to - } else { - transaction.to = utils.getAddress(transaction.to) - } - } - - ['gasPrice', 'gasLimit', 'nonce', 'value'].forEach(function(name) { - if (!transaction[name]) { return } - if (transaction[name].length === 0) { - transaction[name] = utils.bigNumberify(0) - } else { - transaction[name] = utils.bigNumberify(transaction[name]) - } - }) - - if (transaction.nonce) { - transaction.nonce = transaction.nonce.toNumber() - } else { - transaction.nonce = 0 - } - - var v = utils.arrayify(signedTransaction[6]) - var r = utils.arrayify(signedTransaction[7]) - var s = utils.arrayify(signedTransaction[8]) - - if (v.length >= 1 && r.length >= 1 && r.length <= 32 && s.length >= 1 && s.length <= 32) { - transaction.v = utils.bigNumberify(v).toNumber() - transaction.r = signedTransaction[7] - transaction.s = signedTransaction[8] - - var chainId = (transaction.v - 35) / 2 - if (chainId < 0) { chainId = 0 } - chainId = parseInt(chainId) - - transaction.chainId = chainId - - var recoveryParam = transaction.v - 27 - - if (chainId) { - raw.push(utils.hexlify(chainId)) - raw.push('0x') - raw.push('0x') - recoveryParam -= chainId * 2 + 8 - } - - var digest = utils.keccak256(utils.RLP.encode(raw)) - try { - transaction.from = SigningKey.recover(digest, r, s, recoveryParam) - } catch (error) { - console.log(error) - } - } - - - return transaction - } - static encrypt(data, key){ - if(!data || !key) throw new Error('Required Params Missing') - return Ticrypto.encrypt(data,key) - } - static decrypt(data, key){ - return Ticrypto.decrypt(data, key, {format:"json"}) //return null for wrong key - } - static async estimateGasPrice(){ - try{ - return parseInt((await axios.post(ETH_NODE, { - "method": "eth_gasPrice", - "id": "6842", - "jsonrpc": "2.0" - })).data.result)/1e9 - } - catch(err){ - return 1 + + var raw = [] + transactionFields.forEach(function (fieldInfo) { + var value = transaction[fieldInfo.name] || [] + value = utils.arrayify(utils.hexlify(value), fieldInfo.name) + + // Fixed-width field + if ( + fieldInfo.length && + value.length !== fieldInfo.length && + value.length > 0 + ) { + var error = new Error('invalid ' + fieldInfo.name) + error.reason = 'wrong length' + error.value = value + throw error + } + + // Variable-width (with a maximum) + if (fieldInfo.maxLength) { + value = utils.stripZeros(value) + if (value.length > fieldInfo.maxLength) { + var error = new Error('invalid ' + fieldInfo.name) + error.reason = 'too long' + error.value = value + throw error } + } + + raw.push(utils.hexlify(value)) + }) + + if (chainId) { + raw.push(utils.hexlify(chainId)) + raw.push('0x') + raw.push('0x') } - static isValidAddress(address){ - let res = address.match(/^(0x)?[0-9a-fA-F]{40}$/) - return res && res[0].slice(0,2) === '0x' + var digest = utils.keccak256(utils.RLP.encode(raw)) + var signingKey = new SigningKey(this.privateKey) + var signature = signingKey.signDigest(digest) + + var v = 27 + signature.recoveryParam + if (chainId) { + raw.pop() + raw.pop() + raw.pop() + v += chainId * 2 + 8 } - async getBalance(){ - return ETH.getBalance(this.address) - } - async getActions(){ - return ETH.getActions(this.address) - } - async getTransactionCount(){ - if(!this._url){ throw new Error('Base url required') } - var self = this - return (await axios.post(this._url,{ - "jsonrpc":"2.0","method":"eth_getTransactionCount","params":[self.address, "latest"],"id":1 - })).data.result||null - } - signTransaction(transaction){ - var chainId = transaction.chainId - if (chainId == null && this.provider) { chainId = this.provider.chainId } - if (!chainId) { chainId = 0 } + raw.push(utils.hexlify(v)) + raw.push(utils.stripZeros(utils.arrayify(signature.r))) + raw.push(utils.stripZeros(utils.arrayify(signature.s))) - var raw = [] - transactionFields.forEach(function(fieldInfo) { - var value = transaction[fieldInfo.name] || ([]) - value = utils.arrayify(utils.hexlify(value), fieldInfo.name) - - // Fixed-width field - if (fieldInfo.length && value.length !== fieldInfo.length && value.length > 0) { - var error = new Error('invalid ' + fieldInfo.name) - error.reason = 'wrong length' - error.value = value - throw error - } - - // Variable-width (with a maximum) - if (fieldInfo.maxLength) { - value = utils.stripZeros(value) - if (value.length > fieldInfo.maxLength) { - var error = new Error('invalid ' + fieldInfo.name) - error.reason = 'too long' - error.value = value - throw error - } - } - - raw.push(utils.hexlify(value)) - }) - - if (chainId) { - raw.push(utils.hexlify(chainId)) - raw.push('0x') - raw.push('0x') - } - - var digest = utils.keccak256(utils.RLP.encode(raw)) - var signingKey = new SigningKey(this.privateKey) - var signature = signingKey.signDigest(digest) - - var v = 27 + signature.recoveryParam - if (chainId) { - raw.pop() - raw.pop() - raw.pop() - v += chainId * 2 + 8 - } - - raw.push(utils.hexlify(v)) - raw.push(utils.stripZeros(utils.arrayify(signature.r))) - raw.push(utils.stripZeros(utils.arrayify(signature.s))) - - return utils.RLP.encode(raw) - } - async sendTransaction(toAddress, amount, option = {gasFee : GAS_Fee}){ - /**************************************************************** + return utils.RLP.encode(raw) + } + async sendTransaction (toAddress, amount, option = { gasFee: GAS_Fee }) { + /**************************************************************** 1 Ether = 1e18 wei 1Gwei = 1e9 wei *GWei as the unit of gasPrice, minimum gasPrice is 1Gwei *unit of amount is ether,should be translate to wei ****************************************************************/ - let nonce = await this.getTransactionCount() - if(!nonce) nonce = '0x0' - var gasPrice, gasLimit - if(!option.gasPrice || !option.gasLimit){ - //Normal Mode:use customized gasFee( ether ) to caculate gasPrice( wei ), gasLimit use default value - gasLimit = GAS_LIMIT - gasPrice = String(option.gasFee * GAS_UNIT_WEI / gasLimit) - } - else{ - //Advance Mode:specified the gasLimit and gasPrice( gwei ) - gasLimit = option.gasLimit - gasPrice = String(GAS_UNIT_GWEI * option.gasPrice) - } - let transaction = { - nonce: nonce, - gasLimit: gasLimit, - gasPrice: utils.bigNumberify(gasPrice), - to: toAddress, + let nonce = await this.getTransactionCount() + if (!nonce) nonce = '0x0' + var gasPrice, gasLimit + if (!option.gasPrice || !option.gasLimit) { + //Normal Mode:use customized gasFee( ether ) to caculate gasPrice( wei ), gasLimit use default value + gasLimit = GAS_LIMIT + gasPrice = String((option.gasFee * GAS_UNIT_WEI) / gasLimit) + } else { + //Advance Mode:specified the gasLimit and gasPrice( gwei ) + gasLimit = option.gasLimit + gasPrice = String(GAS_UNIT_GWEI * option.gasPrice) + } + let transaction = { + nonce: nonce, + gasLimit: gasLimit, + gasPrice: utils.bigNumberify(gasPrice), + to: toAddress, - value: utils.parseEther(String(amount)), - } - try{ - let signedTransaction = this.signTransaction(transaction) - let ethTxRes = (await axios.post(ETH_NODE,{ - "jsonrpc":"2.0", - "method":"eth_sendRawTransaction", - "params":[signedTransaction.toString('hex')], - "id":6842 - })).data - if(ethTxRes && ethTxRes.result) - return ethTxRes - return null - } - catch(err){ - return null - } + value: utils.parseEther(String(amount)) } - encrypt(key){ - return ETH.encrypt(this, key) + try { + let signedTransaction = this.signTransaction(transaction) + let ethTxRes = ( + await axios.post(ETH_NODE, { + jsonrpc: '2.0', + method: 'eth_sendRawTransaction', + params: [signedTransaction.toString('hex')], + id: 6842 + }) + ).data + if (ethTxRes && ethTxRes.result) return ethTxRes + return null + } catch (err) { + return null } + } + encrypt (key) { + return ETH.encrypt(this, key) + } } -class ERC20 extends ETH{ - constructor(privateKey, contractAddress){ - if(!contractAddress) throw new Error('Missing contractAddress') - super(privateKey) - Object.defineProperty(this, 'contractAddress',{ - enumerable:true, - writable:false, - value:contractAddress - }) +class ERC20 extends ETH { + constructor (privateKey, contractAddress) { + if (!contractAddress) throw new Error('Missing contractAddress') + super(privateKey) + Object.defineProperty(this, 'contractAddress', { + enumerable: true, + writable: false, + value: 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 } - 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) + 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 } - 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) - } - static async getActions(address, contractAddress){ - try{ - let res = (await eth.account.tokentx(address,contractAddress)) - if(res && res.result) - return res.result - } - catch(err){ - return [] - } - return + // 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) + } + static async getActions (address, contractAddress) { + try { + let res = await eth.account.tokentx(address, contractAddress) + if (res && res.result) return res.result + } catch (err) { + return [] } + return + } - async getBalance(){ - return ERC20.getBalance(this.address, this.contractAddress) - } - async getActions(){ - return ERC20.getActions(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 sendTransaction(toAddress, amount, option = {gasFee : GAS_Fee_ERC20}){ - /**************************************************************** + async getBalance () { + return ERC20.getBalance(this.address, this.contractAddress) + } + async getActions () { + return ERC20.getActions(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 sendTransaction ( + toAddress, + amount, + option = { gasFee: GAS_Fee_ERC20 } + ) { + /**************************************************************** 1 Ether = 1e18 wei 1 Gwei = 1e9 wei *GWei as the unit of gasPrice, minimum gasPrice is 1Gwei minimum gaslimit for erc20transaction is 6e4 ****************************************************************/ - var nonce = await this.getTransactionCount() - var gasPrice, gasLimit, decimals, contractAddress = this.contractAddress - if(!nonce) nonce = '0x0' - if(!option.gasPrice || !option.gasLimit){ - //Normal Mode:use customized gasFee( ether ) to caculate gasPrice( wei ), gasLimit use default value - gasLimit = GAS_LIMIT_ERC20 - gasPrice = String(option.gasFee * GAS_UNIT_WEI / gasLimit) - } - else{ - //Advance Mode:specified the gasLimit and gasPrice( gwei ) - gasLimit = option.gasLimit - gasPrice = String(GAS_UNIT_GWEI * option.gasPrice) - } - if(!option.decimals) decimals = await ERC20.getDecimals(contractAddress) - 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 : utils.bigNumberify(gasPrice), - to: contractAddress, - value : 0, - data : txBody - } - let signedTransaction = this.signTransaction(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.result) - return erc20TxRes.result - console.log(erc20TxRes) - return null - } - catch(err){ - return null - } + var nonce = await this.getTransactionCount() + var gasPrice, + gasLimit, + decimals, + contractAddress = this.contractAddress + if (!nonce) nonce = '0x0' + if (!option.gasPrice || !option.gasLimit) { + //Normal Mode:use customized gasFee( ether ) to caculate gasPrice( wei ), gasLimit use default value + gasLimit = GAS_LIMIT_ERC20 + gasPrice = String((option.gasFee * GAS_UNIT_WEI) / gasLimit) + } else { + //Advance Mode:specified the gasLimit and gasPrice( gwei ) + gasLimit = option.gasLimit + gasPrice = String(GAS_UNIT_GWEI * option.gasPrice) } - + if (!option.decimals) decimals = await ERC20.getDecimals(contractAddress) + 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: utils.bigNumberify(gasPrice), + to: contractAddress, + value: 0, + data: txBody + } + let signedTransaction = this.signTransaction(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.result) return erc20TxRes.result + console.log(erc20TxRes) + return null + } catch (err) { + return null + } + } } module.exports = { - ETH, ERC20 + ETH, + ERC20 } - diff --git a/index.js b/index.js index 9525cf1..c13d3f8 100644 --- a/index.js +++ b/index.js @@ -1,16 +1,16 @@ 'use strict' -const TIC = require('./tic.js').TIC; -const ETH = require('./eth.js').ETH; -const ERC20 = require('./eth.js').ERC20; -const BTC = require('./btc.js').BTC; -const Account = require('./Account').Account; -const Crypto = require('tic.crypto'); +const TIC = require('./tic.js').TIC +const ETH = require('./eth.js').ETH +const ERC20 = require('./eth.js').ERC20 +const BTC = require('./btc.js').BTC +const Account = require('./Account').Account +const Crypto = require('tic-crypto') module.exports = { - TIC, - ETH, - BTC, - ERC20, - Account, - Crypto, -} \ No newline at end of file + TIC, + ETH, + BTC, + ERC20, + Account, + Crypto +} diff --git a/package.json b/package.json index 26315fb..7abe0b5 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "tic.tool4chain", + "name": "tic-chaintool", "version": "1.2.1", "dependencies": { "aes-js": "^3.1.1", @@ -11,15 +11,11 @@ "scrypt-js": "^2.0.3", "setimmediate": "^1.0.5", "tic.action": "git+https://git.faronear.org/npm/tic.action#20190714_release_passtoken", - "tic.crypto": "git+https://git.faronear.org/npm/tic.crypto#20190109_preview", + "tic-crypto": "git+https://git.faronear.org/npm/tic-crypto#20190109_preview", "uuid": "^8.3.1" }, "deprecated": false, "description": "blockchain tool for ticwallet", - "keywords": [ - "tool", - "blockchain", - "tic" - ], + "keywords": ["tool", "blockchain", "tic"], "main": "index.js" } diff --git a/tic.js b/tic.js index 415f3f7..c7b2d7a 100644 --- a/tic.js +++ b/tic.js @@ -1,156 +1,155 @@ -"use strict"; -const axios = require("axios"); -const ticCrypto = require("tic.crypto"); -const ticActionTransfer = require("tic.action").ActionTransfer; +'use strict' +const axios = require('axios') +const ticrypto = require('tic-crypto') +const ticActionTransfer = require('tic.action').ActionTransfer -const TIC_TXFEE = 10; -const TIC_NODE = require("./netConfig").TIC_NODE; +const TIC_TXFEE = 10 +const TIC_NODE = require('./netConfig').TIC_NODE class TIC { - constructor(seckey, option = {}) { - if (!seckey || !ticCrypto.isSeckey(seckey)) throw "ERROR:Invalid Seckey"; + constructor (seckey, option = {}) { + if (!seckey || !ticrypto.isSeckey(seckey)) throw 'ERROR:Invalid Seckey' Object.defineProperties(this, { seckey: { value: seckey, enumerable: true, - writable: false, + writable: false }, pubkey: { - value: ticCrypto.seckey2pubkey(seckey), + value: ticrypto.seckey2pubkey(seckey), enumerable: true, - writable: false, + writable: false }, address: { - value: ticCrypto.pubkey2address(ticCrypto.seckey2pubkey(seckey)), + value: ticrypto.pubkey2address(ticrypto.seckey2pubkey(seckey)), enumerable: true, - writable: false, - }, - }); + writable: false + } + }) Object.assign(this, { _url: option._url || TIC_NODE, - _defaultFee: option.fee || TIC_TXFEE, //fee cannot be zero - }); + _defaultFee: option.fee || TIC_TXFEE //fee cannot be zero + }) } - get url() { - return this._url; + get url () { + return this._url } - set url(newURL) { - this._url = newURL; + set url (newURL) { + this._url = newURL } - get txfee() { - return this._defaultFee; + get txfee () { + return this._defaultFee } - set txfee(fee) { - this._defaultFee = fee; + set txfee (fee) { + this._defaultFee = fee } - static generateNewAccount() { - var secword = ticCrypto.randomSecword(); - return Object.assign(new TIC(ticCrypto.secword2keypair(secword).seckey), { - secword: secword, - }); + static generateNewAccount () { + var secword = ticrypto.randomSecword() + return Object.assign(new TIC(ticrypto.secword2keypair(secword).seckey), { + secword: secword + }) } - static fromMnemonic(secword) { - if (!secword || !ticCrypto.isSecword(secword)) - throw "ERROR:Invalid Secword"; - return new TIC(ticCrypto.secword2keypair(secword).seckey); + static fromMnemonic (secword) { + if (!secword || !ticrypto.isSecword(secword)) throw 'ERROR:Invalid Secword' + return new TIC(ticrypto.secword2keypair(secword).seckey) } - static async getBalance(address) { + static async getBalance (address) { if (!address) { - throw new Error("Address is required"); + throw new Error('Address is required') } return ( - await axios.post(TIC_NODE + "/Account/getBalance", { + await axios.post(TIC_NODE + '/Account/getBalance', { Account: { - address: address, - }, + address: address + } }) - ).data; + ).data } - static async getActions(address) { + static async getActions (address) { if (!address) { - throw new Error("Address is required"); + throw new Error('Address is required') } return ( - await axios.post(TIC_NODE + "/Action/getActionList", { + await axios.post(TIC_NODE + '/Action/getActionList', { Action: { actorAddress: address, - toAddress: address, + toAddress: address }, config: { - logic: "OR", - }, + logic: 'OR' + } }) - ).data; + ).data } - static encrypt(data, key) { - if (!data || !key) throw new Error("Required Params Missing"); - return ticCrypto.encrypt(data, key); + static encrypt (data, key) { + if (!data || !key) throw new Error('Required Params Missing') + return ticrypto.encrypt(data, key) } - static decrypt(data, key) { - return ticCrypto.decrypt(data, key, { format: "json" }); //return null for wrong key + static decrypt (data, key) { + return ticrypto.decrypt(data, key, { format: 'json' }) //return null for wrong key } - static isValidAddress(address) { - return ticCrypto.isAddress(address); + static isValidAddress (address) { + return ticrypto.isAddress(address) } - async sendTransaction(toAddress, amount, option = { gasFee: TIC_TXFEE }) { + async sendTransaction (toAddress, amount, option = { gasFee: TIC_TXFEE }) { if (!toAddress || !amount) { - throw new Error("ERROR:RequiredParamsMissing"); + throw new Error('ERROR:RequiredParamsMissing') } //amount cannot be zero let action = new ticActionTransfer({ amount: parseInt(amount), toAddress: toAddress, - fee: option.gasFee, - }); + fee: option.gasFee + }) //对交易数据签名,packMe 内的参数是交易发起人的keypair action.packMe({ seckey: this.seckey, - pubkey: this.pubkey, - }); + pubkey: this.pubkey + }) let data = { - Action: action, - }; + Action: action + } try { - let res = (await axios.post(this._url + "/Action/prepare", data)).data; - return res; + let res = (await axios.post(this._url + '/Action/prepare', data)).data + return res } catch (err) { - return null; + return null } } - async getBalance() { - return TIC.getBalance(this.address); + async getBalance () { + return TIC.getBalance(this.address) } - async getActions() { - return TIC.getActions(this.address); + async getActions () { + return TIC.getActions(this.address) } - getSerializedTx(option) { + getSerializedTx (option) { if (!option.toAddress || !option.amount) { - throw new Error("ERROR:RequiredParamsMissing"); + throw new Error('ERROR:RequiredParamsMissing') } let action = new ticActionTransfer({ amount: parseInt(option.amount), toAddress: option.toAddress, - fee: option.fee || this._defaultFee, - }); + fee: option.fee || this._defaultFee + }) //sign for txBody use function packMe, which needs actor's keypair as parameter action.packMe({ seckey: this.seckey, - pubkey: this.pubkey, - }); - return action; + pubkey: this.pubkey + }) + return action } //default key for sign&encrypt is account's seckey,other keys are optional. - sign(message, key = this.seckey) { - return ticCrypto.sign({ data: message, seckey: key }); + sign (message, key = this.seckey) { + return ticrypto.sign({ data: message, seckey: key }) } - verify(message, signature) { - return ticCrypto.sign({ data: message, signature, seckey: this.seckey }); + verify (message, signature) { + return ticrypto.sign({ data: message, signature, seckey: this.seckey }) } - encrypt(key) { - return TIC.encrypt(this, key); + encrypt (key) { + return TIC.encrypt(this, key) } } -module.exports = { TIC }; +module.exports = { TIC }