#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use crate::builder::{AddressScheme, Seed64, WalletBuilder};
use bdk_wallet::bitcoin::{base58, Network};
const MAINNET_XPUB: &str = "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ";
const MAINNET_TR_ADDR: &str = "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr";
fn reversion(xpub: &str, version: [u8; 4]) -> String {
let mut data = base58::decode_check(xpub).unwrap();
data[0..4].copy_from_slice(&version);
base58::encode_check(&data)
}
#[test]
fn watch_address_rejects_invalid_string() {
let err = WalletBuilder::from_watch_only(Network::Regtest)
.with_watch_address("not-an-address")
.err()
.unwrap();
assert!(err.contains("Invalid address"), "{err}");
}
#[test]
fn watch_address_rejects_network_mismatch() {
let err = WalletBuilder::from_watch_only(Network::Regtest)
.with_watch_address(MAINNET_TR_ADDR)
.err()
.unwrap();
assert!(err.contains("Network mismatch"), "{err}");
}
#[test]
fn watch_address_rejects_non_taproot() {
let dual = WalletBuilder::from_seed(Network::Regtest, Seed64::from_array([0u8; 64]))
.with_scheme(AddressScheme::Dual)
.build()
.unwrap();
let pay = dual.peek_payment_address(0).unwrap().to_string();
let err = WalletBuilder::from_watch_only(Network::Regtest)
.with_watch_address(&pay)
.err()
.unwrap();
assert!(err.contains("taproot"), "{err}");
}
#[test]
fn watch_address_accepts_taproot_and_round_trips() {
let seed_wallet = WalletBuilder::from_seed(Network::Regtest, Seed64::from_array([1u8; 64]))
.with_scheme(AddressScheme::Unified)
.build()
.unwrap();
let tr_addr = seed_wallet.peek_taproot_address(0).to_string();
let watch = WalletBuilder::from_watch_only(Network::Regtest)
.with_watch_address(&tr_addr)
.unwrap()
.build()
.unwrap();
assert_eq!(watch.peek_taproot_address(0).to_string(), tr_addr);
}
#[test]
fn xpub_accepts_zpub_via_version_normalization() {
let zpub = reversion(MAINNET_XPUB, [0x04, 0xB2, 0x47, 0x46]);
assert!(WalletBuilder::from_watch_only(Network::Bitcoin)
.with_xpub(&zpub)
.is_ok());
}
#[test]
fn xpub_accepts_tpub_via_version_normalization() {
let vpub = reversion(MAINNET_XPUB, [0x04, 0x5F, 0x1C, 0xF6]);
assert!(WalletBuilder::from_watch_only(Network::Testnet)
.with_xpub(&vpub)
.is_ok());
}
#[test]
fn xpub_rejects_unsupported_prefix() {
let bad = reversion(MAINNET_XPUB, [0x01, 0x02, 0x03, 0x04]);
let err = WalletBuilder::from_watch_only(Network::Bitcoin)
.with_xpub(&bad)
.err()
.unwrap();
assert!(
err.contains("Unsupported extended public key prefix"),
"{err}"
);
}
#[test]
fn xpub_rejects_garbage() {
let err = WalletBuilder::from_watch_only(Network::Bitcoin)
.with_xpub("definitely not a key")
.err()
.unwrap();
assert!(err.contains("Invalid extended public key"), "{err}");
}
#[test]
fn get_accounts_enumerates_distinct_seed_accounts() {
let w = WalletBuilder::from_seed(Network::Regtest, Seed64::from_array([0u8; 64]))
.with_scheme(AddressScheme::Unified)
.build()
.unwrap();
let accounts = w.get_accounts(3);
assert_eq!(accounts.len(), 3);
assert_eq!(accounts[0].index, 0);
assert_eq!(accounts[2].index, 2);
assert_ne!(accounts[0].taproot_address, accounts[1].taproot_address);
assert_ne!(accounts[1].taproot_address, accounts[2].taproot_address);
}
}