1use regex::Regex;
2use reqwest::Error;
3use std::sync::OnceLock;
4
5static ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000";
6
7pub async fn get_url_content(url: &str) -> Result<String, Error> {
8 let response = reqwest::get(url).await?;
9 response.text().await
10}
11
12pub fn is_valid_ethereum_address(address: &str) -> bool {
23 static REGEX: OnceLock<Regex> = OnceLock::new();
24 REGEX
25 .get_or_init(|| Regex::new(r"(?i)^0x[0-9a-f]{40}$").expect("regex is valid"))
26 .is_match(address)
27 && address != ZERO_ADDRESS
28}
29
30#[cfg(test)]
31mod tests {
32
33 #[test]
34 fn test_is_valid_ethereum_address() {
35 let tests = vec![
36 (
37 "valid address",
38 "0x1234567890abcdef1234567890abcdef12345678",
39 true,
40 ),
41 (
42 "uppercase",
43 "0x1234567890ABCDEF1234567890ABCDEF12345678",
44 true,
45 ),
46 (
47 "too short",
48 "0x1234567890abcdef1234567890abcdef123456",
49 false,
50 ),
51 (
52 "missing 0x prefix",
53 "001234567890abcdef1234567890abcdef12345678",
54 false,
55 ),
56 (
57 "non-hex characters",
58 "0x1234567890abcdef1234567890abcdef123ÅÅÅÅÅ",
59 false,
60 ),
61 ];
62
63 for (name, address, expected) in tests {
64 let result = super::is_valid_ethereum_address(address);
65 assert_eq!(expected, result, "{name}");
66 }
67 }
68}