/// https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md use std::str::FromStr; use regex::Regex; const CAIP2_RE: &str = r"(?P[-a-z0-9]{3,8}):(?P[-a-zA-Z0-9]{1,32})"; #[derive(Clone, Debug, PartialEq)] pub struct ChainId { pub namespace: String, pub reference: String, } #[derive(thiserror::Error, Debug)] #[error("Chain ID parse error")] pub struct ChainIdError; impl FromStr for ChainId { type Err = ChainIdError; fn from_str(value: &str) -> Result { let caip2_re = Regex::new(CAIP2_RE).unwrap(); let caps = caip2_re.captures(value).ok_or(ChainIdError)?; let chain_id = Self { namespace: caps["namespace"].to_string(), reference: caps["reference"].to_string(), }; Ok(chain_id) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_bitcoin_chain_id() { let value = "bip122:000000000019d6689c085ae165831e93"; let chain_id = value.parse::().unwrap(); assert_eq!(chain_id.namespace, "bip122"); assert_eq!(chain_id.reference, "000000000019d6689c085ae165831e93"); } #[test] fn test_parse_ethereum_chain_id() { let value = "eip155:1"; let chain_id = value.parse::().unwrap(); assert_eq!(chain_id.namespace, "eip155"); assert_eq!(chain_id.reference, "1"); } #[test] fn test_parse_invalid_chain_id() { let value = "eip155/1/abcde"; assert!(value.parse::().is_err()); } }