Unilateral exits allow you to move your Ark funds back to the Bitcoin blockchain without requiring server cooperation. This is a critical safety feature that ensures you always maintain full control of your funds.
Exits are expensive (onchain fees) and slow (requires confirmations). Only exit when:
The server is unresponsive or malicious
Your VTXOs are about to expire
You need funds onchain and can’t offboard normally
The Exit subsystem manages the entire unilateral exit lifecycle:
// Access the exit systemlet mut exit = wallet.exit.write().await;// The exit system tracks:// - Which VTXOs are being exited// - The current state of each exit// - Related onchain transactions// - Historical state transitions
use ark::VtxoId;let vtxo_id = VtxoId::from_slice(&[...])?;// Get detailed exit statuslet status = wallet.exit.read().await.get_exit_status( vtxo_id, true, // include history true // include transactions).await?;if let Some(status) = status { println!("VTXO {}", status.vtxo_id); println!("State: {:?}", status.state); if let Some(history) = status.history { println!("State history: {} transitions", history.len()); } for tx_package in status.transactions { println!("Exit TX: {}", tx_package.exit.txid); if let Some(child) = tx_package.child { println!(" Child TX: {}", child.txid); } }}
let exit = wallet.exit.read().await;// Get all exit VTXOslet all_exits = exit.get_exit_vtxos();println!("Total exits: {}", all_exits.len());// Get specific VTXO exitif let Some(exit_vtxo) = exit.get_exit_vtxo(vtxo_id) { println!("Found exit for VTXO {}", exit_vtxo.id()); println!("Amount: {}", exit_vtxo.amount()); println!("State: {:?}", exit_vtxo.state());}
let exit = wallet.exit.read().await;// Check if there are pending exitsif exit.has_pending_exits() { let pending_amount = exit.pending_total(); println!("Pending exits: {}", pending_amount);}// Get claimable heightif let Some(height) = exit.all_claimable_at_height().await { println!("All exits claimable at height {}", height);}
use bitcoin::Psbt;// Assuming you have a PSBT with exit claim inputslet mut psbt: Psbt = /* ... */;let exit = wallet.exit.read().await;exit.sign_exit_claim_inputs(&mut psbt, &wallet).await?;println!("Exit inputs signed");
Always sync your wallet before starting an exit to ensure you’re working with current data:
wallet.maintenance().await?;
2
Monitor exit progress
Regularly progress exits until they’re claimable. Set up a periodic task:
loop { let mut exit = wallet.exit.write().await; exit.progress_exits(&wallet, &mut onchain_wallet, None).await?; tokio::time::sleep(tokio::time::Duration::from_secs(600)).await; // every 10 min}
3
Have onchain funds available
Exits require onchain funds for CPFP (Child Pays For Parent) fee bumping. Ensure your onchain wallet has confirmed funds.
4
Don't exit dust
Small VTXOs cost more in fees than they’re worth. Avoid exiting VTXOs below ~10,000 sats unless absolutely necessary.
5
Use appropriate fee rates
During high fee periods, consider using custom fee rates to avoid overpaying:
let fee_rate = FeeRate::from_sat_per_vb(5).unwrap();exit.progress_exits(&wallet, &mut onchain_wallet, Some(fee_rate)).await?;
Exits create movements that cannot currently be canceled. Once you start an exit, you must complete it or your VTXOs will eventually expire and be lost.