//! Comprehensive Demo for polyfill-rs //! //! This example demonstrates all the major functions and capabilities of the polyfill-rs library: //! - Basic client operations and API calls //! - Order book management and analytics //! - Real-time streaming capabilities //! - Trade execution and fill processing //! - Utility functions and mathematical operations //! - Error handling and retry logic //! - Rate limiting and performance optimizations use polyfill_rs::{ // Core client types ClobClient, PolyfillClient, OrderArgs, Side, OrderType, // Order book management book::{OrderBook, OrderBookManager}, // Streaming capabilities stream::{WebSocketStream, StreamManager}, // Fill execution fill::{FillEngine, FillProcessor}, // Types and structures types::*, // Error handling errors::{PolyfillError, Result}, // Utility functions utils::{crypto, math, retry, time, url, rate_limit, address}, // Configuration ClientConfig, }; use rust_decimal::Decimal; use rust_decimal_macros::dec; use std::time::Duration; use tokio::time::sleep; use tracing::{error, info, debug}; /// Comprehensive demo showcasing all polyfill-rs functionality pub struct PolyfillDemo { /// Basic HTTP client client: ClobClient, /// Advanced client with configuration advanced_client: PolyfillClient, /// Order book manager book_manager: OrderBookManager, /// Fill engine for trade execution fill_engine: FillEngine, /// Fill processor for handling fills fill_processor: FillProcessor, /// Stream manager for real-time data stream_manager: StreamManager, /// Rate limiter rate_limiter: rate_limit::TokenBucket, /// Statistics stats: DemoStats, } /// Demo statistics #[derive(Debug, Clone)] pub struct DemoStats { pub api_calls: u64, pub orders_processed: u64, pub fills_processed: u64, pub stream_messages: u64, pub errors: u64, pub total_volume: Decimal, } impl Default for DemoStats { fn default() -> Self { Self { api_calls: 0, orders_processed: 0, fills_processed: 0, stream_messages: 0, errors: 0, total_volume: dec!(0), } } } impl PolyfillDemo { /// Create a new comprehensive demo pub fn new() -> Result { // Create basic client let client = ClobClient::new("https://clob.polymarket.com"); // Create advanced client with configuration let _config = ClientConfig { base_url: "https://clob.polymarket.com".to_string(), chain_id: 137, // Polygon private_key: None, // Would be set in production api_credentials: None, // Would be set in production max_slippage: Some(dec!(0.01)), // 1% max slippage fee_rate: Some(dec!(0.02)), // 2% fee rate timeout: Some(Duration::from_secs(30)), max_connections: Some(100), }; let advanced_client = PolyfillClient::new("https://clob.polymarket.com"); // Create order book manager let book_manager = OrderBookManager::new(100); // Create fill engine let fill_engine = FillEngine::new( dec!(1.0), // Min fill size dec!(2.0), // Max slippage 2% 5, // 5 bps fee rate ); // Create fill processor let fill_processor = FillProcessor::new(1000); // Create stream manager let stream_manager = StreamManager::new(); // Create rate limiter (100 requests per second) let rate_limiter = rate_limit::TokenBucket::new(100, 100); Ok(Self { client, advanced_client, book_manager, fill_engine, fill_processor, stream_manager, rate_limiter, stats: DemoStats::default(), }) } /// Demo 1: Basic API Operations pub async fn demo_basic_api_operations(&mut self) -> Result<()> { info!("=== Demo 1: Basic API Operations ==="); // Test connectivity let is_ok = self.client.get_ok().await; info!("API connectivity: {}", is_ok); self.stats.api_calls += 1; // Get server time match self.client.get_server_time().await { Ok(timestamp) => { info!("Server time: {}", timestamp); self.stats.api_calls += 1; } Err(e) => { error!("Failed to get server time: {}", e); self.stats.errors += 1; } } // Get sampling markets match self.client.get_sampling_markets(None).await { Ok(markets) => { info!("Found {} markets", markets.data.len()); for market in &markets.data[..std::cmp::min(3, markets.data.len())] { info!(" Market: {} - {}", market.question, market.market_slug); } self.stats.api_calls += 1; } Err(e) => { error!("Failed to get markets: {}", e); self.stats.errors += 1; } } Ok(()) } /// Demo 2: Order Book Operations pub async fn demo_order_book_operations(&mut self) -> Result<()> { info!("=== Demo 2: Order Book Operations ==="); // Example token ID (you would use a real one in production) let token_id = "12345"; // Get order book from API match self.client.get_order_book(token_id).await { Ok(order_book) => { info!("Order book for token {}: {} bids, {} asks", token_id, order_book.bids.len(), order_book.asks.len()); // Create local order book let mut local_book = OrderBook::new(token_id.to_string(), 50); // Apply order book data to local book for (i, bid) in order_book.bids.iter().enumerate() { local_book.apply_delta(OrderDelta { token_id: token_id.to_string(), timestamp: chrono::Utc::now(), side: Side::BUY, price: bid.price, size: bid.size, sequence: i as u64, })?; } for (i, ask) in order_book.asks.iter().enumerate() { local_book.apply_delta(OrderDelta { token_id: token_id.to_string(), timestamp: chrono::Utc::now(), side: Side::SELL, price: ask.price, size: ask.size, sequence: (order_book.bids.len() + i) as u64, })?; } // Get analytics let analytics = local_book.analytics(); info!("Book analytics:"); info!(" Bid levels: {}, Ask levels: {}", analytics.bid_count, analytics.ask_count); info!(" Total bid size: {}, Total ask size: {}", analytics.total_bid_size, analytics.total_ask_size); if let Some(spread) = analytics.spread { info!(" Spread: {} ({:.2}%)", spread, analytics.spread_pct.unwrap_or(dec!(0))); } if let Some(mid) = analytics.mid_price { info!(" Mid price: {}", mid); } // Calculate market impact if let Some(impact) = local_book.calculate_market_impact(Side::BUY, dec!(100.0)) { info!("Market impact for 100 size buy:"); info!(" Average price: {}", impact.average_price); info!(" Impact: {:.2}%", impact.impact_pct); info!(" Total cost: {}", impact.total_cost); } self.stats.api_calls += 1; } Err(e) => { error!("Failed to get order book: {}", e); self.stats.errors += 1; } } Ok(()) } /// Demo 3: Market Data Operations pub async fn demo_market_data_operations(&mut self) -> Result<()> { info!("=== Demo 3: Market Data Operations ==="); let token_id = "12345"; // Get midpoint match self.client.get_midpoint(token_id).await { Ok(midpoint) => { info!("Midpoint for {}: {}", token_id, midpoint.mid); self.stats.api_calls += 1; } Err(e) => { error!("Failed to get midpoint: {}", e); self.stats.errors += 1; } } // Get spread match self.client.get_spread(token_id).await { Ok(spread) => { info!("Spread for {}: {}", token_id, spread.spread); self.stats.api_calls += 1; } Err(e) => { error!("Failed to get spread: {}", e); self.stats.errors += 1; } } // Get price for both sides for side in [Side::BUY, Side::SELL] { match self.client.get_price(token_id, side).await { Ok(price) => { info!("{} price for {}: {}", side.as_str(), token_id, price.price); self.stats.api_calls += 1; } Err(e) => { error!("Failed to get {} price: {}", side.as_str(), e); self.stats.errors += 1; } } } // Get tick size match self.client.get_tick_size(token_id).await { Ok(tick_size) => { info!("Tick size for {}: {}", token_id, tick_size); self.stats.api_calls += 1; } Err(e) => { error!("Failed to get tick size: {}", e); self.stats.errors += 1; } } // Get neg risk match self.client.get_neg_risk(token_id).await { Ok(neg_risk) => { info!("Neg risk for {}: {}", token_id, neg_risk); self.stats.api_calls += 1; } Err(e) => { error!("Failed to get neg risk: {}", e); self.stats.errors += 1; } } Ok(()) } /// Demo 4: Order Creation and Management pub async fn demo_order_operations(&mut self) -> Result<()> { info!("=== Demo 4: Order Creation and Management ==="); // Create order arguments let order_args = OrderArgs::new( "12345", dec!(0.75), dec!(100.0), Side::BUY, ); info!("Created order args: {:?}", order_args); // Create market order request let market_order = MarketOrderRequest { token_id: "12345".to_string(), side: Side::BUY, amount: dec!(100.0), slippage_tolerance: Some(dec!(1.0)), // 1% slippage client_id: Some("demo_market_order".to_string()), }; info!("Created market order request: {:?}", market_order); // Create limit order request let limit_order = OrderRequest { token_id: "12345".to_string(), side: Side::BUY, price: dec!(0.75), size: dec!(100.0), order_type: OrderType::GTC, expiration: None, client_id: Some("demo_limit_order".to_string()), }; info!("Created limit order request: {:?}", limit_order); self.stats.orders_processed += 2; Ok(()) } /// Demo 5: Fill Execution pub async fn demo_fill_execution(&mut self) -> Result<()> { info!("=== Demo 5: Fill Execution ==="); // Create a mock order book for testing let mut book = OrderBook::new("12345".to_string(), 50); // Add some liquidity for i in 1..=5 { book.apply_delta(OrderDelta { token_id: "12345".to_string(), timestamp: chrono::Utc::now(), side: Side::BUY, price: dec!(0.70) + Decimal::from(i) * dec!(0.01), size: dec!(100.0), sequence: i, })?; } for i in 1..=5 { book.apply_delta(OrderDelta { token_id: "12345".to_string(), timestamp: chrono::Utc::now(), side: Side::SELL, price: dec!(0.80) + Decimal::from(i) * dec!(0.01), size: dec!(100.0), sequence: i + 10, })?; } info!("Created order book with liquidity"); // Execute market order let market_order = MarketOrderRequest { token_id: "12345".to_string(), side: Side::BUY, amount: dec!(50.0), slippage_tolerance: Some(dec!(2.0)), client_id: Some("demo_market_buy".to_string()), }; let fill_result = self.fill_engine.execute_market_order(&market_order, &book)?; info!("Market order execution result:"); info!(" Status: {:?}", fill_result.status); info!(" Total size: {}", fill_result.total_size); info!(" Average price: {}", fill_result.average_price); info!(" Total cost: {}", fill_result.total_cost); info!(" Fees: {}", fill_result.fees); info!(" Number of fills: {}", fill_result.fills.len()); // Process fills for fill in &fill_result.fills { self.fill_processor.process_fill(fill.clone())?; self.stats.fills_processed += 1; self.stats.total_volume += fill.size; } // Execute limit order let limit_order = OrderRequest { token_id: "12345".to_string(), side: Side::SELL, price: dec!(0.85), size: dec!(25.0), order_type: OrderType::GTC, expiration: None, client_id: Some("demo_limit_sell".to_string()), }; let limit_result = self.fill_engine.execute_limit_order(&limit_order, &book)?; info!("Limit order execution result:"); info!(" Status: {:?}", limit_result.status); info!(" Total size: {}", limit_result.total_size); info!(" Average price: {}", limit_result.average_price); self.stats.orders_processed += 2; Ok(()) } /// Demo 6: Utility Functions pub async fn demo_utility_functions(&mut self) -> Result<()> { info!("=== Demo 6: Utility Functions ==="); // Time utilities info!("Time utilities:"); info!(" Current timestamp (secs): {}", time::now_secs()); info!(" Current timestamp (millis): {}", time::now_millis()); info!(" Current timestamp (micros): {}", time::now_micros()); // Math utilities info!("Math utilities:"); let price = dec!(0.7534); let tick_size = dec!(0.01); let rounded_price = math::round_to_tick(price, tick_size); info!(" Price: {}, Tick size: {}, Rounded: {}", price, tick_size, rounded_price); let notional = math::notional(price, dec!(100.0)); info!(" Notional value: {}", notional); let spread_pct = math::spread_pct(dec!(0.75), dec!(0.76)); info!(" Spread percentage: {:?}", spread_pct); let mid_price = math::mid_price(dec!(0.75), dec!(0.76)); info!(" Mid price: {:?}", mid_price); // Address utilities info!("Address utilities:"); let address = "0x1234567890123456789012345678901234567890"; match address::parse_address(address) { Ok(addr) => info!(" Parsed address: {:?}", addr), Err(e) => error!(" Failed to parse address: {}", e), } let token_id = "12345"; match address::validate_token_id(token_id) { Ok(_) => info!(" Valid token ID: {}", token_id), Err(e) => error!(" Invalid token ID: {}", e), } // URL utilities info!("URL utilities:"); let endpoint = url::build_endpoint("https://api.example.com", "/v1/orders")?; info!(" Built endpoint: {}", endpoint); // Rate limiting info!("Rate limiting:"); for i in 0..5 { let allowed = self.rate_limiter.try_consume(); info!(" Request {}: {}", i + 1, if allowed { "ALLOWED" } else { "RATE LIMITED" }); } Ok(()) } /// Demo 7: Error Handling and Retry Logic pub async fn demo_error_handling(&mut self) -> Result<()> { info!("=== Demo 7: Error Handling and Retry Logic ==="); // Demonstrate retry logic let retry_config = retry::RetryConfig { max_attempts: 3, initial_delay: Duration::from_millis(100), max_delay: Duration::from_secs(1), backoff_factor: 2.0, jitter: true, }; let operation = || async { // Simulate a potentially failing operation if rand::random::() { Ok("Success!") } else { Err(PolyfillError::network("Simulated network error", std::io::Error::new(std::io::ErrorKind::Other, "Simulated error"))) } }; match retry::with_retry(&retry_config, operation).await { Ok(result) => { info!("Retry operation succeeded: {}", result); } Err(e) => { error!("Retry operation failed after all attempts: {}", e); self.stats.errors += 1; } } // Demonstrate error types info!("Error types demonstration:"); let api_error = PolyfillError::api(400, "Bad Request"); info!(" API Error: {:?}", api_error); let network_error = PolyfillError::network("Connection timeout", std::io::Error::new(std::io::ErrorKind::TimedOut, "Connection timeout")); info!(" Network Error: {:?}", network_error); let parse_error = PolyfillError::parse("Invalid JSON", None); info!(" Parse Error: {:?}", parse_error); let config_error = PolyfillError::config("Invalid configuration"); info!(" Config Error: {:?}", config_error); Ok(()) } /// Demo 8: Streaming Capabilities (Mock) pub async fn demo_streaming_capabilities(&mut self) -> Result<()> { info!("=== Demo 8: Streaming Capabilities ==="); // Create a mock WebSocket stream let _stream = WebSocketStream::new("wss://stream.polymarket.com"); info!("Created WebSocket stream"); // Simulate subscription let subscription = WssSubscription { auth: WssAuth { address: "0x1234567890123456789012345678901234567890".to_string(), signature: "mock_signature".to_string(), timestamp: time::now_secs(), nonce: crypto::generate_nonce().to_string(), }, markets: Some(vec!["market1".to_string(), "market2".to_string()]), asset_ids: Some(vec!["12345".to_string(), "67890".to_string()]), channel_type: "USER".to_string(), }; info!("Created subscription: {:?}", subscription); // Simulate receiving stream messages let messages = vec![ StreamMessage::Heartbeat { timestamp: chrono::Utc::now() }, StreamMessage::BookUpdate { data: OrderDelta { token_id: "12345".to_string(), timestamp: chrono::Utc::now(), side: Side::BUY, price: dec!(0.75), size: dec!(100.0), sequence: 1, } }, StreamMessage::Trade { data: FillEvent { id: "fill1".to_string(), order_id: "order1".to_string(), token_id: "12345".to_string(), side: Side::BUY, price: dec!(0.75), size: dec!(50.0), timestamp: chrono::Utc::now(), maker_address: alloy_primitives::Address::ZERO, taker_address: alloy_primitives::Address::ZERO, fee: dec!(0.375), } }, ]; for message in messages { info!("Received stream message: {:?}", message); self.stats.stream_messages += 1; // Process message based on type match &message { StreamMessage::BookUpdate { data } => { info!(" Processing book update for token: {}", data.token_id); if let Err(e) = self.book_manager.apply_delta(data.clone()) { error!(" Failed to apply book update: {}", e); self.stats.errors += 1; } } StreamMessage::Trade { data } => { info!(" Processing trade: {} {} @ {}", data.side.as_str(), data.size, data.price); if let Err(e) = self.fill_processor.process_fill(data.clone()) { error!(" Failed to process fill: {}", e); self.stats.errors += 1; } } StreamMessage::Heartbeat { timestamp } => { debug!(" Received heartbeat at: {}", timestamp); } _ => { info!(" Unhandled message type"); } } } Ok(()) } /// Demo 9: Performance and Analytics pub async fn demo_performance_analytics(&mut self) -> Result<()> { info!("=== Demo 9: Performance and Analytics ==="); // Get fill engine statistics let fill_stats = self.fill_engine.get_stats(); info!("Fill engine statistics:"); info!(" Total orders: {}", fill_stats.total_orders); info!(" Total fills: {}", fill_stats.total_fills); info!(" Total volume: {}", fill_stats.total_volume); info!(" Total fees: {}", fill_stats.total_fees); // Get fill processor statistics let processor_stats = self.fill_processor.get_stats(); info!("Fill processor statistics:"); info!(" Pending orders: {}", processor_stats.pending_orders); info!(" Pending fills: {}", processor_stats.pending_fills); info!(" Pending volume: {}", processor_stats.pending_volume); info!(" Processed fills: {}", processor_stats.processed_fills); info!(" Processed volume: {}", processor_stats.processed_volume); // Get demo statistics info!("Demo statistics:"); info!(" API calls: {}", self.stats.api_calls); info!(" Orders processed: {}", self.stats.orders_processed); info!(" Fills processed: {}", self.stats.fills_processed); info!(" Stream messages: {}", self.stats.stream_messages); info!(" Errors: {}", self.stats.errors); info!(" Total volume: {}", self.stats.total_volume); // Calculate error rate let total_operations = self.stats.api_calls + self.stats.orders_processed + self.stats.stream_messages; let error_rate = if total_operations > 0 { (self.stats.errors as f64 / total_operations as f64) * 100.0 } else { 0.0 }; info!(" Error rate: {:.2}%", error_rate); Ok(()) } /// Run all demos pub async fn run_all_demos(&mut self) -> Result<()> { info!("Starting comprehensive polyfill-rs demo..."); // Run all demo sections self.demo_basic_api_operations().await?; sleep(Duration::from_millis(500)).await; self.demo_order_book_operations().await?; sleep(Duration::from_millis(500)).await; self.demo_market_data_operations().await?; sleep(Duration::from_millis(500)).await; self.demo_order_operations().await?; sleep(Duration::from_millis(500)).await; self.demo_fill_execution().await?; sleep(Duration::from_millis(500)).await; self.demo_utility_functions().await?; sleep(Duration::from_millis(500)).await; self.demo_error_handling().await?; sleep(Duration::from_millis(500)).await; self.demo_streaming_capabilities().await?; sleep(Duration::from_millis(500)).await; self.demo_performance_analytics().await?; info!("Comprehensive demo completed successfully!"); Ok(()) } } #[tokio::main] async fn main() -> Result<()> { // Initialize logging tracing_subscriber::fmt::init(); info!("Polyfill-rs Comprehensive Demo"); info!("=============================="); // Create and run demo let mut demo = PolyfillDemo::new()?; if let Err(e) = demo.run_all_demos().await { error!("Demo failed: {}", e); std::process::exit(1); } info!("Demo completed successfully!"); Ok(()) }