mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-21 16:51:59 -07:00
165 lines
5.2 KiB
JavaScript
165 lines
5.2 KiB
JavaScript
const Bitcoin = require("bitcoincashjs-lib")
|
|
const coininfo = require("coininfo")
|
|
const bip66 = require("bip66")
|
|
const bip68 = require("bc-bip68")
|
|
|
|
class TransactionBuilder {
|
|
static setAddress(address) {
|
|
TransactionBuilder._address = address
|
|
}
|
|
|
|
constructor(network = "mainnet") {
|
|
let bitcoincash
|
|
if (network === "bitcoincash" || network === "mainnet")
|
|
bitcoincash = coininfo.bitcoincash.main
|
|
else bitcoincash = coininfo.bitcoincash.test
|
|
|
|
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
|
|
this.transaction = new Bitcoin.TransactionBuilder(bitcoincashBitcoinJSLib)
|
|
this.DEFAULT_SEQUENCE = 0xffffffff
|
|
this.hashTypes = {
|
|
SIGHASH_ALL: 0x01,
|
|
SIGHASH_NONE: 0x02,
|
|
SIGHASH_SINGLE: 0x03,
|
|
SIGHASH_ANYONECANPAY: 0x80,
|
|
SIGHASH_BITCOINCASH_BIP143: 0x40,
|
|
ADVANCED_TRANSACTION_MARKER: 0x00,
|
|
ADVANCED_TRANSACTION_FLAG: 0x01
|
|
}
|
|
this.signatureAlgorithms = {
|
|
ECDSA: Bitcoin.ECSignature.ECDSA,
|
|
SCHNORR: Bitcoin.ECSignature.SCHNORR
|
|
}
|
|
this.bip66 = bip66
|
|
this.bip68 = bip68
|
|
this.p2shInput = false
|
|
this.tx
|
|
}
|
|
|
|
/**
|
|
* @api Transaction-Builder.addInput() addInput() - Add input to transaction.
|
|
* @apiName AddInput
|
|
* @apiGroup TransactionBuilder
|
|
* @apiDescription Add input to transaction.
|
|
*
|
|
* @apiExample Example usage:
|
|
* // txid of vout
|
|
* let txid = 'f7890915febe580920df2681d2bac0909ae89bd0cc1d3ed763e5eeba7f337f0e';
|
|
* // add input with txid and index of vout
|
|
* transactionBuilder.addInput(txid, 0);
|
|
*/
|
|
addInput(txHash, vout, sequence = this.DEFAULT_SEQUENCE, prevOutScript) {
|
|
this.transaction.addInput(txHash, vout, sequence, prevOutScript)
|
|
}
|
|
|
|
addInputScript(vout, script) {
|
|
this.tx = this.transaction.buildIncomplete()
|
|
this.tx.setInputScript(vout, script)
|
|
this.p2shInput = true
|
|
}
|
|
|
|
addInputScripts(scripts) {
|
|
this.tx = this.transaction.buildIncomplete()
|
|
scripts.forEach(script => {
|
|
this.tx.setInputScript(script.vout, script.script)
|
|
})
|
|
this.p2shInput = true
|
|
}
|
|
/**
|
|
* @api Transaction-Builder.addOutput() addOutput() - Add output to transaction.
|
|
* @apiName AddOutput
|
|
* @apiGroup TransactionBuilder
|
|
* @apiDescription Add output to transaction.
|
|
*
|
|
* @apiExample Example usage:
|
|
* let originalAmount = 100000;
|
|
* let byteCount = bchjs.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 });
|
|
* // amount to send to receiver. It's the original amount - 1 sat/byte for tx size
|
|
* let sendAmount = originalAmount - byteCount;
|
|
* // add output w/ address and amount to send
|
|
* transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount);
|
|
*/
|
|
addOutput(scriptPubKey, amount) {
|
|
try {
|
|
this.transaction.addOutput(
|
|
TransactionBuilder._address.toLegacyAddress(scriptPubKey),
|
|
amount
|
|
)
|
|
} catch (error) {
|
|
this.transaction.addOutput(scriptPubKey, amount)
|
|
}
|
|
}
|
|
/**
|
|
* @api Transaction-Builder.setLockTime() setLockTime() - Set locktime.
|
|
* @apiName SetLockTime
|
|
* @apiGroup TransactionBuilder
|
|
* @apiDescription Set locktime.
|
|
*
|
|
* @apiExample Example usage:
|
|
* let originalAmount = 100000;
|
|
* let byteCount = bchjs.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 });
|
|
* // amount to send to receiver. It's the original amount - 1 sat/byte for tx size
|
|
* let sendAmount = originalAmount - byteCount;
|
|
* // add output w/ address and amount to send
|
|
* transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount);
|
|
* transactionBuilder.setLockTime(50000)
|
|
*/
|
|
setLockTime(locktime) {
|
|
this.transaction.setLockTime(locktime)
|
|
}
|
|
/**
|
|
* @api Transaction-Builder.sign() sign() - Sign transaction..
|
|
* @apiName Sign.
|
|
* @apiGroup TransactionBuilder
|
|
* @apiDescription Sign transaction. It creates the unlocking script needed to spend an input. Each input has its own script and thus 'sign' must be called for each input even if the keyPair is the same..
|
|
*
|
|
* @apiExample Example usage:
|
|
* let originalAmount = 100000;
|
|
* // node of address which is going to spend utxo
|
|
* let hdnode = bchjs.HDNode.fromXPriv("xprvA3eaDg64MwDr72PVGJ7CkvshNAzCDRz7rn98sYrZVAtDSWCAmNGQhEQeCLDcnmcpSkfjhHevXmu4ZL8ZcT9D4vEbG8LpiToZETrHZttw9Yw");
|
|
* // keypair
|
|
* let keyPair = bchjs.HDNode.toKeyPair(hdnode);
|
|
* // empty redeemScript variable
|
|
* let redeemScript;
|
|
* // sign w/ keyPair
|
|
* transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount, transactionBuilder.signatureAlgorithms.SCHNORR);
|
|
*/
|
|
sign(
|
|
vin,
|
|
keyPair,
|
|
redeemScript,
|
|
hashType = this.hashTypes.SIGHASH_ALL,
|
|
value,
|
|
signatureAlgorithm
|
|
) {
|
|
let witnessScript
|
|
|
|
this.transaction.sign(
|
|
vin,
|
|
keyPair,
|
|
redeemScript,
|
|
hashType,
|
|
value,
|
|
witnessScript,
|
|
signatureAlgorithm
|
|
)
|
|
}
|
|
/**
|
|
* @api Transaction-Builder.build() build() - Build transaction.
|
|
* @apiName Build.
|
|
* @apiGroup TransactionBuilder
|
|
* @apiDescription Build transaction.
|
|
*
|
|
* @apiExample Example usage:
|
|
* // build tx
|
|
* let tx = bchjs.transactionBuilder.build();
|
|
*/
|
|
build() {
|
|
if (this.p2shInput === true) return this.tx
|
|
|
|
return this.transaction.build()
|
|
}
|
|
}
|
|
|
|
module.exports = TransactionBuilder
|