layer_climb_address/address/
evm.rs1use std::{borrow::Cow, str::FromStr};
2
3use anyhow::{anyhow, bail, Result};
4use cosmwasm_schema::cw_schema;
5
6#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, bincode::Encode, bincode::Decode)]
10#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
11#[cfg_attr(feature = "cw-storage", derive(cw_storage_plus::NewTypeKey))]
12pub struct EvmAddr([u8; 20]);
13
14impl EvmAddr {
15 pub fn new(bytes: [u8; 20]) -> Self {
16 Self(bytes)
17 }
18
19 pub fn new_vec(bytes: Vec<u8>) -> Result<Self> {
20 if bytes.len() != 20 {
21 bail!("Invalid length for EVM address");
22 }
23 let mut arr = [0u8; 20];
24 arr.copy_from_slice(&bytes);
25 Ok(Self(arr))
26 }
27
28 pub fn new_pub_key(_pub_key: &tendermint::PublicKey) -> Result<Self> {
29 Err(anyhow!("TODO - support EVM pub key"))
30 }
31
32 pub fn new_str(s: &str) -> Result<Self> {
33 Self::new_vec(const_hex::decode(s.trim())?)
34 }
35
36 pub fn as_bytes(&self) -> [u8; 20] {
37 self.0
38 }
39}
40impl cw_schema::Schemaifier for EvmAddr {
41 #[inline]
42 fn visit_schema(visitor: &mut cw_schema::SchemaVisitor) -> cw_schema::DefinitionReference {
43 let node = cw_schema::Node {
44 name: Cow::Borrowed(std::any::type_name::<Self>()),
45 description: None,
46 value: cw_schema::NodeType::String,
47 };
48
49 visitor.insert(Self::id(), node)
50 }
51}
52
53impl cosmwasm_schema::schemars::JsonSchema for EvmAddr {
54 fn schema_name() -> String {
55 "EvmAddr".into()
56 }
57
58 fn json_schema(
59 _generator: &mut cosmwasm_schema::schemars::r#gen::SchemaGenerator,
60 ) -> cosmwasm_schema::schemars::schema::Schema {
61 cosmwasm_schema::schemars::schema::Schema::Object(
62 cosmwasm_schema::schemars::schema::SchemaObject {
63 instance_type: Some(cosmwasm_schema::schemars::schema::SingleOrVec::Single(
64 Box::new(cosmwasm_schema::schemars::schema::InstanceType::String),
65 )),
66 format: Some("evm-address".into()),
67 ..Default::default()
68 },
69 )
70 }
71}
72
73impl std::fmt::Display for EvmAddr {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(f, "0x{}", const_hex::encode(self.0))
76 }
77}
78
79impl FromStr for EvmAddr {
80 type Err = anyhow::Error;
81
82 fn from_str(s: &str) -> Result<Self> {
83 Self::new_str(s)
84 }
85}
86
87impl serde::Serialize for EvmAddr {
88 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
89 where
90 S: serde::Serializer,
91 {
92 serializer.serialize_str(&self.to_string())
93 }
94}
95
96impl<'de> serde::Deserialize<'de> for EvmAddr {
97 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98 where
99 D: serde::Deserializer<'de>,
100 {
101 let s = String::deserialize(deserializer)?;
102 s.parse().map_err(serde::de::Error::custom)
103 }
104}
105
106impl From<alloy_primitives::Address> for EvmAddr {
108 fn from(addr: alloy_primitives::Address) -> Self {
109 Self(**addr)
110 }
111}
112
113impl From<EvmAddr> for alloy_primitives::Address {
114 fn from(addr: EvmAddr) -> Self {
115 alloy_primitives::Address::new(addr.0)
116 }
117}