#![allow(warnings)] mod constants; mod errors; mod events; mod primary_market; mod registry; mod secondary_market; mod state; mod submit_tx; mod utils; use crate::events::websocket::ProgramEventListener; use crate::primary_market::balance_prover::run_setup::{ check_keys_exist, run_trusted_setup_automated, run_trusted_setup_interactive, validate_keys, }; use axum::{Router, routing::post}; use solana_sdk::pubkey::Pubkey; use state::AppState; use std::env; use std::str::FromStr; use tower_http::cors::{Any, CorsLayer}; #[tokio::main] async fn main() { // general config let rpc_url = env::var("RPC_URL").unwrap_or_else(|_| "http://127.0.0.1:8899".to_string()); let ws_url = env::var("WS_URL").unwrap_or_else(|_| "ws://127.0.0.1:8900".to_string()); let program_id = env::var("PROGRAM_ID") .unwrap_or_else(|_| "ACebqkxGWfinRtBEEwUXVipt9A5A7WVtH14vXN8AXDr4".to_string()); let port = env::var("PORT").unwrap_or_else(|_| "3001".to_string()); // ZK-SNARK setup config let skip_zk_setup = env::var("SKIP_ZK_SETUP") .unwrap_or_else(|_| "false".to_string()) .to_lowercase() == "true"; let force_zk_setup = env::var("FORCE_ZK_SETUP") .unwrap_or_else(|_| "false".to_string()) .to_lowercase() == "true"; // Init app state (handles ZK setup internally) let state = AppState::new(&rpc_url, &program_id, skip_zk_setup, force_zk_setup) .expect("Failed to initialize app state"); // Warn if ZK keys not available if !state.has_zk_keys() { println!("⚠️ WARNING: ZK-SNARK keys not available!"); println!(" Primary market endpoints will return errors."); } //cors - only in prod; TODO: fix this let cors = CorsLayer::new() .allow_origin(Any) .allow_methods(Any) .allow_headers(Any); let program_pubkey = Pubkey::from_str(&program_id).expect("Invalid PROGRAM_ID format"); let event_listener = ProgramEventListener::new( program_pubkey, ws_url, state.clone(), // Pass AppState to listener ); // Spawn the listener in a separate task tokio::spawn(async move { if let Err(e) = event_listener.start().await { eprintln!("Event listener error: {}", e); } }); // Build router with all routes let app = Router::new() .route("/api/submit-tx", post(submit_tx::submit_transaction)) // secondary market routes .route( "/api/secondary-market/deposit-usdc", post(secondary_market::handlers::deposit_usdc::create_deposit_usdc_transaction), ) .route( "/api/secondary-market/withdraw-usdc", post(secondary_market::handlers::withdraw_usdc::create_withdraw_usdc_transaction), ) .route( "/api/secondary-market/initialize-market", post( secondary_market::handlers::initialize_market::create_initialize_market_transaction, ), ) .route( "/api/secondary-market/place-order", post(secondary_market::handlers::place_order::create_place_order_transaction), ) .route( "/api/secondary-market/cancel-order", post(secondary_market::handlers::cancel_order::create_cancel_order_transaction), ) // registry routes .route( "/api/registry/initialize-registry", post(registry::handlers::create_initialize_registry_transaction), ) .route( "/api/registry/register-local-admin", post(registry::handlers::create_register_local_admin_transaction), ) .route( "/api/registry/register-company", post(registry::handlers::create_register_company_transaction), ) .route( "/api/registry/mint-eua", post(registry::handlers::create_mint_eua_to_vault_transaction), ) .route( "/api/registry/mint-eua-to-local-admin", post(registry::handlers::create_mint_eua_to_local_admin_transaction), ) .route( "/api/registry/mint-ghg", post(registry::handlers::create_mint_ghg_to_vault_transaction), ) .route( "/api/registry/transfer-eua", post(registry::handlers::create_transfer_between_vaults_transaction), ) .route( "/api/registry/update-company-status", post(registry::handlers::create_update_company_status_transaction), ) .route( "/api/registry/update-local-admin-status", post(registry::handlers::create_update_local_admin_status_transaction), ) .route( "/api/primary-market/initialize-primary-market", post(primary_market::handlers::create_initialize_primary_market_transaction), ) .route( "/api/primary-market/initialize-vk", post(primary_market::handlers::create_initialize_vk_transaction), ) .route( "/api/primary-market/verify-balance", post(primary_market::handlers::create_verify_balance_transaction), ) .route( "/api/primary-market/publish-auction", post(primary_market::handlers::create_publish_auction_transaction), ) .route( "/api/primary-market/start-auction", post(primary_market::handlers::create_start_auction_transaction), ) .route( "/api/primary-market/join-auction", post(primary_market::handlers::create_join_auction_transaction), ) .route( "/api/primary-market/place-bid", post(primary_market::handlers::create_place_bid_transaction), ) .route( "/api/primary-market/cancel-bid", post(primary_market::handlers::create_cancel_bid_transaction), ) .route( "/api/primary-market/leave-auction", post(primary_market::handlers::create_leave_auction_transaction), ) .layer(cors) .with_state(state); // Start server let addr = format!("0.0.0.0:{}", port); let listener = tokio::net::TcpListener::bind(&addr) .await .expect("failed to bind to address"); println!("server running on http://{}", addr); axum::serve(listener, app) .await .expect("server failed to start"); }