Skip to main content

Overview

Boarding is the process of moving Bitcoin from an onchain wallet into the Ark. Once boarded, funds can be used for instant, low-fee Ark payments.
Boarding requires an onchain wallet. Create your wallet with Wallet::create_with_onchain() or use Wallet::open_with_onchain() to access boarding functionality.

How Boarding Works

1

Create board transaction

Your onchain wallet sends Bitcoin to a special board VTXO script that locks funds with both your key and the Ark server’s key.
2

Wait for confirmations

The transaction must receive the minimum confirmations required by the server (typically 1-6 blocks).
3

Register with server

Once confirmed, the VTXO is registered with the Ark server and becomes spendable in Ark payments.

Boarding a Specific Amount

Board a specific amount while leaving remaining funds onchain:
use bitcoin::Amount;
use bark::onchain::OnchainWallet;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut onchain_wallet = OnchainWallet::load_or_create(
        network,
        seed,
        db.clone()
    ).await?;

    // Board 100,000 sats to Ark
    let amount = Amount::from_sat(100_000);
    let pending_board = wallet.board_amount(
        &mut onchain_wallet,
        amount
    ).await?;

    println!("Board transaction created!");
    println!("VTXO IDs: {:?}", pending_board.vtxos);
    println!("Movement ID: {}", pending_board.movement_id);

    Ok(())
}
The actual onchain amount spent will be slightly higher to cover mining fees.

Boarding All Funds

Board your entire onchain balance to Ark:
// Board all available onchain funds
let pending_board = wallet.board_all(&mut onchain_wallet).await?;

println!("Boarding entire onchain balance");
println!("Boarded VTXOs: {:?}", pending_board.vtxos);

Tracking Pending Boards

Monitor boards that are waiting for confirmations:
// Get all pending boards
let pending_boards = wallet.pending_boards().await?;

for board in pending_boards {
    println!("Movement ID: {}", board.movement_id);
    println!("VTXO IDs: {:?}", board.vtxos);
    println!("Transaction: {}", board.transaction.compute_txid());
}

// Get VTXOs from pending boards
let pending_vtxos = wallet.pending_board_vtxos().await?;
println!("Waiting for {} VTXOs to confirm", pending_vtxos.len());

Syncing Pending Boards

Periodically check if boards have sufficient confirmations and register them:
// Sync pending boards (checks confirmations and registers if ready)
wallet.sync_pending_boards().await?;

// Or use comprehensive maintenance
wallet.maintenance_with_onchain(&mut onchain_wallet).await?;

Registration Process

The sync_pending_boards() method:
  1. Checks the confirmation status of each pending board transaction
  2. Compares confirmations against ArkInfo::required_board_confirmations
  3. Registers sufficiently confirmed boards with the server
  4. Marks VTXOs as spendable after successful registration
  5. Handles expired boards (if VTXO expires before enough confirmations)

Board Confirmation Requirements

The number of confirmations required is determined by the Ark server:
// Get server info including confirmation requirements
let ark_info = wallet.ark_info().await?.expect("connected to server");
println!("Required confirmations: {}", ark_info.required_board_confirmations);
println!("Minimum board amount: {}", ark_info.min_board_amount);

Understanding Board Fees

Boarding involves two types of fees:

Onchain Fees

Paid to Bitcoin miners for including the board transaction:
// These fees are calculated automatically based on current fee rates
let fee_rates = wallet.chain.fee_rates().await;
println!("Regular fee rate: {}", fee_rates.regular);

Ark Service Fees

Paid to the Ark server for processing the board:
let ark_info = wallet.ark_info().await?.expect("connected");
let board_amount = Amount::from_sat(100_000);

// Calculate service fee
let service_fee = ark_info.fees.board.calculate(board_amount)
    .context("fee calculation failed")?;

println!("Boarding {} with service fee {}", board_amount, service_fee);

Handling Board Errors

match wallet.board_amount(&mut onchain_wallet, amount).await {
    Ok(board) => {
        println!("Board successful: {:?}", board.vtxos);
    }
    Err(e) if e.to_string().contains("less than minimum") => {
        println!("Amount too small. Check ark_info.min_board_amount");
    }
    Err(e) if e.to_string().contains("insufficient") => {
        println!("Insufficient onchain funds");
    }
    Err(e) => {
        println!("Board failed: {:#}", e);
        return Err(e);
    }
}

Complete Boarding Workflow

use bark::{Config, Wallet, SqliteClient};
use bark::onchain::OnchainWallet;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Setup
    let network = bitcoin::Network::Signet;
    let mnemonic = bip39::Mnemonic::from_str(&mnemonic_str)?;
    let config = Config::network_default(network);
    let db = Arc::new(SqliteClient::open("db.sqlite").await?);

    // Create wallets
    let mut onchain_wallet = OnchainWallet::load_or_create(
        network,
        mnemonic.to_seed(""),
        db.clone()
    ).await?;

    let wallet = Wallet::open_with_onchain(
        &mnemonic,
        db,
        &onchain_wallet,
        config
    ).await?;

    // Sync onchain wallet
    onchain_wallet.sync().await?;
    let onchain_balance = onchain_wallet.balance().total();
    println!("Onchain balance: {}", onchain_balance);

    // Board funds
    let amount = Amount::from_sat(50_000);
    let board = wallet.board_amount(&mut onchain_wallet, amount).await?;
    println!("Created board: {:?}", board.vtxos);

    // Wait for confirmations and register
    loop {
        wallet.sync_pending_boards().await?;
        let pending = wallet.pending_boards().await?;
        
        if pending.is_empty() {
            println!("All boards registered!");
            break;
        }
        
        println!("Waiting for {} boards to confirm...", pending.len());
        tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;
    }

    // Check new Ark balance
    let balance = wallet.balance().await?;
    println!("Ark balance: {}", balance.spendable);

    Ok(())
}

Advanced: Register Confirmed Boards

Manually register all confirmed boards:
// This is called automatically by sync_pending_boards()
// but you can also call it explicitly
wallet.register_all_confirmed_boards(&mut onchain_wallet).await?;

Best Practices

Boarding creates VTXOs with an expiry. If a board transaction doesn’t receive enough confirmations before the VTXO expires, it will automatically be marked for unilateral exit.
1

Check minimum amounts

Always verify the server’s minimum board amount before boarding:
let ark_info = wallet.ark_info().await?.expect("connected");
if amount < ark_info.min_board_amount {
    println!("Amount too small: minimum is {}", ark_info.min_board_amount);
}
2

Monitor pending boards

Regularly sync pending boards to register them as soon as possible:
// Sync every 30 seconds until registered
wallet.sync_pending_boards().await?;
3

Account for both fee types

When calculating the total cost, include both onchain and service fees.

Next Steps

Sending Payments

Use your boarded funds to send Ark payments

Receiving Payments

Generate addresses to receive Ark payments

Build docs developers (and LLMs) love