1pub mod error;
2pub mod query;
3pub mod registry;
4pub mod types;
5
6pub use error::{ChainRegistryError, Result};
8pub use query::{HealthIssue, RegistryStatistics};
9pub use registry::{ChainRegistry, DEFAULT_CONFIG};
10pub use types::*;
11
12pub use atp_caip::{AssetId, AssetIdBase, ChainId, Curve, TokenPair};
14
15#[cfg(test)]
16mod integration_tests {
17    use super::*;
18    use std::collections::HashMap;
19    use std::str::FromStr;
20
21    #[test]
22    fn test_full_workflow() {
23        let mut registry = ChainRegistry::new();
25
26        let eth_chain = ChainConfig {
28            chain_id: "eip155:1".to_string(),
29            name: "Ethereum Mainnet".to_string(),
30            native_asset: "slip44:60".to_string(),
31            rpc_endpoints: vec!["https://mainnet.infura.io/v3/YOUR-PROJECT-ID".to_string()],
32            explorer_url: Some("https://etherscan.io".to_string()),
33            cryptographic_curve: vec![Curve::Secp256k1],
34            is_testnet: false,
35            assets: vec![
36                AssetIdBase::new("slip44", "60").unwrap(), AssetIdBase::new("erc20", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").unwrap(), ],
39            metadata: HashMap::new(),
40        };
41        registry.add_chain(eth_chain).unwrap();
42
43        let sol_chain = ChainConfig {
45            chain_id: "solana:mainnet".to_string(),
46            name: "Solana Mainnet".to_string(),
47            native_asset: "slip44:501".to_string(),
48            rpc_endpoints: vec!["https://api.mainnet-beta.solana.com".to_string()],
49            explorer_url: Some("https://solscan.io".to_string()),
50            cryptographic_curve: vec![Curve::Ed25519],
51            is_testnet: false,
52            assets: vec![AssetIdBase::new("slip44", "501").unwrap()], metadata: HashMap::new(),
54        };
55        registry.add_chain(sol_chain).unwrap();
56
57        let eth_asset = AssetConfig {
59            asset_id_base: AssetIdBase::new("slip44", "60").unwrap(),
60            symbol: "ETH".to_string(),
61            name: "Ethereum".to_string(),
62            is_native: true,
63            decimals: 18,
64            metadata: HashMap::new(),
65        };
66        registry.add_asset(eth_asset).unwrap();
67
68        let usdc_asset = AssetConfig {
69            asset_id_base: AssetIdBase::new("erc20", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
70                .unwrap(),
71            symbol: "USDC".to_string(),
72            name: "USD Coin".to_string(),
73            is_native: false,
74            decimals: 6,
75            metadata: HashMap::new(),
76        };
77        registry.add_asset(usdc_asset).unwrap();
78
79        let sol_asset = AssetConfig {
80            asset_id_base: AssetIdBase::new("slip44", "501").unwrap(),
81            symbol: "SOL".to_string(),
82            name: "Solana".to_string(),
83            is_native: true,
84            decimals: 9,
85            metadata: HashMap::new(),
86        };
87        registry.add_asset(sol_asset).unwrap();
88
89        let eth_chain_id = ChainId::from_str("eip155:1").unwrap();
91        let sol_chain_id = ChainId::from_str("solana:mainnet").unwrap();
92
93        let eth_asset_id = AssetId::new(eth_chain_id.clone(), "slip44", "60").unwrap();
94        let usdc_asset_id = AssetId::new(
95            eth_chain_id.clone(),
96            "erc20",
97            "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
98        )
99        .unwrap();
100        let sol_asset_id = AssetId::new(sol_chain_id.clone(), "slip44", "501").unwrap();
101
102        let eth_sol_pair = TokenPair::new(eth_asset_id.clone(), sol_asset_id.clone());
104        registry.add_token_pair(eth_sol_pair).unwrap();
105
106        let eth_usdc_pair = TokenPair::new(eth_asset_id.clone(), usdc_asset_id.clone());
108        registry.add_token_pair(eth_usdc_pair).unwrap();
109
110        assert_eq!(registry.list_chains().len(), 2);
112        assert_eq!(registry.list_assets().len(), 3);
113        assert_eq!(registry.list_token_pairs().len(), 2);
114
115        let eth_chains = registry.get_chains_by_curve(&Curve::Secp256k1);
117        assert_eq!(eth_chains.len(), 1);
118        assert_eq!(eth_chains[0].name, "Ethereum Mainnet");
119
120        let mainnet_chains = registry.get_mainnet_chains();
121        assert_eq!(mainnet_chains.len(), 2);
122
123        let eth_assets = registry.get_chain_assets(ð_chain_id).unwrap();
125        assert_eq!(eth_assets.len(), 2);
126
127        let native_eth = registry.get_native_asset(ð_chain_id).unwrap();
128        assert_eq!(native_eth.to_string(), "eip155:1/slip44:60");
129
130        let cross_chain_pairs = registry.get_cross_chain_pairs();
132        assert_eq!(cross_chain_pairs.len(), 1);
133
134        let same_chain_pairs = registry.get_same_chain_pairs();
135        assert_eq!(same_chain_pairs.len(), 1);
136
137        let eth_pairs = registry.get_pairs_for_asset(ð_asset_id);
138        assert_eq!(eth_pairs.len(), 2);
139
140        let routes = registry.find_trading_routes(ð_asset_id, &sol_asset_id, 3);
142        assert_eq!(routes.len(), 1); let stats = registry.get_statistics();
146        assert_eq!(stats.total_chains, 2);
147        assert_eq!(stats.total_assets, 3);
148        assert_eq!(stats.total_pairs, 2);
149        assert_eq!(stats.cross_chain_pairs, 1);
150        assert_eq!(stats.same_chain_pairs, 1);
151
152        let health_issues = registry.check_health();
154        assert!(health_issues.is_empty());
155
156        let chain_id_from_name = registry
158            .get_chain_id_from_config("Ethereum Mainnet")
159            .unwrap();
160        assert_eq!(chain_id_from_name.to_string(), "eip155:1");
161
162        let asset_id_from_config = registry
163            .get_asset_id_from_config("ETH", "eip155:1")
164            .unwrap();
165        assert_eq!(asset_id_from_config.to_string(), "eip155:1/slip44:60");
166    }
167
168    #[test]
169    fn test_serialization() {
170        let mut registry = ChainRegistry::new();
171
172        let asset_config = AssetConfig {
173            asset_id_base: AssetIdBase::new("slip44", "60").unwrap(),
174            symbol: "ETH".to_string(),
175            name: "Ethereum".to_string(),
176            is_native: true,
177            decimals: 18,
178            metadata: HashMap::new(),
179        };
180
181        registry.add_asset(asset_config.clone()).unwrap();
182        assert_eq!(registry.list_assets().len(), 1);
183
184        let chain_config = ChainConfig {
185            chain_id: "eip155:1".to_string(),
186            name: "Ethereum Mainnet".to_string(),
187            native_asset: "slip44:60".to_string(),
188            rpc_endpoints: vec!["https://mainnet.infura.io/v3/YOUR-PROJECT-ID".to_string()],
189            explorer_url: Some("https://etherscan.io".to_string()),
190            cryptographic_curve: vec![Curve::Secp256k1],
191            is_testnet: false,
192            assets: vec![AssetIdBase::new("slip44", "60").unwrap()],
193            metadata: HashMap::new(),
194        };
195        registry.add_chain(chain_config).unwrap();
196
197        let toml_str = registry.to_toml().unwrap();
199        assert!(toml_str.contains("eip155:1"));
200        assert!(toml_str.contains("Ethereum Mainnet"));
201
202        let json_str = registry.to_json().unwrap();
204        assert!(json_str.contains("eip155:1"));
205        assert!(json_str.contains("Ethereum Mainnet"));
206
207        let config_from_toml = ChainRegistry::config_from_toml(&toml_str).unwrap();
209        println!("Config from TOML: {:?}", config_from_toml);
210        let registry_from_config = ChainRegistry::from_config(config_from_toml).unwrap();
211        assert_eq!(registry_from_config.list_chains().len(), 1);
212    }
213}