Skip to main content

polyoxide_clob/core/
chain.rs

1use alloy::primitives::{address, Address};
2
3/// Supported Polygon chains for CLOB order signing.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Chain {
6    /// Polygon mainnet (chain ID 137).
7    PolygonMainnet,
8    /// Polygon Amoy testnet (chain ID 80002).
9    PolygonAmoy,
10}
11
12impl Chain {
13    /// Get the chain ID
14    pub const fn chain_id(&self) -> u64 {
15        match self {
16            Chain::PolygonMainnet => 137,
17            Chain::PolygonAmoy => 80002,
18        }
19    }
20
21    /// Get contracts for this chain
22    pub const fn contracts(&self) -> Contracts {
23        match self {
24            Chain::PolygonMainnet => Contracts::POLYGON_MAINNET,
25            Chain::PolygonAmoy => Contracts::POLYGON_AMOY,
26        }
27    }
28
29    /// Create Chain from chain ID
30    pub const fn from_chain_id(chain_id: u64) -> Option<Self> {
31        match chain_id {
32            137 => Some(Self::PolygonMainnet),
33            80002 => Some(Self::PolygonAmoy),
34            _ => None,
35        }
36    }
37}
38
39/// Contract addresses for different chains
40#[derive(Debug, Clone, Copy)]
41pub struct Contracts {
42    pub exchange: Address,
43    pub neg_risk_exchange: Address,
44    pub neg_risk_adapter: Address,
45    pub collateral: Address,
46    pub conditional_tokens: Address,
47}
48
49impl Contracts {
50    /// Polygon mainnet contracts (chain ID 137)
51    pub const POLYGON_MAINNET: Self = Self {
52        exchange: address!("E111180000d2663C0091e4f400237545B87B996B"), // CTF Exchange V2
53        neg_risk_exchange: address!("e2222d279d744050d28e00520010520000310F59"), // NegRisk CTF Exchange V2
54        neg_risk_adapter: address!("d91E80cF2E7be2e162c6513ceD06f1dD0dA35296"),
55        collateral: address!("2791Bca1f2de4661ED88A30C99A7a9449Aa84174"),
56        conditional_tokens: address!("4D97DCd97eC945f40cF65F87097ACe5EA0476045"),
57    };
58
59    /// Polygon Amoy testnet contracts (chain ID 80002)
60    pub const POLYGON_AMOY: Self = Self {
61        exchange: address!("dFE02Eb6733538f8Ea35D585af8DE5958AD99E40"),
62        neg_risk_exchange: address!("d91E80cF2E7be2e162c6513ceD06f1dD0dA35296"),
63        neg_risk_adapter: address!("d0D0E471E88e0A8E7C304F2df3A0Cc7400fe4635"),
64        collateral: address!("9c4e1703476e875070ee25b56a58b008cfb8fa78"),
65        conditional_tokens: address!("69308FB512518e39F9b16112fA8d994F4e2Bf8bB"),
66    };
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_chain_id() {
75        assert_eq!(Chain::PolygonMainnet.chain_id(), 137);
76        assert_eq!(Chain::PolygonAmoy.chain_id(), 80002);
77    }
78
79    #[test]
80    fn test_from_chain_id() {
81        assert_eq!(Chain::from_chain_id(137), Some(Chain::PolygonMainnet));
82        assert_eq!(Chain::from_chain_id(80002), Some(Chain::PolygonAmoy));
83        assert_eq!(Chain::from_chain_id(1), None);
84        assert_eq!(Chain::from_chain_id(999), None);
85    }
86
87    #[test]
88    fn test_chain_contracts() {
89        let mainnet_contracts = Chain::PolygonMainnet.contracts();
90        assert_eq!(
91            mainnet_contracts.exchange,
92            Contracts::POLYGON_MAINNET.exchange
93        );
94
95        let amoy_contracts = Chain::PolygonAmoy.contracts();
96        assert_eq!(amoy_contracts.exchange, Contracts::POLYGON_AMOY.exchange);
97    }
98
99    #[test]
100    fn polygon_mainnet_uses_v2_exchanges() {
101        let c = Contracts::POLYGON_MAINNET;
102        assert_eq!(
103            c.exchange,
104            address!("E111180000d2663C0091e4f400237545B87B996B"),
105            "CTF Exchange must be the V2 contract"
106        );
107        assert_eq!(
108            c.neg_risk_exchange,
109            address!("e2222d279d744050d28e00520010520000310F59"),
110            "NegRisk Exchange must be the V2 contract"
111        );
112    }
113
114    #[test]
115    fn test_polygon_mainnet_addresses() {
116        let contracts = Contracts::POLYGON_MAINNET;
117
118        // Verify addresses are not zero
119        assert_ne!(contracts.exchange, Address::ZERO);
120        assert_ne!(contracts.neg_risk_exchange, Address::ZERO);
121        assert_ne!(contracts.neg_risk_adapter, Address::ZERO);
122        assert_ne!(contracts.collateral, Address::ZERO);
123        assert_ne!(contracts.conditional_tokens, Address::ZERO);
124    }
125
126    #[test]
127    fn test_polygon_amoy_addresses() {
128        let contracts = Contracts::POLYGON_AMOY;
129
130        // Verify addresses are not zero
131        assert_ne!(contracts.exchange, Address::ZERO);
132        assert_ne!(contracts.neg_risk_exchange, Address::ZERO);
133        assert_ne!(contracts.neg_risk_adapter, Address::ZERO);
134        assert_ne!(contracts.collateral, Address::ZERO);
135        assert_ne!(contracts.conditional_tokens, Address::ZERO);
136    }
137
138    #[test]
139    fn test_chain_is_copy() {
140        let chain = Chain::PolygonMainnet;
141        let _copy1 = chain;
142        let _copy2 = chain; // Should still work
143    }
144
145    #[test]
146    fn test_chain_equality() {
147        assert_eq!(Chain::PolygonMainnet, Chain::PolygonMainnet);
148        assert_eq!(Chain::PolygonAmoy, Chain::PolygonAmoy);
149        assert_ne!(Chain::PolygonMainnet, Chain::PolygonAmoy);
150    }
151}