UNPKG

htmlcoinjs-lib

Version:

An extend lib for bitcoinjs-lib, it supports two new network of althash and althash-testnet, and it can generate contract creating and sending transactions

194 lines (184 loc) 6.98 kB
var bitcoinjs = require('bitcoinjs-lib') var BigNumber = require('bignumber.js') var OPS = require('htmlcoin-opcodes') var Buffer = require('safe-buffer').Buffer /** * This is a function for selecting HTML utxos to build transactions * the transaction object takes at least 3 fields, value(unit is 1e-8 HTML) , confirmations and isStake * * @param [transaction] unspentTransactions * @param Number amount(unit: HTML) * @param Number fee(unit: HTML) * @returns [transaction] */ function selectTxs(unspentTransactions, amount, fee) { //sort the utxo var matureList = [] for(var i = 0; i < unspentTransactions.length; i++) { if(unspentTransactions[i].isStake === true) { if (unspentTransactions[i].confirmations >= 500) { matureList[matureList.length] = unspentTransactions[i] } } else { matureList[matureList.length] = unspentTransactions[i] } } matureList.sort(function(a, b) {return a.value - b.value}) var value = new BigNumber(amount).plus(fee).times(1e8) var find = [] var findTotal = new BigNumber(0) for (var i = 0; i < matureList.length; i++) { var tx = matureList[i] findTotal = findTotal.plus(tx.value) find[find.length] = tx if (findTotal.isGreaterThanOrEqualTo(value)) break } if (value.isGreaterThan(findTotal)) { throw new Error('You do not have enough HTML to send') } return find } /** * This is a helper function to build a pubkeyhash transaction * the transaction object takes at least 5 fields, value(unit is 1e-8 HTML), confirmations, isStake, hash and pos * * @param bitcoinjs-lib.KeyPair keyPair * @param String to * @param Number amount(unit: HTML) * @param Number fee(unit: HTML) * @param [transaction] utxoList * @returns String the built tx */ function buildPubKeyHashTransaction(keyPair, to, amount, fee, utxoList) { var from = keyPair.getAddress() var inputs = selectTxs(utxoList, amount, fee) var tx = new bitcoinjs.TransactionBuilder(keyPair.network) var totalValue = new BigNumber(0) var value = new BigNumber(amount).times(1e8) var sendFee = new BigNumber(fee).times(1e8) for (var i = 0; i < inputs.length; i++) { tx.addInput(inputs[i].hash, inputs[i].pos) totalValue = totalValue.plus(inputs[i].value) } tx.addOutput(to, new BigNumber(value).toNumber()) if (totalValue.minus(value).minus(sendFee).toNumber() > 0) { tx.addOutput(from, totalValue.minus(value).minus(sendFee).toNumber()) } for (var i = 0; i < inputs.length; i++) { tx.sign(i, keyPair) } return tx.build().toHex() } /** * This is a helper function to build a create-contract transaction * the transaction object takes at least 5 fields, value(unit is 1e-8 HTML), confirmations, isStake, hash and pos * * @param bitcoinjs-lib.KeyPair keyPair * @param String code The contract byte code * @param Number gasLimit * @param Number gasPrice(unit: 1e-8 HTML/gas) * @param Number fee(unit: HTML) * @param [transaction] utxoList * @returns String the built tx */ function buildCreateContractTransaction(keyPair, code, gasLimit, gasPrice, fee, utxoList) { var from = keyPair.getAddress() var amount = 0 fee = new BigNumber(gasLimit).times(gasPrice).div(1e8).plus(fee).toNumber() var inputs = selectTxs(utxoList, amount, fee) var tx = new bitcoinjs.TransactionBuilder(keyPair.network) var totalValue = new BigNumber(0) var sendFee = new BigNumber(fee).times(1e8) for (var i = 0; i < inputs.length; i++) { tx.addInput(inputs[i].hash, inputs[i].pos) totalValue = totalValue.plus(inputs[i].value) } var contract = bitcoinjs.script.compile([ OPS.OP_4, number2Buffer(gasLimit), number2Buffer(gasPrice), hex2Buffer(code), OPS.OP_CREATE ]) tx.addOutput(contract, 0) if (totalValue.minus(sendFee).toNumber() > 0) { tx.addOutput(from, totalValue.minus(sendFee).toNumber()) } for (var i = 0; i < inputs.length; i++) { tx.sign(i, keyPair) } return tx.build().toHex() } /** * This is a helper function to build a send-to-contract transaction * the transaction object takes at least 5 fields, value(unit is 1e-8 HTML), confirmations, isStake, hash and pos * * @param bitcoinjs-lib.KeyPair keyPair * @param String contractAddress The contract address * @param String encodedData The encoded abi data * @param Number gasLimit * @param Number gasPrice(unit: 1e-8 HTML/gas) * @param Number fee(unit: HTML) * @param [transaction] utxoList * @param Number amount * @returns String the built tx */ function buildSendToContractTransaction(keyPair, contractAddress, encodedData, gasLimit, gasPrice, fee, utxoList, amount=0) { var from = keyPair.getAddress() fee = new BigNumber(gasLimit).times(gasPrice).div(1e8).plus(fee).toNumber() var inputs = selectTxs(utxoList, amount, fee) var tx = new bitcoinjs.TransactionBuilder(keyPair.network) var totalValue = new BigNumber(0) var sendFee = new BigNumber(fee).times(1e8) for (var i = 0; i < inputs.length; i++) { tx.addInput(inputs[i].hash, inputs[i].pos) totalValue = totalValue.plus(inputs[i].value) } var contract = bitcoinjs.script.compile([ OPS.OP_4, number2Buffer(gasLimit), number2Buffer(gasPrice), hex2Buffer(encodedData), hex2Buffer(contractAddress), OPS.OP_CALL ]) var sendAmount = new BigNumber(amount).times(1e8).toNumber() tx.addOutput(contract, sendAmount) if (totalValue.minus(sendFee).minus(sendAmount).toNumber() > 0.00072799) { tx.addOutput(from, totalValue.minus(sendFee).minus(sendAmount).toNumber()) } for (var i = 0; i < inputs.length; i++) { tx.sign(i, keyPair) } return tx.build().toHex() } function number2Buffer(num) { var buffer = [] var neg = (num < 0) num = Math.abs(num) while(num) { buffer[buffer.length] = num & 0xff num = num >> 8 } var top = buffer[buffer.length - 1] if (top & 0x80) { buffer[buffer.length] = neg ? 0x80 : 0x00 } else if (neg) { buffer[buffer.length - 1] = top | 0x80; } return Buffer.from(buffer) } function hex2Buffer(hexString) { var buffer = [] for (var i = 0; i < hexString.length; i += 2) { buffer[buffer.length] = (parseInt(hexString[i], 16) << 4) | parseInt(hexString[i+1], 16) } return Buffer.from(buffer) } module.exports = { selectTxs: selectTxs, buildPubKeyHashTransaction: buildPubKeyHashTransaction, buildCreateContractTransaction: buildCreateContractTransaction, buildSendToContractTransaction: buildSendToContractTransaction, }