use alloy_primitives::Address;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::error::{OstiumError, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Network {
Mainnet,
Testnet,
}
impl Network {
pub fn config(self) -> NetworkConfig {
match self {
Network::Mainnet => NetworkConfig::mainnet(),
Network::Testnet => NetworkConfig::testnet(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkConfig {
pub network: Network,
pub rpc_url: Url,
pub chain_id: u64,
pub graphql_url: Url,
pub trading_contract: Address,
pub storage_contract: Address,
pub price_feed_contract: Address,
pub usdc_address: Address,
}
impl NetworkConfig {
pub fn mainnet() -> Self {
Self {
network: Network::Mainnet,
chain_id: 42161,
rpc_url: "https://arb1.arbitrum.io/rpc".parse().expect("Valid URL"),
graphql_url: "https://subgraph.satsuma-prod.com/391a61815d32/ostium/ost-prod/api"
.parse()
.expect("Valid URL"),
usdc_address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
.parse()
.expect("Valid address"),
trading_contract: "0x6D0bA1f9996DBD8885827e1b2e8f6593e7702411"
.parse()
.expect("Valid address"),
storage_contract: "0xcCd5891083A8acD2074690F65d3024E7D13d66E7"
.parse()
.expect("Valid address"),
price_feed_contract: "0x0000000000000000000000000000000000000003"
.parse()
.expect("Valid address"),
}
}
pub fn testnet() -> Self {
Self {
network: Network::Testnet,
chain_id: 421614,
rpc_url: "https://sepolia-rollup.arbitrum.io/rpc"
.parse()
.expect("Valid URL"),
graphql_url: "https://subgraph.satsuma-prod.com/391a61815d32/ostium/ost-sep-final/api"
.parse()
.expect("Valid URL"),
usdc_address: "0xe73B11Fb1e3eeEe8AF2a23079A4410Fe1B370548"
.parse()
.expect("Valid address"),
trading_contract: "0x2A9B9c988393f46a2537B0ff11E98c2C15a95afe"
.parse()
.expect("Valid address"),
storage_contract: "0x0b9F5243B29938668c9Cfbd7557A389EC7Ef88b8"
.parse()
.expect("Valid address"),
price_feed_contract: "0x0000000000000000000000000000000000000003"
.parse()
.expect("Valid address"),
}
}
pub fn custom(
rpc_url: Url,
chain_id: u64,
graphql_url: Url,
trading_contract: Address,
storage_contract: Address,
price_feed_contract: Address,
usdc_address: Address,
) -> Self {
Self {
network: Network::Mainnet, rpc_url,
chain_id,
graphql_url,
trading_contract,
storage_contract,
price_feed_contract,
usdc_address,
}
}
pub fn validate(&self) -> Result<()> {
match self.network {
Network::Mainnet if self.chain_id != 42161 => {
return Err(OstiumError::config("Invalid chain ID for mainnet"));
}
Network::Testnet if self.chain_id != 421614 => {
return Err(OstiumError::config("Invalid chain ID for testnet"));
}
_ => {}
}
if self.trading_contract == Address::ZERO {
return Err(OstiumError::config(
"Trading contract address cannot be zero",
));
}
if self.storage_contract == Address::ZERO {
return Err(OstiumError::config(
"Storage contract address cannot be zero",
));
}
if self.price_feed_contract == Address::ZERO {
return Err(OstiumError::config(
"Price feed contract address cannot be zero",
));
}
if self.usdc_address == Address::ZERO {
return Err(OstiumError::config("USDC address cannot be zero"));
}
Ok(())
}
}
pub struct NetworkConfigBuilder {
config: NetworkConfig,
}
impl NetworkConfigBuilder {
pub fn new(network: Network) -> Self {
Self {
config: network.config(),
}
}
pub fn with_rpc_url(mut self, url: Url) -> Self {
self.config.rpc_url = url;
self
}
pub fn with_graphql_url(mut self, url: Url) -> Self {
self.config.graphql_url = url;
self
}
pub fn with_contracts(
mut self,
trading: Address,
storage: Address,
price_feed: Address,
) -> Self {
self.config.trading_contract = trading;
self.config.storage_contract = storage;
self.config.price_feed_contract = price_feed;
self
}
pub fn build(self) -> Result<NetworkConfig> {
self.config.validate()?;
Ok(self.config)
}
}