// Copyright (C) 2024-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 bitcoincash::TokenID; use rocket::{get, State}; use serde_json::json; use serde_json::Value; use crate::db::DB; use crate::rpc::err::{bad_request, db_error, ApiErrorCode, CachedApiResult}; use crate::rpc::response::{cached_ok, CACHE_NONE}; /// Get the latest Cauldron transactions, optionally filtered by token. /// /// Status: Stable /// /// - limit: Maximum number of results (default: 100, max: 10000) /// - offset: Pagination offset (default: 0) /// - token: The 32 byte token ID to filter by (optional) /// /// Note: `blockhash` is `null` for unconfirmed transactions. /// `timestamp_guess` is an estimate derived from block time. /// /// **Response Example:** /// ```json /// [ /// { /// "txid": "94a933a0fa55093a0965eb867f1b9cac2bb07488ced4825bc31f86c9371f76aa", /// "blockhash": "000000000000000002b4e6c0a1f4b3d2e5c7f891a2b3c4d5e6f7a8b9c0d1e2f3", /// "timestamp_guess": 1709468902 /// } /// ] /// ``` #[get("/tx/latest?&&")] pub async fn tx_latest( limit: Option, offset: Option, token: Option<&str>, conn: &State, ) -> CachedApiResult { let limit = limit.unwrap_or(100).min(10000); let offset = offset.unwrap_or(0); let token = match token { None => None, Some(tokenhex) => match tokenhex.parse::() { Ok(token) => Some(token), Err(_) => { return Err(bad_request( ApiErrorCode::InvalidTokenId, "Invalid token ID", )) } }, }; let txs = crate::db::cauldron::tx::latest(&conn.cauldron_r, limit, offset, token) .await .map_err(db_error)?; let txs_json: Vec = txs .into_iter() .map(|tx| { json!({ "txid": tx.0.to_string(), "blockhash": tx.1.map(|blockhex| blockhex.to_string()), "timestamp_guess": tx.2 }) }) .collect(); Ok(cached_ok(json!(txs_json), CACHE_NONE)) }