use std::sync::Arc;
use std::time::Duration;
use cdk::amount::SplitTarget;
use cdk::nuts::nut00::ProofsMethods;
use cdk::nuts::{CurrencyUnit, PaymentMethod};
use cdk::wallet::Wallet;
use cdk::Amount;
use cdk_sqlite::wallet::memory;
use rand::random;
use tokio::time::sleep;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
println!("BIP-353 CDK Example");
println!("===================");
let bip353_address = "tsk@thesimplekid.com";
println!("Attempting to use BIP-353 address: {}", bip353_address);
let seed = random::<[u8; 64]>();
let mint_url = "https://fake.thesimplekid.dev";
let unit = CurrencyUnit::Sat;
let initial_amount = Amount::from(1000);
let localstore = Arc::new(memory::empty().await?);
let wallet = Wallet::new(mint_url, unit, localstore, seed, None)?;
println!("Requesting mint quote for {} sats...", initial_amount);
let mint_quote = wallet
.mint_quote(PaymentMethod::BOLT12, Some(initial_amount), None, None)
.await?;
println!(
"Pay this invoice to fund the wallet: {}",
mint_quote.request
);
println!("Waiting for payment... (in real use, pay the above invoice)");
let timeout = Duration::from_secs(30);
let start = std::time::Instant::now();
while start.elapsed() < timeout {
let status = wallet.check_mint_quote_status(&mint_quote.id).await?;
if status.amount_paid >= initial_amount {
break;
}
println!("Amount paid: {} (waiting...)", status.amount_paid);
sleep(Duration::from_secs(2)).await;
}
let proofs = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.await?;
let received_amount = proofs.total_amount()?;
println!("Successfully minted {} sats", received_amount);
let payment_amount_sats = 100;
println!(
"Attempting to pay {} sats using BIP-353 address...",
payment_amount_sats
);
match wallet
.melt_bip353_quote(
bip353_address,
payment_amount_sats * 1_000,
bitcoin::Network::Bitcoin,
)
.await
{
Ok(melt_quote) => {
println!("BIP-353 melt quote received:");
println!(" Quote ID: {}", melt_quote.id);
println!(" Amount: {} sats", melt_quote.amount);
println!(" Fee Reserve: {} sats", melt_quote.fee_reserve);
println!(" State: {}", melt_quote.state);
match wallet
.prepare_melt(&melt_quote.id, std::collections::HashMap::new())
.await
{
Ok(prepared) => {
println!("Prepared melt:");
println!(" Amount: {} sats", prepared.amount());
println!(" Total Fee: {} sats", prepared.total_fee());
match prepared.confirm().await {
Ok(confirmed) => {
println!("BIP-353 payment successful!");
println!(" State: {}", confirmed.state());
println!(" Amount paid: {} sats", confirmed.amount());
println!(" Fee paid: {} sats", confirmed.fee_paid());
if let Some(preimage) = confirmed.payment_proof() {
println!(" Payment preimage: {}", preimage);
}
}
Err(e) => {
println!("BIP-353 payment failed: {}", e);
}
}
}
Err(e) => {
println!("Failed to prepare melt: {}", e);
}
}
}
Err(e) => {
println!("Failed to get BIP-353 melt quote: {}", e);
println!("This could be because:");
println!("1. The BIP-353 address format is invalid");
println!("2. DNS resolution failed (expected for this example)");
println!("3. No BOLT12 offer found in the DNS records");
println!("4. DNSSEC validation failed");
}
}
Ok(())
}