riftenlabs-indexer/src/db/cauldron/tokenlist/list_cached.rs

229 lines
7.3 KiB
Rust
Raw Normal View History

2026-01-21 12:34:59 +01:00
// Copyright (C) 2024-2026 Whiterun LLC
2025-09-05 13:53:10 +00:00
//
// This software is licensed under the GNU Affero General Public License (AGPL), version 3.0 or later.
// A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/agpl-3.0.html
use anyhow::Result;
use rusqlite::{params_from_iter, Connection};
use crate::bcmr::parsedbcmr::ParsedBCMR;
use crate::db::bcmr::{get_token_bcmr, get_well_known_bcmr};
use crate::db::cauldron::tokenlist::db_utils::{order_clause, CachedSort};
#[derive(Serialize)]
pub struct TokenListItemCached {
pub token_id: String,
pub trade_volume: u64,
pub tvl_sats: u64,
pub tvl_tokens: u64,
pub bcmr_well_known: Vec<ParsedBCMR>,
pub bcmr: Option<ParsedBCMR>,
pub trade_count: u64,
pub score: i64,
pub score_rank: i64,
2025-09-11 07:36:06 +00:00
pub price_now: f64, // NOT NULL
pub price_24h: Option<f64>, // NULL → None, 0.0 → Some(0.0)
pub price_7d: Option<f64>, // "
pub change_24h_bp: Option<i64>, // "
pub change_7d_bp: Option<i64>, // "
pub display_name: Option<String>, // NULL → None, "" → Some("")
pub display_symbol: Option<String>,
pub price_now_usd: f64, // NOT NULL
pub price_24h_usd: Option<f64>,
pub price_7d_usd: Option<f64>,
pub change_24h_usd_bp: Option<i64>,
pub change_7d_usd_bp: Option<i64>,
pub apy_30d_bp: Option<i64>,
2025-09-05 13:53:10 +00:00
}
const TOKEN_METRICS_COLUMNS: &str = r#"
hex(token_id) as token_id,
2025-09-05 13:53:10 +00:00
trade_volume,
tvl_sats,
tvl_tokens,
score,
price_now,
price_24h,
price_7d,
change_24h_bp,
change_7d_bp,
display_name,
display_symbol,
price_now_usd,
price_24h_usd,
price_7d_usd,
change_24h_usd_bp,
change_7d_usd_bp,
apy_30d_bp,
score_rank
"#;
pub fn db_list_tokens_cached(
cauldron_conn: &Connection,
bcmr_conn: &Connection,
limit: usize,
offset: usize,
sort: CachedSort,
) -> Result<Vec<TokenListItemCached>> {
let order_sql = order_clause(sort);
let sql = format!(
r#"
SELECT
{cols}
FROM cached_token_metrics
WHERE tvl_sats > 0
{order_sql}
LIMIT ?1 OFFSET ?2
"#,
cols = TOKEN_METRICS_COLUMNS,
order_sql = order_sql
);
let mut stmt = cauldron_conn.prepare(&sql)?;
let mut rows = stmt.query(rusqlite::params![limit as i64, offset as i64])?;
let mut tokens = Vec::with_capacity(limit);
while let Some(row) = rows.next()? {
let token_id: String = row.get::<_, String>("token_id")?.to_lowercase();
2025-09-05 13:53:10 +00:00
let trade_volume: u64 = row.get("trade_volume")?;
let tvl_sats: u64 = row.get::<_, i64>("tvl_sats")? as u64;
let tvl_tokens: u64 = row.get::<_, i64>("tvl_tokens")? as u64;
let score: i64 = row.get("score")?;
let price_now: f64 = row.get("price_now")?;
2025-09-11 07:36:06 +00:00
let price_24h: Option<f64> = row.get("price_24h")?;
let price_7d: Option<f64> = row.get("price_7d")?;
let change_24h_bp: Option<i64> = row.get("change_24h_bp")?;
let change_7d_bp: Option<i64> = row.get("change_7d_bp")?;
let display_name: Option<String> = row.get("display_name")?;
let display_symbol: Option<String> = row.get("display_symbol")?;
2025-09-05 13:53:10 +00:00
let price_now_usd: f64 = row.get("price_now_usd")?;
2025-09-11 07:36:06 +00:00
let price_24h_usd: Option<f64> = row.get("price_24h_usd")?;
let price_7d_usd: Option<f64> = row.get("price_7d_usd")?;
let change_24h_usd_bp: Option<i64> = row.get("change_24h_usd_bp")?;
let change_7d_usd_bp: Option<i64> = row.get("change_7d_usd_bp")?;
let apy_30d_bp: Option<i64> = row.get("apy_30d_bp")?;
2025-09-05 13:53:10 +00:00
let score_rank: i64 = row.get("score_rank")?;
let bcmr = get_token_bcmr(bcmr_conn, &token_id)?;
let bcmr_well_known = get_well_known_bcmr(bcmr_conn, &token_id)?;
tokens.push(TokenListItemCached {
token_id,
trade_volume,
tvl_sats,
tvl_tokens,
bcmr,
bcmr_well_known,
trade_count: 0,
score,
score_rank,
price_now,
price_24h,
price_7d,
change_24h_bp,
change_7d_bp,
display_name,
display_symbol,
price_now_usd,
price_24h_usd,
price_7d_usd,
change_24h_usd_bp,
change_7d_usd_bp,
apy_30d_bp,
});
}
Ok(tokens)
}
pub fn db_list_tokens_cached_by_ids(
cauldron_conn: &Connection,
bcmr_conn: &Connection,
token_ids: &[String],
sort: CachedSort,
) -> Result<Vec<TokenListItemCached>> {
if token_ids.is_empty() {
return Ok(vec![]);
}
let order_sql = order_clause(sort);
let placeholders = vec!["?"; token_ids.len()].join(",");
let sql = format!(
r#"
SELECT
{cols}
FROM cached_token_metrics
WHERE token_id IN ({ph}) AND tvl_sats > 0
{order_sql}
"#,
cols = TOKEN_METRICS_COLUMNS,
ph = placeholders,
order_sql = order_sql
);
let token_blobs: Vec<Vec<u8>> = token_ids
.iter()
.filter_map(|s| hex::decode(s).ok())
.collect();
2025-09-05 13:53:10 +00:00
let mut stmt = cauldron_conn.prepare(&sql)?;
let mut rows = stmt.query(params_from_iter(token_blobs.iter()))?;
2025-09-05 13:53:10 +00:00
let mut tokens = Vec::with_capacity(token_ids.len());
while let Some(row) = rows.next()? {
let token_id: String = row.get::<_, String>("token_id")?.to_lowercase();
2025-09-05 13:53:10 +00:00
let trade_volume: u64 = row.get("trade_volume")?;
let tvl_sats: u64 = row.get::<_, i64>("tvl_sats")? as u64;
let tvl_tokens: u64 = row.get::<_, i64>("tvl_tokens")? as u64;
let score: i64 = row.get("score")?;
2025-09-11 07:36:06 +00:00
2025-09-05 13:53:10 +00:00
let price_now: f64 = row.get("price_now")?;
2025-09-11 07:36:06 +00:00
let price_24h: Option<f64> = row.get("price_24h")?;
let price_7d: Option<f64> = row.get("price_7d")?;
let change_24h_bp: Option<i64> = row.get("change_24h_bp")?;
let change_7d_bp: Option<i64> = row.get("change_7d_bp")?;
let display_name: Option<String> = row.get("display_name")?;
let display_symbol: Option<String> = row.get("display_symbol")?;
2025-09-05 13:53:10 +00:00
let price_now_usd: f64 = row.get("price_now_usd")?;
2025-09-11 07:36:06 +00:00
let price_24h_usd: Option<f64> = row.get("price_24h_usd")?;
let price_7d_usd: Option<f64> = row.get("price_7d_usd")?;
let change_24h_usd_bp: Option<i64> = row.get("change_24h_usd_bp")?;
let change_7d_usd_bp: Option<i64> = row.get("change_7d_usd_bp")?;
let apy_30d_bp: Option<i64> = row.get("apy_30d_bp")?;
2025-09-05 13:53:10 +00:00
let score_rank: i64 = row.get("score_rank")?;
let bcmr = get_token_bcmr(bcmr_conn, &token_id)?;
let bcmr_well_known = get_well_known_bcmr(bcmr_conn, &token_id)?;
tokens.push(TokenListItemCached {
token_id,
trade_volume,
tvl_sats,
tvl_tokens,
bcmr,
bcmr_well_known,
trade_count: 0,
score,
score_rank,
price_now,
price_24h,
price_7d,
change_24h_bp,
change_7d_bp,
display_name,
display_symbol,
price_now_usd,
price_24h_usd,
price_7d_usd,
change_24h_usd_bp,
change_7d_usd_bp,
apy_30d_bp,
});
}
Ok(tokens)
}