Skip to main content

bark/onchain/
mod.rs

1//! Onchain wallet integration interfaces.
2//!
3//! This module defines the traits and types that an external onchain wallet must
4//! implement to be used by the library. The goal is to let integrators plug in
5//! their own wallet implementation, so features like boarding (moving onchain funds
6//! into Ark) and unilateral exit (claiming VTXOs onchain without server cooperation)
7//! are supported.
8//!
9//! Key concepts exposed here:
10//! - [Utxo], [LocalUtxo] & [SpendableExit]: lightweight types representing wallet UTXOs and
11//!   spendable exit outputs.
12//! - [PreparePsbt] & [SignPsbt]: funding and signing interfaces for building transactions.
13//! - [GetBalance], [GetWalletTx], [GetSpendingTx]: read-access to wallet state for balance
14//!   and [Transaction] lookups required by various parts of the library.
15//! - [MakeCpfp]: CPFP construction interfaces used for create child transactions.
16//! - [ExitUnilaterally]: a convenience trait that aggregates the required capabilities a
17//!   wallet must provide to support unilateral exits.
18//!
19//! A reference implementation based on BDK is available behind the `onchain-bdk`
20//! cargo feature. Enable it to use the provided [OnchainWallet] implementation.
21//! You can use all features from BDK because [bdk_wallet] is re-exported.
22
23#[cfg(feature = "onchain-bdk")]
24mod bdk;
25
26#[cfg(feature = "onchain-bdk")]
27pub use bdk_wallet;
28
29pub use bitcoin_ext::cpfp::{CpfpError, MakeCpfpFees};
30
31/// BDK-backed onchain wallet implementation.
32///
33/// Available only when the `onchain-bdk` feature is enabled.
34#[cfg(feature = "onchain-bdk")]
35pub use crate::onchain::bdk::{OnchainWallet, TxBuilderExt};
36
37use std::sync::Arc;
38
39use bitcoin::{
40	Address, Amount, FeeRate, OutPoint, Psbt, SignedAmount, Transaction, Txid
41};
42
43use ark::Vtxo;
44use ark::vtxo::Full;
45use bitcoin_ext::{BlockHeight, BlockRef};
46
47use crate::chain::ChainSource;
48
49/// Summary of a wallet transaction produced by [OnchainWallet::list_transaction_infos].
50#[derive(Debug, Clone)]
51pub struct WalletTxInfo {
52	pub txid: Txid,
53	pub tx: Arc<Transaction>,
54	/// Total fee paid by the transaction, when computable. `None` for inbound or
55	/// collaboratively-funded txs whose foreign prevouts BDK has not indexed
56	/// (e.g. after a bitcoind-rpc sync — esplora syncs populate prevouts).
57	pub onchain_fees: Option<Amount>,
58	/// Net change to the wallet's balance: `received - sent` over wallet-owned outputs.
59	pub balance_change: SignedAmount,
60	/// `Some` if the transaction is confirmed in a block, `None` if still in the mempool.
61	pub confirmation: Option<BlockRef>,
62}
63
64/// Represents an onchain UTXO known to the wallet.
65///
66/// This can be either:
67/// - `Local`: a standard wallet UTXO
68/// - `Exit`: a spendable exit output produced by the Ark exit mechanism
69#[derive(Debug, Clone)]
70pub enum Utxo {
71	Local(LocalUtxo),
72	Exit(SpendableExit),
73}
74
75/// A standard wallet [Utxo] owned by the local wallet implementation.
76#[derive(Debug, Clone)]
77pub struct LocalUtxo {
78	/// The outpoint referencing the UTXO.
79	pub outpoint: OutPoint,
80	/// The amount contained in the UTXO.
81	pub amount: Amount,
82	/// Optional confirmation height; `None` if unconfirmed.
83	pub confirmation_height: Option<BlockHeight>,
84}
85
86/// A spendable unilateral exit of a [Vtxo] which can be claimed onchain.
87///
88/// When exiting unilaterally, the wallet will end up with onchain outputs that correspond to
89/// previously-held VTXOs. These can be claimed and used for further spending.
90#[derive(Debug, Clone)]
91pub struct SpendableExit {
92	/// The VTXO being exited.
93	pub vtxo: Vtxo<Full>,
94	/// The block height associated with the exits' validity window.
95	pub height: BlockHeight,
96}
97
98/// Ability to finalize a [Psbt] into a fully signed [Transaction].
99///
100/// Wallets should apply all necessary signatures and finalize inputs according
101/// to their internal key management and policies.
102#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
103#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
104pub trait SignPsbt {
105	/// Consume a [Psbt] and return a fully signed [Psbt] with all witnesses filled in.
106	///
107	/// Useful when the signed [Psbt] is needed after signing, e.g. to compute fees
108	/// via [Psbt::fee] before extracting the final [Transaction].
109	async fn finish_psbt(&mut self, psbt: Psbt) -> anyhow::Result<Psbt>;
110}
111
112/// Ability to get the next onchain address from the wallet.
113#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
114#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
115pub trait GetAddress {
116	async fn address(&mut self) -> anyhow::Result<Address>;
117}
118
119/// Ability to query the wallets' total balance.
120///
121/// This is used by higher-level flows to decide when onchain funds are available for boarding or
122/// fee bumping, and to present balance information to users.
123pub trait GetBalance {
124	/// Get the total balance of the wallet.
125	fn get_balance(&self) -> Amount;
126}
127
128/// Ability to look up transactions known to the wallet.
129///
130/// Implementations should return wallet-related transactions and, when possible,
131/// the block information those transactions confirmed in.
132pub trait GetWalletTx {
133	/// Retrieve the wallet [Transaction] for the given [Txid] if any.
134	fn get_wallet_tx(&self, txid: Txid) -> Option<Arc<Transaction>>;
135
136	/// Retrieve information about the block, if any, a given wallet transaction was confirmed in.
137	fn get_wallet_tx_confirmed_block(&self, txid: Txid) -> anyhow::Result<Option<BlockRef>>;
138}
139
140/// Ability to construct funded PSBTs for specific destinations or to drain the wallet.
141///
142/// These methods are used to build transactions for boarding, exits, and fee bumping.
143pub trait PreparePsbt {
144	/// Prepare a [Transaction] which will send to the given destinations.
145	fn prepare_tx(
146		&mut self,
147		destinations: &[(Address, Amount)],
148		fee_rate: FeeRate,
149	) -> anyhow::Result<Psbt>;
150
151	/// Prepare a [Transaction] for sending all wallet funds to the given destination.
152	fn prepare_drain_tx(
153		&mut self,
154		destination: Address,
155		fee_rate: FeeRate,
156	) -> anyhow::Result<Psbt>;
157}
158
159/// Ability to find wallet-local spends of a specific [OutPoint].
160///
161/// This helps identify if the wallet has already spent an exit or parent [Transaction].
162pub trait GetSpendingTx {
163	/// This should search the wallet and look for any [Transaction] that spends the given
164	/// [OutPoint]. The intent of the function is to only look at spends which happen in the wallet
165	/// itself.
166	fn get_spending_tx(&self, outpoint: OutPoint) -> Option<Arc<Transaction>>;
167}
168
169/// Ability to create and persist CPFP transactions for spending P2A outputs.
170#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
171#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
172pub trait MakeCpfp {
173	/// Creates a signed Child Pays for Parent (CPFP) transaction using a Pay-to-Anchor (P2A) output
174	/// to broadcast unilateral exits and other TRUC transactions.
175	///
176	/// For more information please see [BIP431](https://github.com/bitcoin/bips/blob/master/bip-0431.mediawiki#topologically-restricted-until-confirmation).
177	///
178	/// # Arguments
179	///
180	/// * `tx` - A parent `Transaction` that is guaranteed to have one P2A output which
181	///          implementations must spend so that both the parent and child transactions can be
182	///          broadcast to the network as a v3 transaction package.
183	/// * `fees` - Informs the implementation how fees should be paid by the child transaction. Note
184	///            that an effective fee rate should be calculated using the weight of both the
185	///            parent and child transactions.
186	///
187	/// # Returns
188	///
189	/// Returns a `Result` containing:
190	/// * `Transaction` - The signed CPFP transaction ready to be broadcasted to the network with
191	///                   the given parent transaction if construction and signing were successful.
192	/// * `CpfpError` - An error indicating the reason for failure in constructing the CPFP
193	///                 transaction (e.g., insufficient funds, invalid parent transaction, or
194	///                 signing failure).
195	fn make_signed_p2a_cpfp(
196		&mut self,
197		tx: &Transaction,
198		fees: MakeCpfpFees,
199	) -> Result<Transaction, CpfpError>;
200
201	/// Persist the signed CPFP transaction so it can be rebroadcast or retrieved as needed.
202	async fn store_signed_p2a_cpfp(&mut self, tx: &Transaction) -> anyhow::Result<(), CpfpError>;
203}
204
205/// Trait alias for wallets that support boarding.
206///
207/// Any wallet type implementing these component traits automatically implements
208/// `Board`. The trait requires Send + Sync because boarding flows may be
209/// executed from async tasks and across threads.
210///
211/// Required capabilities:
212/// - [SignPsbt]: to finalize transactions
213/// - [GetWalletTx]: to query related transactions and their confirmations
214/// - [PreparePsbt]: to prepare transactions for boarding
215pub trait Board: PreparePsbt + SignPsbt + GetWalletTx + Send + Sync {}
216
217impl <W: PreparePsbt + SignPsbt + GetWalletTx + Send + Sync> Board for W {}
218
219/// Trait alias for wallets that support unilateral exit end-to-end.
220///
221/// Any wallet type implementing these component traits automatically implements
222/// `ExitUnilaterally`. The trait requires Send + Sync because exit flows may be
223/// executed from async tasks and across threads.
224///
225/// Required capabilities:
226/// - [GetBalance]: to evaluate available funds
227/// - [GetWalletTx]: to query related transactions and their confirmations
228/// - [MakeCpfp]: to accelerate slow/pinned exits
229/// - [SignPsbt]: to finalize transactions
230/// - [GetSpendingTx]: to detect local spends relevant to exit coordination
231pub trait ExitUnilaterally:
232	GetBalance +
233	GetWalletTx +
234	MakeCpfp +
235	SignPsbt +
236	GetSpendingTx +
237	Send + Sync + {}
238
239impl <W: GetBalance +
240	GetWalletTx +
241	MakeCpfp +
242	SignPsbt +
243	GetSpendingTx +
244	Send + Sync> ExitUnilaterally for W {}
245
246/// Ability to sync the wallet with the onchain network.
247#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
248#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
249pub trait ChainSync {
250	/// Sync the wallet with the onchain network.
251	async fn sync(&mut self, chain: &ChainSource) -> anyhow::Result<()>;
252}
253
254/// Trait that covers the requirements to use an onchain wallet with
255/// [Wallet::run_daemon](crate::Wallet::run_daemon).
256pub trait DaemonizableOnchainWallet: ExitUnilaterally + ChainSync {}
257impl <W: ExitUnilaterally + ChainSync> DaemonizableOnchainWallet for W {}