pub struct TransactionBuilder<'info, const MAX_MODIFIED_ACCOUNTS: usize, const MAX_INPUTS_TO_SIGN: usize, RuneSet>{
pub transaction: Transaction,
pub tx_statuses: MempoolInfo,
pub inputs_to_sign: FixedRefList<InputToSign, MAX_INPUTS_TO_SIGN>,
pub total_btc_input: u64,
pub total_rune_inputs: RuneSet,
pub runestone: Runestone,
pub total_btc_consolidation_input: u64,
pub extra_tx_size_for_consolidation: usize,
/* private fields */
}Expand description
A zero-heap Bitcoin transaction builder for the Arch runtime.
TransactionBuilder provides a type-safe, heap-free way to construct Bitcoin transactions
that interact with the Arch runtime. It manages transaction inputs, outputs, state transitions,
and fee calculations while maintaining compatibility with constrained environments like the
Solana BPF VM.
§Design Philosophy
The builder is designed around three core principles:
- Zero-heap allocation: All collections use fixed-size arrays determined at compile time
- Type safety: Generic parameters prevent runtime errors by enforcing limits at compile time
- Arch integration: Built-in support for Arch-specific concepts like state transitions and account modifications
§Generic Parameters
MAX_MODIFIED_ACCOUNTS: Maximum number of program accounts that can be modified in a single transactionMAX_INPUTS_TO_SIGN: Maximum number of transaction inputs that require signaturesRuneSet: Collection type for tracking rune inputs (only used withrunesfeature)
These bounds are enforced at compile time to ensure the builder remains heap-free.
§Feature Flags
runes: Enables rune transaction support with automatic rune input/output trackingutxo-consolidation: Enables UTXO consolidation features for managing fragmented UTXOsserde: Enables serialization support for transaction data
§Basic Usage
use satellite_bitcoin_transactions::TransactionBuilder;
use satellite_bitcoin_transactions::fee_rate::FeeRate;
// Create a builder with capacity for 8 modified accounts and 4 inputs to sign
let mut builder: TransactionBuilder<8, 4, satellite_bitcoin_transactions::utxo_info::SingleRuneSet> = TransactionBuilder::new();
// The builder starts with an empty version 2 transaction
assert_eq!(builder.transaction.input.len(), 0);
assert_eq!(builder.transaction.output.len(), 0);
assert_eq!(builder.total_btc_input, 0);
// Add inputs and outputs using the builder methods...§Working with State Transitions
State transitions are a core concept in Arch. Use these methods to manage program account updates:
// Add a state transition for an existing account
builder.add_state_transition(&account, SignPolicy::Managed)?;
// The builder automatically:
// 1. Adds the account to modified_accounts list
// 2. Creates an InputToSign entry
// 3. Updates total_btc_input with DUST_LIMIT
// 4. Adds the state transition to the transaction§Adding User Inputs
Add user-controlled UTXOs to the transaction:
// Add a regular input that requires signing
builder.add_tx_input(&utxo, &status, Some(&signer))?;
// For precise control over input order:
builder.insert_tx_input(0, &utxo, &status, Some(&signer))?;§Fee Management
The builder provides sophisticated fee management with mempool ancestry tracking:
// Set target fee rate
let fee_rate = FeeRate::try_from(25.0)?; // 25 sat/vB
// Automatically adjust transaction to meet fee requirements
builder.adjust_transaction_to_pay_fees(&fee_rate, Some(change_address))?;
// Validate the effective fee rate (including ancestors)
builder.is_fee_rate_valid(&fee_rate)?;
// Get fee breakdown
let user_fee = builder.get_fee_paid_by_user(&fee_rate);
let total_fee = builder.get_fee_paid()?;§UTXO Selection
Automatically select UTXOs to meet funding requirements:
// Find UTXOs to cover a specific amount
let amount_needed = 100_000; // 100k sats
let (selected_indices, total_found) = builder.find_btc_in_utxos(
&utxos,
&program_pubkey,
amount_needed
)?;
// The builder automatically selects the most efficient UTXOs
// and adds them to the transaction§Rune Support (with runes feature)
When compiled with the runes feature, the builder automatically tracks rune inputs and outputs:
// Rune inputs are automatically tracked when adding UTXOs
// The builder maintains total_rune_inputs and runestone data
// Access rune information
let rune_count = builder.total_rune_inputs.len();
let runestone = &builder.runestone;§UTXO Consolidation (with utxo-consolidation feature)
Automatically consolidate fragmented UTXOs to reduce transaction sizes:
// Add consolidation UTXOs to reduce fragmentation
builder.add_consolidation_utxos(
&pool_pubkey,
&fee_rate,
&utxos,
&potential_changes
);
// Get fee breakdown
let program_fee = builder.get_fee_paid_by_program(&fee_rate);
let user_fee = builder.get_fee_paid_by_user(&fee_rate);§Size Estimation
Estimate transaction sizes for fee calculation:
// Estimate current transaction size
let current_vsize = builder.estimate_final_tx_vsize();
// Estimate size with additional inputs/outputs
let estimated_vsize = builder.estimate_tx_vsize_with_additional_inputs_outputs(
&potential_changes
);§Error Handling
The builder provides detailed error information:
// Capacity limits are enforced at runtime
match builder.inputs_to_sign.len() {
len if len >= 4 => {
// Handle InputToSignListFull error
}
_ => {
// Safe to add more inputs
}
}
// Fee validation errors
match builder.get_fee_paid() {
Ok(fee) => println!("Fee: {} sats", fee),
Err(BitcoinTxError::InsufficientInputAmount) => {
// Handle insufficient input funds
}
Err(e) => {
// Handle other errors
}
}§Finalization
Complete the transaction and prepare it for signing:
// After adding all inputs, outputs, and adjusting fees
builder.finalize()?;
// The transaction is now ready for the Arch runtime to collect signatures
// and broadcast to the Bitcoin network§Performance Considerations
- All operations are O(1) or O(n) where n is bounded by the generic parameters
- No heap allocations occur during normal operation
- Memory usage is deterministic and known at compile time
- Suitable for use in constrained environments like the Solana BPF VM
§Thread Safety
TransactionBuilder is not thread-safe and should not be shared between threads.
Create separate builders for concurrent transaction construction.
Fields§
§transaction: TransactionThis transaction will be broadcast through Arch to indicate a state transition in the program
tx_statuses: MempoolInfo§inputs_to_sign: FixedRefList<InputToSign, MAX_INPUTS_TO_SIGN>This tells Arch which inputs in [InstructionContext::transaction] still need to be signed, along with which key needs to sign each of them
total_btc_input: u64§total_rune_inputs: RuneSet§runestone: Runestone§total_btc_consolidation_input: u64§extra_tx_size_for_consolidation: usizeImplementations§
Source§impl<'info, const MAX_MODIFIED_ACCOUNTS: usize, const MAX_INPUTS_TO_SIGN: usize, RuneSet> TransactionBuilder<'info, MAX_MODIFIED_ACCOUNTS, MAX_INPUTS_TO_SIGN, RuneSet>
impl<'info, const MAX_MODIFIED_ACCOUNTS: usize, const MAX_INPUTS_TO_SIGN: usize, RuneSet> TransactionBuilder<'info, MAX_MODIFIED_ACCOUNTS, MAX_INPUTS_TO_SIGN, RuneSet>
Sourcepub fn find_btc_in_utxos<T>(
&mut self,
utxos: &[T],
program_info_pubkey: &Pubkey,
amount: u64,
) -> Result<(Vec<usize>, u64), BitcoinTxError>
pub fn find_btc_in_utxos<T>( &mut self, utxos: &[T], program_info_pubkey: &Pubkey, amount: u64, ) -> Result<(Vec<usize>, u64), BitcoinTxError>
Greedily selects UTXOs until at least amount satoshis are gathered.
Returns the indices of the chosen items plus the total value selected.
Sourcepub fn find_btc_in_utxos_from_holder<BtcHolder>(
&mut self,
holder: &[BtcHolder],
program_info_pubkey: &Pubkey,
amount: u64,
enforce_dust_remainder: bool,
) -> Result<u64, BitcoinTxError>where
BtcHolder: BtcUtxoHolder,
pub fn find_btc_in_utxos_from_holder<BtcHolder>(
&mut self,
holder: &[BtcHolder],
program_info_pubkey: &Pubkey,
amount: u64,
enforce_dust_remainder: bool,
) -> Result<u64, BitcoinTxError>where
BtcHolder: BtcUtxoHolder,
Greedily selects UTXOs from holders until at least amount satoshis are gathered.
Optionally targets amount + DUST_LIMIT with early exit allowed on exact amount.
Source§impl<'info, const MAX_MODIFIED_ACCOUNTS: usize, const MAX_INPUTS_TO_SIGN: usize, RuneSet> TransactionBuilder<'info, MAX_MODIFIED_ACCOUNTS, MAX_INPUTS_TO_SIGN, RuneSet>
impl<'info, const MAX_MODIFIED_ACCOUNTS: usize, const MAX_INPUTS_TO_SIGN: usize, RuneSet> TransactionBuilder<'info, MAX_MODIFIED_ACCOUNTS, MAX_INPUTS_TO_SIGN, RuneSet>
Sourcepub fn new() -> TransactionBuilder<'info, MAX_MODIFIED_ACCOUNTS, MAX_INPUTS_TO_SIGN, RuneSet>
pub fn new() -> TransactionBuilder<'info, MAX_MODIFIED_ACCOUNTS, MAX_INPUTS_TO_SIGN, RuneSet>
Creates a new empty transaction builder with rune support.
Initializes a blank builder containing an empty version 2 Bitcoin transaction with lock_time = 0.
All internal counters and collections start empty, including rune-specific tracking.
§Initial State
transaction: Empty version 2 transactiontotal_btc_input: 0 satoshistotal_rune_inputs: Empty rune setrunestone: Default runestonemodified_accounts: Empty fixed-size listinputs_to_sign: Empty fixed-size listtx_statuses: Default mempool info
§Rune Features
With the runes feature enabled, the builder automatically:
- Tracks rune inputs when adding UTXOs
- Maintains runestone data for rune operations
- Handles rune arithmetic and validation
§Examples
use satellite_bitcoin_transactions::TransactionBuilder;
use arch_program::rune::RuneAmount;
// Create a builder that can handle up to 8 modified accounts and 4 inputs to sign
let mut builder: TransactionBuilder<8, 4, satellite_bitcoin_transactions::utxo_info::SingleRuneSet> = TransactionBuilder::new();
// Verify initial state
assert_eq!(builder.transaction.input.len(), 0);
assert_eq!(builder.transaction.output.len(), 0);
assert_eq!(builder.total_btc_input, 0);
assert_eq!(builder.total_rune_inputs.len(), 0);
assert_eq!(builder.inputs_to_sign.len(), 0);§Generic Parameters
Choose your bounds based on your use case:
- Small transactions:
TransactionBuilder<4, 2, SmallRuneSet>for simple operations - Medium transactions:
TransactionBuilder<8, 4, MediumRuneSet>for typical use cases - Large transactions:
TransactionBuilder<16, 8, LargeRuneSet>for complex operations
The RuneSet parameter determines how many different rune types can be tracked simultaneously.
pub fn new_with_transaction( transaction: Transaction, mempool_data: &impl MempoolDataView, user_utxos: &[UtxoInfo<RuneSet>], ) -> Result<TransactionBuilder<'info, MAX_MODIFIED_ACCOUNTS, MAX_INPUTS_TO_SIGN, RuneSet>, BitcoinTxError>
Sourcepub fn add_state_transition(
&mut self,
account: &AccountInfo<'info>,
policy: SignPolicy,
) -> Result<u32, BitcoinTxError>
pub fn add_state_transition( &mut self, account: &AccountInfo<'info>, policy: SignPolicy, ) -> Result<u32, BitcoinTxError>
Adds a state transition for an existing program account.
This method handles the complete process of adding a state transition to the transaction, which is required when updating any program-derived account (PDA) or state account on Arch.
§What it does
The method performs these operations atomically:
- Adds signing requirement: Creates an
InputToSignentry so Arch knows which key must sign the input - Adds meta-instruction: Appends the state transition meta-instruction to the transaction
- Tracks modification: Adds the account to the
modified_accountslist for Arch’s state saving - Updates input total: Increments
total_btc_inputbyconstants::DUST_LIMIT(546 sats)
§When to use
Use this method when you need to:
- Update an existing program account
- Modify state stored in a PDA
- Perform any operation that changes account data
§Account Requirements
The account must:
- Have a valid UTXO backing it on-chain
- Be owned by a program that you have authority to modify
- Have exactly
constants::DUST_LIMITsatoshis in its UTXO
§Examples
// Add a state transition for an existing liquidity pool account
builder.add_state_transition(&account, SignPolicy::Managed)?;
// The builder now knows:
// - This account will be modified
// - The account's key must sign the transaction
// - 546 sats are consumed from the account's UTXO§Error Handling
Returns BitcoinTxError::InputToSignListFull if the builder has reached its
MAX_INPUTS_TO_SIGN limit, or BitcoinTxError::ModifiedAccountListFull if
the MAX_MODIFIED_ACCOUNTS limit is exceeded.
§See Also
Self::insert_state_transition_inputfor position-specific insertions
Sourcepub fn insert_state_transition_input(
&mut self,
tx_index: usize,
account: &AccountInfo<'info>,
policy: SignPolicy,
) -> Result<(), BitcoinTxError>
pub fn insert_state_transition_input( &mut self, tx_index: usize, account: &AccountInfo<'info>, policy: SignPolicy, ) -> Result<(), BitcoinTxError>
Inserts an existing state‐transition input at the given tx_index keeping all
internal bookkeeping consistent.
Use this when the input order matters and you need a state-transition (program
account) input to appear in a specific position. The function updates
TransactionBuilder::inputs_to_sign indices, tracks the modified account and bumps
TransactionBuilder::total_btc_input.
Sourcepub fn add_tx_input<RS>(
&mut self,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
signer: Option<&Pubkey>,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
pub fn add_tx_input<RS>(
&mut self,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
signer: Option<&Pubkey>,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
Adds a regular input owned by signer.
Besides pushing the TxIn into the underlying transaction, this helper:
- Records mempool ancestry via
TransactionBuilder::add_tx_status. - Adds an
InputToSign. - Updates
total_btc_input(andtotal_rune_inputwhen compiled with therunesfeature).
Sourcepub fn add_user_tx_input<RS>(
&mut self,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
tx_in: TxIn,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
pub fn add_user_tx_input<RS>(
&mut self,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
tx_in: TxIn,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
Appends a user-supplied TxIn (already built elsewhere) while still tracking the
UTXO ancestry for fee-rate purposes.
Sourcepub fn insert_tx_input<RS>(
&mut self,
tx_index: usize,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
signer: Option<&Pubkey>,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
pub fn insert_tx_input<RS>(
&mut self,
tx_index: usize,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
signer: Option<&Pubkey>,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
Inserts a regular (non-state–account) TxIn at the given position tx_index.
Besides pushing the new input into TransactionBuilder::transaction, this helper keeps
all internal bookkeeping consistent:
- Records the mempool ancestry for fee-rate calculations via
Self::add_tx_status. - Shifts the
indexof every existingarch_program::input_to_sign::InputToSignthat appears at or aftertx_indexso their indices continue to match the underlying transaction after the insertion. - Pushes a fresh
InputToSignforsignerso Arch knows which key must later provide a witness for the inserted input. - Bumps
Self::total_btc_input(andtotal_rune_inputwhen compiled with therunesfeature) by the value ofutxo.
Use this when the order of inputs matters – for example when signing with PSBTs that expect user inputs to appear before program-generated ones.
§Parameters
tx_index– zero-based index where the input should be inserted.utxo– metadata of the UTXO being spent.status– mempool status ofutxo; contributes to ancestor fee/size tracking.signer– optional public key that will sign the input.
Sourcepub fn insert_user_tx_input<RS>(
&mut self,
tx_index: usize,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
tx_in: &TxIn,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
pub fn insert_user_tx_input<RS>(
&mut self,
tx_index: usize,
utxo: &UtxoInfo<RS>,
status: &TxStatus,
tx_in: &TxIn,
) -> Result<(), BitcoinTxError>where
RS: FixedCapacitySet<Item = RuneAmount>,
Inserts a pre-constructed TxIn – built elsewhere – at the specified tx_index.
The function behaves similarly to Self::insert_tx_input but does not create a new
InputToSign, as the caller may already have handled signature tracking. It still:
- Accounts for the input’s mempool ancestry using
Self::add_tx_status. - Shifts the indices of all existing
InputToSignthat come aftertx_indexso they remain correct. - Updates BTC / rune running totals.
This is handy when you have a non-standard script or any other reason to fully craft the
TxIn outside of the builder but still need to place it at a precise position inside the
transaction.
§Parameters
tx_index– position wheretx_inshould be inserted.utxo– the UTXO consumed bytx_in.status– mempool status ofutxo.tx_in– ready-made transaction input (will be cloned).
Sourcepub fn adjust_transaction_to_pay_fees(
&mut self,
fee_rate: &FeeRate,
address_to_send_remaining_btc: Option<ScriptBuf>,
) -> Result<(), BitcoinTxError>
pub fn adjust_transaction_to_pay_fees( &mut self, fee_rate: &FeeRate, address_to_send_remaining_btc: Option<ScriptBuf>, ) -> Result<(), BitcoinTxError>
Greedily selects UTXOs until at least amount satoshis are gathered.
Selection strategy:
- With the
utxo-consolidationfeature enabled: prefer UTXOs without theneeds_consolidationflag, then sort by descending value. - Without the feature: simply sort by descending value.
Returns the indices of the chosen items inside the original slice plus the total value selected.
§Errors
BitcoinTxError::NotEnoughBtcInPool– not enough value inutxosto satisfyamount. find_btc_in_utxos_from_holder has been moved to thefind_btcmodule for clarity. Automatically adjusts the transaction to meet the target fee rate.
This method optimizes the transaction’s fee structure by analyzing the current input/output balance and adjusting outputs to achieve the desired fee rate. It handles both overpayment (creating change) and underpayment (reducing outputs) scenarios.
§How it works
The method evaluates the current transaction and:
- Calculates required fee: Based on transaction size and target fee rate
- Handles excess funds: Creates or increases change output if inputs exceed requirements
- Handles insufficient funds: Reduces change output or returns error if impossible
- Considers ancestors: Accounts for mempool ancestry when calculating effective fee rate
§Change Output Behavior
address_to_send_remaining_btc = Some(address): Creates new change output or increases existing oneaddress_to_send_remaining_btc = None: Only adjusts existing outputs, never creates new ones
§Examples
// Set target fee rate (25 sat/vB)
let fee_rate = FeeRate::try_from(25.0)?;
// Create change output for excess funds
let change_address = ScriptBuf::new(); // Your change address
builder.adjust_transaction_to_pay_fees(&fee_rate, Some(change_address))?;
// Or adjust without creating change (only reduce existing outputs)
builder.adjust_transaction_to_pay_fees(&fee_rate, None)?;§Fee Calculation Details
The method considers:
- Transaction size: Estimated final size including witness data
- Input signatures: Size overhead for each required signature
- Mempool ancestry: Fees and sizes of unconfirmed parent transactions
- Consolidation: Extra size from UTXO consolidation (if enabled)
§Error Handling
Returns an error if:
- Insufficient funds to cover minimum fee requirements
- Cannot reduce outputs enough to meet fee rate
- Transaction would exceed size limits
- Fee rate calculation fails
§Best Practices
// Always validate fee rate after adjustment
let fee_rate = FeeRate::try_from(15.0)?;
builder.adjust_transaction_to_pay_fees(&fee_rate, Some(change_address))?;
// Verify the final fee rate meets requirements
builder.is_fee_rate_valid(&fee_rate)?;
// Check final fee amount
let final_fee = builder.get_fee_paid()?;
println!("Final fee: {} sats", final_fee);§See Also
Self::is_fee_rate_validfor validating the resulting fee rateSelf::get_fee_paidfor checking the final fee amountSelf::get_fee_paid_by_userfor user-specific fee calculation
Sourcepub fn add_consolidation_utxos<BtcHolder>(
&mut self,
pool_pubkey: &Pubkey,
fee_rate: &FeeRate,
pool_shard_btc_utxos: &[BtcHolder],
new_potential_inputs_and_outputs: &NewPotentialInputsAndOutputs,
)where
BtcHolder: BtcUtxoHolder,
pub fn add_consolidation_utxos<BtcHolder>(
&mut self,
pool_pubkey: &Pubkey,
fee_rate: &FeeRate,
pool_shard_btc_utxos: &[BtcHolder],
new_potential_inputs_and_outputs: &NewPotentialInputsAndOutputs,
)where
BtcHolder: BtcUtxoHolder,
Attempts to sweep pool-owned UTXOs marked for consolidation into the current transaction.
This helper is only available when the utxo-consolidation feature is enabled. It acts as
a thin wrapper around [crate::consolidation::add_consolidation_utxos], forwarding the
relevant context from the builder and then updating the builder’s running totals so that
fee-calculation logic is aware of the extra inputs.
The consolidated inputs are signed by pool_pubkey. Only UTXOs whose
needs_consolidation value is greater than or equal to fee_rate are considered. The
function stops adding inputs as soon as the draft transaction would exceed
arch_program::MAX_BTC_TX_SIZE.
After execution the following builder fields are updated:
§Parameters
pool_pubkey– public key of the liquidity-pool program (signer of consolidation inputs).fee_rate– current mempool fee-rate used to decide which UTXOs are worth consolidating.pool_shard_btc_utxos– slice with the candidate pool UTXOs.new_potential_inputs_and_outputs– hypothetical inputs/outputs the caller may add later; needed to keep size estimations accurate.
pub fn get_fee_paid_by_program(&self, fee_rate: &FeeRate) -> u64
pub fn get_fee_paid_by_user( &mut self, fee_rate: &FeeRate, ) -> Result<u64, BitcoinTxError>
pub fn estimate_final_tx_vsize(&mut self) -> Result<usize, BitcoinTxError>
Sourcepub fn estimate_tx_size_with_additional_inputs_outputs(
&mut self,
new_potential_inputs_and_outputs: &NewPotentialInputsAndOutputs,
) -> Result<usize, BitcoinTxError>
pub fn estimate_tx_size_with_additional_inputs_outputs( &mut self, new_potential_inputs_and_outputs: &NewPotentialInputsAndOutputs, ) -> Result<usize, BitcoinTxError>
Returns the weight (in bytes) the transaction would have if the draft
new_potential_inputs_and_outputs were added.
Helpful during fee-bumping logic when you need to know “how much bigger will the TX get if I add N more inputs/outputs?”.
Sourcepub fn estimate_tx_vsize_with_additional_inputs_outputs(
&mut self,
new_potential_inputs_and_outputs: &NewPotentialInputsAndOutputs,
) -> Result<usize, BitcoinTxError>
pub fn estimate_tx_vsize_with_additional_inputs_outputs( &mut self, new_potential_inputs_and_outputs: &NewPotentialInputsAndOutputs, ) -> Result<usize, BitcoinTxError>
Same as Self::estimate_tx_size_with_additional_inputs_outputs but returns vsize
instead of raw size.
Sourcepub fn get_ancestors_totals(&self) -> Result<(usize, u64), BitcoinTxError>
pub fn get_ancestors_totals(&self) -> Result<(usize, u64), BitcoinTxError>
Returns the aggregate mempool size (bytes) and fees (sats) of all ancestor transactions referenced by pending inputs.
Sourcepub fn get_fee_paid(&self) -> Result<u64, BitcoinTxError>
pub fn get_fee_paid(&self) -> Result<u64, BitcoinTxError>
Calculates the fee currently paid by the partially-built transaction (inputs − outputs).
Fails with BitcoinTxError::InsufficientInputAmount if outputs exceed inputs.
Sourcepub fn is_fee_rate_valid(
&mut self,
fee_rate: &FeeRate,
) -> Result<(), BitcoinTxError>
pub fn is_fee_rate_valid( &mut self, fee_rate: &FeeRate, ) -> Result<(), BitcoinTxError>
Checks that the effective fee-rate (including ancestors) is at least fee_rate.
Returns an error when the calculated rate is below the target.
Sourcepub fn get_non_state_transition_inputs(&self) -> &[TxIn]
pub fn get_non_state_transition_inputs(&self) -> &[TxIn]
Returns a slice of transaction inputs that are not state transitions.
State transitions are always at the beginning of the transaction and correspond
to entries in modified_accounts. This method returns all inputs after the
state transition inputs.
§Returns
A slice of TxIn containing only non-state-transition inputs. Returns an
empty slice if all inputs are state transitions or if there are no inputs.
§Examples
// After adding state transitions and regular inputs...
let non_state_transition_inputs = builder.get_non_state_transition_inputs();
// Process only non-state-transition inputs
for input in non_state_transition_inputs {
// Handle regular UTXO inputs
}Sourcepub fn finalize(&mut self) -> Result<(), ProgramError>
pub fn finalize(&mut self) -> Result<(), ProgramError>
Finalizes the transaction and prepares it for signing by the Arch runtime.
This method completes the transaction building process by transferring the constructed transaction and all associated metadata to the Arch runtime. Once called, the transaction is ready for the signature collection phase.
§What it does
The method performs these final steps:
- Transfers ownership: Passes the transaction to the Arch runtime
- Provides metadata: Includes modified accounts and signing requirements
- Enables signing: Makes the transaction available for signature collection
- Prepares broadcast: Sets up the transaction for network submission
§Important Notes
- No further changes: After calling
finalize(), the builder should not be modified - Not broadcasting: This method does NOT broadcast the transaction to the network
- Signing phase: The transaction enters the signing phase, handled by Arch runtime
- State consistency: All modified accounts and inputs must be properly configured
§Prerequisites
Before calling finalize(), ensure:
- All required inputs have been added
- All outputs have been configured
- Fees have been adjusted with
Self::adjust_transaction_to_pay_fees - Fee rate has been validated with
Self::is_fee_rate_valid
§Transaction Lifecycle
1. TransactionBuilder::new() ← Create builder
2. Add inputs/outputs ← Populate transaction
3. adjust_transaction_to_pay_fees() ← Set correct fees
4. finalize() ← Prepare for signing
5. [Arch runtime signs] ← Automatic signing
6. [Arch runtime broadcasts] ← Network submission§Examples
// After building your transaction...
// 1. Adjust fees
let fee_rate = FeeRate::try_from(20.0)?;
let change_address = ScriptBuf::new();
builder.adjust_transaction_to_pay_fees(&fee_rate, Some(change_address))?;
// 2. Validate fee rate
builder.is_fee_rate_valid(&fee_rate)?;
// 3. Finalize and hand over to Arch
builder.finalize()?;
// Transaction is now ready for signing and broadcast§Error Handling
Returns ProgramError if:
- The transaction data is invalid
- Required metadata is missing
- The Arch runtime cannot accept the transaction
- Internal state is inconsistent
§See Also
Self::adjust_transaction_to_pay_feesfor fee adjustmentSelf::is_fee_rate_validfor fee validationarch_program::program::set_transaction_to_signfor the underlying mechanism