#![allow(clippy::use_debug)]
use std::sync::Arc;
use std::time::Duration;
use cdk::amount::SplitTarget;
use cdk::nuts::nut00::KnownMethod;
use cdk::nuts::{CurrencyUnit, PaymentMethod};
use cdk::wallet::payment_request::CreateRequestParams;
use cdk::wallet::WalletRepositoryBuilder;
use cdk_sqlite::wallet::memory;
use rand::random;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
println!("NUT-18 Payment Request Example");
println!("===============================\n");
let seed: [u8; 64] = random();
let mint_url = "https://fake.thesimplekid.dev";
let unit = CurrencyUnit::Sat;
let initial_amount = cdk::Amount::from(100);
let localstore = Arc::new(memory::empty().await?);
let wallet = WalletRepositoryBuilder::new()
.localstore(localstore)
.seed(seed)
.build()
.await?;
wallet.add_wallet(mint_url.parse()?).await?;
println!("Using mint: {}", mint_url);
println!("\nStep 1: Creating payment request...");
let mint_wallet = wallet
.create_wallet(mint_url.parse()?, unit.clone(), None)
.await?;
let mint_quote = mint_wallet
.mint_quote(
PaymentMethod::Known(KnownMethod::Bolt11),
Some(initial_amount),
None,
None,
)
.await?;
println!(
"Pay this invoice to fund the wallet:\n{}",
mint_quote.request
);
println!("\nQuote ID: {}", mint_quote.id);
println!("\nWaiting for payment...");
let _proofs = mint_wallet
.wait_and_mint_quote(
mint_quote,
SplitTarget::default(),
None,
Duration::from_secs(300),
)
.await?;
let balances = wallet.total_balance().await?;
let balance = balances
.get(&CurrencyUnit::Sat)
.copied()
.unwrap_or(cdk::Amount::ZERO);
println!("Wallet funded with {} sats\n", balance);
println!("\n╔════════════════════════════════════════════════════════════════╗");
println!("║ Example 1: Payment Request with Nostr Transport ║");
println!("╚════════════════════════════════════════════════════════════════╝\n");
println!("Creating a payment request for 10 sats via Nostr...\n");
let nostr_params = CreateRequestParams {
amount: Some(10),
unit: "sat".to_string(),
description: Some("Coffee payment".to_string()),
pubkeys: None,
num_sigs: 1,
hash: None,
preimage: None,
transport: "nostr".to_string(),
http_url: None,
nostr_relays: Some(vec![
"wss://relay.damus.io".to_string(),
"wss://nos.lol".to_string(),
]),
};
let (payment_request, nostr_wait_info) = wallet.create_request(nostr_params).await?;
println!("Payment Request Created!");
println!("------------------------");
println!("Encoded: {}\n", payment_request);
println!("Request Details:");
println!(" Amount: {:?}", payment_request.amount);
println!(" Unit: {:?}", payment_request.unit);
println!(" Description: {:?}", payment_request.description);
println!(" Mints: {:?}", payment_request.mints);
println!(" Transports: {:?}", payment_request.transports);
if let Some(ref info) = nostr_wait_info {
println!("\nNostr Wait Info:");
println!(" Relays: {:?}", info.relays);
println!(" Pubkey: {}", info.pubkey);
println!("\nTo receive payment, call:");
println!(" let amount = wallet.wait_for_nostr_payment(nostr_wait_info).await?;");
println!("\nThis will:");
println!(" 1. Connect to the specified Nostr relays");
println!(" 2. Subscribe for gift-wrapped payment events");
println!(" 3. Receive and process the first valid payment");
println!(" 4. Return the received amount");
}
println!("\n\n╔════════════════════════════════════════════════════════════════╗");
println!("║ Example 2: Payment Request with HTTP Transport ║");
println!("╚════════════════════════════════════════════════════════════════╝\n");
println!("Creating a payment request for 21 sats via HTTP...\n");
let http_params = CreateRequestParams {
amount: Some(21),
unit: "sat".to_string(),
description: Some("Tip jar".to_string()),
pubkeys: None,
num_sigs: 1,
hash: None,
preimage: None,
transport: "http".to_string(),
http_url: Some("https://example.com/cashu/callback".to_string()),
nostr_relays: None,
};
let (http_request, _) = wallet.create_request(http_params).await?;
println!("Payment Request Created!");
println!("------------------------");
println!("Encoded: {}\n", http_request);
println!("Request Details:");
println!(" Amount: {:?}", http_request.amount);
println!(" Unit: {:?}", http_request.unit);
println!(" Description: {:?}", http_request.description);
println!(" Transports: {:?}", http_request.transports);
println!("\nWith HTTP transport:");
println!(" - Payer will POST tokens to: https://example.com/cashu/callback");
println!(" - Your server receives the token and calls wallet.receive()");
println!("\n\n╔════════════════════════════════════════════════════════════════╗");
println!("║ Example 3: Payment Request with P2PK Lock ║");
println!("╚════════════════════════════════════════════════════════════════╝\n");
println!("Creating a P2PK-locked payment request...\n");
let secret = cdk::nuts::SecretKey::generate();
let pubkey_hex = secret.public_key().to_string();
let p2pk_params = CreateRequestParams {
amount: Some(50),
unit: "sat".to_string(),
description: Some("Locked payment".to_string()),
pubkeys: Some(vec![pubkey_hex.clone()]),
num_sigs: 1,
hash: None,
preimage: None,
transport: "nostr".to_string(),
http_url: None,
nostr_relays: Some(vec!["wss://relay.damus.io".to_string()]),
};
let (p2pk_request, _) = wallet.create_request(p2pk_params).await?;
println!("P2PK Payment Request Created!");
println!("-----------------------------");
println!("Encoded: {}\n", p2pk_request);
println!("Security:");
println!(" - Tokens sent to this request will be locked to pubkey:");
println!(" {}", pubkey_hex);
println!(" - Only the holder of the corresponding secret key can spend");
println!("\n\n╔════════════════════════════════════════════════════════════════╗");
println!("║ Example 4: Paying a Payment Request ║");
println!("╚════════════════════════════════════════════════════════════════╝\n");
println!("To pay a payment request from another wallet:\n");
println!("```rust");
println!("// Decode the payment request");
println!("let request = PaymentRequest::from_str(\"creqA...\")?;");
println!();
println!("// Pay the request (sends tokens via the specified transport)");
println!("let result = wallet.pay_request(request).await?;");
println!();
println!("println!(\"Sent {{}} sats\", result.amount_sent);");
println!("```\n");
println!("The pay_request method will:");
println!(" 1. Select proofs matching the requested amount and unit");
println!(" 2. Apply any spending conditions from the request");
println!(" 3. Deliver the token via the request's transport (Nostr/HTTP)");
println!("\n✓ Example complete!");
Ok(())
}