1use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
5pub enum ChainType {
6 Evm(EvmChain),
7 Aptos(AptosChain),
8 Sui(SuiChain),
9 Solana(SolanaChain),
10 Custom(String),
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
14pub enum EvmChain {
15 Ethereum,
16 Polygon,
17 BinanceSmartChain,
18 Arbitrum,
19 Optimism,
20 Avalanche,
21 Base,
22 Custom(String),
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
26pub enum AptosChain {
27 Mainnet,
28 Testnet,
29 Devnet,
30 Custom(String),
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
34pub enum SuiChain {
35 Mainnet,
36 Testnet,
37 Devnet,
38 Custom(String),
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
42pub enum SolanaChain {
43 Mainnet,
44 Testnet,
45 Devnet,
46 Custom(String),
47}
48
49impl ChainType {
50 pub fn get_standard_chain_id(&self) -> String {
51 match self {
52 ChainType::Evm(evm_chain) => match evm_chain {
53 EvmChain::Ethereum => "1",
54 EvmChain::Polygon => "137",
55 EvmChain::BinanceSmartChain => "56",
56 EvmChain::Arbitrum => "42161",
57 EvmChain::Optimism => "10",
58 EvmChain::Avalanche => "43114",
59 EvmChain::Base => "8453",
60 EvmChain::Custom(id) => id,
61 }
62 .to_string(),
63 ChainType::Aptos(aptos_chain) => match aptos_chain {
64 AptosChain::Mainnet => "1",
65 AptosChain::Testnet => "2",
66 AptosChain::Devnet => "devnet",
67 AptosChain::Custom(id) => id,
68 }
69 .to_string(),
70 ChainType::Sui(sui_chain) => match sui_chain {
71 SuiChain::Mainnet => "mainnet",
72 SuiChain::Testnet => "testnet",
73 SuiChain::Devnet => "devnet",
74 SuiChain::Custom(id) => id,
75 }
76 .to_string(),
77 ChainType::Solana(solana_chain) => match solana_chain {
78 SolanaChain::Mainnet => "mainnet-beta",
79 SolanaChain::Testnet => "testnet",
80 SolanaChain::Devnet => "devnet",
81 SolanaChain::Custom(id) => id,
82 }
83 .to_string(),
84 ChainType::Custom(id) => id.clone(),
85 }
86 }
87
88 pub fn get_display_name(&self) -> String {
89 match self {
90 ChainType::Evm(evm_chain) => match evm_chain {
91 EvmChain::Ethereum => "Ethereum",
92 EvmChain::Polygon => "Polygon",
93 EvmChain::BinanceSmartChain => "BNB Smart Chain",
94 EvmChain::Arbitrum => "Arbitrum",
95 EvmChain::Optimism => "Optimism",
96 EvmChain::Avalanche => "Avalanche",
97 EvmChain::Base => "Base",
98 EvmChain::Custom(name) => name,
99 }
100 .to_string(),
101 ChainType::Aptos(aptos_chain) => match aptos_chain {
102 AptosChain::Mainnet => "Aptos Mainnet",
103 AptosChain::Testnet => "Aptos Testnet",
104 AptosChain::Devnet => "Aptos Devnet",
105 AptosChain::Custom(name) => name,
106 }
107 .to_string(),
108 ChainType::Sui(sui_chain) => match sui_chain {
109 SuiChain::Mainnet => "Sui Mainnet",
110 SuiChain::Testnet => "Sui Testnet",
111 SuiChain::Devnet => "Sui Devnet",
112 SuiChain::Custom(name) => name,
113 }
114 .to_string(),
115 ChainType::Solana(solana_chain) => match solana_chain {
116 SolanaChain::Mainnet => "Solana Mainnet",
117 SolanaChain::Testnet => "Solana Testnet",
118 SolanaChain::Devnet => "Solana Devnet",
119 SolanaChain::Custom(name) => name,
120 }
121 .to_string(),
122 ChainType::Custom(name) => name.clone(),
123 }
124 }
125
126 pub fn is_evm(&self) -> bool {
127 matches!(self, ChainType::Evm(_))
128 }
129
130 pub fn is_aptos(&self) -> bool {
131 matches!(self, ChainType::Aptos(_))
132 }
133
134 pub fn is_sui(&self) -> bool {
135 matches!(self, ChainType::Sui(_))
136 }
137
138 pub fn is_solana(&self) -> bool {
139 matches!(self, ChainType::Solana(_))
140 }
141}
142
143impl ChainType {
144 pub fn ethereum() -> Self {
145 ChainType::Evm(EvmChain::Ethereum)
146 }
147
148 pub fn polygon() -> Self {
149 ChainType::Evm(EvmChain::Polygon)
150 }
151
152 pub fn bsc() -> Self {
153 ChainType::Evm(EvmChain::BinanceSmartChain)
154 }
155
156 pub fn aptos_mainnet() -> Self {
157 ChainType::Aptos(AptosChain::Mainnet)
158 }
159
160 pub fn sui_mainnet() -> Self {
161 ChainType::Sui(SuiChain::Mainnet)
162 }
163
164 pub fn solana_mainnet() -> Self {
165 ChainType::Solana(SolanaChain::Mainnet)
166 }
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct ChainConfig {
171 pub chain_type: ChainType,
172 pub chain_id: String,
173 pub rpc_url: Option<String>,
174}
175
176impl ChainConfig {
177 pub fn new(chain_type: ChainType, rpc_url: Option<String>) -> Self {
178 let chain_id = chain_type.get_standard_chain_id();
179 Self {
180 chain_type,
181 chain_id,
182 rpc_url,
183 }
184 }
185
186 pub fn from_chain_type(chain_type: ChainType) -> Self {
187 Self::new(chain_type, None)
188 }
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct PaymentRequest {
193 pub amount: String,
194 pub currency: Currency,
195 pub recipient: String,
196 pub chain: ChainConfig,
197 pub description: Option<String>,
198 pub expires_at: Option<u64>,
199 pub nonce: String,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub enum Currency {
204 Native,
205 Token { address: String, decimals: u8 },
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct PaymentVerification {
210 pub is_paid: bool,
211 pub paid_amount: String,
212 pub transaction_hash: Option<String>,
213 pub verified_at: u64,
214 pub chain: ChainConfig,
215 pub transaction_logs: Vec<TransactionLog>,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct X402ProtocolResponse {
220 pub status: u16,
221 pub payment_required: PaymentRequest,
222 pub verification_url: Option<String>,
223}
224
225#[derive(Debug, Clone)]
226pub struct VerificationResult {
227 pub should_serve_content: bool,
228 pub http_status: u16,
229 pub x402_response: Option<X402ProtocolResponse>,
230 pub verification: Option<PaymentVerification>,
231}
232
233#[derive(Debug, Clone)]
234pub struct X402Config {
235 pub default_chain: ChainConfig,
236 pub service_address: String,
237 pub service_fee: String,
238 pub cache_ttl: u64,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct TransactionLog {
243 pub transaction_hash: String,
244 pub from: String,
245 pub to: String,
246 pub value: String,
247 pub block_number: u64,
248 pub log_index: u64,
249 pub data: Option<String>,
250}