Skip to main content

xmtp_id/associations/ident/
ethereum.rs

1use serde::{Deserialize, Serialize};
2use std::fmt::Display;
3use xmtp_cryptography::signature::{IdentifierValidationError, sanitize_evm_addresses};
4
5#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
6pub struct Ethereum(pub String);
7
8impl Ethereum {
9    #[cfg(any(test, feature = "test-utils"))]
10    pub fn rand() -> Self {
11        Self(xmtp_common::rand_hexstring())
12    }
13
14    pub fn sanitize(self) -> Result<Self, IdentifierValidationError> {
15        let mut sanitized = sanitize_evm_addresses(&[self.0])?;
16        Ok(Self(sanitized.pop().expect("Always should be one")))
17    }
18
19    /// Whether the address is in the one form a signer is derived in: `0x`
20    /// followed by exactly 40 lowercase hexadecimal characters.
21    pub fn is_canonical(&self) -> bool {
22        self.0.strip_prefix("0x").is_some_and(|hex| {
23            hex.len() == 40 && hex.bytes().all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'f'))
24        })
25    }
26}
27
28impl Display for Ethereum {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        write!(f, "{}", self.0)
31    }
32}