Skip to main content

eth_avatars/modules/ethereum/
mod.rs

1use 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/**
22 * CAIP-2 Ethereum `eip155:` Uri
23 */
24#[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}