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.
98 lines
3.5 KiB
Rust
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>;
|
|
}
|