Преглед изворни кода

Refactor mintd used in itest (#616)

thesimplekid пре 1 месец
родитељ
комит
827e4aebde

+ 11 - 2
.github/workflows/ci.yml

@@ -13,6 +13,7 @@ jobs:
   self-care:
     name: Flake self-check
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     steps:
       - uses: actions/checkout@v4
       - name: Check Nix flake inputs
@@ -23,6 +24,7 @@ jobs:
   pre-commit-checks:
     name: "Cargo fmt, typos"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     steps:
       - name: checkout
         uses: actions/checkout@v4
@@ -45,6 +47,7 @@ jobs:
   examples:
     name: "Run examples"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         build-args:
@@ -69,6 +72,7 @@ jobs:
   clippy:
     name: "Stable build, clippy and test"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         build-args:
@@ -128,6 +132,7 @@ jobs:
   itest:
     name: "Integration regtest tests"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         build-args:
@@ -138,7 +143,6 @@ jobs:
           [
             REDB,
             SQLITE,
-            MEMORY,
           ]
     steps:
       - name: checkout
@@ -157,6 +161,7 @@ jobs:
   fake-wallet-itest:
     name: "Integration fake wallet tests"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         build-args:
@@ -167,7 +172,6 @@ jobs:
           [
           REDB,
           SQLITE,
-          MEMORY,
           ]
     steps:
       - name: checkout
@@ -186,6 +190,7 @@ jobs:
   pure-itest:
     name: "Integration fake wallet tests"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     steps:
       - name: checkout
         uses: actions/checkout@v4
@@ -201,6 +206,7 @@ jobs:
   msrv-build:
     name: "MSRV build"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         build-args:
@@ -233,6 +239,7 @@ jobs:
   db-msrv-build:
     name: "DB MSRV build"
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         build-args:
@@ -255,6 +262,7 @@ jobs:
   check-wasm:
     name: Check WASM
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         rust:
@@ -283,6 +291,7 @@ jobs:
   check-wasm-msrv:
     name: Check WASM
     runs-on: ubuntu-latest
+    timeout-minutes: 15
     strategy:
       matrix:
         rust:

+ 1 - 0
.gitignore

@@ -9,3 +9,4 @@ config.toml
 .pre-commit-config.yaml
 result
 Cargo.lock
+.aider*

+ 0 - 33
crates/cdk-integration-tests/src/bin/fake_wallet.rs

@@ -1,33 +0,0 @@
-use std::env;
-
-use anyhow::Result;
-use cdk::cdk_database::mint_memory::MintMemoryDatabase;
-use cdk_integration_tests::init_fake_wallet::start_fake_mint;
-use cdk_integration_tests::init_regtest::get_temp_dir;
-use cdk_redb::MintRedbDatabase;
-use cdk_sqlite::MintSqliteDatabase;
-
-#[tokio::main]
-async fn main() -> Result<()> {
-    let addr = "127.0.0.1";
-    let port = 8086;
-
-    let mint_db_kind = env::var("MINT_DATABASE")?;
-
-    match mint_db_kind.as_str() {
-        "MEMORY" => {
-            start_fake_mint(addr, port, MintMemoryDatabase::default()).await?;
-        }
-        "SQLITE" => {
-            let sqlite_db = MintSqliteDatabase::new(&get_temp_dir().join("mint")).await?;
-            sqlite_db.migrate().await;
-            start_fake_mint(addr, port, sqlite_db).await?;
-        }
-        "REDB" => {
-            let redb_db = MintRedbDatabase::new(&get_temp_dir().join("mint")).unwrap();
-            start_fake_mint(addr, port, redb_db).await?;
-        }
-        _ => panic!("Unknown mint db type: {}", mint_db_kind),
-    };
-    Ok(())
-}

+ 0 - 209
crates/cdk-integration-tests/src/bin/regtest_mint.rs

@@ -1,209 +0,0 @@
-use std::env;
-
-use anyhow::Result;
-use cdk::cdk_database::mint_memory::MintMemoryDatabase;
-use cdk_integration_tests::init_regtest::{
-    create_cln_backend, create_lnd_backend, create_mint, fund_ln, generate_block, get_bitcoin_dir,
-    get_cln_dir, get_lnd_cert_file_path, get_lnd_dir, get_lnd_macaroon_path, get_temp_dir,
-    init_bitcoin_client, init_bitcoind, init_lnd, open_channel, BITCOIN_RPC_PASS, BITCOIN_RPC_USER,
-    LND_ADDR, LND_RPC_ADDR, LND_TWO_ADDR, LND_TWO_RPC_ADDR,
-};
-use cdk_redb::MintRedbDatabase;
-use cdk_sqlite::MintSqliteDatabase;
-use ln_regtest_rs::cln::Clnd;
-use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
-use tracing_subscriber::EnvFilter;
-
-const CLN_ADDR: &str = "127.0.0.1:19846";
-const CLN_TWO_ADDR: &str = "127.0.0.1:19847";
-
-#[tokio::main]
-async fn main() -> Result<()> {
-    let default_filter = "debug";
-
-    let sqlx_filter = "sqlx=warn";
-    let hyper_filter = "hyper=warn";
-    let h2_filter = "h2=warn";
-    let rustls_filter = "rustls=warn";
-
-    let env_filter = EnvFilter::new(format!(
-        "{},{},{},{},{}",
-        default_filter, sqlx_filter, hyper_filter, h2_filter, rustls_filter
-    ));
-
-    tracing_subscriber::fmt().with_env_filter(env_filter).init();
-
-    let mut bitcoind = init_bitcoind();
-    bitcoind.start_bitcoind()?;
-
-    let bitcoin_client = init_bitcoin_client()?;
-    bitcoin_client.create_wallet().ok();
-    bitcoin_client.load_wallet()?;
-
-    let new_add = bitcoin_client.get_new_address()?;
-    bitcoin_client.generate_blocks(&new_add, 200).unwrap();
-
-    let cln_one_dir = get_cln_dir("one");
-    let mut clnd = Clnd::new(
-        get_bitcoin_dir(),
-        cln_one_dir.clone(),
-        CLN_ADDR.into(),
-        BITCOIN_RPC_USER.to_string(),
-        BITCOIN_RPC_PASS.to_string(),
-    );
-    clnd.start_clnd()?;
-
-    let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
-
-    cln_client.wait_chain_sync().await.unwrap();
-
-    fund_ln(&bitcoin_client, &cln_client).await.unwrap();
-
-    // Create second cln
-    let cln_two_dir = get_cln_dir("two");
-    let mut clnd_two = Clnd::new(
-        get_bitcoin_dir(),
-        cln_two_dir.clone(),
-        CLN_TWO_ADDR.into(),
-        BITCOIN_RPC_USER.to_string(),
-        BITCOIN_RPC_PASS.to_string(),
-    );
-    clnd_two.start_clnd()?;
-
-    let cln_two_client = ClnClient::new(cln_two_dir.clone(), None).await?;
-
-    cln_two_client.wait_chain_sync().await.unwrap();
-
-    fund_ln(&bitcoin_client, &cln_two_client).await.unwrap();
-
-    let lnd_dir = get_lnd_dir("one");
-    println!("{}", lnd_dir.display());
-
-    let mut lnd = init_lnd(lnd_dir.clone(), LND_ADDR, LND_RPC_ADDR).await;
-    lnd.start_lnd().unwrap();
-    tracing::info!("Started lnd node");
-
-    let lnd_client = LndClient::new(
-        format!("https://{}", LND_RPC_ADDR),
-        get_lnd_cert_file_path(&lnd_dir),
-        get_lnd_macaroon_path(&lnd_dir),
-    )
-    .await?;
-
-    lnd_client.wait_chain_sync().await.unwrap();
-
-    fund_ln(&bitcoin_client, &lnd_client).await.unwrap();
-
-    // create second lnd node
-    let lnd_two_dir = get_lnd_dir("two");
-    let mut lnd_two = init_lnd(lnd_two_dir.clone(), LND_TWO_ADDR, LND_TWO_RPC_ADDR).await;
-    lnd_two.start_lnd().unwrap();
-    tracing::info!("Started second lnd node");
-
-    let lnd_two_client = LndClient::new(
-        format!("https://{}", LND_TWO_RPC_ADDR),
-        get_lnd_cert_file_path(&lnd_two_dir),
-        get_lnd_macaroon_path(&lnd_two_dir),
-    )
-    .await?;
-
-    lnd_two_client.wait_chain_sync().await.unwrap();
-
-    fund_ln(&bitcoin_client, &lnd_two_client).await.unwrap();
-
-    // Open channels concurrently
-    // Open channels
-    {
-        open_channel(&cln_client, &lnd_client).await.unwrap();
-        tracing::info!("Opened channel between cln and lnd one");
-        generate_block(&bitcoin_client)?;
-        // open_channel(&bitcoin_client, &cln_client, &cln_two_client)
-        //     .await
-        //     .unwrap();
-        // tracing::info!("Opened channel between cln and cln two");
-
-        open_channel(&lnd_client, &lnd_two_client).await.unwrap();
-        tracing::info!("Opened channel between lnd and lnd two");
-        generate_block(&bitcoin_client)?;
-
-        // open_channel(&cln_client, &lnd_two_client).await.unwrap();
-        // tracing::info!("Opened channel between cln and lnd two");
-        open_channel(&cln_two_client, &lnd_client).await.unwrap();
-        tracing::info!("Opened channel between cln two and lnd");
-        generate_block(&bitcoin_client)?;
-
-        open_channel(&cln_client, &lnd_two_client).await.unwrap();
-        tracing::info!("Opened channel between cln and lnd two");
-        generate_block(&bitcoin_client)?;
-
-        cln_client.wait_channels_active().await?;
-        cln_two_client.wait_channels_active().await?;
-        lnd_client.wait_channels_active().await?;
-        lnd_two_client.wait_channels_active().await?;
-    }
-
-    let mint_addr = "127.0.0.1";
-    let cln_mint_port = 8085;
-
-    let mint_db_kind = env::var("MINT_DATABASE")?;
-
-    let lnd_mint_db_path = get_temp_dir().join("lnd_mint");
-    let cln_mint_db_path = get_temp_dir().join("cln_mint");
-
-    let cln_backend = create_cln_backend(&cln_client).await?;
-    let lnd_mint_port = 8087;
-
-    let lnd_backend = create_lnd_backend(&lnd_two_client).await?;
-
-    match mint_db_kind.as_str() {
-        "MEMORY" => {
-            tokio::spawn(async move {
-                create_mint(
-                    mint_addr,
-                    cln_mint_port,
-                    MintMemoryDatabase::default(),
-                    cln_backend,
-                )
-                .await
-                .expect("Could not start cln mint");
-            });
-
-            create_mint(
-                mint_addr,
-                lnd_mint_port,
-                MintMemoryDatabase::default(),
-                lnd_backend,
-            )
-            .await?;
-        }
-        "SQLITE" => {
-            tokio::spawn(async move {
-                let cln_sqlite_db = MintSqliteDatabase::new(&cln_mint_db_path)
-                    .await
-                    .expect("Could not create CLN mint db");
-                cln_sqlite_db.migrate().await;
-                create_mint(mint_addr, cln_mint_port, cln_sqlite_db, cln_backend)
-                    .await
-                    .expect("Could not start cln mint");
-            });
-
-            let lnd_sqlite_db = MintSqliteDatabase::new(&lnd_mint_db_path).await?;
-            lnd_sqlite_db.migrate().await;
-            create_mint(mint_addr, lnd_mint_port, lnd_sqlite_db, lnd_backend).await?;
-        }
-        "REDB" => {
-            tokio::spawn(async move {
-                let cln_redb_db = MintRedbDatabase::new(&cln_mint_db_path).unwrap();
-                create_mint(mint_addr, cln_mint_port, cln_redb_db, cln_backend)
-                    .await
-                    .expect("Could not start cln mint");
-            });
-
-            let lnd_redb_db = MintRedbDatabase::new(&lnd_mint_db_path).unwrap();
-            create_mint(mint_addr, lnd_mint_port, lnd_redb_db, lnd_backend).await?;
-        }
-        _ => panic!("Unknown mint db type: {}", mint_db_kind),
-    };
-
-    Ok(())
-}

+ 63 - 0
crates/cdk-integration-tests/src/bin/start_regtest.rs

@@ -0,0 +1,63 @@
+use std::fs::OpenOptions;
+use std::io::Write;
+use std::sync::Arc;
+use std::time::Duration;
+
+use anyhow::{bail, Result};
+use cdk_integration_tests::init_regtest::{get_temp_dir, start_regtest_end};
+use tokio::signal;
+use tokio::sync::{oneshot, Notify};
+use tokio::time::timeout;
+use tracing_subscriber::EnvFilter;
+
+fn signal_progress() {
+    let temp_dir = get_temp_dir();
+    let mut pipe = OpenOptions::new()
+        .write(true)
+        .open(temp_dir.join("progress_pipe"))
+        .expect("Failed to open pipe");
+
+    pipe.write_all(b"checkpoint1\n")
+        .expect("Failed to write to pipe");
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+    let default_filter = "debug";
+
+    let sqlx_filter = "sqlx=warn";
+    let hyper_filter = "hyper=warn";
+    let h2_filter = "h2=warn";
+    let rustls_filter = "rustls=warn";
+
+    let env_filter = EnvFilter::new(format!(
+        "{},{},{},{},{}",
+        default_filter, sqlx_filter, hyper_filter, h2_filter, rustls_filter
+    ));
+
+    tracing_subscriber::fmt().with_env_filter(env_filter).init();
+
+    let shutdown_regtest = Arc::new(Notify::new());
+    let shutdown_clone = shutdown_regtest.clone();
+    let (tx, rx) = oneshot::channel();
+    tokio::spawn(async move {
+        start_regtest_end(tx, shutdown_clone)
+            .await
+            .expect("Error starting regtest");
+    });
+
+    match timeout(Duration::from_secs(300), rx).await {
+        Ok(_) => {
+            tracing::info!("Regtest set up");
+            signal_progress();
+        }
+        Err(_) => {
+            tracing::error!("regtest setup timed out after 5 minutes");
+            bail!("Could not set up regtest");
+        }
+    }
+
+    signal::ctrl_c().await?;
+
+    Ok(())
+}

+ 0 - 83
crates/cdk-integration-tests/src/init_fake_wallet.rs

@@ -1,83 +0,0 @@
-use std::collections::{HashMap, HashSet};
-use std::sync::Arc;
-
-use anyhow::Result;
-use bip39::Mnemonic;
-use cdk::cdk_database::{self, MintDatabase};
-use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
-use cdk::nuts::{CurrencyUnit, PaymentMethod};
-use cdk::types::QuoteTTL;
-use cdk_fake_wallet::FakeWallet;
-use tracing_subscriber::EnvFilter;
-
-use crate::init_mint::start_mint;
-
-pub async fn start_fake_mint<D>(addr: &str, port: u16, database: D) -> Result<()>
-where
-    D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
-{
-    let default_filter = "debug";
-
-    let sqlx_filter = "sqlx=warn";
-    let hyper_filter = "hyper=warn";
-
-    let env_filter = EnvFilter::new(format!(
-        "{},{},{}",
-        default_filter, sqlx_filter, hyper_filter
-    ));
-
-    // Parse input
-    tracing_subscriber::fmt().with_env_filter(env_filter).init();
-
-    let fee_reserve = FeeReserve {
-        min_fee_reserve: 1.into(),
-        percent_fee_reserve: 0.0,
-    };
-
-    let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
-
-    let mut mint_builder = MintBuilder::new();
-
-    let localstore = Arc::new(database);
-    mint_builder = mint_builder.with_localstore(localstore.clone());
-
-    mint_builder = mint_builder.add_ln_backend(
-        CurrencyUnit::Sat,
-        PaymentMethod::Bolt11,
-        MintMeltLimits::new(1, 5_000),
-        Arc::new(fake_wallet),
-    );
-
-    let fee_reserve = FeeReserve {
-        min_fee_reserve: 1.into(),
-        percent_fee_reserve: 0.0,
-    };
-
-    let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
-
-    mint_builder = mint_builder.add_ln_backend(
-        CurrencyUnit::Usd,
-        PaymentMethod::Bolt11,
-        MintMeltLimits::new(1, 5_000),
-        Arc::new(fake_wallet),
-    );
-
-    let mnemonic = Mnemonic::generate(12)?;
-
-    mint_builder = mint_builder
-        .with_name("fake test mint".to_string())
-        .with_description("fake test mint".to_string())
-        .with_seed(mnemonic.to_seed_normalized("").to_vec());
-
-    localstore
-        .set_mint_info(mint_builder.mint_info.clone())
-        .await?;
-    let quote_ttl = QuoteTTL::new(10000, 10000);
-    localstore.set_quote_ttl(quote_ttl).await?;
-
-    let mint = mint_builder.build().await?;
-
-    start_mint(addr, port, mint).await?;
-
-    Ok(())
-}

+ 0 - 37
crates/cdk-integration-tests/src/init_mint.rs

@@ -1,37 +0,0 @@
-use std::sync::Arc;
-
-use anyhow::Result;
-use axum::Router;
-use cdk::mint::Mint;
-use tokio::sync::Notify;
-use tower_http::cors::CorsLayer;
-use tracing::instrument;
-
-#[instrument(skip_all)]
-pub async fn start_mint(addr: &str, port: u16, mint: Mint) -> Result<()> {
-    let mint_arc = Arc::new(mint);
-
-    let v1_service = cdk_axum::create_mint_router(Arc::clone(&mint_arc))
-        .await
-        .unwrap();
-
-    let mint_service = Router::new()
-        .merge(v1_service)
-        .layer(CorsLayer::permissive());
-
-    let mint = Arc::clone(&mint_arc);
-
-    let shutdown = Arc::new(Notify::new());
-
-    tokio::spawn({
-        let shutdown = Arc::clone(&shutdown);
-        async move { mint.wait_for_paid_invoices(shutdown).await }
-    });
-
-    tracing::info!("Staring Axum server");
-    axum::Server::bind(&format!("{}:{}", addr, port).as_str().parse().unwrap())
-        .serve(mint_service.into_make_service())
-        .await?;
-
-    Ok(())
-}

+ 127 - 46
crates/cdk-integration-tests/src/init_regtest.rs

@@ -3,21 +3,16 @@ use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
 use anyhow::Result;
-use bip39::Mnemonic;
-use cdk::cdk_database::{self, MintDatabase};
-use cdk::cdk_lightning::{self, MintLightning};
-use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
-use cdk::nuts::{CurrencyUnit, PaymentMethod};
-use cdk::types::QuoteTTL;
+use cdk::mint::FeeReserve;
 use cdk_cln::Cln as CdkCln;
 use cdk_lnd::Lnd as CdkLnd;
 use ln_regtest_rs::bitcoin_client::BitcoinClient;
 use ln_regtest_rs::bitcoind::Bitcoind;
+use ln_regtest_rs::cln::Clnd;
 use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
 use ln_regtest_rs::lnd::Lnd;
-use tracing::instrument;
-
-use crate::init_mint::start_mint;
+use tokio::sync::oneshot::Sender;
+use tokio::sync::Notify;
 
 pub const BITCOIND_ADDR: &str = "127.0.0.1:18443";
 pub const ZMQ_RAW_BLOCK: &str = "tcp://127.0.0.1:28332";
@@ -33,6 +28,9 @@ pub const LND_RPC_ADDR: &str = "localhost:10009";
 pub const LND_TWO_ADDR: &str = "0.0.0.0:18410";
 pub const LND_TWO_RPC_ADDR: &str = "localhost:10010";
 
+pub const CLN_ADDR: &str = "127.0.0.1:19846";
+pub const CLN_TWO_ADDR: &str = "127.0.0.1:19847";
+
 pub fn get_mint_addr() -> String {
     env::var("cdk_itests_mint_addr").expect("Temp dir set")
 }
@@ -149,43 +147,6 @@ pub async fn create_lnd_backend(lnd_client: &LndClient) -> Result<CdkLnd> {
     .await?)
 }
 
-#[instrument(skip_all)]
-pub async fn create_mint<D, L>(addr: &str, port: u16, database: D, lighting: L) -> Result<()>
-where
-    D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
-    L: MintLightning<Err = cdk_lightning::Error> + Send + Sync + 'static,
-{
-    let mut mint_builder = MintBuilder::new();
-    let localstore = Arc::new(database);
-    mint_builder = mint_builder.with_localstore(localstore.clone());
-
-    mint_builder = mint_builder.add_ln_backend(
-        CurrencyUnit::Sat,
-        PaymentMethod::Bolt11,
-        MintMeltLimits::new(1, 5_000),
-        Arc::new(lighting),
-    );
-
-    let mnemonic = Mnemonic::generate(12)?;
-
-    mint_builder = mint_builder
-        .with_name("regtest mint".to_string())
-        .with_description("regtest mint".to_string())
-        .with_seed(mnemonic.to_seed_normalized("").to_vec());
-
-    let mint = mint_builder.build().await?;
-
-    localstore
-        .set_mint_info(mint_builder.mint_info.clone())
-        .await?;
-    let quote_ttl = QuoteTTL::new(10000, 10000);
-    localstore.set_quote_ttl(quote_ttl).await?;
-
-    start_mint(addr, port, mint).await?;
-
-    Ok(())
-}
-
 pub async fn fund_ln<C>(bitcoin_client: &BitcoinClient, ln_client: &C) -> Result<()>
 where
     C: LightningClient,
@@ -230,3 +191,123 @@ where
 
     Ok(())
 }
+
+pub async fn start_regtest_end(sender: Sender<()>, notify: Arc<Notify>) -> anyhow::Result<()> {
+    let mut bitcoind = init_bitcoind();
+    bitcoind.start_bitcoind()?;
+
+    let bitcoin_client = init_bitcoin_client()?;
+    bitcoin_client.create_wallet().ok();
+    bitcoin_client.load_wallet()?;
+
+    let new_add = bitcoin_client.get_new_address()?;
+    bitcoin_client.generate_blocks(&new_add, 200).unwrap();
+
+    let cln_one_dir = get_cln_dir("one");
+    let mut clnd = Clnd::new(
+        get_bitcoin_dir(),
+        cln_one_dir.clone(),
+        CLN_ADDR.into(),
+        BITCOIN_RPC_USER.to_string(),
+        BITCOIN_RPC_PASS.to_string(),
+    );
+    clnd.start_clnd()?;
+
+    let cln_client = ClnClient::new(cln_one_dir.clone(), None).await?;
+
+    cln_client.wait_chain_sync().await.unwrap();
+
+    fund_ln(&bitcoin_client, &cln_client).await.unwrap();
+
+    // Create second cln
+    let cln_two_dir = get_cln_dir("two");
+    let mut clnd_two = Clnd::new(
+        get_bitcoin_dir(),
+        cln_two_dir.clone(),
+        CLN_TWO_ADDR.into(),
+        BITCOIN_RPC_USER.to_string(),
+        BITCOIN_RPC_PASS.to_string(),
+    );
+    clnd_two.start_clnd()?;
+
+    let cln_two_client = ClnClient::new(cln_two_dir.clone(), None).await?;
+
+    cln_two_client.wait_chain_sync().await.unwrap();
+
+    fund_ln(&bitcoin_client, &cln_two_client).await.unwrap();
+
+    let lnd_dir = get_lnd_dir("one");
+    println!("{}", lnd_dir.display());
+
+    let mut lnd = init_lnd(lnd_dir.clone(), LND_ADDR, LND_RPC_ADDR).await;
+    lnd.start_lnd().unwrap();
+    tracing::info!("Started lnd node");
+
+    let lnd_client = LndClient::new(
+        format!("https://{}", LND_RPC_ADDR),
+        get_lnd_cert_file_path(&lnd_dir),
+        get_lnd_macaroon_path(&lnd_dir),
+    )
+    .await?;
+
+    lnd_client.wait_chain_sync().await.unwrap();
+
+    fund_ln(&bitcoin_client, &lnd_client).await.unwrap();
+
+    // create second lnd node
+    let lnd_two_dir = get_lnd_dir("two");
+    let mut lnd_two = init_lnd(lnd_two_dir.clone(), LND_TWO_ADDR, LND_TWO_RPC_ADDR).await;
+    lnd_two.start_lnd().unwrap();
+    tracing::info!("Started second lnd node");
+
+    let lnd_two_client = LndClient::new(
+        format!("https://{}", LND_TWO_RPC_ADDR),
+        get_lnd_cert_file_path(&lnd_two_dir),
+        get_lnd_macaroon_path(&lnd_two_dir),
+    )
+    .await?;
+
+    lnd_two_client.wait_chain_sync().await.unwrap();
+
+    fund_ln(&bitcoin_client, &lnd_two_client).await.unwrap();
+
+    // Open channels concurrently
+    // Open channels
+    {
+        open_channel(&cln_client, &lnd_client).await.unwrap();
+        tracing::info!("Opened channel between cln and lnd one");
+        generate_block(&bitcoin_client)?;
+        // open_channel(&bitcoin_client, &cln_client, &cln_two_client)
+        //     .await
+        //     .unwrap();
+        // tracing::info!("Opened channel between cln and cln two");
+
+        open_channel(&lnd_client, &lnd_two_client).await.unwrap();
+        tracing::info!("Opened channel between lnd and lnd two");
+        generate_block(&bitcoin_client)?;
+
+        // open_channel(&cln_client, &lnd_two_client).await.unwrap();
+        // tracing::info!("Opened channel between cln and lnd two");
+        open_channel(&cln_two_client, &lnd_client).await.unwrap();
+        tracing::info!("Opened channel between cln two and lnd");
+        generate_block(&bitcoin_client)?;
+
+        open_channel(&cln_client, &lnd_two_client).await.unwrap();
+        tracing::info!("Opened channel between cln and lnd two");
+        generate_block(&bitcoin_client)?;
+
+        cln_client.wait_channels_active().await?;
+        cln_two_client.wait_channels_active().await?;
+        lnd_client.wait_channels_active().await?;
+        lnd_two_client.wait_channels_active().await?;
+    }
+
+    // Send notification that regtest set up is complete
+    sender.send(()).expect("Could not send oneshot");
+
+    // Wait until we are told to shutdown
+    // If we return the bitcoind, lnd, and cln will be dropped and shutdown
+    notify.notified().await;
+
+    Ok(())
+}

+ 35 - 95
crates/cdk-integration-tests/src/lib.rs

@@ -1,24 +1,13 @@
-use std::str::FromStr;
 use std::sync::Arc;
 
 use anyhow::{bail, Result};
 use cdk::amount::{Amount, SplitTarget};
-use cdk::dhke::construct_proofs;
-use cdk::mint_url::MintUrl;
 use cdk::nuts::nut00::ProofsMethods;
-use cdk::nuts::nut17::Params;
-use cdk::nuts::{
-    CurrencyUnit, Id, KeySet, MintBolt11Request, MintQuoteBolt11Request, MintQuoteState,
-    NotificationPayload, PreMintSecrets, Proofs, State,
-};
-use cdk::wallet::client::{HttpClient, MintConnector};
-use cdk::wallet::subscription::SubscriptionManager;
+use cdk::nuts::{MintQuoteState, NotificationPayload, State};
 use cdk::wallet::WalletSubscription;
 use cdk::Wallet;
-use tokio::time::{timeout, Duration};
+use tokio::time::{sleep, timeout, Duration};
 
-pub mod init_fake_wallet;
-pub mod init_mint;
 pub mod init_pure_tests;
 pub mod init_regtest;
 
@@ -30,19 +19,7 @@ pub async fn wallet_mint(
 ) -> Result<()> {
     let quote = wallet.mint_quote(amount, description).await?;
 
-    let mut subscription = wallet
-        .subscribe(WalletSubscription::Bolt11MintQuoteState(vec![quote
-            .id
-            .clone()]))
-        .await;
-
-    while let Some(msg) = subscription.recv().await {
-        if let NotificationPayload::MintQuoteBolt11Response(response) = msg {
-            if response.state == MintQuoteState::Paid {
-                break;
-            }
-        }
-    }
+    wait_for_mint_to_be_paid(&wallet, &quote.id, 60).await?;
 
     let proofs = wallet.mint(&quote.id, split_target, None).await?;
 
@@ -53,70 +30,6 @@ pub async fn wallet_mint(
     Ok(())
 }
 
-pub async fn mint_proofs(
-    mint_url: &str,
-    amount: Amount,
-    keyset_id: Id,
-    mint_keys: &KeySet,
-    description: Option<String>,
-) -> anyhow::Result<Proofs> {
-    println!("Minting for ecash");
-    println!();
-
-    let wallet_client = HttpClient::new(MintUrl::from_str(mint_url)?);
-
-    let request = MintQuoteBolt11Request {
-        amount,
-        unit: CurrencyUnit::Sat,
-        description,
-        pubkey: None,
-    };
-
-    let mint_quote = wallet_client.post_mint_quote(request).await?;
-
-    println!("Please pay: {}", mint_quote.request);
-
-    let subscription_client = SubscriptionManager::new(Arc::new(wallet_client.clone()));
-
-    let mut subscription = subscription_client
-        .subscribe(
-            mint_url.parse()?,
-            Params {
-                filters: vec![mint_quote.quote.clone()],
-                kind: cdk::nuts::nut17::Kind::Bolt11MintQuote,
-                id: "sub".into(),
-            },
-        )
-        .await;
-
-    while let Some(msg) = subscription.recv().await {
-        if let NotificationPayload::MintQuoteBolt11Response(response) = msg {
-            if response.state == MintQuoteState::Paid {
-                break;
-            }
-        }
-    }
-
-    let premint_secrets = PreMintSecrets::random(keyset_id, amount, &SplitTarget::default())?;
-
-    let request = MintBolt11Request {
-        quote: mint_quote.quote,
-        outputs: premint_secrets.blinded_messages(),
-        signature: None,
-    };
-
-    let mint_response = wallet_client.post_mint(request).await?;
-
-    let pre_swap_proofs = construct_proofs(
-        mint_response.signatures,
-        premint_secrets.rs(),
-        premint_secrets.secrets(),
-        &mint_keys.clone().keys,
-    )?;
-
-    Ok(pre_swap_proofs)
-}
-
 // Get all pending from wallet and attempt to swap
 // Will panic if there are no pending
 // Will return Ok if swap fails as expected
@@ -154,6 +67,7 @@ pub async fn attempt_to_swap_pending(wallet: &Wallet) -> Result<()> {
     Ok(())
 }
 
+#[allow(clippy::incompatible_msrv)]
 pub async fn wait_for_mint_to_be_paid(
     wallet: &Wallet,
     mint_quote_id: &str,
@@ -164,7 +78,6 @@ pub async fn wait_for_mint_to_be_paid(
             mint_quote_id.to_owned(),
         ]))
         .await;
-
     // Create the timeout future
     let wait_future = async {
         while let Some(msg) = subscription.recv().await {
@@ -177,9 +90,36 @@ pub async fn wait_for_mint_to_be_paid(
         Ok(())
     };
 
-    // Wait for either the payment to complete or timeout
-    match timeout(Duration::from_secs(timeout_secs), wait_future).await {
-        Ok(result) => result,
-        Err(_) => Err(anyhow::anyhow!("Timeout waiting for mint quote to be paid")),
+    let timeout_future = timeout(Duration::from_secs(timeout_secs), wait_future);
+
+    let check_interval = Duration::from_secs(5);
+
+    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(());
+                    }
+                }
+                Err(e) => {
+                    tracing::error!("Could not check mint quote status: {:?}", e);
+                }
+            }
+            sleep(check_interval).await;
+        }
+    };
+
+    tokio::select! {
+        result = timeout_future => {
+            match result {
+                Ok(payment_result) => payment_result,
+                Err(_) => Err(anyhow::anyhow!("Timeout waiting for mint quote to be paid")),
+            }
+        }
+        result = periodic_task => {
+            result // Now propagates the result from periodic checks
+        }
     }
 }

+ 36 - 0
crates/cdk-integration-tests/tests/fake_wallet.rs

@@ -378,6 +378,41 @@ async fn test_fake_melt_change_in_quote() -> Result<()> {
 }
 
 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
+async fn test_database_type() -> Result<()> {
+    // Get the database type and work dir from environment
+    let db_type = std::env::var("MINT_DATABASE").expect("MINT_DATABASE env var should be set");
+    let work_dir =
+        std::env::var("CDK_MINTD_WORK_DIR").expect("CDK_MINTD_WORK_DIR env var should be set");
+
+    // Check that the correct database file exists
+    match db_type.as_str() {
+        "REDB" => {
+            let db_path = std::path::Path::new(&work_dir).join("cdk-mintd.redb");
+            assert!(
+                db_path.exists(),
+                "Expected redb database file to exist at {:?}",
+                db_path
+            );
+        }
+        "SQLITE" => {
+            let db_path = std::path::Path::new(&work_dir).join("cdk-mintd.sqlite");
+            assert!(
+                db_path.exists(),
+                "Expected sqlite database file to exist at {:?}",
+                db_path
+            );
+        }
+        "MEMORY" => {
+            // Memory database has no file to check
+            println!("Memory database in use - no file to check");
+        }
+        _ => bail!("Unknown database type: {}", db_type),
+    }
+
+    Ok(())
+}
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
 async fn test_fake_mint_with_witness() -> Result<()> {
     let wallet = Wallet::new(
         MINT_URL,
@@ -803,6 +838,7 @@ async fn test_fake_mint_multiple_unit_melt() -> Result<()> {
         };
 
         let http_client = HttpClient::new(MINT_URL.parse()?);
+
         let response = http_client.post_melt(melt_request.clone()).await;
 
         match response {

+ 96 - 30
crates/cdk-integration-tests/tests/regtest.rs

@@ -14,7 +14,8 @@ use cdk::nuts::{
     PreMintSecrets, State,
 };
 use cdk::wallet::client::{HttpClient, MintConnector};
-use cdk::wallet::{Wallet, WalletSubscription};
+use cdk::wallet::Wallet;
+use cdk::WalletSubscription;
 use cdk_integration_tests::init_regtest::{
     get_cln_dir, get_lnd_cert_file_path, get_lnd_dir, get_lnd_macaroon_path, get_mint_port,
     get_mint_url, get_mint_ws_url, LND_RPC_ADDR, LND_TWO_RPC_ADDR,
@@ -140,7 +141,8 @@ async fn test_regtest_mint_melt_round_trip() -> Result<()> {
         NotificationPayload::MeltQuoteBolt11Response(melt) => melt,
         _ => panic!("Wrong payload"),
     };
-    assert_eq!(payload.amount + payload.fee_reserve, 100.into());
+
+    assert_eq!(payload.amount + payload.fee_reserve, 50.into());
     assert_eq!(payload.quote.to_string(), melt.id);
     assert_eq!(payload.state, MeltQuoteState::Unpaid);
 
@@ -151,7 +153,7 @@ async fn test_regtest_mint_melt_round_trip() -> Result<()> {
         NotificationPayload::MeltQuoteBolt11Response(melt) => melt,
         _ => panic!("Wrong payload"),
     };
-    assert_eq!(payload.amount + payload.fee_reserve, 100.into());
+    assert_eq!(payload.amount + payload.fee_reserve, 50.into());
     assert_eq!(payload.quote.to_string(), melt.id);
     assert_eq!(payload.state, MeltQuoteState::Paid);
 
@@ -422,19 +424,7 @@ async fn test_cached_mint() -> Result<()> {
     let quote = wallet.mint_quote(mint_amount, None).await?;
     lnd_client.pay_invoice(quote.request).await?;
 
-    let mut subscription = wallet
-        .subscribe(WalletSubscription::Bolt11MintQuoteState(vec![quote
-            .id
-            .clone()]))
-        .await;
-
-    while let Some(msg) = subscription.recv().await {
-        if let NotificationPayload::MintQuoteBolt11Response(response) = msg {
-            if response.state == MintQuoteState::Paid {
-                break;
-            }
-        }
-    }
+    wait_for_mint_to_be_paid(&wallet, &quote.id, 60).await?;
 
     let active_keyset_id = wallet.get_active_mint_keyset().await?.id;
     let http_client = HttpClient::new(get_mint_url("0").as_str().parse()?);
@@ -459,6 +449,59 @@ async fn test_cached_mint() -> Result<()> {
 }
 
 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
+async fn test_websocket_connection() -> Result<()> {
+    let wallet = Wallet::new(
+        &get_mint_url("0"),
+        CurrencyUnit::Sat,
+        Arc::new(WalletMemoryDatabase::default()),
+        &Mnemonic::generate(12)?.to_seed_normalized(""),
+        None,
+    )?;
+
+    // Create a small mint quote to test notifications
+    let mint_quote = wallet.mint_quote(10.into(), None).await?;
+
+    // Subscribe to notifications for this quote
+    let mut subscription = wallet
+        .subscribe(WalletSubscription::Bolt11MintQuoteState(vec![mint_quote
+            .id
+            .clone()]))
+        .await;
+
+    // First check we get the unpaid state
+    let msg = timeout(Duration::from_secs(10), subscription.recv())
+        .await
+        .expect("timeout waiting for unpaid notification")
+        .ok_or_else(|| anyhow::anyhow!("No unpaid notification received"))?;
+
+    match msg {
+        NotificationPayload::MintQuoteBolt11Response(response) => {
+            assert_eq!(response.quote.to_string(), mint_quote.id);
+            assert_eq!(response.state, MintQuoteState::Unpaid);
+        }
+        _ => bail!("Unexpected notification type"),
+    }
+
+    let lnd_client = init_lnd_client().await;
+    lnd_client.pay_invoice(mint_quote.request).await?;
+
+    // Wait for paid notification with 10 second timeout
+    let msg = timeout(Duration::from_secs(10), subscription.recv())
+        .await
+        .expect("timeout waiting for paid notification")
+        .ok_or_else(|| anyhow::anyhow!("No paid notification received"))?;
+
+    match msg {
+        NotificationPayload::MintQuoteBolt11Response(response) => {
+            assert_eq!(response.quote.to_string(), mint_quote.id);
+            assert_eq!(response.state, MintQuoteState::Paid);
+            Ok(())
+        }
+        _ => bail!("Unexpected notification type"),
+    }
+}
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
 async fn test_multimint_melt() -> Result<()> {
     let lnd_client = init_lnd_client().await;
 
@@ -482,26 +525,14 @@ async fn test_multimint_melt() -> Result<()> {
     // Fund the wallets
     let quote = wallet1.mint_quote(mint_amount, None).await?;
     lnd_client.pay_invoice(quote.request.clone()).await?;
-    loop {
-        let quote_status = wallet1.mint_quote_state(&quote.id).await?;
-        if quote_status.state == MintQuoteState::Paid {
-            break;
-        }
-        tracing::debug!("Quote not yet paid");
-    }
+    wait_for_mint_to_be_paid(&wallet1, &quote.id, 60).await?;
     wallet1
         .mint(&quote.id, SplitTarget::default(), None)
         .await?;
 
     let quote = wallet2.mint_quote(mint_amount, None).await?;
     lnd_client.pay_invoice(quote.request.clone()).await?;
-    loop {
-        let quote_status = wallet2.mint_quote_state(&quote.id).await?;
-        if quote_status.state == MintQuoteState::Paid {
-            break;
-        }
-        tracing::debug!("Quote not yet paid");
-    }
+    wait_for_mint_to_be_paid(&wallet2, &quote.id, 60).await?;
     wallet2
         .mint(&quote.id, SplitTarget::default(), None)
         .await?;
@@ -538,3 +569,38 @@ async fn test_multimint_melt() -> Result<()> {
     assert!(result1.state == MeltQuoteState::Paid);
     Ok(())
 }
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
+async fn test_database_type() -> Result<()> {
+    // Get the database type and work dir from environment
+    let db_type = std::env::var("MINT_DATABASE").expect("MINT_DATABASE env var should be set");
+    let work_dir =
+        std::env::var("CDK_MINTD_WORK_DIR").expect("CDK_MINTD_WORK_DIR env var should be set");
+
+    // Check that the correct database file exists
+    match db_type.as_str() {
+        "REDB" => {
+            let db_path = std::path::Path::new(&work_dir).join("cdk-mintd.redb");
+            assert!(
+                db_path.exists(),
+                "Expected redb database file to exist at {:?}",
+                db_path
+            );
+        }
+        "SQLITE" => {
+            let db_path = std::path::Path::new(&work_dir).join("cdk-mintd.sqlite");
+            assert!(
+                db_path.exists(),
+                "Expected sqlite database file to exist at {:?}",
+                db_path
+            );
+        }
+        "MEMORY" => {
+            // Memory database has no file to check
+            println!("Memory database in use - no file to check");
+        }
+        _ => bail!("Unknown database type: {}", db_type),
+    }
+
+    Ok(())
+}

+ 3 - 0
crates/cdk-lnd/src/error.rs

@@ -33,6 +33,9 @@ pub enum Error {
     /// Errors coming from the backend
     #[error("LND error: `{0}`")]
     LndError(Status),
+    /// Errors invalid config
+    #[error("LND invalid config: `{0}`")]
+    InvalidConfig(String),
 }
 
 impl From<Error> for cdk::cdk_lightning::Error {

+ 26 - 0
crates/cdk-lnd/src/lib.rs

@@ -55,6 +55,32 @@ impl Lnd {
         macaroon_file: PathBuf,
         fee_reserve: FeeReserve,
     ) -> Result<Self, Error> {
+        // Validate address is not empty
+        if address.is_empty() {
+            return Err(Error::InvalidConfig("LND address cannot be empty".into()));
+        }
+
+        // Validate cert_file exists and is not empty
+        if !cert_file.exists() || cert_file.metadata().map(|m| m.len() == 0).unwrap_or(true) {
+            return Err(Error::InvalidConfig(format!(
+                "LND certificate file not found or empty: {:?}",
+                cert_file
+            )));
+        }
+
+        // Validate macaroon_file exists and is not empty
+        if !macaroon_file.exists()
+            || macaroon_file
+                .metadata()
+                .map(|m| m.len() == 0)
+                .unwrap_or(true)
+        {
+            return Err(Error::InvalidConfig(format!(
+                "LND macaroon file not found or empty: {:?}",
+                macaroon_file
+            )));
+        }
+
         let client = fedimint_tonic_lnd::connect(address.to_string(), &cert_file, &macaroon_file)
             .await
             .map_err(|err| {

+ 1 - 1
crates/cdk-mintd/Cargo.toml

@@ -42,7 +42,7 @@ bitcoin = { version = "0.32.2", features = [
     "rand",
     "rand-std",
 ] }
-tokio = { version = "1", default-features = false }
+tokio = { version = "1", default-features = false, features = ["signal"] }
 tracing = { version = "0.1", default-features = false, features = [
     "attributes",
     "log",

+ 18 - 12
crates/cdk-mintd/src/main.rs

@@ -412,29 +412,28 @@ async fn main() -> anyhow::Result<()> {
             .parse()?,
     )
     .serve(mint_service.into_make_service())
-    .await;
+    .with_graceful_shutdown(shutdown_signal());
 
-    shutdown.notify_waiters();
-
-    #[cfg(feature = "management-rpc")]
-    {
-        if let Some(rpc_server) = rpc_server {
-            rpc_server.stop().await?;
-        }
-    }
-
-    match axum_result {
+    match axum_result.await {
         Ok(_) => {
             tracing::info!("Axum server stopped with okay status");
         }
         Err(err) => {
             tracing::warn!("Axum server stopped with error");
             tracing::error!("{}", err);
-
             bail!("Axum exited with error")
         }
     }
 
+    shutdown.notify_waiters();
+
+    #[cfg(feature = "management-rpc")]
+    {
+        if let Some(rpc_server) = rpc_server {
+            rpc_server.stop().await?;
+        }
+    }
+
     Ok(())
 }
 
@@ -469,3 +468,10 @@ fn work_dir() -> Result<PathBuf> {
 
     Ok(dir)
 }
+
+async fn shutdown_signal() {
+    tokio::signal::ctrl_c()
+        .await
+        .expect("failed to install CTRL+C handler");
+    tracing::info!("Shutdown signal received");
+}

+ 21 - 11
misc/fake_itests.sh

@@ -4,12 +4,9 @@
 cleanup() {
     echo "Cleaning up..."
 
-    # Kill the Rust binary process
-    echo "Killing the Rust binary with PID $RUST_BIN_PID"
-    kill $CDK_ITEST_MINT_BIN_PID
-
-    # Wait for the Rust binary to terminate
-    wait $CDK_ITEST_MINT_BIN_PID
+    echo "Killing the cdk mintd"
+    kill -2 $cdk_mintd_pid
+    wait $cdk_mintd_pid
 
     echo "Mint binary terminated"
     
@@ -29,7 +26,6 @@ export cdk_itests=$(mktemp -d)
 export cdk_itests_mint_addr="127.0.0.1";
 export cdk_itests_mint_port=8086;
 
-URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port/v1/info"
 # Check if the temporary directory was created successfully
 if [[ ! -d "$cdk_itests" ]]; then
     echo "Failed to create temp directory"
@@ -40,11 +36,25 @@ echo "Temp directory created: $cdk_itests"
 export MINT_DATABASE="$1";
 
 cargo build -p cdk-integration-tests 
-cargo build --bin fake_wallet 
-cargo run --bin fake_wallet &
-# Capture its PID
-CDK_ITEST_MINT_BIN_PID=$!
 
+
+export CDK_MINTD_URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port";
+export CDK_MINTD_WORK_DIR="$cdk_itests";
+export CDK_MINTD_LISTEN_HOST=$cdk_itests_mint_addr;
+export CDK_MINTD_LISTEN_PORT=$cdk_itests_mint_port;
+export CDK_MINTD_LN_BACKEND="fakewallet";
+export CDK_MINTD_FAKE_WALLET_SUPPORTED_UNITS="sat,usd";
+export CDK_MINTD_MNEMONIC="eye survey guilt napkin crystal cup whisper salt luggage manage unveil loyal";
+export CDK_MINTD_FAKE_WALLET_FEE_PERCENT="0";
+export CDK_MINTD_FAKE_WALLET_RESERVE_FEE_MIN="1";
+export CDK_MINTD_DATABASE=$MINT_DATABASE;
+
+
+echo "Starting fake mintd";
+cargo run --bin cdk-mintd &
+cdk_mintd_pid=$!
+
+URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port/v1/info"
 TIMEOUT=100
 START_TIME=$(date +%s)
 # Loop until the endpoint returns a 200 OK status or timeout is reached

+ 107 - 18
misc/itests.sh

@@ -4,20 +4,21 @@
 cleanup() {
     echo "Cleaning up..."
 
-    # Kill the Rust binary process
-    echo "Killing the Rust binary with PID $RUST_BIN_PID"
-    kill $CDK_ITEST_MINT_BIN_PID
+    echo "Killing the cdk mintd"
+    kill -2 $cdk_mintd_pid
+    wait $cdk_mintd_pid
+
+    
+    echo "Killing the cdk lnd mintd"
+    kill -2 $cdk_mintd_lnd_pid
+    wait $cdk_mintd_lnd_pid
+
+    echo "Killing the cdk regtest"
+    kill -2 $cdk_regtest_pid
+    wait $cdk_regtest_pid
 
-    # Wait for the Rust binary to terminate
-    wait $CDK_ITEST_MINT_BIN_PID
 
     echo "Mint binary terminated"
-    # Kill processes
-    lncli --lnddir="$cdk_itests/lnd/one" --network=regtest stop
-    lncli --lnddir="$cdk_itests/lnd/two" --network=regtest --rpcserver=localhost:10010 stop
-    lightning-cli --regtest --lightning-dir="$cdk_itests/cln/one/" stop
-    lightning-cli --regtest --lightning-dir="$cdk_itests/cln/two/" stop
-    bitcoin-cli --datadir="$cdk_itests/bitcoin"  -rpcuser=testuser -rpcpassword=testpass -rpcport=18443 stop
 
     # Remove the temporary directory
     rm -rf "$cdk_itests"
@@ -36,7 +37,6 @@ export cdk_itests_mint_addr="127.0.0.1";
 export cdk_itests_mint_port_0=8085;
 export cdk_itests_mint_port_1=8087;
 
-URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port_0/v1/info"
 # Check if the temporary directory was created successfully
 if [[ ! -d "$cdk_itests" ]]; then
     echo "Failed to create temp directory"
@@ -47,13 +47,102 @@ echo "Temp directory created: $cdk_itests"
 export MINT_DATABASE="$1";
 
 cargo build -p cdk-integration-tests 
-cargo build --bin regtest_mint 
-# cargo run --bin regtest_mint > "$cdk_itests/mint.log" 2>&1 &
-cargo run --bin regtest_mint &
+
+cargo run --bin start_regtest &
+
+cdk_regtest_pid=$!
+mkfifo "$cdk_itests/progress_pipe"
+rm -f "$cdk_itests/signal_received"  # Ensure clean state
+# Start reading from pipe in background
+(while read line; do
+    case "$line" in
+        "checkpoint1")
+            echo "Reached first checkpoint"
+            touch "$cdk_itests/signal_received"
+            exit 0
+            ;;
+    esac
+done < "$cdk_itests/progress_pipe") &
+# Wait for up to 120 seconds
+for ((i=0; i<120; i++)); do
+    if [ -f "$cdk_itests/signal_received" ]; then
+        echo "break signal received"
+        break
+    fi
+    sleep 1
+done
+echo "Regtest set up continuing"
+
+echo "Starting regtest mint"
+# cargo run --bin regtest_mint &
+
+export CDK_MINTD_CLN_RPC_PATH="$cdk_itests/cln/one/regtest/lightning-rpc";
+
+
+export CDK_MINTD_URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port_0";
+export CDK_MINTD_WORK_DIR="$cdk_itests";
+export CDK_MINTD_LISTEN_HOST=$cdk_itests_mint_addr;
+export CDK_MINTD_LISTEN_PORT=$cdk_itests_mint_port_0;
+export CDK_MINTD_LN_BACKEND="cln";
+export CDK_MINTD_MNEMONIC="eye survey guilt napkin crystal cup whisper salt luggage manage unveil loyal";
+export CDK_MINTD_DATABASE=$MINT_DATABASE;
+
+echo "Starting cln mintd";
+cargo run --bin cdk-mintd &
+cdk_mintd_pid=$!
+
 
 echo $cdk_itests
-# Capture its PID
-CDK_ITEST_MINT_BIN_PID=$!
+
+URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port_0/v1/info"
+
+TIMEOUT=100
+START_TIME=$(date +%s)
+# Loop until the endpoint returns a 200 OK status or timeout is reached
+while true; do
+    # Get the current time
+    CURRENT_TIME=$(date +%s)
+    
+    # Calculate the elapsed time
+    ELAPSED_TIME=$((CURRENT_TIME - START_TIME))
+
+    # Check if the elapsed time exceeds the timeout
+    if [ $ELAPSED_TIME -ge $TIMEOUT ]; then
+        echo "Timeout of $TIMEOUT seconds reached. Exiting..."
+        exit 1
+    fi
+
+    # Make a request to the endpoint and capture the HTTP status code
+    HTTP_STATUS=$(curl -o /dev/null -s -w "%{http_code}" $URL)
+
+    # Check if the HTTP status is 200 OK
+    if [ "$HTTP_STATUS" -eq 200 ]; then
+        echo "Received 200 OK from $URL"
+        break
+    else
+        echo "Waiting for 200 OK response, current status: $HTTP_STATUS"
+        sleep 2  # Wait for 2 seconds before retrying
+    fi
+done
+
+
+export CDK_MINTD_LND_ADDRESS="https://localhost:10010";
+export CDK_MINTD_LND_CERT_FILE="$cdk_itests/lnd/two/tls.cert";
+export CDK_MINTD_LND_MACAROON_FILE="$cdk_itests/lnd/two/data/chain/bitcoin/regtest/admin.macaroon";
+
+export CDK_MINTD_URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port_1";
+mkdir -p "$cdk_itests/lnd_mint"
+export CDK_MINTD_WORK_DIR="$cdk_itests/lnd_mint";
+export CDK_MINTD_LISTEN_HOST=$cdk_itests_mint_addr;
+export CDK_MINTD_LISTEN_PORT=$cdk_itests_mint_port_1;
+export CDK_MINTD_LN_BACKEND="lnd";
+export CDK_MINTD_MNEMONIC="eye survey guilt napkin crystal cup whisper salt luggage manage unveil loyal";
+
+echo "Starting lnd mintd";
+cargo run --bin cdk-mintd &
+cdk_mintd_lnd_pid=$!
+
+URL="http://$cdk_itests_mint_addr:$cdk_itests_mint_port_1/v1/info"
 
 TIMEOUT=100
 START_TIME=$(date +%s)
@@ -88,7 +177,7 @@ done
 # Run cargo test
 cargo test -p cdk-integration-tests --test regtest
 
-# # Run cargo test with the http_subscription feature
+# Run cargo test with the http_subscription feature
 cargo test -p cdk-integration-tests --test regtest --features http_subscription
 
 # Switch Mints: Run tests with LND mint