mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-18 21:25:09 +01:00
feat: bolt12
This commit is contained in:
@@ -8,6 +8,7 @@ use std::{env, fs};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use async_trait::async_trait;
|
||||
use bip39::Mnemonic;
|
||||
use cashu::{MeltQuoteBolt12Request, MintQuoteBolt12Request, MintQuoteBolt12Response};
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::{self, WalletDatabase};
|
||||
use cdk::mint::{MintBuilder, MintMeltLimits};
|
||||
@@ -72,7 +73,7 @@ impl MintConnector for DirectMintConnection {
|
||||
request: MintQuoteBolt11Request,
|
||||
) -> Result<MintQuoteBolt11Response<String>, Error> {
|
||||
self.mint
|
||||
.get_mint_bolt11_quote(request)
|
||||
.get_mint_quote(request.into())
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
@@ -98,7 +99,7 @@ impl MintConnector for DirectMintConnection {
|
||||
request: MeltQuoteBolt11Request,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
self.mint
|
||||
.get_melt_bolt11_quote(&request)
|
||||
.get_melt_quote(request.into())
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
@@ -119,7 +120,7 @@ impl MintConnector for DirectMintConnection {
|
||||
request: MeltRequest<String>,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let request_uuid = request.try_into().unwrap();
|
||||
self.mint.melt_bolt11(&request_uuid).await.map(Into::into)
|
||||
self.mint.melt(&request_uuid).await.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_swap(&self, swap_request: SwapRequest) -> Result<SwapResponse, Error> {
|
||||
@@ -152,6 +153,59 @@ impl MintConnector for DirectMintConnection {
|
||||
|
||||
*auth_wallet = wallet;
|
||||
}
|
||||
|
||||
async fn post_mint_bolt12_quote(
|
||||
&self,
|
||||
request: MintQuoteBolt12Request,
|
||||
) -> Result<MintQuoteBolt12Response<String>, Error> {
|
||||
let res: MintQuoteBolt12Response<Uuid> =
|
||||
self.mint.get_mint_quote(request.into()).await?.try_into()?;
|
||||
Ok(res.into())
|
||||
}
|
||||
|
||||
async fn get_mint_quote_bolt12_status(
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MintQuoteBolt12Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
let quote: MintQuoteBolt12Response<Uuid> = self
|
||||
.mint
|
||||
.check_mint_quote("e_id_uuid)
|
||||
.await?
|
||||
.try_into()?;
|
||||
|
||||
Ok(quote.into())
|
||||
}
|
||||
|
||||
/// Melt Quote [NUT-23]
|
||||
async fn post_melt_bolt12_quote(
|
||||
&self,
|
||||
request: MeltQuoteBolt12Request,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
self.mint
|
||||
.get_melt_quote(request.into())
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
/// Melt Quote Status [NUT-23]
|
||||
async fn get_melt_bolt12_quote_status(
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_melt_quote("e_id_uuid)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
/// Melt [NUT-23]
|
||||
async fn post_melt_bolt12(
|
||||
&self,
|
||||
_request: MeltRequest<String>,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
// Implementation to be added later
|
||||
Err(Error::UnsupportedPaymentMethod)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_tracing() {
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::env;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use cashu::Bolt11Invoice;
|
||||
use cashu::{Bolt11Invoice, PaymentMethod};
|
||||
use cdk::amount::{Amount, SplitTarget};
|
||||
use cdk::nuts::{MintQuoteState, NotificationPayload, State};
|
||||
use cdk::wallet::WalletSubscription;
|
||||
@@ -86,6 +86,10 @@ pub async fn wait_for_mint_to_be_paid(
|
||||
if response.state == MintQuoteState::Paid {
|
||||
return Ok(());
|
||||
}
|
||||
} else if let NotificationPayload::MintQuoteBolt12Response(response) = msg {
|
||||
if response.amount_paid > Amount::ZERO {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(anyhow!("Subscription ended without quote being paid"))
|
||||
@@ -95,18 +99,40 @@ pub async fn wait_for_mint_to_be_paid(
|
||||
|
||||
let check_interval = Duration::from_secs(5);
|
||||
|
||||
let method = wallet
|
||||
.localstore
|
||||
.get_mint_quote(mint_quote_id)
|
||||
.await?
|
||||
.map(|q| q.payment_method)
|
||||
.unwrap_or_default();
|
||||
|
||||
let periodic_task = async {
|
||||
loop {
|
||||
match wallet.mint_quote_state(mint_quote_id).await {
|
||||
Ok(result) => {
|
||||
if result.state == MintQuoteState::Paid {
|
||||
tracing::info!("mint quote paid via poll");
|
||||
return Ok(());
|
||||
match method {
|
||||
PaymentMethod::Bolt11 => match wallet.mint_quote_state(mint_quote_id).await {
|
||||
Ok(result) => {
|
||||
if result.state == MintQuoteState::Paid {
|
||||
tracing::info!("mint quote paid via poll");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Could not check mint quote status: {:?}", e);
|
||||
}
|
||||
},
|
||||
PaymentMethod::Bolt12 => {
|
||||
match wallet.mint_bolt12_quote_state(mint_quote_id).await {
|
||||
Ok(result) => {
|
||||
if result.amount_paid > Amount::ZERO {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Could not check mint quote status: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Could not check mint quote status: {:?}", e);
|
||||
}
|
||||
PaymentMethod::Custom(_) => (),
|
||||
}
|
||||
sleep(check_interval).await;
|
||||
}
|
||||
@@ -166,7 +192,6 @@ pub async fn init_lnd_client() -> LndClient {
|
||||
pub async fn pay_if_regtest(invoice: &Bolt11Invoice) -> Result<()> {
|
||||
// Check if the invoice is for the regtest network
|
||||
if invoice.network() == bitcoin::Network::Regtest {
|
||||
println!("Regtest invoice");
|
||||
let lnd_client = init_lnd_client().await;
|
||||
lnd_client.pay_invoice(invoice.to_string()).await?;
|
||||
Ok(())
|
||||
|
||||
332
crates/cdk-integration-tests/tests/bolt12.rs
Normal file
332
crates/cdk-integration-tests/tests/bolt12.rs
Normal file
@@ -0,0 +1,332 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use bip39::Mnemonic;
|
||||
use cashu::amount::SplitTarget;
|
||||
use cashu::nut23::Amountless;
|
||||
use cashu::{Amount, CurrencyUnit, MintRequest, PreMintSecrets, ProofsMethods};
|
||||
use cdk::wallet::{HttpClient, MintConnector, Wallet};
|
||||
use cdk_integration_tests::init_regtest::get_cln_dir;
|
||||
use cdk_integration_tests::{get_mint_url_from_env, wait_for_mint_to_be_paid};
|
||||
use cdk_sqlite::wallet::memory;
|
||||
use ln_regtest_rs::ln_client::ClnClient;
|
||||
|
||||
/// Tests basic BOLT12 minting functionality:
|
||||
/// - Creates a wallet
|
||||
/// - Gets a BOLT12 quote for a specific amount (100 sats)
|
||||
/// - Pays the quote using Core Lightning
|
||||
/// - Mints tokens and verifies the correct amount is received
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_regtest_bolt12_mint() {
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url_from_env(),
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(memory::empty().await.unwrap()),
|
||||
&Mnemonic::generate(12).unwrap().to_seed_normalized(""),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mint_amount = Amount::from(100);
|
||||
|
||||
let mint_quote = wallet
|
||||
.mint_bolt12_quote(Some(mint_amount), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(mint_quote.amount, Some(mint_amount));
|
||||
|
||||
let cln_one_dir = get_cln_dir("one");
|
||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await.unwrap();
|
||||
cln_client
|
||||
.pay_bolt12_offer(None, mint_quote.request)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proofs = wallet
|
||||
.mint_bolt12(&mint_quote.id, None, SplitTarget::default(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(proofs.total_amount().unwrap(), 100.into());
|
||||
}
|
||||
|
||||
/// Tests multiple payments to a single BOLT12 quote:
|
||||
/// - Creates a wallet and gets a BOLT12 quote without specifying amount
|
||||
/// - Makes two separate payments (10,000 sats and 11,000 sats) to the same quote
|
||||
/// - Verifies that each payment can be minted separately and correctly
|
||||
/// - Tests the functionality of reusing a quote for multiple payments
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_regtest_bolt12_mint_multiple() -> Result<()> {
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url_from_env(),
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(memory::empty().await?),
|
||||
&Mnemonic::generate(12)?.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
let mint_quote = wallet.mint_bolt12_quote(None, None).await?;
|
||||
|
||||
let cln_one_dir = get_cln_dir("one");
|
||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
|
||||
cln_client
|
||||
.pay_bolt12_offer(Some(10000), mint_quote.request.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60).await?;
|
||||
|
||||
wallet.mint_bolt12_quote_state(&mint_quote.id).await?;
|
||||
|
||||
let proofs = wallet
|
||||
.mint_bolt12(&mint_quote.id, None, SplitTarget::default(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(proofs.total_amount().unwrap(), 10.into());
|
||||
|
||||
cln_client
|
||||
.pay_bolt12_offer(Some(11_000), mint_quote.request)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60).await?;
|
||||
|
||||
wallet.mint_bolt12_quote_state(&mint_quote.id).await?;
|
||||
|
||||
let proofs = wallet
|
||||
.mint_bolt12(&mint_quote.id, None, SplitTarget::default(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(proofs.total_amount().unwrap(), 11.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests that multiple wallets can pay the same BOLT12 offer:
|
||||
/// - Creates a BOLT12 offer through CLN that both wallets will pay
|
||||
/// - Creates two separate wallets with different minting amounts
|
||||
/// - Has each wallet get their own quote and make payments
|
||||
/// - Verifies both wallets can successfully mint their tokens
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_regtest_bolt12_multiple_wallets() -> Result<()> {
|
||||
// Create first wallet
|
||||
let wallet_one = Wallet::new(
|
||||
&get_mint_url_from_env(),
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(memory::empty().await?),
|
||||
&Mnemonic::generate(12)?.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
// Create second wallet
|
||||
let wallet_two = Wallet::new(
|
||||
&get_mint_url_from_env(),
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(memory::empty().await?),
|
||||
&Mnemonic::generate(12)?.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
// Create a BOLT12 offer that both wallets will use
|
||||
let cln_one_dir = get_cln_dir("one");
|
||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
|
||||
// First wallet payment
|
||||
let quote_one = wallet_one
|
||||
.mint_bolt12_quote(Some(10_000.into()), None)
|
||||
.await?;
|
||||
cln_client
|
||||
.pay_bolt12_offer(None, quote_one.request.clone())
|
||||
.await?;
|
||||
wait_for_mint_to_be_paid(&wallet_one, "e_one.id, 60).await?;
|
||||
let proofs_one = wallet_one
|
||||
.mint_bolt12("e_one.id, None, SplitTarget::default(), None)
|
||||
.await?;
|
||||
|
||||
assert_eq!(proofs_one.total_amount()?, 10_000.into());
|
||||
|
||||
// Second wallet payment
|
||||
let quote_two = wallet_two
|
||||
.mint_bolt12_quote(Some(15_000.into()), None)
|
||||
.await?;
|
||||
cln_client
|
||||
.pay_bolt12_offer(None, quote_two.request.clone())
|
||||
.await?;
|
||||
wait_for_mint_to_be_paid(&wallet_two, "e_two.id, 60).await?;
|
||||
|
||||
let proofs_two = wallet_two
|
||||
.mint_bolt12("e_two.id, None, SplitTarget::default(), None)
|
||||
.await?;
|
||||
assert_eq!(proofs_two.total_amount()?, 15_000.into());
|
||||
|
||||
let offer = cln_client
|
||||
.get_bolt12_offer(None, false, "test_multiple_wallets".to_string())
|
||||
.await?;
|
||||
|
||||
let wallet_one_melt_quote = wallet_one
|
||||
.melt_bolt12_quote(
|
||||
offer.to_string(),
|
||||
Some(cashu::MeltOptions::Amountless {
|
||||
amountless: Amountless {
|
||||
amount_msat: 1500.into(),
|
||||
},
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let wallet_two_melt_quote = wallet_two
|
||||
.melt_bolt12_quote(
|
||||
offer.to_string(),
|
||||
Some(cashu::MeltOptions::Amountless {
|
||||
amountless: Amountless {
|
||||
amount_msat: 1000.into(),
|
||||
},
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let melted = wallet_one.melt(&wallet_one_melt_quote.id).await?;
|
||||
|
||||
assert!(melted.preimage.is_some());
|
||||
|
||||
let melted_two = wallet_two.melt(&wallet_two_melt_quote.id).await?;
|
||||
|
||||
assert!(melted_two.preimage.is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests the BOLT12 melting (spending) functionality:
|
||||
/// - Creates a wallet and mints 20,000 sats using BOLT12
|
||||
/// - Creates a BOLT12 offer for 10,000 sats
|
||||
/// - Tests melting (spending) tokens using the BOLT12 offer
|
||||
/// - Verifies the correct amount is melted
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_regtest_bolt12_melt() -> Result<()> {
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url_from_env(),
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(memory::empty().await?),
|
||||
&Mnemonic::generate(12)?.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
wallet.get_mint_info().await?;
|
||||
|
||||
let mint_amount = Amount::from(20_000);
|
||||
|
||||
// Create a single-use BOLT12 quote
|
||||
let mint_quote = wallet.mint_bolt12_quote(Some(mint_amount), None).await?;
|
||||
|
||||
assert_eq!(mint_quote.amount, Some(mint_amount));
|
||||
// Pay the quote
|
||||
let cln_one_dir = get_cln_dir("one");
|
||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
|
||||
cln_client
|
||||
.pay_bolt12_offer(None, mint_quote.request.clone())
|
||||
.await?;
|
||||
|
||||
// Wait for payment to be processed
|
||||
wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60).await?;
|
||||
|
||||
let offer = cln_client
|
||||
.get_bolt12_offer(Some(10_000), true, "hhhhhhhh".to_string())
|
||||
.await?;
|
||||
|
||||
let _proofs = wallet
|
||||
.mint_bolt12(&mint_quote.id, None, SplitTarget::default(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let quote = wallet.melt_bolt12_quote(offer.to_string(), None).await?;
|
||||
|
||||
let melt = wallet.melt("e.id).await?;
|
||||
|
||||
assert_eq!(melt.amount, 10.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests security validation for BOLT12 minting to prevent overspending:
|
||||
/// - Creates a wallet and gets an open-ended BOLT12 quote
|
||||
/// - Makes a payment of 10,000 millisats
|
||||
/// - Attempts to mint more tokens (500 sats) than were actually paid for
|
||||
/// - Verifies that the mint correctly rejects the oversized mint request
|
||||
/// - Ensures proper error handling with TransactionUnbalanced error
|
||||
/// This test is crucial for ensuring the economic security of the minting process
|
||||
/// by preventing users from minting more tokens than they have paid for.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_regtest_bolt12_mint_extra() -> Result<()> {
|
||||
let wallet = Wallet::new(
|
||||
&get_mint_url_from_env(),
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(memory::empty().await?),
|
||||
&Mnemonic::generate(12)?.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
wallet.get_mint_info().await?;
|
||||
|
||||
// Create a single-use BOLT12 quote
|
||||
let mint_quote = wallet.mint_bolt12_quote(None, None).await?;
|
||||
|
||||
let state = wallet.mint_bolt12_quote_state(&mint_quote.id).await?;
|
||||
|
||||
assert_eq!(state.amount_paid, Amount::ZERO);
|
||||
assert_eq!(state.amount_issued, Amount::ZERO);
|
||||
|
||||
let active_keyset_id = wallet.get_active_mint_keyset().await?.id;
|
||||
|
||||
let pay_amount_msats = 10_000;
|
||||
|
||||
let cln_one_dir = get_cln_dir("one");
|
||||
let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
|
||||
cln_client
|
||||
.pay_bolt12_offer(Some(pay_amount_msats), mint_quote.request.clone())
|
||||
.await?;
|
||||
|
||||
wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 10).await?;
|
||||
|
||||
let state = wallet.mint_bolt12_quote_state(&mint_quote.id).await?;
|
||||
|
||||
assert_eq!(state.amount_paid, (pay_amount_msats / 1_000).into());
|
||||
assert_eq!(state.amount_issued, Amount::ZERO);
|
||||
|
||||
let pre_mint = PreMintSecrets::random(active_keyset_id, 500.into(), &SplitTarget::None)?;
|
||||
|
||||
let quote_info = wallet
|
||||
.localstore
|
||||
.get_mint_quote(&mint_quote.id)
|
||||
.await?
|
||||
.expect("there is a quote");
|
||||
|
||||
let mut mint_request = MintRequest {
|
||||
quote: mint_quote.id,
|
||||
outputs: pre_mint.blinded_messages(),
|
||||
signature: None,
|
||||
};
|
||||
|
||||
if let Some(secret_key) = quote_info.secret_key {
|
||||
mint_request.sign(secret_key)?;
|
||||
}
|
||||
|
||||
let http_client = HttpClient::new(get_mint_url_from_env().parse().unwrap(), None);
|
||||
|
||||
let response = http_client.post_mint(mint_request.clone()).await;
|
||||
|
||||
match response {
|
||||
Err(err) => match err {
|
||||
cdk::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
err => {
|
||||
bail!("Wrong mint error returned: {}", err.to_string());
|
||||
}
|
||||
},
|
||||
Ok(_) => {
|
||||
bail!("Should not have allowed second payment");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -514,7 +514,7 @@ async fn test_reuse_auth_proof() {
|
||||
.await
|
||||
.expect("Quote should be allowed");
|
||||
|
||||
assert!(quote.amount == 10.into());
|
||||
assert!(quote.amount == Some(10.into()));
|
||||
}
|
||||
|
||||
wallet
|
||||
@@ -645,7 +645,7 @@ async fn test_refresh_access_token() {
|
||||
.await
|
||||
.expect("failed to get mint quote with refreshed token");
|
||||
|
||||
assert_eq!(mint_quote.amount, mint_amount);
|
||||
assert_eq!(mint_quote.amount, Some(mint_amount));
|
||||
|
||||
// Verify the total number of auth tokens
|
||||
let total_auth_proofs = wallet.get_unspent_auth_proofs().await.unwrap();
|
||||
@@ -731,7 +731,7 @@ async fn test_auth_token_spending_order() {
|
||||
.await
|
||||
.expect("failed to get mint quote");
|
||||
|
||||
assert_eq!(mint_quote.amount, 10.into());
|
||||
assert_eq!(mint_quote.amount, Some(10.into()));
|
||||
|
||||
// Check remaining tokens after each operation
|
||||
let remaining = wallet.get_unspent_auth_proofs().await.unwrap();
|
||||
|
||||
@@ -100,6 +100,10 @@ async fn test_happy_mint_melt_round_trip() {
|
||||
let invoice = Bolt11Invoice::from_str(&mint_quote.request).unwrap();
|
||||
pay_if_regtest(&invoice).await.unwrap();
|
||||
|
||||
wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 10)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proofs = wallet
|
||||
.mint(&mint_quote.id, SplitTarget::default(), None)
|
||||
.await
|
||||
@@ -210,7 +214,7 @@ async fn test_happy_mint() {
|
||||
|
||||
let mint_quote = wallet.mint_quote(mint_amount, None).await.unwrap();
|
||||
|
||||
assert_eq!(mint_quote.amount, mint_amount);
|
||||
assert_eq!(mint_quote.amount, Some(mint_amount));
|
||||
|
||||
let invoice = Bolt11Invoice::from_str(&mint_quote.request).unwrap();
|
||||
pay_if_regtest(&invoice).await.unwrap();
|
||||
@@ -285,6 +289,8 @@ async fn test_restore() {
|
||||
let restored = wallet_2.restore().await.unwrap();
|
||||
let proofs = wallet_2.get_unspent_proofs().await.unwrap();
|
||||
|
||||
assert!(!proofs.is_empty());
|
||||
|
||||
let expected_fee = wallet.get_proofs_fee(&proofs).await.unwrap();
|
||||
wallet_2
|
||||
.swap(None, SplitTarget::default(), proofs, None, false)
|
||||
@@ -431,7 +437,9 @@ async fn test_pay_invoice_twice() {
|
||||
Err(err) => match err {
|
||||
cdk::Error::RequestAlreadyPaid => (),
|
||||
err => {
|
||||
panic!("Wrong invoice already paid: {}", err.to_string());
|
||||
if !err.to_string().contains("Duplicate entry") {
|
||||
panic!("Wrong invoice already paid: {}", err.to_string());
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(_) => {
|
||||
|
||||
@@ -832,11 +832,11 @@ async fn test_concurrent_double_spend_melt() {
|
||||
let melt_request3 = melt_request.clone();
|
||||
|
||||
// Spawn 3 concurrent tasks to process the melt requests
|
||||
let task1 = tokio::spawn(async move { mint_clone1.melt_bolt11(&melt_request).await });
|
||||
let task1 = tokio::spawn(async move { mint_clone1.melt(&melt_request).await });
|
||||
|
||||
let task2 = tokio::spawn(async move { mint_clone2.melt_bolt11(&melt_request2).await });
|
||||
let task2 = tokio::spawn(async move { mint_clone2.melt(&melt_request2).await });
|
||||
|
||||
let task3 = tokio::spawn(async move { mint_clone3.melt_bolt11(&melt_request3).await });
|
||||
let task3 = tokio::spawn(async move { mint_clone3.melt(&melt_request3).await });
|
||||
|
||||
// Wait for all tasks to complete
|
||||
let results = tokio::try_join!(task1, task2, task3).expect("Tasks failed to complete");
|
||||
|
||||
@@ -89,7 +89,7 @@ async fn test_internal_payment() {
|
||||
|
||||
let _melted = wallet.melt(&melt.id).await.unwrap();
|
||||
|
||||
wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60)
|
||||
wait_for_mint_to_be_paid(&wallet_2, &mint_quote.id, 60)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -348,7 +348,7 @@ async fn test_regtest_melt_amountless() {
|
||||
|
||||
let mint_quote = wallet.mint_quote(mint_amount, None).await.unwrap();
|
||||
|
||||
assert_eq!(mint_quote.amount, mint_amount);
|
||||
assert_eq!(mint_quote.amount, Some(mint_amount));
|
||||
|
||||
lnd_client
|
||||
.pay_invoice(mint_quote.request)
|
||||
|
||||
@@ -28,6 +28,10 @@ async fn test_swap() {
|
||||
let invoice = Bolt11Invoice::from_str(&mint_quote.request).unwrap();
|
||||
pay_if_regtest(&invoice).await.unwrap();
|
||||
|
||||
wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 10)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let _mint_amount = wallet
|
||||
.mint(&mint_quote.id, SplitTarget::default(), None)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user