Skip to main content

Overview

The Wallet is the central entry point for using Bark as an Ark client. This guide shows you how to create and configure a wallet using the Rust API.

Prerequisites

Before creating a wallet, you’ll need:
  • A BIP39 mnemonic (12 or 24 words) for deterministic key derivation
  • A database implementation (e.g., SqliteClient)
  • Network configuration (Bitcoin, Signet, Regtest)
  • Ark server connection details

Creating a New Wallet

Basic Wallet Creation

Create an offchain-only wallet without onchain capabilities:
use std::path::PathBuf;
use std::sync::Arc;
use bark::{Config, SqliteClient, Wallet};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Configure network
    let network = bitcoin::Network::Signet;

    // Configure the wallet
    let config = Config {
        server_address: String::from("https://ark.signet.2nd.dev"),
        esplora_address: Some(String::from("https://esplora.signet.2nd.dev")),
        ..Config::network_default(network)
    };

    // Create a SQLite database
    let datadir = PathBuf::from("./bark");
    let db = Arc::new(SqliteClient::open(datadir.join("db.sqlite")).await?);

    // Generate and store a mnemonic
    let mnemonic = bip39::Mnemonic::generate(12)?;
    tokio::fs::write(
        datadir.join("mnemonic"),
        mnemonic.to_string().as_bytes()
    ).await?;

    // Create the wallet
    let wallet = Wallet::create(
        &mnemonic,
        network,
        config,
        db,
        false // force flag
    ).await?;

    Ok(())
}

Wallet with Onchain Support

For full functionality including boarding and unilateral exits, create a wallet with onchain support:
use bark::onchain::OnchainWallet;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let network = bitcoin::Network::Signet;
    let mnemonic = bip39::Mnemonic::generate(12)?;
    let config = Config {
        server_address: String::from("https://ark.signet.2nd.dev"),
        esplora_address: Some(String::from("https://esplora.signet.2nd.dev")),
        ..Config::network_default(network)
    };

    let db = Arc::new(SqliteClient::open("db.sqlite").await?);

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

    // Create Ark wallet with onchain support
    let wallet = Wallet::create_with_onchain(
        &mnemonic,
        network,
        config,
        db,
        &onchain_wallet,
        false
    ).await?;

    Ok(())
}

Opening an Existing Wallet

Restore a previously created wallet using the stored mnemonic:
use std::str::FromStr;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let datadir = PathBuf::from("./bark");
    let config = Config {
        server_address: String::from("https://ark.signet.2nd.dev"),
        esplora_address: Some(String::from("https://esplora.signet.2nd.dev")),
        ..Config::network_default(bitcoin::Network::Signet)
    };

    // Load database and mnemonic
    let db = Arc::new(SqliteClient::open(datadir.join("db.sqlite")).await?);
    let mnemonic_str = tokio::fs::read_to_string(datadir.join("mnemonic")).await?;
    let mnemonic = bip39::Mnemonic::from_str(&mnemonic_str)?;

    // Open the wallet
    let wallet = Wallet::open(&mnemonic, db, config).await?;

    Ok(())
}

Opening with Onchain Support

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

Configuration Options

The Config struct controls wallet behavior:
let config = Config {
    // Server connection
    server_address: String::from("https://ark.signet.2nd.dev"),

    // Chain data source (choose one)
    esplora_address: Some(String::from("https://esplora.signet.2nd.dev")),
    // OR
    bitcoind_address: Some(String::from("http://localhost:8332")),
    bitcoind_user: Some(String::from("user")),
    bitcoind_pass: Some(String::from("password")),

    // Fallback fee rate if chain source unavailable
    fallback_fee_rate: FeeRate::from_sat_per_kwu(1000),

    // VTXO refresh threshold (blocks before expiry)
    vtxo_refresh_expiry_threshold: 144,

    // Exit safety margin
    vtxo_exit_margin: 6,

    // Lightning receive claim delta
    htlc_recv_claim_delta: 40,

    ..Config::network_default(network)
};

Wallet Properties

Retrieve wallet metadata:
// Get wallet properties
let properties = wallet.properties().await?;
println!("Network: {}", properties.network);
println!("Fingerprint: {}", properties.fingerprint);

// Get fingerprint directly
let fingerprint = wallet.fingerprint();

// Get network
let network = wallet.network().await?;

Key Derivation

Bark uses BIP32 hierarchical deterministic key derivation:
  • Derivation path: m/350'/0'/[index] for VTXO keys
  • Mailbox key: m/350'/1' for receiving payments
// Derive and store next keypair
let (keypair, index) = wallet.derive_store_next_keypair().await?;
println!("Derived keypair at index {}", index);

// Peek at a keypair (must be previously derived)
let keypair = wallet.peak_keypair(0).await?;

// Get keypair for a public key
if let Some((index, keypair)) = wallet.pubkey_keypair(&pubkey).await? {
    println!("Found keypair at index {}", index);
}

Best Practices

1

Secure mnemonic storage

Never hardcode mnemonics. Store them encrypted or in secure hardware.
2

Verify chain source version

If using Bitcoin Core, ensure it supports ephemeral anchors:
wallet.require_chainsource_version()?;
3

Handle server pubkey changes

The wallet stores the server’s public key on first connection. If it changes, users must exit their VTXOs:
let properties = wallet.properties().await?;
if let Some(stored_key) = properties.server_pubkey {
    // Server pubkey is tracked
}
4

Use network-specific defaults

Leverage built-in network configurations:
let config = Config::network_default(bitcoin::Network::Signet);
// Then override specific fields as needed

Error Handling

Common wallet creation errors:
match Wallet::create(&mnemonic, network, config, db, false).await {
    Ok(wallet) => println!("Wallet created successfully"),
    Err(e) if e.to_string().contains("already existing") => {
        println!("Wallet already exists, opening instead");
        // Use Wallet::open() instead
    }
    Err(e) if e.to_string().contains("Failed to connect") => {
        println!("Server unreachable. Use force=true or check connection");
    }
    Err(e) => return Err(e),
}

Next Steps

Boarding Funds

Move Bitcoin from onchain to Ark

Receiving Payments

Generate addresses and receive Ark payments

Build docs developers (and LLMs) love