diff --git a/.github/workflows/nutshell_itest.yml b/.github/workflows/nutshell_itest.yml index 7a8ecb1c..220ff41a 100644 --- a/.github/workflows/nutshell_itest.yml +++ b/.github/workflows/nutshell_itest.yml @@ -7,11 +7,6 @@ jobs: name: Nutshell Mint Integration Tests runs-on: ubuntu-latest steps: - - name: Pull and start mint - run: | - docker run -d -p 3338:3338 --name nutshell -e MINT_LIGHTNING_BACKEND=FakeWallet -e MINT_LISTEN_HOST=0.0.0.0 -e MINT_LISTEN_PORT=3338 -e MINT_PRIVATE_KEY=TEST_PRIVATE_KEY cashubtc/nutshell:latest poetry run mint - - name: Check running containers - run: docker ps - name: checkout uses: actions/checkout@v4 - name: Install Nix @@ -21,7 +16,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 - name: Test Nutshell - run: nix develop -i -L .#stable --command just test-nutshell + run: nix develop -i -L .#integration --command just test-nutshell - name: Show logs if tests fail if: failure() run: docker logs nutshell diff --git a/crates/cdk-fake-wallet/src/lib.rs b/crates/cdk-fake-wallet/src/lib.rs index 8f49cb9f..228cd856 100644 --- a/crates/cdk-fake-wallet/src/lib.rs +++ b/crates/cdk-fake-wallet/src/lib.rs @@ -207,7 +207,7 @@ impl MintPayment for FakeWallet { payment_proof: Some("".to_string()), payment_lookup_id: payment_hash, status: payment_status, - total_spent: melt_quote.amount, + total_spent: melt_quote.amount + 1.into(), unit: melt_quote.unit, }) } diff --git a/crates/cdk-integration-tests/src/lib.rs b/crates/cdk-integration-tests/src/lib.rs index ad8dd7bb..65d083a9 100644 --- a/crates/cdk-integration-tests/src/lib.rs +++ b/crates/cdk-integration-tests/src/lib.rs @@ -2,11 +2,14 @@ use std::env; use std::sync::Arc; use anyhow::{anyhow, bail, Result}; +use cashu::Bolt11Invoice; use cdk::amount::{Amount, SplitTarget}; use cdk::nuts::{MintQuoteState, NotificationPayload, State}; use cdk::wallet::WalletSubscription; use cdk::Wallet; -use init_regtest::get_mint_url; +use cdk_fake_wallet::create_fake_invoice; +use init_regtest::{get_lnd_dir, get_mint_url, LND_RPC_ADDR}; +use ln_regtest_rs::ln_client::{LightningClient, LndClient}; use tokio::time::{sleep, timeout, Duration}; pub mod init_auth_mint; @@ -145,3 +148,71 @@ pub fn get_second_mint_url_from_env() -> String { Err(_) => get_mint_url("1"), } } + +// This is the ln wallet we use to send/receive ln payements as the wallet +pub async fn init_lnd_client() -> LndClient { + let lnd_dir = get_lnd_dir("one"); + let cert_file = lnd_dir.join("tls.cert"); + let macaroon_file = lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon"); + LndClient::new( + format!("https://{}", LND_RPC_ADDR), + cert_file, + macaroon_file, + ) + .await + .unwrap() +} + +/// Pays a Bolt11Invoice if it's on the regtest network, otherwise returns Ok +/// +/// This is useful for tests that need to pay invoices in regtest mode but +/// should be skipped in other environments. +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(()) + } else { + // Not a regtest invoice, just return Ok + Ok(()) + } +} + +/// Determines if we're running in regtest mode based on environment variable +/// +/// Checks the CDK_TEST_REGTEST environment variable: +/// - If set to "1", "true", or "yes" (case insensitive), returns true +/// - Otherwise returns false +pub fn is_regtest_env() -> bool { + match env::var("CDK_TEST_REGTEST") { + Ok(val) => { + let val = val.to_lowercase(); + val == "1" || val == "true" || val == "yes" + } + Err(_) => false, + } +} + +/// Creates a real invoice if in regtest mode, otherwise returns a fake invoice +/// +/// Uses the is_regtest_env() function to determine whether to +/// create a real regtest invoice or a fake one for testing. +pub async fn create_invoice_for_env(amount_sat: Option) -> Result { + if is_regtest_env() { + // In regtest mode, create a real invoice + let lnd_client = init_lnd_client().await; + lnd_client + .create_invoice(amount_sat) + .await + .map_err(|e| anyhow!("Failed to create regtest invoice: {}", e)) + } else { + // Not in regtest mode, create a fake invoice + let fake_invoice = create_fake_invoice( + amount_sat.expect("Amount must be defined") * 1_000, + "".to_string(), + ); + Ok(fake_invoice.to_string()) + } +} diff --git a/crates/cdk-integration-tests/tests/happy_path_mint_wallet.rs b/crates/cdk-integration-tests/tests/happy_path_mint_wallet.rs index 61159b41..41bf1ea4 100644 --- a/crates/cdk-integration-tests/tests/happy_path_mint_wallet.rs +++ b/crates/cdk-integration-tests/tests/happy_path_mint_wallet.rs @@ -15,93 +15,24 @@ use std::sync::Arc; use std::time::Duration; use std::{char, env}; -use anyhow::{anyhow, bail, Result}; +use anyhow::{bail, Result}; use bip39::Mnemonic; use cashu::{MeltBolt11Request, PreMintSecrets}; use cdk::amount::{Amount, SplitTarget}; use cdk::nuts::nut00::ProofsMethods; use cdk::nuts::{CurrencyUnit, MeltQuoteState, NotificationPayload, State}; use cdk::wallet::{HttpClient, MintConnector, Wallet}; -use cdk_fake_wallet::create_fake_invoice; -use cdk_integration_tests::init_regtest::{get_lnd_dir, LND_RPC_ADDR}; -use cdk_integration_tests::{get_mint_url_from_env, wait_for_mint_to_be_paid}; +use cdk_integration_tests::{ + create_invoice_for_env, get_mint_url_from_env, pay_if_regtest, wait_for_mint_to_be_paid, +}; use cdk_sqlite::wallet::memory; use futures::{SinkExt, StreamExt}; use lightning_invoice::Bolt11Invoice; -use ln_regtest_rs::ln_client::{LightningClient, LndClient}; use serde_json::json; use tokio::time::timeout; use tokio_tungstenite::connect_async; use tokio_tungstenite::tungstenite::protocol::Message; -// This is the ln wallet we use to send/receive ln payements as the wallet -async fn init_lnd_client() -> LndClient { - let lnd_dir = get_lnd_dir("one"); - let cert_file = lnd_dir.join("tls.cert"); - let macaroon_file = lnd_dir.join("data/chain/bitcoin/regtest/admin.macaroon"); - LndClient::new( - format!("https://{}", LND_RPC_ADDR), - cert_file, - macaroon_file, - ) - .await - .unwrap() -} - -/// Pays a Bolt11Invoice if it's on the regtest network, otherwise returns Ok -/// -/// This is useful for tests that need to pay invoices in regtest mode but -/// should be skipped in other environments. -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(()) - } else { - // Not a regtest invoice, just return Ok - Ok(()) - } -} - -/// Determines if we're running in regtest mode based on environment variable -/// -/// Checks the CDK_TEST_REGTEST environment variable: -/// - If set to "1", "true", or "yes" (case insensitive), returns true -/// - Otherwise returns false -fn is_regtest_env() -> bool { - match env::var("CDK_TEST_REGTEST") { - Ok(val) => { - let val = val.to_lowercase(); - val == "1" || val == "true" || val == "yes" - } - Err(_) => false, - } -} - -/// Creates a real invoice if in regtest mode, otherwise returns a fake invoice -/// -/// Uses the is_regtest_env() function to determine whether to -/// create a real regtest invoice or a fake one for testing. -async fn create_invoice_for_env(amount_sat: Option) -> Result { - if is_regtest_env() { - // In regtest mode, create a real invoice - let lnd_client = init_lnd_client().await; - lnd_client - .create_invoice(amount_sat) - .await - .map_err(|e| anyhow!("Failed to create regtest invoice: {}", e)) - } else { - // Not in regtest mode, create a fake invoice - let fake_invoice = create_fake_invoice( - amount_sat.expect("Amount must be defined") * 1_000, - "".to_string(), - ); - Ok(fake_invoice.to_string()) - } -} - async fn get_notification> + Unpin, E: Debug>( reader: &mut T, timeout_to_wait: Duration, @@ -263,7 +194,7 @@ async fn test_happy_mint_melt_round_trip() -> Result<()> { /// /// This ensures the basic minting flow works correctly from quote to token issuance. #[tokio::test(flavor = "multi_thread", worker_threads = 1)] -async fn test_happy_mint_melt() -> Result<()> { +async fn test_happy_mint() -> Result<()> { let wallet = Wallet::new( &get_mint_url_from_env(), CurrencyUnit::Sat, @@ -330,7 +261,7 @@ async fn test_restore() -> Result<()> { .mint(&mint_quote.id, SplitTarget::default(), None) .await?; - assert!(wallet.total_balance().await? == 100.into()); + assert_eq!(wallet.total_balance().await?, 100.into()); let wallet_2 = Wallet::new( &get_mint_url_from_env(), @@ -340,18 +271,23 @@ async fn test_restore() -> Result<()> { None, )?; - assert!(wallet_2.total_balance().await? == 0.into()); + assert_eq!(wallet_2.total_balance().await?, 0.into()); let restored = wallet_2.restore().await?; let proofs = wallet_2.get_unspent_proofs().await?; + let expected_fee = wallet.get_proofs_fee(&proofs).await?; wallet_2 .swap(None, SplitTarget::default(), proofs, None, false) .await?; - assert!(restored == 100.into()); + assert_eq!(restored, 100.into()); - assert_eq!(wallet_2.total_balance().await?, 100.into()); + // Since we have to do a swap we expect to restore amount - fee + assert_eq!( + wallet_2.total_balance().await?, + Amount::from(100) - expected_fee + ); let proofs = wallet.get_unspent_proofs().await?; diff --git a/crates/cdk-integration-tests/tests/integration_tests_pure.rs b/crates/cdk-integration-tests/tests/integration_tests_pure.rs index df561622..28139d8e 100644 --- a/crates/cdk-integration-tests/tests/integration_tests_pure.rs +++ b/crates/cdk-integration-tests/tests/integration_tests_pure.rs @@ -634,6 +634,50 @@ async fn test_mint_enforce_fee() { let _ = mint_bob.process_swap_request(swap_request).await.unwrap(); } +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_mint_change_with_fee_melt() { + setup_tracing(); + let mint_bob = create_and_start_test_mint() + .await + .expect("Failed to create test mint"); + + mint_bob + .rotate_keyset(CurrencyUnit::Sat, 1, 32, 1, &HashMap::new()) + .await + .unwrap(); + + let wallet_alice = create_test_wallet_for_mint(mint_bob.clone()) + .await + .expect("Failed to create test wallet"); + + // Alice gets 100 sats + fund_wallet( + wallet_alice.clone(), + 100, + Some(SplitTarget::Value(Amount::ONE)), + ) + .await + .expect("Failed to fund wallet"); + + let proofs = wallet_alice + .get_unspent_proofs() + .await + .expect("Could not get proofs"); + + let fake_invoice = create_fake_invoice(1000, "".to_string()); + + let melt_quote = wallet_alice + .melt_quote(fake_invoice.to_string(), None) + .await + .unwrap(); + + let w = wallet_alice + .melt_proofs(&melt_quote.id, proofs) + .await + .unwrap(); + + assert_eq!(w.change.unwrap().total_amount().unwrap(), 97.into()); +} /// Tests concurrent double-spending attempts by trying to use the same proofs /// in 3 swap transactions simultaneously using tokio tasks #[tokio::test(flavor = "multi_thread", worker_threads = 3)] diff --git a/crates/cdk-integration-tests/tests/nutshell_wallet.rs b/crates/cdk-integration-tests/tests/nutshell_wallet.rs index eabfe01e..fa0c2ce7 100644 --- a/crates/cdk-integration-tests/tests/nutshell_wallet.rs +++ b/crates/cdk-integration-tests/tests/nutshell_wallet.rs @@ -112,7 +112,7 @@ async fn get_wallet_balance(base_url: &str) -> u64 { } /// Test the Nutshell wallet's ability to mint tokens from a Lightning invoice -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test] async fn test_nutshell_wallet_mint() { // Get the wallet URL from environment variable let base_url = std::env::var("WALLET_URL").expect("Wallet url is not set"); @@ -137,7 +137,7 @@ async fn test_nutshell_wallet_mint() { } /// Test the Nutshell wallet's ability to mint tokens from a Lightning invoice -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test] async fn test_nutshell_wallet_swap() { // Get the wallet URL from environment variable let base_url = std::env::var("WALLET_URL").expect("Wallet url is not set"); @@ -194,11 +194,12 @@ async fn test_nutshell_wallet_swap() { let token_received = balance - initial_balance; - assert_eq!(token_received, send_amount); + let fee = 1; + assert_eq!(token_received, send_amount - fee); } /// Test the Nutshell wallet's ability to melt tokens to pay a Lightning invoice -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test] async fn test_nutshell_wallet_melt() { // Get the wallet URL from environment variable let base_url = std::env::var("WALLET_URL").expect("Wallet url is not set"); diff --git a/crates/cdk-integration-tests/tests/test_fees.rs b/crates/cdk-integration-tests/tests/test_fees.rs new file mode 100644 index 00000000..299244b0 --- /dev/null +++ b/crates/cdk-integration-tests/tests/test_fees.rs @@ -0,0 +1,125 @@ +use std::str::FromStr; +use std::sync::Arc; + +use anyhow::Result; +use bip39::Mnemonic; +use cashu::{Bolt11Invoice, ProofsMethods}; +use cdk::amount::{Amount, SplitTarget}; +use cdk::nuts::CurrencyUnit; +use cdk::wallet::{SendKind, SendOptions, Wallet}; +use cdk_integration_tests::{ + create_invoice_for_env, get_mint_url_from_env, pay_if_regtest, wait_for_mint_to_be_paid, +}; +use cdk_sqlite::wallet::memory; + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_swap() -> Result<()> { + let seed = Mnemonic::generate(12)?.to_seed_normalized(""); + let wallet = Wallet::new( + &get_mint_url_from_env(), + CurrencyUnit::Sat, + Arc::new(memory::empty().await?), + &seed, + None, + )?; + + let mint_quote = wallet.mint_quote(100.into(), None).await?; + + let invoice = Bolt11Invoice::from_str(&mint_quote.request)?; + pay_if_regtest(&invoice).await?; + + let _mint_amount = wallet + .mint(&mint_quote.id, SplitTarget::default(), None) + .await?; + + let proofs: Vec = wallet + .get_unspent_proofs() + .await? + .iter() + .map(|p| p.amount) + .collect(); + + println!("{:?}", proofs); + + let send = wallet + .prepare_send( + 4.into(), + SendOptions { + send_kind: SendKind::OfflineExact, + ..Default::default() + }, + ) + .await?; + + let proofs = send.proofs(); + + let fee = wallet.get_proofs_fee(&proofs).await?; + + assert_eq!(fee, 1.into()); + + let send = wallet.send(send, None).await?; + + let rec_amount = wallet + .receive(&send.to_string(), SplitTarget::default(), &[], &[]) + .await?; + + assert_eq!(rec_amount, 3.into()); + + let wallet_balance = wallet.total_balance().await?; + + assert_eq!(wallet_balance, 99.into()); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_fake_melt_change_in_quote() -> 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_quote(100.into(), None).await?; + + let bolt11 = Bolt11Invoice::from_str(&mint_quote.request)?; + + pay_if_regtest(&bolt11).await?; + + wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60).await?; + + let _mint_amount = wallet + .mint(&mint_quote.id, SplitTarget::default(), None) + .await?; + + let invoice_amount = 9; + + let invoice = create_invoice_for_env(Some(invoice_amount)).await?; + + let melt_quote = wallet.melt_quote(invoice.to_string(), None).await?; + + let proofs = wallet.get_unspent_proofs().await?; + + let proofs_total = proofs.total_amount().unwrap(); + + let fee = wallet.get_proofs_fee(&proofs).await?; + let melt = wallet.melt_proofs(&melt_quote.id, proofs.clone()).await?; + let change = melt.change.unwrap().total_amount().unwrap(); + let idk = proofs.total_amount()? - Amount::from(invoice_amount) - change; + + println!("{}", idk); + println!("{}", fee); + println!("{}", proofs_total); + println!("{}", change); + + let ln_fee = 1; + + assert_eq!( + wallet.total_balance().await?, + Amount::from(100 - invoice_amount - u64::from(fee) - ln_fee) + ); + + Ok(()) +} diff --git a/crates/cdk-mintd/src/main.rs b/crates/cdk-mintd/src/main.rs index 989d8acd..450572e0 100644 --- a/crates/cdk-mintd/src/main.rs +++ b/crates/cdk-mintd/src/main.rs @@ -207,6 +207,10 @@ async fn main() -> anyhow::Result<()> { ) .await?; + if let Some(input_fee) = settings.info.input_fee_ppk { + mint_builder = mint_builder.set_unit_fee(&CurrencyUnit::Sat, input_fee)?; + } + let nut17_supported = SupportedMethods::new(PaymentMethod::Bolt11, CurrencyUnit::Sat); mint_builder = mint_builder.add_supported_websockets(nut17_supported); @@ -226,6 +230,9 @@ async fn main() -> anyhow::Result<()> { Arc::new(lnbits), ) .await?; + if let Some(input_fee) = settings.info.input_fee_ppk { + mint_builder = mint_builder.set_unit_fee(&CurrencyUnit::Sat, input_fee)?; + } let nut17_supported = SupportedMethods::new(PaymentMethod::Bolt11, CurrencyUnit::Sat); @@ -246,6 +253,9 @@ async fn main() -> anyhow::Result<()> { Arc::new(lnd), ) .await?; + if let Some(input_fee) = settings.info.input_fee_ppk { + mint_builder = mint_builder.set_unit_fee(&CurrencyUnit::Sat, input_fee)?; + } let nut17_supported = SupportedMethods::new(PaymentMethod::Bolt11, CurrencyUnit::Sat); @@ -272,6 +282,9 @@ async fn main() -> anyhow::Result<()> { fake.clone(), ) .await?; + if let Some(input_fee) = settings.info.input_fee_ppk { + mint_builder = mint_builder.set_unit_fee(&unit, input_fee)?; + } let nut17_supported = SupportedMethods::new(PaymentMethod::Bolt11, unit); @@ -308,6 +321,9 @@ async fn main() -> anyhow::Result<()> { Arc::new(processor), ) .await?; + if let Some(input_fee) = settings.info.input_fee_ppk { + mint_builder = mint_builder.set_unit_fee(&unit, input_fee)?; + } let nut17_supported = SupportedMethods::new(PaymentMethod::Bolt11, unit); mint_builder = mint_builder.add_supported_websockets(nut17_supported); diff --git a/crates/cdk/src/mint/builder.rs b/crates/cdk/src/mint/builder.rs index 3f04264a..711f1e9b 100644 --- a/crates/cdk/src/mint/builder.rs +++ b/crates/cdk/src/mint/builder.rs @@ -292,6 +292,20 @@ impl MintBuilder { self } + /// Sets the input fee ppk for a given unit + /// + /// The unit **MUST** already have been added with a ln backend + pub fn set_unit_fee(mut self, unit: &CurrencyUnit, input_fee_ppk: u64) -> Result { + let (input_fee, _max_order) = self + .supported_units + .get_mut(unit) + .ok_or(Error::UnsupportedUnit)?; + + *input_fee = input_fee_ppk; + + Ok(self) + } + /// Build mint pub async fn build(&self) -> anyhow::Result { let localstore = self diff --git a/crates/cdk/src/mint/melt.rs b/crates/cdk/src/mint/melt.rs index 05f1cedc..73419d04 100644 --- a/crates/cdk/src/mint/melt.rs +++ b/crates/cdk/src/mint/melt.rs @@ -669,7 +669,10 @@ impl Mint { return Err(Error::BlindedMessageAlreadySigned); } - let change_target = melt_request.proofs_amount()? - total_spent; + let fee = self.get_proofs_fee(melt_request.inputs()).await?; + + let change_target = melt_request.proofs_amount()? - total_spent - fee; + let mut amounts = change_target.split(); let mut change_sigs = Vec::with_capacity(amounts.len()); diff --git a/justfile b/justfile index 9fdfb895..f84151e1 100644 --- a/justfile +++ b/justfile @@ -45,7 +45,7 @@ test: build cargo test --lib # Run pure integration tests - cargo test -p cdk-integration-tests --test mint + cargo test -p cdk-integration-tests --test mint # run doc tests @@ -66,12 +66,34 @@ test-all db="memory": ./misc/fake_itests.sh "{{db}}" test-nutshell: - #!/usr/bin/env bash - export CDK_TEST_MINT_URL=http://127.0.0.1:3338 - export LN_BACKEND=FAKEWALLET - cargo test -p cdk-integration-tests --test happy_path_mint_wallet - unset CDK_TEST_MINT_URL - unset LN_BACKEND + #!/usr/bin/env bash + docker run -d -p 3338:3338 --name nutshell -e MINT_LIGHTNING_BACKEND=FakeWallet -e MINT_LISTEN_HOST=0.0.0.0 -e MINT_LISTEN_PORT=3338 -e MINT_PRIVATE_KEY=TEST_PRIVATE_KEY -e MINT_INPUT_FEE_PPK=100 cashubtc/nutshell:latest poetry run mint + + # Wait for the Nutshell service to be ready + echo "Waiting for Nutshell to start..." + max_attempts=30 + attempt=0 + while ! curl -s http://127.0.0.1:3338/v1/info > /dev/null; do + attempt=$((attempt+1)) + if [ $attempt -ge $max_attempts ]; then + echo "Nutshell failed to start after $max_attempts attempts" + docker stop nutshell + docker rm nutshell + exit 1 + fi + echo "Waiting for Nutshell to start (attempt $attempt/$max_attempts)..." + sleep 1 + done + echo "Nutshell is ready!" + + export CDK_TEST_MINT_URL=http://127.0.0.1:3338 + export LN_BACKEND=FAKEWALLET + cargo test -p cdk-integration-tests --test happy_path_mint_wallet + cargo test -p cdk-integration-tests --test test_fees + unset CDK_TEST_MINT_URL + unset LN_BACKEND + docker stop nutshell + docker rm nutshell # run `cargo clippy` on everything diff --git a/misc/nutshell_wallet_itest.sh b/misc/nutshell_wallet_itest.sh index b015ba4d..e468852b 100755 --- a/misc/nutshell_wallet_itest.sh +++ b/misc/nutshell_wallet_itest.sh @@ -33,6 +33,7 @@ cleanup() { unset CDK_MINTD_LN_BACKEND CDK_MINTD_FAKE_WALLET_SUPPORTED_UNITS CDK_MINTD_MNEMONIC unset CDK_MINTD_FAKE_WALLET_FEE_PERCENT CDK_MINTD_FAKE_WALLET_RESERVE_FEE_MIN CDK_MINTD_DATABASE unset TEST_STATUS + unset CDK_MINTD_INPUT_FEE_PPK echo "Cleanup complete." } @@ -55,6 +56,7 @@ export CDK_MINTD_MNEMONIC="eye survey guilt napkin crystal cup whisper salt lugg export CDK_MINTD_FAKE_WALLET_FEE_PERCENT="0" export CDK_MINTD_FAKE_WALLET_RESERVE_FEE_MIN="1" export CDK_MINTD_DATABASE="redb" +export CDK_MINTD_INPUT_FEE_PPK="100" echo "Starting fake mintd" @@ -150,10 +152,12 @@ fi # Export URLs as environment variables export MINT_URL=${MINT_URL} export WALLET_URL=${WALLET_URL} +export CDK_TEST_MINT_URL=${MINT_URL} # Run the integration test echo "Running integration test..." -cargo test -p cdk-integration-tests --tests nutshell_wallet +cargo test -p cdk-integration-tests --test nutshell_wallet +cargo test -p cdk-integration-tests --test test_fees TEST_STATUS=$? # Exit with the test status