diff --git a/crates/settings/src/config.rs b/crates/settings/src/config.rs index a473a0f28..bbe724303 100644 --- a/crates/settings/src/config.rs +++ b/crates/settings/src/config.rs @@ -34,6 +34,8 @@ pub struct Config { pub deployments: HashMap>, pub sentry: Option, pub raindex_version: Option, + #[typeshare(typescript(type = "Record"))] + pub watchlist: Option>>, } pub type Subgraph = Url; @@ -169,6 +171,12 @@ impl TryFrom for Config { }) .collect::>, ParseConfigSourceError>>()?; + let watchlist = item.watchlist.map(|wl| { + wl.into_iter() + .map(|(name, address)| (name, Arc::new(address))) + .collect::>>() + }); + let config = Config { raindex_version: item.raindex_version, networks, @@ -182,6 +190,7 @@ impl TryFrom for Config { charts, deployments, sentry: item.sentry, + watchlist, }; Ok(config) @@ -273,6 +282,10 @@ mod tests { let charts = HashMap::new(); let deployments = HashMap::new(); let sentry = Some(true); + let watchlist = Some(HashMap::from([( + "name-one".to_string(), + "address-one".to_string(), + )])); let config_string = ConfigSource { raindex_version: Some("0x123".to_string()), @@ -288,6 +301,7 @@ mod tests { charts, deployments, sentry, + watchlist, }; let config_result = Config::try_from(config_string); @@ -346,5 +360,13 @@ mod tests { // Verify raindex_version assert_eq!(config.raindex_version, Some("0x123".to_string())); + + // Verify watchlist + assert!(config.watchlist.is_some()); + let watchlist = config.watchlist.as_ref().unwrap(); + assert_eq!(watchlist.len(), 1); + let (name, address) = watchlist.iter().next().unwrap(); + assert_eq!(name, "name-one"); + assert_eq!(address.as_str(), "address-one"); } } diff --git a/crates/settings/src/config_source.rs b/crates/settings/src/config_source.rs index 9c22fb4d3..95e143d40 100644 --- a/crates/settings/src/config_source.rs +++ b/crates/settings/src/config_source.rs @@ -38,6 +38,8 @@ pub struct ConfigSource { pub sentry: Option, #[serde(skip_serializing_if = "Option::is_none")] pub raindex_version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub watchlist: Option>, } #[typeshare] @@ -371,7 +373,11 @@ deployments: scenario: mainScenario order: buyETH -sentry: true"#, +sentry: true + +watchlist: + name-one: address-one + name-two: address-two"#, mocked_chain_id_server.url("/json") ); @@ -476,6 +482,10 @@ sentry: true"#, assert_eq!(order.orderbook, expected_order.orderbook); assert_eq!(config.raindex_version, Some("123".to_string())); + + let watchlist = config.watchlist.unwrap(); + assert_eq!(watchlist.get("name-one").unwrap(), "address-one"); + assert_eq!(watchlist.get("name-two").unwrap(), "address-two"); } #[tokio::test] diff --git a/crates/settings/src/merge.rs b/crates/settings/src/merge.rs index 06de126bd..feb2f67b0 100644 --- a/crates/settings/src/merge.rs +++ b/crates/settings/src/merge.rs @@ -36,6 +36,9 @@ pub enum MergeError { #[error("There is already a remote networks definition called {0}")] RemoteNetworksCollision(String), + + #[error("There is already a watchlist called {0}")] + WatchlistCollision(String), } impl ConfigSource { @@ -147,6 +150,22 @@ impl ConfigSource { (Some(_), Some(_)) => Err(MergeError::DeploymentCollision("sentry".into())), }?; + // Watchlist + match (&mut self.watchlist, other.watchlist) { + (Some(watchlist), Some(other_watchlist)) => { + for (key, value) in other_watchlist { + if watchlist.contains_key(&key) { + return Err(MergeError::WatchlistCollision(key)); + } + watchlist.insert(key, value); + } + } + (None, Some(other_watchlist)) => { + self.watchlist = Some(other_watchlist); + } + _ => {} + } + Ok(()) } } @@ -251,6 +270,22 @@ impl Config { (Some(_), Some(_)) => Err(MergeError::DeploymentCollision("sentry".into())), }?; + // Watchlist + match (&mut self.watchlist, other.watchlist) { + (Some(watchlist), Some(other_watchlist)) => { + for (key, value) in other_watchlist { + if watchlist.contains_key(&key) { + return Err(MergeError::WatchlistCollision(key)); + } + watchlist.insert(key, value); + } + } + (None, Some(other_watchlist)) => { + self.watchlist = Some(other_watchlist); + } + _ => {} + } + Ok(()) } } @@ -277,6 +312,7 @@ mod tests { networks: HashMap::new(), deployments: HashMap::new(), sentry: None, + watchlist: None, }; let other = ConfigSource { @@ -293,6 +329,7 @@ mod tests { networks: HashMap::new(), deployments: HashMap::new(), sentry: None, + watchlist: None, }; assert_eq!(config.merge(other), Ok(())); @@ -314,6 +351,7 @@ mod tests { networks: HashMap::new(), deployments: HashMap::new(), sentry: None, + watchlist: None, }; let mut other = ConfigSource { @@ -330,6 +368,7 @@ mod tests { networks: HashMap::new(), deployments: HashMap::new(), sentry: None, + watchlist: None, }; // Add a collision to cause an unsuccessful merge @@ -365,6 +404,7 @@ mod tests { networks: HashMap::new(), deployments: HashMap::new(), sentry: None, + watchlist: None, }; let mut other = ConfigSource { @@ -381,6 +421,7 @@ mod tests { networks: HashMap::new(), deployments: HashMap::new(), sentry: None, + watchlist: None, }; other.metaboards.insert( diff --git a/crates/settings/src/scenario.rs b/crates/settings/src/scenario.rs index 052c4627e..6d457d6df 100644 --- a/crates/settings/src/scenario.rs +++ b/crates/settings/src/scenario.rs @@ -213,6 +213,7 @@ mod tests { charts: HashMap::new(), // Assuming no charts for simplification deployments: HashMap::new(), sentry: None, + watchlist: None, // Assuming no watchlist for simplification }; // Perform the conversion diff --git a/tauri-app/src/lib/mocks/settings.ts b/tauri-app/src/lib/mocks/settings.ts index 5007872fe..beab1514c 100644 --- a/tauri-app/src/lib/mocks/settings.ts +++ b/tauri-app/src/lib/mocks/settings.ts @@ -31,6 +31,10 @@ const mockConfigSource: ConfigSource = { metaboards: { metaboard1: 'https://example.com/metaboard1', }, + watchlist: { + name_one: 'address_one', + name_two: 'address_two', + }, }; export const mockSettingsStore = writable(mockConfigSource); diff --git a/tauri-app/src/lib/stores/settings.ts b/tauri-app/src/lib/stores/settings.ts index f802b3f8d..5d9b8ace8 100644 --- a/tauri-app/src/lib/stores/settings.ts +++ b/tauri-app/src/lib/stores/settings.ts @@ -103,6 +103,9 @@ export const hasRequiredSettings = derived( $activeNetworkRef !== undefined && $activeOrderbookRef !== undefined, ); +// watchlist +export const watchlist = derived(settings, ($settings) => $settings?.watchlist ?? []); + // When networks / orderbooks settings updated, reset active network / orderbook settings.subscribe(async () => { const $settings = await settings.load(); diff --git a/tauri-app/src/tests/pickConfig.test.ts b/tauri-app/src/tests/pickConfig.test.ts index d423a1390..9185fafa3 100644 --- a/tauri-app/src/tests/pickConfig.test.ts +++ b/tauri-app/src/tests/pickConfig.test.ts @@ -151,6 +151,10 @@ export const config: Config = { }, }, }, + watchlist: { + name_one: 'address_one', + name_two: 'address_two', + }, }; export const configSource: ConfigSource = { @@ -214,6 +218,10 @@ export const configSource: ConfigSource = { order: 'sell', }, }, + watchlist: { + name_one: 'address_one', + name_two: 'address_two', + }, }; test('pick deployments', () => {