Be sure to review the section on Bitcoin Script from the Developer Guide.
Creating a Transaction
Transactions never stand in isolation. Every new transaction we create must “spend from” another, existing transaction. Referring to the above diagram:
In order to construct a Transaction [c1], we need to do the following:
- Obtain a copy of Transaction [b1]
- Obtain the Output Script (aka scriptPubKey) in the Output of Transaction [b1] (marked in orange)
- Create an Input Script (aka scriptSig) in the Input of Transaction [c1] (marked in blue)
(1) Obtaining a Transaction to spend from
One can obtain the Transaction to spend from in any of a number of ways. These include:
- Quering the Merchant API of a service provider (e.g. WhatsOnchain)
- Have it passed directly to you by a counter party
For our purposes, we will assume that we have the following Transaction, serialised in hexadecimal to act as our Transaction [b1]
var b1Hex = '01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006a473044022013fa3089327b50263029265572ae1b022a91d10ac80eb4f32f291c914533670b02200d8a5ed5f62634a7e1a0dc9188a3cc460a986267ae4d58faf50c79105431327501210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000';
(2) Obtain the Output to spend from
List<TransactionOutput> outputList = Transaction.fromHex(b1Hex).outputs; //let's assume we are spending the first output in the list var utxo = outputList;
(3) Create the spending Transaction
We now use a TransactionBuilder to construct the spending transaction.
//our new transaction [c1] will contain an Output Script. The coins in that script //will be locked using an address of our choosing. We use a P2PKHLockBuilder //to help us construct a canonical P2PKH locking script. var locker = P2PKHLockBuilder(recipientAddress); //In order to create our spending Input Script in Transaction *[c1]* we use //another utility (P2PKHUnlockBuilder), to help us construct the unlocking/spending script. var unlocker = P2PKHUnlockBuilder(privateKey.publicKey); //Transaction() employs the builder pattern for convenience. var txn = Transaction() .spendFromOutput(utxo, Transaction.NLOCKTIME_MAX_VALUE, scriptBuilder: unlocker) .spendTo(recipientAddress, BigInt.from(50000000),scriptBuilder: locker) .sendChangeTo(changeAddress, scriptBuilder: locker) .withFeePerKb(1024); //set a one satoshi per byte fee
Signing a Transaction
We still have to sign the Transaction [c1] using a private key. This assumes that the output we are spending from was locked using a public key (pubKeyHash) corresponding to our private key.
It is important to note that when signing transactions for broadcast on the BitcoinSV network, we must always include the SIGHASH_FORKID value. See Signature Schemes section.
txn.signInput(0, privateKey, sighashType: SighashType.SIGHASH_ALL | SighashType.SIGHASH_FORKID); //obtain a hexadecimal version (raw transaction) which is //ready for broadcast using something like the Merchant API var txHex = txn.serialize();