So you want to send $BCH transactions? Worthy goal. Follow this guide and soon the transactions will flow like the champaign of the Illinois countryside.
Installation
First things first. You’re gonna need BITBOX. For that you’ll need NodeJS and npm
.
NodeJS and npm
NodeJS is a javascript runtime built on Chrome’s V8 engine. npm is the package manager for NodeJS. Both can be installed via nvm
the node version manager.
Install nvm
w/
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
Once you have nvm
install NodeJS v9.4.0 w/
nvm install 9.4.0
This also installs npm
v5.6.0.
BITBOX
Once those are both installed you’re ready to install BITBOX.
npm install bitbox-cli --global
This will install the bitbox-cli
command line utility and give you bitbox new
, bitbox console
and bitbox paper
Create a new app
Now BITBOX is installed and you can have it scaffold out an app.
bitbox new myApp
****** ** ********** ****** ******* ** **
/*////** /**/////**/// /*////** **/////** //** **
/* /** /** /** /* /** ** //** //** **
/****** /** /** /****** /** /** //***
/*//// **/** /** /*//// **/** /** **/**
/* /**/** /** /* /**//** ** ** //**
/******* /** /** /******* //******* ** //**
/////// // // /////// /////// // //
Creating myApp/ directory
Creating src/ directory: ./myApp/src
Creating tests/ directory: ./myApp/tests
Creating bitbox.js configuration file: ./myApp/bitbox.js
All done. ✅
Go get em! Remember--with great power comes great responsibility. 🚀
cd myApp/
bitbox.js
bitbox new
creates an empty BITBOX app directory structure w/ bitbox.js
configuration file. bitbox.js
contains credentials to connect to your local running BITBOX or a remote full $BCH node.
exports.config = {
networks: {
development: {
restURL: "https://rest.bitbox.earth/v1/"
}
}
};
Console
BITBOX ships w/ a custom NodeJS repl that has the entire BITBOX API built in. To use it run the following:
bitbox console --environment development
> BITBOX.Mnemonic.generate(256);
// fresh base moral lunch jacket later shallow verify coffee answer gospel memory lawn economy cover legal slam help giggle enroll basic series essay during
> BITBOX.BitcoinCash.toSatoshi(9);
900000000
If you don’t pass in an --environment
flag it will connect to the development
environment by default.
Setup
We’re almost ready to create and send $BCH transactions. A couple more things to set up first.
Mnemonic
For the rest of this demo you’ll need a mnemonic to generate keypairs w/. I’ll use the one I generated above.
let mnemonic = 'hamster lend force inch sort account task saddle output world olive affair oval govern length churn zoo design off element forget current situate beauty';
BIP44 Account and addresses
Now we need a BIP44 account. BIP44 derivation paths follow a certain format.
m / purpose' / coin_type' / account' / change / address_index
We’ll be deriving the first hardened account or m / 44' / 145' / 0'
and we’ll cycle through it’s n
th external change address 0 / n
.
// root seed buffer
let rootSeed = BITBOX.Mnemonic.toSeed(mnemonic);
// master HDNode
let masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, 'bitcoincash');
// HDNode of BIP44 account
let bip44BCHAccount = BITBOX.HDNode.derivePath(masterHDNode, "m/44'/145'/0'");
// get the xpriv so we can recreate this node later
let xpriv = BITBOX.HDNode.toXPriv(bip44BCHAccount);
// xprv9ycRUKofpapUBBdkNbBrLAZodKr4Q7LhgmcLppwS7yicaGuEQ9egswHEsgJj8sjsxgab79GMkmVXRNSJVT8Dsp5Q8MBmAe5ELN1yUbP9Vb1
// derive the first external change address HDNode which is going to spend utxo
let changeAddressNode0 = BITBOX.HDNode.derivePath(bip44BCHAccount, "0/0");
// get the cash address
let changeAddress0 = BITBOX.HDNode.toCashAddress(changeAddressNode0);
// bitcoincash:qqavrxsgx7hufrudzjq0mc8sk9rw09jy0cmgrkdm3q
Prepare the utxo
In this demo I’m going to do 1-to-1, 1-to-many, many-to-many, many-to-1 and OP_RETURN P2PKH SIGHASH_ALL $BCH transactions. For that we need to set up 2 unspent transaction outputs.
Take the changeAddress0
from the previous step and send it 2 small $BCH transactions. I created 2 utxo.
- bb2dff2544db7908cec8a41d9003a17f2c02814aa13095448e4bb31b283f5844
- 72eb365f0f8d692edb5aa8b0d32948c21a80938b8f2870b68a5d58cefdabd513
Live demo
Here is changeAddress0
on blockchair so you can see this address and transactions on the actual $BCH blockchain.
Now everything is set up and we’re ready to send our 1st $BCH transaction.
1-to-1
The most basic type of $BCH transaction is a 1-to-1 Pay to PubKeyHash (P2PKH) SIGHASH_ALL script. That’s a mouthful but basically that just means 1 person sending another person some $BCH. Let’s see how that would look w/ BITBOX.
addInput
Building on our previous code examples we need to create an instance of TransactionBuilder
, get the keyPair of the node which wants to spend the utxo and pass it w/ the txid
and vin
of the utxo to addInput
.
// instance of transaction builder
let transactionBuilder = new BITBOX.TransactionBuilder();
// original amount of satoshis in vin
let originalAmount = 75827;
// txid of vin
let txid = 'bb2dff2544db7908cec8a41d9003a17f2c02814aa13095448e4bb31b283f5844';
// add input with txid and index of vout
transactionBuilder.addInput(txid, 0);
addOutput
Next we need to calculate the byte count and subtract that number from the original number of satoshis to get a fee of 1 sat/B and add the receive address and send amount to addOutput
.
// get byte count to calculate fee. paying 1 sat/byte
let byteCount = BITBOX.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);
sign
and send to the network
Our transaction is almost ready to roll. Now we need to sign and build it. Then convert it to hex and send it to the $BCH network.
// keypair
let keyPair = BITBOX.HDNode.toKeyPair(changeAddressNode0);
// 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();
// 020000000144583f281bb34b8e449530a14a81022c7fa103901da4c8ce0879db4425ff2dbb000000006b48304502210080da7c89e203c0fbfd28ce88508aaa2af81e38136e6dbf6d884b53842eac84ca02206e0edbf92c535273368a4cf8d1da359661972e03e6957ddadeafa1834e727b1f4121022d426ef365d6480b127b4980afa4b9415cad5e6f0a9e11b1536d3523597197f3ffffffff0173270100000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac00000000
// sendRawTransaction to running BCH node
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
// 4238d4319e526b090aced641370366a5b830a796e96ef110783c53ebaa287678
Note the call to RawTransactions.sendRawTransaction
does an actual POST
to the full node whose credentials we added to bitbox.js
and returns a Promise
. If all went well we’ll get returned a txid. In this case it was successful and we got 4238d4319e526b090aced641370366a5b830a796e96ef110783c53ebaa287678.
1-to-many
Another type of $BCH transaction is a 1-to-many. In the case where both the vins
and vouts
of a tx are P2PKH you can send from 1 address to as many as 2936 before you hit the wall of 100kb per tx.
In our example we’re going to send from 1-to-5. Close your BITBOX console via control^c and reopen it w/ bitbox console --environment production
. Notice that we’re recreating the bip44BCHAccount
HDNode via the xpriv
instead of via a mnemonic.
let xpriv = 'xprv9ycRUKofpapUBBdkNbBrLAZodKr4Q7LhgmcLppwS7yicaGuEQ9egswHEsgJj8sjsxgab79GMkmVXRNSJVT8Dsp5Q8MBmAe5ELN1yUbP9Vb1';
// HDNode of BIP44 account
let bip44BCHAccount = BITBOX.HDNode.fromXPriv(xpriv);
// derive the first external change address HDNode which is going to spend utxo
let changeAddressNode0 = BITBOX.HDNode.derivePath(bip44BCHAccount, "0/0");
// instance of transaction builder
let transactionBuilder = new BITBOX.TransactionBuilder();
// txid of vin
let txid = 'c2aa3c36c77c836f99b73210994d86067db49977920a0e49e04041bac137923d';
// original amount of satoshis in vin
let originalAmount = 15221;
// add input with txid and index of vin
transactionBuilder.addInput(txid, 0);
Now we need to update the call to getByteCount
to reflect that we’re sending to 5 addresses. We also want to do a for
loop where we derive siblings of changeAddressNode0
. We then get each sibling’s cash address and send it 1/5th of our original amount minus the tx fee.
// get byte count to calculate fee. paying 1 sat/byte
let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 5 });
// 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
for(let i = 0; i < 5; i++) {
let childNode = BITBOX.HDNode.derivePath(bip44BCHAccount, `0/${i+1}`);
let cashAddress = BITBOX.HDNode.toCashAddress(childNode);
transactionBuilder.addOutput(cashAddress, Math.floor(sendAmount / 5));
}
// keypair
let keyPair = BITBOX.HDNode.toKeyPair(changeAddressNode0);
// sign w/ HDNode's keyPair
let redeemScript;
transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount);
// build tx
let tx = transactionBuilder.build();
// output rawhex
let hex = tx.toHex();
// 02000000015e5280280f8bc76bc477c6b630538a9de1238f6e614fb5fc8d2b50b0cf6386f4010000006a473044022063136391ad2bc25f256038a11b4816ca6e601887eeb96c9fe93874e8688f70e90220709ce5a856c68d8bf293fd1e49bd4027f841cde4d43b2c2fc2795d0a107743844121024e61dcf27b337780b14dcf5ae5976a16bb37ac1caa901c9cc0db9b822924cef0ffffffff0acf050000000000001976a914fa5c1df9cf0f19e994a13a595bd02f8d49ebf13788accf050000000000001976a914bcd90726a2d5d6a05c3098f9bfc723792ad8a00588accf050000000000001976a91438e3fb157f1aeec35640a3b323db427acadf065c88accf050000000000001976a9147839b1ed73725f6e82dc04cdf1d0ff1e434066d888accf050000000000001976a91489608c1629cfb2603dce15b84b793bf73387403e88accf050000000000001976a914c5eefec653b511bcf68409d9bb697b6996719ab988accf050000000000001976a914a83acc43ea289229d1698655a39bc8a88c69385588accf050000000000001976a9144e422cf666727cfff8fd698cfe968f15b350053788accf050000000000001976a914f44a0a98ed70b191c4443d05811ecf25238ae7d888accf050000000000001976a914015c1b97fe120ada76efd8cd31f04f51d838acd288ac00000000
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
// 72eb365f0f8d692edb5aa8b0d32948c21a80938b8f2870b68a5d58cefdabd513
Again we can see this was successful and sendRawTransaction
returned a txid. In this case 72eb365f0f8d692edb5aa8b0d32948c21a80938b8f2870b68a5d58cefdabd513.
many-to-many
Now that we’ve sent satoshis from 1 to 5 addresses we want to send from 5-to-5. Exit your console w/ control^c and restart it w/ bitbox console --environment production
. Again we’re recreating the bip44BCHAccount
node from the xpriv
.
let xpriv = 'xprv9ycRUKofpapUBBdkNbBrLAZodKr4Q7LhgmcLppwS7yicaGuEQ9egswHEsgJj8sjsxgab79GMkmVXRNSJVT8Dsp5Q8MBmAe5ELN1yUbP9Vb1';
// HDNode of BIP44 account
let bip44BCHAccount = BITBOX.HDNode.fromXPriv(xpriv);
// instance of transaction builder
let transactionBuilder = new BITBOX.TransactionBuilder();
// txid of vin
let txid = '72eb365f0f8d692edb5aa8b0d32948c21a80938b8f2870b68a5d58cefdabd513';
// add input with txid and index of vin
for(let i = 0; i < 5; i++) {
transactionBuilder.addInput(txid, i);
}
let originalAmount = 14890;
We also have to update the call to getByteCount
to reflect that we’re sending from 5 to 5.
// get byte count to calculate fee. paying 1 sat/byte
let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 5 }, { P2PKH: 5 });
// 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
for(let i = 5; i < 10; i++) {
let childNode = BITBOX.HDNode.derivePath(bip44BCHAccount, `0/${i+1}`);
let cashAddress = BITBOX.HDNode.toCashAddress(childNode);
transactionBuilder.addOutput(cashAddress, Math.floor(sendAmount / 5));
}
let redeemScript;
for(let i = 0; i < 5; i++) {
// sign w/ HDNode's keyPair
let childNode = BITBOX.HDNode.derivePath(bip44BCHAccount, `0/${i+1}`);
transactionBuilder.sign(i, BITBOX.HDNode.toKeyPair(childNode), redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, 2978);
}
// build tx
let tx = transactionBuilder.build();
// output rawhex
let hex = tx.toHex();
// 020000000513d5abfdce585d8ab670288f8b93801ac24829d3b0a85adb2e698d0f5f36eb72000000006b483045022100c80969a9b9333ca6223ff75186e99a7e98ee8a7950fad8f54aee9e2e6160b60102204758d8db0562cc8d9832f702dc4d29dfd0cc9f3e4081d47154e391b8fb9aad54412102de80682cd27e513fc57f86d5323761422dc8b59cc5d2ba3903c928b533532734ffffffff13d5abfdce585d8ab670288f8b93801ac24829d3b0a85adb2e698d0f5f36eb72010000006a4730440220280d4a9954c5afe24089bdd545466bd7a8caad8b295e30de9d3cb5e56fccf64e022036663b2c53b5fac674b4b935b53e2a4ea88dfc71c9b879870976d82887542ab4412102969479fa9bea3082697dce683ac05b13ae63016b41d5ca1a450ad40f6c543751ffffffff13d5abfdce585d8ab670288f8b93801ac24829d3b0a85adb2e698d0f5f36eb72020000006b483045022100ba2c3b717e023966cb16df65ca83f77029e2a5b80c47c47b6956474ac9ff281302201d48ee3292439e284a6654a0e79ac2b8f7fff5c6b0d715260aa296501a239c6441210259a3f18d4982fe1afc9e11ee4b376b42297e1581932e643d384314b1605ab15bffffffff13d5abfdce585d8ab670288f8b93801ac24829d3b0a85adb2e698d0f5f36eb72030000006b483045022100ee602988d358468404cb5aad86520419b54a9a3d72d7b93c8319bdd13cd115b002202a35ea83fb453eb2e90ceb636ddc8e0b6f6d6c8a30318f0921991410522fb5d44121039b3ff05f3db13a71bb394da22c545ca2a0eb6bebc687d2adeee9ab5b118f6da1ffffffff13d5abfdce585d8ab670288f8b93801ac24829d3b0a85adb2e698d0f5f36eb72040000006b483045022100fbdca1650e49b7a2e9ac355742169533bf894f69d1b67879baf502fa996e9c1002202b4825441e146f5bd10d1a45798ab2d8e8ab0b062b2d9e432d4cf36887d8d844412103be9b4460171a2495c1bfcdd4a42191c4d7242c0a280c68e51b8355fda41c6988ffffffff05ea0a0000000000001976a914c4dd01fe9359ee69c18cfd17a99c0fdf932c46d188acea0a0000000000001976a9140b7088dd957fcfbbc2c0d5e0f08ea4e69c5df18788acea0a0000000000001976a914738172d921de96c57e771edf7fd33d63e3a415c288acea0a0000000000001976a914dd6a28961399731111afee0e28ea80e218c3387288acea0a0000000000001976a9147df8e9ea7ed021cc400a361f04933d3428290ab988ac00000000
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
// 67d32ac84d78caa7eaaf8bab6197a66a0945625a282595e75622c33aaccfa1b9
This was successful and sendRawTransaction
returned a txid. In this case 67d32ac84d78caa7eaaf8bab6197a66a0945625a282595e75622c33aaccfa1b9.
many-to-1
Finally we want to consolidate the 5 newly created utxo from the previous step back in to a single address. For that we’ll again exit our BITBOX console w/ control^c and reopen it w/ bitbox console --environment production
.
let xpriv = 'xprv9ycRUKofpapUBBdkNbBrLAZodKr4Q7LhgmcLppwS7yicaGuEQ9egswHEsgJj8sjsxgab79GMkmVXRNSJVT8Dsp5Q8MBmAe5ELN1yUbP9Vb1';
// HDNode of BIP44 account
let bip44BCHAccount = BITBOX.HDNode.fromXPriv(xpriv);
// instance of transaction builder
let transactionBuilder = new BITBOX.TransactionBuilder();
// txid of vin
let txid = '67d32ac84d78caa7eaaf8bab6197a66a0945625a282595e75622c33aaccfa1b9';
Now we need to update the call to getByteCount
to have 5 vins and 1 vout and subtract it’s result from the originalAmount for the fee. In a many-to-1 tx the originalAmount
is the sum of the vins
.
let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 5 }, { P2PKH: 1 });
let vinAmount = 2794;
let originalAmount = vinAmount * 5;
let amount = originalAmount - byteCount;
transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', amount);
Next we need to do another for
loop and derive the i
th sibling HDNode which we sent the satoshis to in the 1-to-many tx.
We have to finish adding all the inputs before we can sign the tx which is why we have two successive for
loops.
// add input with txid and index of vin
for(let i = 0; i < 5; i++) {
transactionBuilder.addInput(txid, i);
}
let redeemScript;
for(let i = 5; i < 10; i++) {
// sign w/ HDNode's keypair
let node = BITBOX.HDNode.derivePath(bip44BCHAccount, `0/${i+1}`);
let keyPair = BITBOX.HDNode.toKeyPair(node);
transactionBuilder.sign(i-5, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, vinAmount);
}
Now sign, build and send the raw hex to the $BCH network.
// build tx
let tx = transactionBuilder.build();
// output rawhex
let hex = tx.toHex();
// 020000000a7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc000000006b483045022100bb01adf71e4a3e8fe35256f87198c368646da2d2ccbb1e3e79abef3e657a95590220407ab69ca6899ce117a5c19a53231ca0a4c1934046c7092dc747d720feb27d6841210356d2f623aeaac4e8b03a79fd3bd0daff0dde04a633e27bba272d00763c85e624ffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc010000006b48304502210097a184bc8bc66ad4502b34237dc591531bd78d26a8c3f401b5760c4df80347f0022011b4354cb02a62442ecdf21fd9e81de2a18a4dbcbdcd554c4343a9616fe5ed334121031c181414441c18141567d03ddca2cbc6594aad7ca570b1e31eb8b18b92026e80ffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc020000006a47304402206cc790156041c1a76961149f860189f344a0059678b65edb6c243722c64b362a022070e3531e2c14cc4f8fbc45d392a73233d6f9ee254b5c09543a518f5a02735e374121037b5e3041ac872adb29580d9f0c573f452f0f0e78780d80193b86e515ba76d67cffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc030000006a473044022059bc2a0851a0c30b7cecd9828f856b16947d70a3ebe75693996ff4972bec983b022069fe4630a0564fca9a4c70b6c619930dc86a8f5e4f1df7ea236dc51b930049224121034c148d91b046f71618344ca27912d2f90d18e5d7e6f8e36de8b3509d383a0e30ffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc040000006a473044022069a5316bee13caf57f4f0d3f3b2eefd9a1f21c0d346234fd066cf0d1c2d1e36002200a80609efbd3d48ddeb85a91eb5a09b4101636177ff233ef5c4d44bf2b6ddba84121032658d2f1a21d956d10a75e6c145098f90f4769caa69527633d232c1254e143cfffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc050000006a47304402205b90e07c8374312906123d7c2d392afbb3247bc028508ad00b5a547a345bf7d502204f6a1db6236f63573b10fcc33bafe298a8ecc0e8bbd9ae6d4156191a618314254121021ac6c44f198477d44c1544f9adac4b397b4697cf00778e51f448cbabbaf27761ffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc060000006b48304502210096644f34edd4d673f964916c4bbc6b18fc4de9a37fd22489899dd8a7f6352d880220137611bb458b8f2dfc950db002242c4ee08fa2f7f760494d61cac20e52864443412102963beefaf2231bba12a4e4340c6d87314a9485bce1a6c3df73a6b3ad64157519ffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc070000006a473044022054d7f60de750de8d242f3379ff4e7bfbb8e8ef476e44f12c8abf7aefe76d611b0220291e08d838e95901d1f6793e827a65c803cbffceb4671afd4d6e94c73b925760412102e7a01e6d04d1cd69d5850d6d2ca3b66dfca33efaa88ec25b4ae0e05e5f8ffc52ffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc080000006a473044022045b069c430e904a2cf4105594ba2cdcddb6510e16332610c6fde7fd1d9cf18f102201174acd68022d5970db0c876f387b39afd2f9ac28c02a0b5ced92b9a800f07484121037652b17ea5edb1e7751d76b7507373862168f725f65c1ce81c723ae5b8665524ffffffff7c5c2a6711da26d97c8f00facd5c21f516f3e5cba3d0071d48941e96d9aebadc090000006a47304402201132689bce414a05fa992d0bd2103a0c3921bf35b429f6e32b81a199b7ae3e1e022009892366a4b64e8e3e1416db02a2786b18d1affde9e8b1c6861763cfb1eee81f4121025c87b65e739def6453728c2cc9e652d16daca7bea1970a5b1488a2b79fcb7c67ffffffff0122340000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac00000000
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
// 40a265bcf7fac883568eb50a394887e653eeaa8446699ca0134a7a5dc1f5ee15
As you can see sendRawTransaction
returned a txid
which means it was successful. 40a265bcf7fac883568eb50a394887e653eeaa8446699ca0134a7a5dc1f5ee15.
OP_RETURN
The OP_RETURN
OP code allows you to write arbitrary data to the blockchain. It’s been limited to 80 bytes but on May 15th the $BCH network will upgrade to support 220 bytes.
Let’s write #BCHForEveryone
to the blockchain.
// instance of transaction builder
let transactionBuilder = new BITBOX.TransactionBuilder();
// amount of satoshis at vout
let originalAmount = 7651;
// txid
let txid = "40e974d91a269b333adcb6d3ca7ac871681262ab84170b7e741141193013bad0";
// add input txid and vout index
transactionBuilder.addInput(txid, 1)
// encode #BCHForEveryone as a buffer
let buf = new Buffer('#BCHForEveryone');
// encode w/ OP_RETURN
let data = BITBOX.Script.encode([
BITBOX.Script.opcodes.OP_RETURN,
buf
])
// get size of tx to calculate fee
let byteCount = BITBOX.BitcoinCash.getByteCount({ P2PKH: 1 }, { P2PKH: 2 });
// calculate fee @ 1 sat/B
let sendAmount = originalAmount - byteCount;
// add cash address output
transactionBuilder.addOutput("bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw", sendAmount);
// add OP_RETURN and data as output w/ 0 satoshis
transactionBuilder.addOutput(data, 0);
// xpriv
let xpriv = 'xprv9ycRUKofpapUBBdkNbBrLAZodKr4Q7LhgmcLppwS7yicaGuEQ9egswHEsgJj8sjsxgab79GMkmVXRNSJVT8Dsp5Q8MBmAe5ELN1yUbP9Vb1';
// instance of bip44BCHAccount node
let node = BITBOX.HDNode.fromXPriv(xpriv);
// first external change address node
let childNode = BITBOX.HDNode.derivePath(node, `0/0`);
let key = BITBOX.HDNode.toKeyPair(childNode);
let redeemScript;
// sign tx
transactionBuilder.sign(0, key, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount);
// to raw hex
let hex = transactionBuilder.build().toHex();
// 0200000001d0ba1330194111747e0b1784ab62126871c87acad3b6dc3a339b261ad974e940010000006b483045022100a284b4ac5ed55ac0e2baa02b6bdabbf06f98d2bf6b3fdcea1aea50f55766afd002206181c8e60f738116ba6e16177f3d408e8da2c463c69b27c2531fab84b63a63b24121022d426ef365d6480b127b4980afa4b9415cad5e6f0a9e11b1536d3523597197f3ffffffff02011d0000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac0000000000000000116a0f23424348466f7245766572796f6e6500000000
// POST to full $BCH node
BITBOX.RawTransactions.sendRawTransaction(hex).then((result) => { console.log(result); }, (err) => { console.log(err); });
// 0f5c2dbde622734d9221afe1a896add4508bfa49045274d3110ab879a2562992
sendRawTransaction
returned a txid
0f5c2dbde622734d9221afe1a896add4508bfa49045274d3110ab879a2562992
which means our data was written to the blockchain. You can see it at this unspendable UTXO: d-694556d7d579da66fc57a52b06fc7ac6.
If you decode the raw hex you’ll see OP_RETURN 23424348466f7245766572796f6e65
which you can decode back to the original string w/ BITBOX.
let fromASM = BITBOX.Script.fromASM("OP_RETURN 23424348466f7245766572796f6e65");
let arr = BITBOX.Script.decode(fromASM);
arr[1].toString('ascii');
// #BCHForEveryone
Summary
If you made it this far you’re a champion. You’re now ready to change the world and make a fortune.
Please let me know if you have any questions or spot any bugs in the examples. Now go forth and flood the network w/ transactions!