Skip to main content

haima_api/
lib.rs

1//! HTTP API for Haima — wallet, balance, transactions, payment endpoints.
2//!
3//! Endpoints:
4//! - `GET /health` — health check (public, no auth)
5//! - `GET /state` — get full financial state projection (protected)
6//! - `POST /v1/facilitate` — x402 payment facilitation (public)
7//! - `GET /v1/facilitator/stats` — facilitator dashboard stats (public)
8//! - `GET /v1/bureau/:agent_id` — agent credit bureau report (public)
9//!
10//! Auth is controlled via `HAIMA_JWT_SECRET` or `AUTH_SECRET` env var.
11//! If neither is set, auth is disabled (local dev mode).
12
13pub mod auth;
14pub mod insurance;
15pub mod outcome;
16pub mod routes;
17
18use std::collections::HashMap;
19use std::sync::Arc;
20
21use axum::Router;
22use haima_core::bureau::{PaymentHistory, TrustContext};
23use haima_core::credit::CreditScore;
24use haima_core::lending::CreditLine;
25use haima_lago::{FinancialState, InsuranceState, OutcomePricingState};
26use haima_outcome::OutcomeEngine;
27use haima_x402::FacilitatorStatsCounter;
28use tokio::sync::RwLock;
29
30use crate::auth::AuthConfig;
31
32/// Shared application state for the Haima API.
33#[derive(Clone)]
34pub struct AppState {
35    pub financial_state: Arc<RwLock<FinancialState>>,
36    pub auth_config: Arc<AuthConfig>,
37    /// In-memory facilitator statistics counter.
38    pub facilitator_stats: Arc<FacilitatorStatsCounter>,
39    /// Facilitator fee in basis points.
40    pub facilitator_fee_bps: u32,
41    /// In-memory credit score cache, keyed by `agent_id`.
42    pub credit_scores: Arc<RwLock<HashMap<String, CreditScore>>>,
43    /// In-memory credit lines, keyed by `agent_id`.
44    pub credit_lines: Arc<RwLock<HashMap<String, CreditLine>>>,
45    /// In-memory trust context cache, keyed by `agent_id` (from Autonomic).
46    pub trust_contexts: Arc<RwLock<HashMap<String, TrustContext>>>,
47    /// In-memory payment history cache, keyed by `agent_id`.
48    pub payment_histories: Arc<RwLock<HashMap<String, PaymentHistory>>>,
49    /// Outcome-based pricing state (contracts, task stats, pending tasks).
50    pub outcome_state: Arc<RwLock<OutcomePricingState>>,
51    /// Outcome pricing engine (contract → verify → bill → refund orchestrator).
52    pub outcome_engine: Arc<RwLock<OutcomeEngine>>,
53    /// Insurance marketplace state (products, policies, claims, pool).
54    pub insurance_state: Arc<RwLock<InsuranceState>>,
55}
56
57impl AppState {
58    /// Create a new `AppState` with the given auth config and default financial state.
59    pub fn new(auth_config: AuthConfig) -> Self {
60        let outcome_state = Arc::new(RwLock::new(OutcomePricingState::default()));
61        let financial_state = Arc::new(RwLock::new(FinancialState::default()));
62        let engine = OutcomeEngine::new(Arc::clone(&outcome_state), Arc::clone(&financial_state));
63
64        Self {
65            financial_state,
66            auth_config: Arc::new(auth_config),
67            facilitator_stats: Arc::new(FacilitatorStatsCounter::new()),
68            facilitator_fee_bps: haima_x402::DEFAULT_FEE_BPS,
69            credit_scores: Arc::new(RwLock::new(HashMap::new())),
70            credit_lines: Arc::new(RwLock::new(HashMap::new())),
71            trust_contexts: Arc::new(RwLock::new(HashMap::new())),
72            payment_histories: Arc::new(RwLock::new(HashMap::new())),
73            outcome_state,
74            outcome_engine: Arc::new(RwLock::new(engine)),
75            insurance_state: Arc::new(RwLock::new(InsuranceState::default())),
76        }
77    }
78
79    /// Create a new `AppState` with the insurance marketplace bootstrapped
80    /// (default pool with seed reserves, products, self-insurance provider,
81    /// and a licensed MGA provider stub).
82    #[allow(clippy::field_reassign_with_default)]
83    pub fn with_insurance(auth_config: AuthConfig) -> Self {
84        let pool_id = "life-network-pool";
85        let mut pool = haima_core::marketplace::create_pool(
86            pool_id,
87            "Life Network Self-Insurance Pool",
88            250, // 2.5% management fee
89        );
90        // Seed the pool with initial reserves ($100 = 100M micro-USD).
91        // In production this would come from network funding events.
92        haima_core::marketplace::contribute_to_pool(&mut pool, 100_000_000);
93
94        let products = haima_core::marketplace::default_products(pool_id);
95        let pool_provider = haima_core::marketplace::default_pool_provider(pool_id);
96
97        // Register a licensed MGA (Managing General Agent) provider stub.
98        // This represents a partnership with a licensed insurer for higher-tier
99        // coverage that exceeds the self-insurance pool's capacity.
100        let mga_provider = haima_core::insurance::InsuranceProvider {
101            provider_id: "mga-aegis-underwriters".to_string(),
102            name: "Aegis AI Underwriters MGA".to_string(),
103            provider_type: haima_core::insurance::ProviderType::LicensedInsurer,
104            offered_products: vec![
105                haima_core::insurance::InsuranceProductType::FinancialError,
106                haima_core::insurance::InsuranceProductType::DataBreach,
107            ],
108            commission_rate_bps: 2000, // 20% facilitation commission
109            active: true,
110            api_endpoint: Some("https://api.aegis-underwriters.example/v1".to_string()),
111            registered_at: chrono::Utc::now(),
112        };
113
114        let mut products_map = std::collections::HashMap::new();
115        for p in products {
116            products_map.insert(p.product_id.clone(), p);
117        }
118        let mut providers_map = std::collections::HashMap::new();
119        providers_map.insert(pool_provider.provider_id.clone(), pool_provider);
120        providers_map.insert(mga_provider.provider_id.clone(), mga_provider);
121        let insurance = InsuranceState {
122            pool: Some(pool),
123            products: products_map,
124            providers: providers_map,
125            ..Default::default()
126        };
127
128        let outcome_state = Arc::new(RwLock::new(OutcomePricingState::default()));
129        let financial_state = Arc::new(RwLock::new(FinancialState::default()));
130        let engine = OutcomeEngine::new(Arc::clone(&outcome_state), Arc::clone(&financial_state));
131
132        Self {
133            financial_state,
134            auth_config: Arc::new(auth_config),
135            facilitator_stats: Arc::new(FacilitatorStatsCounter::new()),
136            facilitator_fee_bps: haima_x402::DEFAULT_FEE_BPS,
137            credit_scores: Arc::new(RwLock::new(HashMap::new())),
138            credit_lines: Arc::new(RwLock::new(HashMap::new())),
139            trust_contexts: Arc::new(RwLock::new(HashMap::new())),
140            payment_histories: Arc::new(RwLock::new(HashMap::new())),
141            outcome_state,
142            outcome_engine: Arc::new(RwLock::new(engine)),
143            insurance_state: Arc::new(RwLock::new(insurance)),
144        }
145    }
146}
147
148impl Default for AppState {
149    fn default() -> Self {
150        let outcome_state = Arc::new(RwLock::new(OutcomePricingState::default()));
151        let financial_state = Arc::new(RwLock::new(FinancialState::default()));
152        let engine = OutcomeEngine::new(Arc::clone(&outcome_state), Arc::clone(&financial_state));
153
154        Self {
155            financial_state,
156            auth_config: Arc::new(AuthConfig { jwt_secret: None }),
157            facilitator_stats: Arc::new(FacilitatorStatsCounter::new()),
158            facilitator_fee_bps: haima_x402::DEFAULT_FEE_BPS,
159            credit_scores: Arc::new(RwLock::new(HashMap::new())),
160            credit_lines: Arc::new(RwLock::new(HashMap::new())),
161            trust_contexts: Arc::new(RwLock::new(HashMap::new())),
162            payment_histories: Arc::new(RwLock::new(HashMap::new())),
163            outcome_state,
164            outcome_engine: Arc::new(RwLock::new(engine)),
165            insurance_state: Arc::new(RwLock::new(InsuranceState::default())),
166        }
167    }
168}
169
170/// Build the Haima API router.
171pub fn router(state: AppState) -> Router {
172    let outcome = outcome::outcome_routes(state.clone());
173    let insurance = insurance::insurance_routes(state.clone());
174    routes::routes(state).merge(outcome).merge(insurance)
175}