diff --git a/src/db/cauldron/tokentoken.rs b/src/db/cauldron/tokentoken.rs index 95b7f51..473c8f0 100644 --- a/src/db/cauldron/tokentoken.rs +++ b/src/db/cauldron/tokentoken.rs @@ -439,6 +439,60 @@ pub async fn db_active_pools_for_pair( Ok(out) } +/// Every active pool (`withdrawn_in_txid IS NULL`) at its latest state, with no +/// pair filter. Drives the frontend pooled-pair selector, which needs the full +/// set of pools to show which token pairs have liquidity (without probing each +/// candidate pair individually). +pub async fn db_all_active_pools(pool: &SqlitePool) -> Result> { + let rows = sqlx::query( + "SELECT p.creation_utxo, p.nft_owner, p.token_a_id, p.token_b_id, p.fee_rate, p.min_fee, + phe.reserve_a, phe.reserve_b, phe.main_sats, phe.storage_sats, + phe.txid, phe.tx_pos, phe.storage_tx_pos + FROM tokentoken_pool p + JOIN tokentoken_pool_history_entry phe ON phe.pool = p.creation_utxo + AND phe.sequence = ( + SELECT MAX(sequence) FROM tokentoken_pool_history_entry WHERE pool = p.creation_utxo + ) + WHERE p.withdrawn_in_txid IS NULL", + ) + .fetch_all(pool) + .await?; + + let mut out = Vec::with_capacity(rows.len()); + for row in rows { + let pool_blob: Vec = row.get(0); + let nft_owner_blob: Vec = row.get(1); + let token_a_blob: Vec = row.get(2); + let token_b_blob: Vec = row.get(3); + let fee_rate: i64 = row.get(4); + let min_fee: i64 = row.get(5); + let reserve_a: i64 = row.get(6); + let reserve_b: i64 = row.get(7); + let main_sats: i64 = row.get(8); + let storage_sats: i64 = row.get(9); + let txid_blob: Vec = row.get(10); + let tx_pos: i64 = row.get(11); + let storage_tx_pos: i64 = row.get(12); + + out.push(ActiveTokenTokenPool { + pool_id: blob_to_display_hex::(&pool_blob)?, + nft_owner: hex::encode(&nft_owner_blob), + token_a_id: blob_to_display_hex::(&token_a_blob)?, + token_b_id: blob_to_display_hex::(&token_b_blob)?, + reserve_a: reserve_a as u64, + reserve_b: reserve_b as u64, + fee_rate: fee_rate as u32, + min_fee: min_fee as u64, + main_sats: main_sats as u64, + storage_sats: storage_sats as u64, + txid: blob_to_display_hex::(&txid_blob)?, + main_vout: tx_pos as u32, + storage_vout: storage_tx_pos as u32, + }); + } + Ok(out) +} + /// Distinct token ids that appear in at least one active TokenToken pool. pub async fn db_pair_tokens(pool: &SqlitePool) -> Result> { let rows = sqlx::query( diff --git a/src/main.rs b/src/main.rs index 1f1fcaf..894f123 100644 --- a/src/main.rs +++ b/src/main.rs @@ -630,6 +630,7 @@ async fn launch() -> _ { "/tokentoken", routes![ rpc::tokentoken::list_active_pools, + rpc::tokentoken::list_all_pools, rpc::tokentoken::list_tokens, ], ) diff --git a/src/rpc/tokentoken.rs b/src/rpc/tokentoken.rs index c92c43a..d128cf6 100644 --- a/src/rpc/tokentoken.rs +++ b/src/rpc/tokentoken.rs @@ -7,7 +7,7 @@ use crate::{ db::{ - cauldron::tokentoken::{db_active_pools_for_pair, db_pair_tokens}, + cauldron::tokentoken::{db_active_pools_for_pair, db_all_active_pools, db_pair_tokens}, DB, }, rpc::err::{bad_request, db_error, ApiErrorCode, CachedApiResult}, @@ -67,3 +67,15 @@ pub async fn list_tokens(conn: &State) -> CachedApiResult { let tokens = db_pair_tokens(&conn.cauldron_r).await.map_err(db_error)?; Ok(cached_ok(json!({ "tokens": tokens }), CACHE_AGGREGATE)) } + +/// List ALL active TokenToken pools, regardless of pair — every pool at its +/// latest state. Drives the frontend pooled-pair selector, so it can present the +/// token pairs that have liquidity (with which token is A/main vs B/storage) +/// without probing each candidate pair individually. +#[get("/pools")] +pub async fn list_all_pools(conn: &State) -> CachedApiResult { + let active = db_all_active_pools(&conn.cauldron_r) + .await + .map_err(db_error)?; + Ok(cached_ok(json!({ "active": active }), CACHE_NONE)) +}