11use super :: block_explorer;
2- use crate :: ValidatedWaitParams ;
2+ use crate :: { Network , ValidatedWaitParams } ;
33use anyhow:: Result ;
44use camino:: Utf8PathBuf ;
55use configuration:: Config ;
@@ -10,6 +10,37 @@ pub const fn show_explorer_links_default() -> bool {
1010 true
1111}
1212
13+ #[ derive( Deserialize , Serialize , Clone , Debug , PartialEq , Default ) ]
14+ #[ serde( deny_unknown_fields) ]
15+ pub struct NetworksConfig {
16+ pub mainnet : Option < String > ,
17+ pub sepolia : Option < String > ,
18+ pub devnet : Option < String > ,
19+ }
20+
21+ impl NetworksConfig {
22+ #[ must_use]
23+ pub fn get_url ( & self , network : Network ) -> Option < & String > {
24+ match network {
25+ Network :: Mainnet => self . mainnet . as_ref ( ) ,
26+ Network :: Sepolia => self . sepolia . as_ref ( ) ,
27+ Network :: Devnet => self . devnet . as_ref ( ) ,
28+ }
29+ }
30+
31+ pub fn override_with ( & mut self , other : & NetworksConfig ) {
32+ if other. mainnet . is_some ( ) {
33+ self . mainnet . clone_from ( & other. mainnet ) ;
34+ }
35+ if other. sepolia . is_some ( ) {
36+ self . sepolia . clone_from ( & other. sepolia ) ;
37+ }
38+ if other. devnet . is_some ( ) {
39+ self . devnet . clone_from ( & other. devnet ) ;
40+ }
41+ }
42+ }
43+
1344#[ derive( Deserialize , Serialize , Clone , Debug , PartialEq ) ]
1445pub struct CastConfig {
1546 #[ serde( default ) ]
@@ -46,6 +77,10 @@ pub struct CastConfig {
4677 ) ]
4778 /// Print links pointing to pages with transaction details in the chosen block explorer
4879 pub show_explorer_links : bool ,
80+
81+ #[ serde( default ) ]
82+ /// Configurable urls of predefined networks - mainnet, sepolia, and devnet are supported
83+ pub networks : NetworksConfig ,
4984}
5085
5186impl Default for CastConfig {
@@ -58,6 +93,7 @@ impl Default for CastConfig {
5893 wait_params : ValidatedWaitParams :: default ( ) ,
5994 block_explorer : Some ( block_explorer:: Service :: default ( ) ) ,
6095 show_explorer_links : show_explorer_links_default ( ) ,
96+ networks : NetworksConfig :: default ( ) ,
6197 }
6298 }
6399}
@@ -71,3 +107,71 @@ impl Config for CastConfig {
71107 Ok ( serde_json:: from_value :: < CastConfig > ( config) ?)
72108 }
73109}
110+
111+ #[ cfg( test) ]
112+ mod tests {
113+ use super :: * ;
114+
115+ #[ test]
116+ fn test_networks_config_get ( ) {
117+ let networks = NetworksConfig {
118+ mainnet : Some ( "https://mainnet.example.com" . to_string ( ) ) ,
119+ sepolia : Some ( "https://sepolia.example.com" . to_string ( ) ) ,
120+ devnet : Some ( "https://devnet.example.com" . to_string ( ) ) ,
121+ } ;
122+
123+ assert_eq ! (
124+ networks. get_url( Network :: Mainnet ) ,
125+ Some ( & "https://mainnet.example.com" . to_string( ) )
126+ ) ;
127+ assert_eq ! (
128+ networks. get_url( Network :: Sepolia ) ,
129+ Some ( & "https://sepolia.example.com" . to_string( ) )
130+ ) ;
131+ assert_eq ! (
132+ networks. get_url( Network :: Devnet ) ,
133+ Some ( & "https://devnet.example.com" . to_string( ) )
134+ ) ;
135+ }
136+
137+ #[ test]
138+ fn test_networks_config_override ( ) {
139+ let mut global = NetworksConfig {
140+ mainnet : Some ( "https://global-mainnet.example.com" . to_string ( ) ) ,
141+ sepolia : Some ( "https://global-sepolia.example.com" . to_string ( ) ) ,
142+ devnet : None ,
143+ } ;
144+ let local = NetworksConfig {
145+ mainnet : Some ( "https://local-mainnet.example.com" . to_string ( ) ) ,
146+ sepolia : None ,
147+ devnet : None ,
148+ } ;
149+
150+ global. override_with ( & local) ;
151+
152+ // Local mainnet should override global
153+ assert_eq ! (
154+ global. mainnet,
155+ Some ( "https://local-mainnet.example.com" . to_string( ) )
156+ ) ;
157+ // Global sepolia should remain
158+ assert_eq ! (
159+ global. sepolia,
160+ Some ( "https://global-sepolia.example.com" . to_string( ) )
161+ ) ;
162+ }
163+
164+ #[ test]
165+ fn test_networks_config_rejects_unknown_fields_and_typos ( ) {
166+ // Unknown fields should cause an error
167+ let toml_str = r#"
168+ mainnet = "https://mainnet.example.com"
169+ custom = "https://custom.example.com"
170+ wrong_key = "https://sepolia.example.com"
171+ "# ;
172+
173+ let result: Result < NetworksConfig , _ > = toml:: from_str ( toml_str) ;
174+ assert ! ( result. is_err( ) ) ;
175+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "unknown field" ) ) ;
176+ }
177+ }
0 commit comments