// Copyright (C) 2025-2026 Whiterun LLC // // 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 std::collections::HashMap; use anyhow::Result; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rocket::{get, State}; use rusqlite::Connection; use serde_json::{json, Value}; use crate::db::{ cauldron::poolvisitor::{ db_visit_pool_entries, OptionalFields, OptionalPoolFields, PoolFilters, PoolVisitor, }, DB, }; use crate::rpc::err::{db_error, CachedApiResult}; use crate::rpc::response::{cached_ok, CACHE_AGGREGATE, CACHE_IMMUTABLE}; #[derive(Default)] pub struct TvlByTokenVisitor { tvl: HashMap, } impl TvlByTokenVisitor { pub fn into_map(self) -> HashMap { self.tvl } } impl PoolVisitor for TvlByTokenVisitor { fn optional_fields_wanted(&self) -> u64 { OptionalPoolFields::TokenId as u64 } fn visit(&mut self, sats: u64, tokens: u64, optional_fields: OptionalFields) -> Result { let token_id = optional_fields.token_id.unwrap(); let entry = self.tvl.entry(token_id).or_insert((0u64, 0u64)); entry.0 += sats; entry.1 += tokens; Ok(true) } } #[derive(Default)] struct TvlVisitor { sats: u64, tokens: u64, } impl PoolVisitor for TvlVisitor { fn optional_fields_wanted(&self) -> u64 { 0 } fn visit(&mut self, sats: u64, tokens: u64, _optional_fields: OptionalFields) -> Result { self.sats += sats; self.tokens += tokens; Ok(true) } } #[derive(Default)] struct TvlSatsOnlyVisitor { sats: u64, } impl PoolVisitor for TvlSatsOnlyVisitor { fn optional_fields_wanted(&self) -> u64 { 0 } fn visit(&mut self, sats: u64, _tokens: u64, _optional_fields: OptionalFields) -> Result { self.sats += sats; Ok(true) } } /// Fetch TVL for all tokens by token id (deprecated) pub fn deprecated_get_all_token_tvl( connection: &Connection, max_timestamp: usize, ) -> Result> { let mut visitor = TvlByTokenVisitor::default(); db_visit_pool_entries( connection, &mut visitor, PoolFilters { timestamp_lt: Some(max_timestamp as u64), timestamp_lte: None, timestamp_gt: None, timestamp_gte: None, token_id: None, owner: None, }, )?; Ok(visitor.tvl) } /// Fetch sats side of TVL for all tokens pub fn get_total_sats_tvl(connection: &Connection, max_timestamp: Option) -> Result { let mut visitor = TvlSatsOnlyVisitor::default(); db_visit_pool_entries( connection, &mut visitor, PoolFilters { timestamp_lt: max_timestamp.map(|t| t as u64), timestamp_lte: None, timestamp_gt: None, timestamp_gte: None, token_id: None, owner: None, }, )?; Ok(visitor.sats) } /// Get TVL for a single token pub fn get_token_tvl( connection: &Connection, max_timestamp: Option, token_id: &str, ) -> Result<(u64, u64)> { let mut visitor = TvlVisitor::default(); db_visit_pool_entries( connection, &mut visitor, PoolFilters { timestamp_lt: max_timestamp.map(|t| t as u64), timestamp_lte: None, timestamp_gt: None, timestamp_gte: None, token_id: Some(token_id.to_string()), owner: None, }, )?; Ok((visitor.sats, visitor.tokens)) } /// Status: Deprecated /// use valuelocked with optional parameters /// used by defilama; fix adapter before removing #[get("/tvl/