1use std::{
2 fmt::{Debug, Display},
3 str::FromStr,
4};
5
6use serde::{Deserialize, Serialize};
7
8use crate::core::{Address, Asset, NetworkFamily};
9
10#[derive(Debug, Clone, Copy)]
11pub struct EvmNetwork {
12 pub name: &'static str,
13 pub chain_id: u64,
14 pub network_id: &'static str,
15}
16
17impl NetworkFamily for EvmNetwork {
18 fn network_name(&self) -> &str {
19 self.name
20 }
21 fn network_id(&self) -> &str {
22 self.network_id
23 }
24}
25
26#[derive(Clone, Copy, PartialEq, Eq, Hash)]
27pub struct EvmAddress(pub alloy_primitives::Address);
28
29impl From<alloy_primitives::Address> for EvmAddress {
30 fn from(addr: alloy_primitives::Address) -> Self {
31 EvmAddress(addr)
32 }
33}
34
35impl FromStr for EvmAddress {
36 type Err = alloy_primitives::AddressError;
37
38 fn from_str(s: &str) -> Result<Self, Self::Err> {
39 let addr = alloy_primitives::Address::from_str(s)?;
40 Ok(EvmAddress(addr))
41 }
42}
43
44impl Display for EvmAddress {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(f, "{}", self.0)
47 }
48}
49
50impl Debug for EvmAddress {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 write!(f, "EvmAddress({})", self.0)
53 }
54}
55
56impl Serialize for EvmAddress {
57 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58 where
59 S: serde::Serializer,
60 {
61 serializer.serialize_str(&self.to_string())
62 }
63}
64
65impl<'de> Deserialize<'de> for EvmAddress {
66 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
67 where
68 D: serde::Deserializer<'de>,
69 {
70 let s = String::deserialize(deserializer)?;
71 EvmAddress::from_str(&s).map_err(serde::de::Error::custom)
72 }
73}
74
75impl Address for EvmAddress {
76 type Network = EvmNetwork;
77}
78
79#[derive(Clone, Copy, PartialEq, Eq, Hash)]
80pub struct EvmSignature(pub alloy_primitives::Signature);
81
82impl Display for EvmSignature {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "{}", self.0)
85 }
86}
87
88impl Debug for EvmSignature {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 write!(f, "EvmSignature({})", self.0)
91 }
92}
93
94impl FromStr for EvmSignature {
95 type Err = alloy_primitives::SignatureError;
96
97 fn from_str(s: &str) -> Result<Self, Self::Err> {
98 let sig = alloy_primitives::Signature::from_str(s)?;
99 Ok(EvmSignature(sig))
100 }
101}
102
103impl Serialize for EvmSignature {
104 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
105 where
106 S: serde::Serializer,
107 {
108 serializer.serialize_str(&self.to_string())
109 }
110}
111
112impl<'de> Deserialize<'de> for EvmSignature {
113 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114 where
115 D: serde::Deserializer<'de>,
116 {
117 let s = String::deserialize(deserializer)?;
118 EvmSignature::from_str(&s).map_err(serde::de::Error::custom)
119 }
120}
121
122impl From<alloy_primitives::Signature> for EvmSignature {
123 fn from(sig: alloy_primitives::Signature) -> Self {
124 EvmSignature(sig)
125 }
126}
127
128pub type EvmAsset = Asset<EvmAddress>;
129
130pub trait ExplicitEvmNetwork {
131 const NETWORK: EvmNetwork;
132}
133
134#[derive(Debug, Clone, Copy, Serialize)]
135pub struct Eip712Domain {
136 pub name: &'static str,
137 pub version: &'static str,
138}
139
140pub trait ExplicitEvmAsset {
141 type Network: ExplicitEvmNetwork;
142
143 const ASSET: EvmAsset;
144 const EIP712_DOMAIN: Option<Eip712Domain>;
145}
146
147impl<T> From<T> for EvmNetwork
148where
149 T: ExplicitEvmNetwork,
150{
151 fn from(_: T) -> Self {
152 T::NETWORK
153 }
154}
155
156pub mod networks {
157 use super::*;
158
159 macro_rules! define_explicit_evm_network {
160 ($struct_name:ident, $network_const:expr) => {
161 pub struct $struct_name;
162
163 impl ExplicitEvmNetwork for $struct_name {
164 const NETWORK: EvmNetwork = $network_const;
165 }
166 };
167 }
168
169 define_explicit_evm_network!(
170 Ethereum,
171 EvmNetwork {
172 name: "ethereum",
173 chain_id: 1,
174 network_id: "eip155:1",
175 }
176 );
177 define_explicit_evm_network!(
178 EthereumSepolia,
179 EvmNetwork {
180 name: "ethereum-sepolia",
181 chain_id: 11155111,
182 network_id: "eip155:11155111",
183 }
184 );
185 define_explicit_evm_network!(
186 Base,
187 EvmNetwork {
188 name: "base",
189 chain_id: 8453,
190 network_id: "eip155:8453",
191 }
192 );
193 define_explicit_evm_network!(
194 BaseSepolia,
195 EvmNetwork {
196 name: "base-sepolia",
197 chain_id: 84532,
198 network_id: "eip155:84532",
199 }
200 );
201}
202
203pub mod assets {
204 use alloy_primitives::address;
205
206 use super::*;
207
208 macro_rules! define_explicit_evm_asset {
209 (
210 $struct_name:ident,
211 $network_struct:ty,
212 $addr:expr,
213 $decimals:expr,
214 $name:expr,
215 $symbol:expr,
216 $eip712_domain:expr
217 ) => {
218 pub struct $struct_name;
219
220 impl ExplicitEvmAsset for $struct_name {
221 type Network = $network_struct;
222
223 const ASSET: EvmAsset = EvmAsset {
224 address: EvmAddress(address!($addr)),
225 decimals: $decimals,
226 name: $name,
227 symbol: $symbol,
228 };
229
230 const EIP712_DOMAIN: Option<Eip712Domain> = $eip712_domain;
231 }
232 };
233 }
234
235 macro_rules! define_explicit_usdc {
236 ($struct_name:ident, $network_struct:ty, $addr:expr) => {
237 define_explicit_evm_asset!(
238 $struct_name,
239 $network_struct,
240 $addr,
241 6,
242 "USDC",
243 "USDC",
244 Some(Eip712Domain {
245 name: "USDC",
246 version: "2",
247 })
248 );
249 };
250 }
251
252 define_explicit_usdc!(
253 UsdcEthereum,
254 networks::Ethereum,
255 "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
256 );
257
258 define_explicit_usdc!(
259 UsdcEthereumSepolia,
260 networks::EthereumSepolia,
261 "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
262 );
263
264 define_explicit_usdc!(
265 UsdcBase,
266 networks::Base,
267 "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
268 );
269
270 define_explicit_usdc!(
271 UsdcBaseSepolia,
272 networks::BaseSepolia,
273 "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
274 );
275}