eth_avatars/modules/ethereum/
mod.rs1use std::{str::FromStr, sync::LazyLock};
2
3use alloy::primitives::{Address, ChainId, U256};
4use regex::Regex;
5use strum::{Display, EnumString};
6
7use crate::{Locator, LocatorError, Resource};
8
9pub mod abi;
10pub mod nft;
11pub mod resolver;
12pub use resolver::EthereumResolver;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumString, Display)]
15#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
16pub enum ContractType {
17 ERC721,
18 ERC1155,
19}
20
21#[derive(Debug, PartialEq, Eq)]
25pub struct Ethereum {
26 pub network_id: ChainId,
27 pub contract_type: ContractType,
28 pub contract: Address,
29 pub token_id: U256,
30}
31
32static EIP155_URI: LazyLock<Regex> = LazyLock::new(|| {
33 Regex::new(r"^(?i:eip155):([0-9]+)/(?i:(erc1155|erc721)):0x([0-9a-fA-F]{40})/([0-9]+)$")
34 .expect("should be a valid regex")
35});
36
37impl FromStr for Ethereum {
38 type Err = LocatorError;
39
40 fn from_str(s: &str) -> Result<Self, Self::Err> {
41 let (_, [network_id, contract_type, contract, token_id]) = EIP155_URI
42 .captures(s)
43 .ok_or(LocatorError::Invalid)?
44 .extract();
45
46 Ok(Self {
47 network_id: network_id.parse().map_err(|_| LocatorError::Invalid)?,
48 contract_type: contract_type.parse().map_err(|_| LocatorError::Invalid)?,
49 contract: contract.parse().map_err(|_| LocatorError::Invalid)?,
50 token_id: U256::from_str_radix(token_id, 10).map_err(|_| LocatorError::Invalid)?,
51 })
52 }
53}
54
55impl Locator for Ethereum {
56 fn of(resource: &Resource) -> Option<&Self> {
57 match resource {
58 Resource::Ethereum(ethereum) => Some(ethereum),
59 _ => None,
60 }
61 }
62}