mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-26 07:32:33 +01:00
* Remove support for v19 of bitcoind * Remove downloading v19 bitcoind inside of bitcoind-rpc.sbt * Clean up docs * Move unit tests in BitcoindV19RpcClientTest into other test files so we don't remove them, these rpcs are supported in future versions of bitcoind
144 lines
4.7 KiB
Markdown
144 lines
4.7 KiB
Markdown
---
|
|
id: txbuilder
|
|
title: TxBuilder Example
|
|
---
|
|
|
|
Bitcoin-S features a transaction building API that allows you to construct and sign Bitcoin transactions. Here's an example of how to use it
|
|
|
|
```scala mdoc:invisible
|
|
import scala.concurrent._
|
|
|
|
import org.bitcoins.core._
|
|
import number._
|
|
import currency._
|
|
import org.bitcoins.crypto._
|
|
import protocol.transaction._
|
|
import protocol.script._
|
|
|
|
import wallet.builder._
|
|
import wallet.fee._
|
|
import wallet.utxo._
|
|
|
|
```
|
|
|
|
```scala mdoc:to-string
|
|
|
|
implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
|
|
|
|
// Initialize a transaction builder
|
|
val builder = RawTxBuilder()
|
|
|
|
// generate a fresh private key that we are going to use in the scriptpubkey
|
|
val privKey = ECPrivateKey.freshPrivateKey
|
|
val pubKey = privKey.publicKey
|
|
|
|
// this is the script that the TxBuilder is going to create a
|
|
// script signature that validly spends this scriptPubKey
|
|
val creditingSpk = P2PKHScriptPubKey(pubKey = privKey.publicKey)
|
|
val amount = 10000.satoshis
|
|
|
|
// this is the UTXO we are going to be spending
|
|
val utxo =
|
|
TransactionOutput(value = amount, scriptPubKey = creditingSpk)
|
|
|
|
// the private key that locks the funds for the script we are spending too
|
|
val destinationPrivKey = ECPrivateKey.freshPrivateKey
|
|
|
|
// the amount we are sending -- 5000 satoshis -- to the destinationSPK
|
|
val destinationAmount = 5000.satoshis
|
|
|
|
// the script that corresponds to destination private key, this is what is receiving the money
|
|
val destinationSPK =
|
|
P2PKHScriptPubKey(pubKey = destinationPrivKey.publicKey)
|
|
|
|
// this is where we are sending money too
|
|
// we could add more destinations here if we
|
|
// wanted to batch transactions
|
|
val destinations = {
|
|
val destination0 = TransactionOutput(value = destinationAmount,
|
|
scriptPubKey = destinationSPK)
|
|
|
|
Vector(destination0)
|
|
}
|
|
|
|
// Add the destinations to the tx builder
|
|
builder ++= destinations
|
|
|
|
// we have to fabricate a transaction that contains the
|
|
// UTXO we are trying to spend. If this were a real blockchain
|
|
// we would need to reference the UTXO set
|
|
val creditingTx = BaseTransaction(version = Int32.one,
|
|
inputs = Vector.empty,
|
|
outputs = Vector(utxo),
|
|
lockTime = UInt32.zero)
|
|
|
|
// this is the information we need from the crediting TX
|
|
// to properly "link" it in the transaction we are creating
|
|
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
|
val input = TransactionInput(
|
|
outPoint,
|
|
EmptyScriptSignature,
|
|
sequenceNumber = UInt32.zero)
|
|
|
|
// Add a new input to our builder
|
|
builder += input
|
|
|
|
// We can now generate a RawTxBuilderResult ready to be finalized
|
|
val builderResult = builder.result()
|
|
|
|
// this contains the information needed to analyze our input during finalization
|
|
val inputInfo = P2PKHInputInfo(outPoint, amount, privKey.publicKey)
|
|
|
|
// this is how much we are going to pay as a fee to the network
|
|
// for this example, we are going to pay 1 satoshi per byte
|
|
val feeRate = SatoshisPerByte(1.satoshi)
|
|
|
|
val changePrivKey = ECPrivateKey.freshPrivateKey
|
|
val changeSPK = P2PKHScriptPubKey(pubKey = changePrivKey.publicKey)
|
|
|
|
// We chose a finalizer that adds a change output to our tx based on a fee rate
|
|
val finalizer = StandardNonInteractiveFinalizer(
|
|
Vector(inputInfo),
|
|
feeRate,
|
|
changeSPK)
|
|
|
|
// We can now finalize the tx builder result from earlier with this finalizer
|
|
val unsignedTx: Transaction = finalizer.buildTx(builderResult)
|
|
|
|
// We now turn to signing the unsigned transaction
|
|
// this contains all the information we need to
|
|
// validly sign the UTXO above
|
|
val utxoInfo = ScriptSignatureParams(inputInfo = inputInfo,
|
|
prevTransaction = creditingTx,
|
|
signers = Vector(privKey),
|
|
hashType =
|
|
HashType.sigHashAll)
|
|
|
|
// all of the UTXO spending information, since we only have
|
|
// one input, this is just one element
|
|
val utxoInfos: Vector[ScriptSignatureParams[InputInfo]] = Vector(utxoInfo)
|
|
|
|
// Yay! Now we use the RawTxSigner object to sign the tx.
|
|
// The 'sign' method is going produce a validly signed transaction
|
|
// This is going to iterate through each of the UTXOs and use
|
|
// the corresponding ScriptSignatureParams to produce a validly
|
|
// signed input. This UTXO has:
|
|
// 1: one input
|
|
// 2: outputs (destination and change outputs)
|
|
// 3: a fee rate of 1 satoshi/byte
|
|
val signedTx: Transaction =
|
|
RawTxSigner.sign(
|
|
utx = unsignedTx,
|
|
utxoInfos = utxoInfos,
|
|
expectedFeeRate = feeRate
|
|
)
|
|
```
|
|
|
|
```scala mdoc:to-string
|
|
signedTx.inputs.length
|
|
|
|
signedTx.outputs.length
|
|
|
|
//remember, you can call .hex on any bitcoin-s data structure to get the hex representation!
|
|
signedTx.hex
|
|
```
|