Architecture
Balancing pipeline
Transaction balancing transforms a partial transaction (user-specified
outputs, no inputs or fees) into a fully balanced transaction ready for
signing. The core entry point is balanceTx in
Cardano.Balance.Tx.Balance.
Pipeline stages
flowchart TD
A["Partial Tx + UTxO + Protocol Params"] --> B
B["1. Coin Selection<br/>(CoinSelection)"]
B -- "inputs selected" --> C
C["2. Fee Estimation<br/>(SizeEstimation, Sign)"]
C -- "fee computed" --> D
D["3. Change Outputs<br/>(Surplus, TokenBundleSize)"]
D -- "change distributed" --> E
E["4. Redeemer Assignment<br/>(Redeemers)"]
E -- "redeemers reindexed" --> F
F["5. Validation"]
F --> G["Balanced Tx (ready to sign)"]
Iteration
The algorithm must iterate because adding inputs changes the transaction size and therefore the fee. Each iteration:
- Estimates the fee for the current transaction
- Runs coin selection if more inputs are needed
- Recomputes change outputs
- Checks if the fee has stabilized
Convergence is guaranteed because each round can only add inputs (never remove them), and the UTxO set is finite.
flowchart TD
A["Estimate fee"] --> B["Run coin selection"]
B --> C["Recompute change outputs"]
C --> D{"Fee stabilized?"}
D -- "No" --> A
D -- "Yes" --> E["Proceed to validation"]
Module organization
The library is organized into three layers:
Core types
Primitive— lightweight value types (coin, token bundle, address) inlined fromcardano-wallet-primitive, bridging to ledger types viaPrimitive.ConvertTx— transaction/PParams types, serialization, key witness counting, minimum-ada computationTxWithUTxO— a transaction paired with its resolved UTxO contextEras— era definitions (RecentEracovering Conway/Dijkstra)
Balancing logic
Balance— the mainbalanceTxfunction and error typesBalance.CoinSelection— adapter between ledger types and thecardano-coin-selectionlibraryBalance.Surplus— distributing fee surplus between padding and changeBalance.TokenBundleSize— assessing whether token bundles fit in a single output
Utilities
SizeEstimation— predicting serialized transaction sizeRedeemers— assigning script redeemer indicesSign— signing-related size/fee estimation and witness counting (estimateSignedTxSize,estimateSignedTxMinFee,KeyWitnessCounts)TimeTranslation— slot/time conversion from epoch infoUTxOAssumptions— assumptions about UTxO script types for size estimation
graph TD
subgraph Core["Core types"]
Primitive
Tx
TxWithUTxO
Eras
end
subgraph Balancing["Balancing logic"]
Balance
CoinSelection["Balance.CoinSelection"]
Surplus["Balance.Surplus"]
TokenBundleSize["Balance.TokenBundleSize"]
end
subgraph Utilities
SizeEstimation
Redeemers
Sign
TimeTranslation
UTxOAssumptions
end
Balance --> CoinSelection
Balance --> Surplus
Balance --> TokenBundleSize
Balance --> SizeEstimation
Balance --> Redeemers
Balancing --> Core
Utilities --> Core
Era support
The library uses a RecentEra GADT to support the two most recent eras
— Conway and Dijkstra — so the same code can construct transactions on
either side of a hard fork. All era-specific logic is isolated in Eras
and pattern-matched where needed, keeping the core balancing algorithm
era-polymorphic. (Babbage and earlier are modelled as non-recent eras;
serialization round-trip tests still cover Babbage golden fixtures for
backwards compatibility.)