aldabra/crates/aldabra-chain/src/lib.rs
Kayos a42043dec4 docs: scrub internal host references from public docs
Removed mentions of Rackham + Sulkta-runs-its-own-Koios claims from
README + module doc-comments + Cargo.toml descriptions. aldabra works
against any Koios endpoint — public api.koios.rest, preprod/preview,
or operator-self-hosted — so the docs now reflect that capability
neutrally instead of advertising our internal infra.
2026-05-10 18:24:57 -07:00

98 lines
3.5 KiB
Rust

//! aldabra chain backends — Koios first, Ogmios next.
//!
//! Trait-first design: the MCP server depends on [`ChainBackend`], not
//! on a specific implementation. Swapping Koios → Ogmios is a config
//! change.
//!
//! Phase 1: read-only queries (`get_utxos`, `get_balance`) against
//! Koios over HTTPS.
//!
//! Phase 2 (TODO): submission paths — `submit_tx`, `tx_status`.
//!
//! ## Backends
//!
//! - [`koios::KoiosClient`] — Koios REST client (POST `/address_utxos`,
//! `/address_info`). Points at any Koios endpoint —
//! `https://api.koios.rest/api/v1` for the public mainnet instance,
//! the preprod/preview equivalents for testnets, or a self-hosted
//! Koios at any URL.
//! - Ogmios (TODO) — websocket client.
use serde::{Deserialize, Serialize};
use thiserror::Error;
pub mod koios;
pub use koios::KoiosClient;
#[derive(Debug, Error)]
pub enum ChainError {
#[error("network error: {0}")]
Network(String),
#[error("backend returned malformed response: {0}")]
Decode(String),
#[error("not yet implemented (phase 1 scaffold)")]
NotYetImplemented,
}
/// One UTXO at an address. Multi-asset bundle is a flat map of
/// `policy_id || asset_name_hex` → quantity for now. We'll model it
/// more strictly when minting lands in phase 3.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Utxo {
pub tx_hash: String,
pub output_index: u32,
pub lovelace: u64,
/// Hex-encoded `policy_id || asset_name_hex` → quantity.
/// Empty for plain ADA UTXOs.
pub assets: std::collections::BTreeMap<String, u64>,
}
/// Aggregated balance at an address.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Balance {
pub lovelace: u64,
pub assets: std::collections::BTreeMap<String, u64>,
}
/// Confirmation status of a submitted transaction.
///
/// `NotFound` covers two cases the chain backend can't easily
/// distinguish: the tx is in some mempool but not yet indexed by
/// Koios, or it was never submitted / was rejected. Treat
/// `NotFound` as "keep polling" up to a reasonable timeout, after
/// which give up.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum TxStatus {
/// Confirmed on-chain with `num_confirmations` blocks built on
/// top of it (1 = just landed, ~15 = practically final on
/// preprod, ≥3 stake-pool epochs = absolute finality on mainnet).
Confirmed { num_confirmations: u64 },
/// Koios's `/tx_status` returned a record for this tx but with
/// `num_confirmations: null` — the tx is known to the backend
/// (some node accepted it) but is not yet in a block.
Pending,
/// Not seen by the chain backend (not in any node's pool,
/// not confirmed, possibly never submitted or rejected).
NotFound,
}
#[async_trait::async_trait]
pub trait ChainBackend: Send + Sync {
/// All UTXOs at the given address.
async fn get_utxos(&self, address: &str) -> Result<Vec<Utxo>, ChainError>;
/// Aggregated ADA + native-asset balance at the address.
async fn get_balance(&self, address: &str) -> Result<Balance, ChainError>;
/// Submit a signed transaction. `raw_tx_cbor` is the binary CBOR
/// payload of the signed tx; on success returns the tx hash as
/// a hex string.
async fn submit_tx(&self, raw_tx_cbor: &[u8]) -> Result<String, ChainError>;
/// Poll the chain backend for a tx's current confirmation status.
async fn tx_status(&self, tx_hash: &str) -> Result<TxStatus, ChainError>;
}