use scope::config::Config;
use scope::domain::address_book::AddressBook;
use scope::market::{MarketVenue, VenueRegistry};
use scope::tokens::TokenAliases;
#[derive(Debug, Clone, Default)]
pub struct Vocab {
pub labels: Vec<String>,
pub aliases: Vec<String>,
pub venues: Vec<String>,
pub chains: Vec<String>,
}
impl Vocab {
pub fn load(config: &Config) -> Self {
let mut labels: Vec<String> = AddressBook::load(&config.data_dir())
.map(|b| b.addresses.into_iter().filter_map(|a| a.label).collect())
.unwrap_or_default();
labels.sort();
labels.dedup();
let mut aliases: Vec<String> = TokenAliases::load()
.list()
.into_iter()
.map(|t| t.symbol.clone())
.collect();
aliases.sort();
aliases.dedup();
let venues = VenueRegistry::load()
.map(|r| MarketVenue::ids(&r))
.unwrap_or_default();
Self {
labels,
aliases,
venues,
chains: scope::chains::registry::client_chain_ids()
.iter()
.map(|c| c.to_string())
.collect(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_load_with_missing_stores_still_has_chains() {
let dir = tempfile::tempdir().unwrap();
let mut config = Config::default();
config.address_book.data_dir = Some(dir.path().join("nothing-here"));
let v = Vocab::load(&config);
assert!(v.labels.is_empty());
assert!(v.chains.iter().any(|c| c == "ethereum"));
}
#[test]
fn test_load_with_corrupt_address_book_gives_empty_labels() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("address_book.yaml"), "addresses: [unclosed").unwrap();
let mut config = Config::default();
config.address_book.data_dir = Some(dir.path().to_path_buf());
let v = Vocab::load(&config);
assert!(v.labels.is_empty());
}
#[test]
fn test_labels_come_from_the_address_book() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(
dir.path().join("address_book.yaml"),
"addresses:\n - address: '0x1'\n label: cold\n chain: ethereum\n tags: []\n added_at: 0\n",
)
.unwrap();
let mut config = Config::default();
config.address_book.data_dir = Some(dir.path().to_path_buf());
assert_eq!(Vocab::load(&config).labels, vec!["cold"]);
}
}