tic-chaintool/btc.js

174 lines
5.5 KiB
JavaScript

'use strict'
const axios = require('axios')
const HDNode = require('./utils/hdnode')
const bitcoinjs = require('bitcoinjs-lib')
const ticc = 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 (!ticc.is_prikey({ prikey: privateKey }))
throw new Error('Invalid PrivateKey')
var publicKey = ticc.prikey_to_pubkey(privateKey)
Object.defineProperties(this, {
privateKey: {
enumerable: true,
writable: false,
value: privateKey
},
publicKey: {
enumerable: true,
writable: false,
value: ticc.prikey_to_pubkey({ prikey: privateKey, coin: 'BTC' })
},
address: {
enumerable: true,
writable: false,
value: ticc.pubkey_to_address({ pubkey: 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 = ticc.randomize_secword()
return Object.assign(
new BTC(
ticc.secword_to_keypair({ secword: mnemonic, coin: 'BTC' }).prikey
),
{ mnemonic: mnemonic }
)
}
static fromMnemonic (mnemonic) {
HDNode.isValidMnemonic(mnemonic)
return Object.assign(
new BTC(
ticc.secword_to_keypair({ secword: mnemonic, coin: 'BTC' }).prikey
),
{ 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
}
}
static encrypt (data, key) {
if (!data || !key) throw new Error('Required Params Missing')
return ticc.encrypt_easy({ data, key })
}
static decrypt (data, key) {
return ticc.decrypt_easy(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 < tx.length; i++) {
//将UTXO的相关信息依次填入交易体中
txb.addInput(tx[i].tx_hash_big_endian, tx[i].tx_output_n)
tot += tx[i].value
}
txb.addOutput(toAddress, amount - 1e4) //填入转出目标地址和对应的金额
txb.addOutput(this.address, tot - amount) //填入找零地址,也就是原地址,并填入把找零金额
for (var i = 0; i < tx.length; i++) {
//对交易体中的UTXO依次签名
txb.sign(i, set)
}
// let txBody = txb.buildIncomplete().toHex()
let data = { tx: txb.buildIncomplete().toHex() }
try {
let res = await axios.post(`${BTC_NODE}/txs/push`, data)
return res
} catch (error) {
return null
}
}
// async sendTransaction(toAddress, amount, option = {gasFee : BTC_TXFEE}){
// var privateKey = bitcore.PrivateKey(this.privateKey)
// var ecdsa = new bitcore.crypto.ECDSA()
// var newtx = {
// inputs: [{addresses: [this.address]}],
// outputs: [{addresses: [toAddress], value: amount}]
// }
// try {
// var tmptx = (await axios.post('https://api.blockcypher.com/v1/btc/test3/txs/new',newtx)).data
// tmptx.pubkeys = []
// tmptx.pubkeys.push(privateKey.toPublicKey().toString("hex"))
// ecdsa.hashbuf = bitcore.crypto.Hash.sha256(new Buffer(tmptx.tosign))
// ecdsa.privkey = privateKey
// ecdsa.pubkey = privateKey.toPublicKey()
// ecdsa.deterministicK()
// let signatureExpected = ecdsa.sign()
// tmptx.signatures = [Buffer.from(signatureExpected.sig.toDER()).toString('hex')]
// let res = (await axios.post('https://api.blockcypher.com/v1/btc/test3/txs/send',tmptx)).data
// return res
// } catch (error) {
// return error.response.data
// }
// }
async getBalance () {
return await BTC.getBalance(this.address)
}
async getActions () {
return await BTC.getActions(this.address)
}
encrypt (key) {
return BTC.encrypt(this, key)
}
}
module.exports = {
BTC
}