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