ido: add /<id>/aggregates endpoint for entry totals

Sum demand/supply amounts and count entries for an IDO, used to show
"raised so far" for active offerings where on-chain state keeps no
running total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hossein Zoda 2026-06-11 01:27:33 +00:00
parent a410aee95f
commit aec0a6f0f8
3 changed files with 48 additions and 0 deletions

View file

@ -2709,6 +2709,34 @@ pub async fn list_ido_entries(
.collect()
}
#[derive(Serialize, Clone)]
pub struct IdoEntryAggregatesRpc {
pub total_demand_amount: i64,
pub total_supply_amount: i64,
pub entry_count: i64,
}
/// Aggregate totals over an IDO's entries. Used to show "raised so far" for
/// ACTIVE offerings, where on-chain state keeps no running total.
pub async fn get_ido_entry_aggregates(
pool: &SqlitePool,
internal_id: i64,
) -> Result<IdoEntryAggregatesRpc> {
let row = sqlx::query(
"SELECT COALESCE(SUM(demand_amount), 0) AS total_demand_amount, \
COALESCE(SUM(supply_amount), 0) AS total_supply_amount, \
COUNT(*) AS entry_count FROM ido_entry WHERE ido_id = ?",
)
.bind(internal_id)
.fetch_one(pool)
.await?;
Ok(IdoEntryAggregatesRpc {
total_demand_amount: row.get(0),
total_supply_amount: row.get(1),
entry_count: row.get(2),
})
}
pub async fn list_ido_txchain(
pool: &SqlitePool,
internal_id: i64,

View file

@ -575,6 +575,7 @@ async fn launch() -> _ {
rpc::ido::get_ido_by_id,
rpc::ido::get_ido_by_offering_token,
rpc::ido::list_ido_entries,
rpc::ido::get_ido_entries_aggregates,
rpc::ido::get_txchain_tx,
];
// Debug-only IDO endpoints, mounted only when `debug = true` in the config.

View file

@ -122,6 +122,25 @@ pub async fn list_ido_entries(
Ok(cached_ok(serde_json::to_value(items).unwrap(), CACHE_NONE))
}
/// Aggregate totals over an IDO's entries (summed demand/supply and count).
///
/// - `id`: the IDO's public id (preinit txid, 64-char hex)
///
/// Returns `{"total_demand_amount", "total_supply_amount", "entry_count"}`.
#[get("/<id>/aggregates")]
pub async fn get_ido_entries_aggregates(
id: &str,
db: &State<DB>,
) -> CachedApiResult<Value> {
let (internal_id, _preinit_txid_hex) = resolve_ido(id, &db.ido_r).await?;
let agg = crate::db::ido::get_ido_entry_aggregates(&db.ido_r, internal_id)
.await
.map_err(db_error)?;
Ok(cached_ok(serde_json::to_value(agg).unwrap(), CACHE_NONE))
}
/// Get the raw transaction hex for a txchain item by its txid.
/// Returns `{"tx": "<hex>"}` or `{"tx": null}` if not found.
#[get("/txchain/<txid>/tx")]