ostium_rust_sdk/
config.rs

1//! Network configuration for the Ostium SDK
2//!
3//! This module provides network-specific configuration including RPC URLs,
4//! chain IDs, contract addresses, and GraphQL endpoints.
5
6use alloy_primitives::Address;
7use serde::{Deserialize, Serialize};
8use url::Url;
9
10use crate::error::{OstiumError, Result};
11
12/// Supported networks for the Ostium platform
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14pub enum Network {
15    /// Arbitrum mainnet
16    Mainnet,
17    /// Arbitrum testnet (Sepolia)
18    Testnet,
19}
20
21impl Network {
22    /// Get the configuration for this network
23    pub fn config(self) -> NetworkConfig {
24        match self {
25            Network::Mainnet => NetworkConfig::mainnet(),
26            Network::Testnet => NetworkConfig::testnet(),
27        }
28    }
29}
30
31/// Network configuration containing all necessary endpoints and addresses
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct NetworkConfig {
34    /// Network identifier
35    pub network: Network,
36    /// RPC URL for the network
37    pub rpc_url: Url,
38    /// Chain ID
39    pub chain_id: u64,
40    /// GraphQL API endpoint
41    pub graphql_url: Url,
42    /// Trading contract address
43    pub trading_contract: Address,
44    /// Storage contract address
45    pub storage_contract: Address,
46    /// Price feed contract address
47    pub price_feed_contract: Address,
48    /// USDC token address
49    pub usdc_address: Address,
50}
51
52impl NetworkConfig {
53    /// Create a mainnet configuration
54    pub fn mainnet() -> Self {
55        Self {
56            network: Network::Mainnet,
57            chain_id: 42161,
58            rpc_url: "https://arb1.arbitrum.io/rpc".parse().expect("Valid URL"),
59            graphql_url: "https://subgraph.satsuma-prod.com/391a61815d32/ostium/ost-prod/api"
60                .parse()
61                .expect("Valid URL"),
62            usdc_address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
63                .parse()
64                .expect("Valid address"),
65            trading_contract: "0x6D0bA1f9996DBD8885827e1b2e8f6593e7702411"
66                .parse()
67                .expect("Valid address"),
68            storage_contract: "0xcCd5891083A8acD2074690F65d3024E7D13d66E7"
69                .parse()
70                .expect("Valid address"),
71            price_feed_contract: "0x0000000000000000000000000000000000000003"
72                .parse()
73                .expect("Valid address"),
74        }
75    }
76
77    /// Create a testnet configuration
78    pub fn testnet() -> Self {
79        Self {
80            network: Network::Testnet,
81            chain_id: 421614,
82            rpc_url: "https://sepolia-rollup.arbitrum.io/rpc"
83                .parse()
84                .expect("Valid URL"),
85            graphql_url: "https://subgraph.satsuma-prod.com/391a61815d32/ostium/ost-sep-final/api"
86                .parse()
87                .expect("Valid URL"),
88            usdc_address: "0xe73B11Fb1e3eeEe8AF2a23079A4410Fe1B370548"
89                .parse()
90                .expect("Valid address"),
91            trading_contract: "0x2A9B9c988393f46a2537B0ff11E98c2C15a95afe"
92                .parse()
93                .expect("Valid address"),
94            storage_contract: "0x0b9F5243B29938668c9Cfbd7557A389EC7Ef88b8"
95                .parse()
96                .expect("Valid address"),
97            price_feed_contract: "0x0000000000000000000000000000000000000003"
98                .parse()
99                .expect("Valid address"),
100        }
101    }
102
103    /// Create a custom network configuration
104    pub fn custom(
105        rpc_url: Url,
106        chain_id: u64,
107        graphql_url: Url,
108        trading_contract: Address,
109        storage_contract: Address,
110        price_feed_contract: Address,
111        usdc_address: Address,
112    ) -> Self {
113        Self {
114            network: Network::Mainnet, // Default to mainnet for custom
115            rpc_url,
116            chain_id,
117            graphql_url,
118            trading_contract,
119            storage_contract,
120            price_feed_contract,
121            usdc_address,
122        }
123    }
124
125    /// Validate the configuration
126    pub fn validate(&self) -> Result<()> {
127        // Ensure chain ID matches expected values
128        match self.network {
129            Network::Mainnet if self.chain_id != 42161 => {
130                return Err(OstiumError::config("Invalid chain ID for mainnet"));
131            }
132            Network::Testnet if self.chain_id != 421614 => {
133                return Err(OstiumError::config("Invalid chain ID for testnet"));
134            }
135            _ => {}
136        }
137
138        // Ensure no zero addresses
139        if self.trading_contract == Address::ZERO {
140            return Err(OstiumError::config(
141                "Trading contract address cannot be zero",
142            ));
143        }
144        if self.storage_contract == Address::ZERO {
145            return Err(OstiumError::config(
146                "Storage contract address cannot be zero",
147            ));
148        }
149        if self.price_feed_contract == Address::ZERO {
150            return Err(OstiumError::config(
151                "Price feed contract address cannot be zero",
152            ));
153        }
154        if self.usdc_address == Address::ZERO {
155            return Err(OstiumError::config("USDC address cannot be zero"));
156        }
157
158        Ok(())
159    }
160}
161
162/// Builder for creating custom network configurations
163pub struct NetworkConfigBuilder {
164    config: NetworkConfig,
165}
166
167impl NetworkConfigBuilder {
168    /// Create a new builder starting from a base network
169    pub fn new(network: Network) -> Self {
170        Self {
171            config: network.config(),
172        }
173    }
174
175    /// Set a custom RPC URL
176    pub fn with_rpc_url(mut self, url: Url) -> Self {
177        self.config.rpc_url = url;
178        self
179    }
180
181    /// Set a custom GraphQL URL
182    pub fn with_graphql_url(mut self, url: Url) -> Self {
183        self.config.graphql_url = url;
184        self
185    }
186
187    /// Set custom contract addresses
188    pub fn with_contracts(
189        mut self,
190        trading: Address,
191        storage: Address,
192        price_feed: Address,
193    ) -> Self {
194        self.config.trading_contract = trading;
195        self.config.storage_contract = storage;
196        self.config.price_feed_contract = price_feed;
197        self
198    }
199
200    /// Build and validate the configuration
201    pub fn build(self) -> Result<NetworkConfig> {
202        self.config.validate()?;
203        Ok(self.config)
204    }
205}