Sending transactions is at the heart of BCH. BITBOX has been able to send transactions for a while but w/ BITBOX Cloud and REST taking shape we wanted to revisit the steps for sending transactions to show how to best leverage the new functionality.
Setup
Before we get started let’s create an HDNode and send it some satohis.
Mnemonic
First we generate a random 256 bit mnemonic.
let mnemonic = BITBOX.Mnemonic.generate(256)
// slam tag city glass asthma mention rich leader snake prevent fatal trick typical gallery scare sort clip wolf strike float dwarf just clip mail
Root seed
From that mnemonic we create a root seed buffer.
// root seed buffer
let rootSeed = BITBOX.Mnemonic.toSeed(mnemonic);
Master HD Node
With our root seed we can create a BIP32 master hd node. The 2nd argument is the network. pass in 'bitcoincash'
for mainnet and 'testnet'
for testnet.
// master HDNode
let masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, 'bitcoincash');
Account
Next create a BIP44 account. The 2nd argument is the BIP44 HD path.
// HDNode of BIP44 account
let account = BITBOX.HDNode.derivePath(masterHDNode, "m/44'/145'/0'");
Change
Create the first external change address per BIP44.
// derive the first external change address HDNode which is going to spend utxo
let change = BITBOX.HDNode.derivePath(account, "0/0");
Cash Address
// get the cash address
let cashAddress = BITBOX.HDNode.toCashAddress(change);
// bitcoincash:qqn2yf5jzrhwr3magjps5muz30akqqgsm5q7wcgkga
Send some satoshis
Now we send a few satoshis to bitcoincash:qqn2yf5jzrhwr3magjps5muz30akqqgsm5q7wcgkga
. You can see that at aeaadaa9e952bf9fe02db6f261f31db2ab42224c9c8da73d78e2978eca372594
With that all set up lets now look at leveraging BITBOX Cloud.
BITBOX Cloud
BITBOX Cloud is your ‘Blockchain as a Service.’ We recently started integrating w/ bitbox-cli
so you can leverage BITBOX Cloud w/out any additional setup.
You can use Address.utxo to get back a list of uxto for an address
BITBOX.Address.utxo('bitcoincash:qqn2yf5jzrhwr3magjps5muz30akqqgsm5q7wcgkga').then((result) => {
console.log(result);
// [ { txid: 'aeaadaa9e952bf9fe02db6f261f31db2ab42224c9c8da73d78e2978eca372594',
// vout: 0,
// scriptPubKey: '76a91426a2269210eee1c77d44830a6f828bfb600110dd88ac',
// amount: 0.00006893,
// satoshis: 6893,
// height: 530048,
// confirmations: 1,
// legacyAddress: '14XGviVV31TudFn8TEkBduLFyLa8fwPE5G',
// cashAddress: 'bitcoincash:qqn2yf5jzrhwr3magjps5muz30akqqgsm5q7wcgkga' } ]
}, (err) => { console.log(err);
});
Now lets spend the utxo.
TransactionBuilder instance
First create an instance of TransactionBuilder
. Note the 'bitcoincash'
argument is optionnal and it will default to mainnet if you pass nothing in. Pass in 'testnet'
to create testnet transactions. For this example we’ll use the mainnet.
// instance of transaction builder
let transactionBuilder = new BITBOX.TransactionBuilder('bitcoincash');
Original amount
Now get the original amount of satoshis from the utxo. This is returned from the call to BITBOX.Address.utxo
.
// original amount of satoshis in vin
let originalAmount = result[0].satoshis;
And the index
Get the index of the vout which you want to spend.
// index of vout
let vout = result[0].vout;
Get the txid
Next get the txid of the uxto you want to spend
// txid of vout
let txid = result[0].txid;
Add the inputs
Now we’re ready to add the input to our transactionBuilder
instance. First pass in the txid
and next the vout
index.
// add input with txid and index of vout
transactionBuilder.addInput(txid, vout);
Calculate the fee
Next use BitcoinCash.getByteCount to calculate the fee. Here we pass in 2 objects describing the type and number of inputs/outputs. For this example we have 1 P2PKH
input and 1 P2PKH
output.
// get byte count to calculate fee. paying 1 sat/byte
let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 });
// 192
Calculate the fee
A transaction w/ 1 P2PKH
input and 1 P2PKH
output is 192 bytes. We subtract that from the original amount of satoshis to get a fee of 1 satoshi per byte.
// amount to send to receiver. It's the original amount - 1 sat/byte for tx size
let sendAmount = originalAmount - byteCount;
Add the output
Add the address where you want to send the satoshis and the send amount which is the original amount minus the 1 satoshi per byte.
// add output w/ address and amount to send
transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount);
Get the node’s keypair
Now get the change node’s keypair to sign the transaction.
// keypair
let keyPair = BITBOX.HDNode.toKeyPair(change);
Sign input
Sign the input. Pass in the index of the input you’re signing. In this case we only have 1 input so the index is 0
. Next pass in the node’s keypair to sign the tx, a placeholder redeemScript
var which isn’t needed here, the hash type which is SIGHASH_ALL
and lastly the original amount of satoshis in the utxo which we’re spending.
// sign w/ HDNode
let redeemScript;
transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount);
Build and get raw hex
Now build the transaction and get the raw hex.
// build tx
let tx = transactionBuilder.build();
// output rawhex
let hex = tx.toHex();
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
POST the transaction
Finally we’re ready to send our transaction to the BCH network.
// sendRawTransaction to running BCH node
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
All together now
// include BITBOX
let BITBOXCli = require('bitbox-cli/lib/bitbox-cli').default;
// Instantiate BITBOX and pass in creds for a full node.
let BITBOX = new BITBOXCli();
// create mnemonic
let mnemonic = 'slam tag city glass asthma mention rich leader snake prevent fatal trick typical gallery scare sort clip wolf strike float dwarf just clip mail';
// root seed buffer
let rootSeed = BITBOX.Mnemonic.toSeed(mnemonic);
// master HDNode
let masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, 'bitcoincash');
// HDNode of BIP44 account
let account = BITBOX.HDNode.derivePath(masterHDNode, "m/44'/145'/0'");
// derive the first external change address HDNode which is going to spend utxo
let change = BITBOX.HDNode.derivePath(account, "0/0");
// get the cash address
let cashAddress = BITBOX.HDNode.toCashAddress(change);
// bitcoincash:qqn2yf5jzrhwr3magjps5muz30akqqgsm5q7wcgkga
BITBOX.Address.utxo('bitcoincash:qqn2yf5jzrhwr3magjps5muz30akqqgsm5q7wcgkga').then((result) => {
console.log(result);
// [ { txid: '51366a68d148f360c30714f878584ce534cad53e6827937c1040a18ef16f623e',
// vout: 0,
// scriptPubKey: '76a91426a2269210eee1c77d44830a6f828bfb600110dd88ac',
// amount: 0.00009613,
// satoshis: 9613,
// confirmations: 0,
// ts: 1527795652,
// legacyAddress: '14XGviVV31TudFn8TEkBduLFyLa8fwPE5G',
// cashAddress: 'bitcoincash:qqn2yf5jzrhwr3magjps5muz30akqqgsm5q7wcgkga' } ]
// instance of transaction builder
let transactionBuilder = new BITBOX.TransactionBuilder('bitcoincash');
// original amount of satoshis in vin
let originalAmount = result[0].satoshis;
// index of vout
let vout = result[0].vout;
// txid of vout
let txid = result[0].txid;
// add input with txid and index of vout
transactionBuilder.addInput(txid, vout);
// get byte count to calculate fee. paying 1 sat/byte
let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 1 });
// 192
// 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);
// keypair
let keyPair = BITBOX.HDNode.toKeyPair(change);
// sign w/ HDNode
let redeemScript;
transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount);
// build tx
let tx = transactionBuilder.build();
// output rawhex
let hex = tx.toHex();
// sendRawTransaction to running BCH node
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
}, (err) => { console.log(err);
});
Success
If we did that correct we should get back a txid 1549abf70bf1f59618d650d72bb71711ef62e53e30138e326aab996ab6e54bb3.
Summary
This was to show step by step how to create a mnemonic, root seed, master node, bip44 account and bip44 change node. It showed how to create a cash address.
Once you have utxo which are spendable it showed how to call BITBOX Cloud via BITBOX.Address.utxo
to get back a list of spendable utxo.
It next showed how to build a transaction, sign it and POST
it to the BCH network.
If your app needs to send BCH transactions BITBOX is the tool and this tutorial shows you how to make it happen.