1pub mod blockchain;
8pub mod client;
9pub mod crypto;
10pub mod error;
11pub mod facilitator;
12pub mod middleware;
13pub mod proxy;
14pub mod real_facilitator;
15pub mod template;
16pub mod types;
17pub mod wallet;
18
19pub use blockchain::{BlockchainClient, BlockchainClientFactory};
21pub use client::X402Client;
22pub use error::{Result, X402Error};
23pub use real_facilitator::{
24 BlockchainFacilitatorClient, BlockchainFacilitatorConfig, BlockchainFacilitatorFactory,
25};
26pub use types::*;
27pub use wallet::{Wallet, WalletFactory};
28
29#[cfg(feature = "axum")]
31pub mod axum;
32
33#[cfg(feature = "actix-web")]
34pub mod actix_web;
35
36#[cfg(feature = "warp")]
37pub mod warp;
38
39pub const VERSION: &str = env!("CARGO_PKG_VERSION");
41
42pub const X402_VERSION: u32 = 1;
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn test_version_constants() {
51 assert_eq!(X402_VERSION, 1);
52 assert_eq!(VERSION, "0.1.0");
54 }
55
56 #[test]
57 fn test_payment_requirements_creation() {
58 let requirements = PaymentRequirements::new(
59 "exact",
60 "base-sepolia",
61 "1000000",
62 "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
63 "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
64 "https://example.com/test",
65 "Test payment",
66 );
67
68 assert_eq!(requirements.scheme, "exact");
69 assert_eq!(requirements.network, "base-sepolia");
70 assert_eq!(requirements.max_amount_required, "1000000");
71 assert_eq!(
72 requirements.asset,
73 "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
74 );
75 assert_eq!(
76 requirements.pay_to,
77 "0x209693Bc6afc0C5328bA36FaF03C514EF312287C"
78 );
79 assert_eq!(requirements.resource, "https://example.com/test");
80 assert_eq!(requirements.description, "Test payment");
81 }
82
83 #[test]
84 fn test_payment_requirements_usdc_info() {
85 let mut requirements = PaymentRequirements::new(
86 "exact",
87 "base-sepolia",
88 "1000000",
89 "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
90 "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
91 "https://example.com/test",
92 "Test payment",
93 );
94
95 requirements
96 .set_usdc_info(crate::types::Network::Testnet)
97 .unwrap();
98 assert!(requirements.extra.is_some());
99
100 let extra = requirements.extra.as_ref().unwrap();
101 assert_eq!(extra["name"], "USDC");
102 assert_eq!(extra["version"], "2");
103 }
104
105 #[test]
106 fn test_payment_payload_creation() {
107 let authorization = ExactEvmPayloadAuthorization::new(
108 "0x857b06519E91e3A54538791bDbb0E22373e36b66",
109 "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
110 "1000000",
111 "1745323800",
112 "1745323985",
113 "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480",
114 );
115
116 let payload = ExactEvmPayload {
117 signature: "0x2d6a7588d6acca505cbf0d9a4a227e0c52c6c34008c8e8986a1283259764173608a2ce6496642e377d6da8dbbf5836e9bd15092f9ecab05ded3d6293af148b571c".to_string(),
118 authorization,
119 };
120
121 let payment_payload = PaymentPayload::new("exact", "base-sepolia", payload);
122
123 assert_eq!(payment_payload.x402_version, X402_VERSION);
124 assert_eq!(payment_payload.scheme, "exact");
125 assert_eq!(payment_payload.network, "base-sepolia");
126 }
127
128 #[test]
129 fn test_payment_payload_base64_encoding() {
130 let authorization = ExactEvmPayloadAuthorization::new(
131 "0x857b06519E91e3A54538791bDbb0E22373e36b66",
132 "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
133 "1000000",
134 "1745323800",
135 "1745323985",
136 "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480",
137 );
138
139 let payload = ExactEvmPayload {
140 signature: "0x2d6a7588d6acca505cbf0d9a4a227e0c52c6c34008c8e8986a1283259764173608a2ce6496642e377d6da8dbbf5836e9bd15092f9ecab05ded3d6293af148b571c".to_string(),
141 authorization,
142 };
143
144 let payment_payload = PaymentPayload::new("exact", "base-sepolia", payload);
145 let encoded = payment_payload.to_base64().unwrap();
146 let decoded = PaymentPayload::from_base64(&encoded).unwrap();
147
148 assert_eq!(payment_payload.x402_version, decoded.x402_version);
149 assert_eq!(payment_payload.scheme, decoded.scheme);
150 assert_eq!(payment_payload.network, decoded.network);
151 }
152
153 #[test]
154 fn test_authorization_validity() {
155 let now = chrono::Utc::now().timestamp();
156 let valid_after = (now - 100).to_string();
157 let valid_before = (now + 100).to_string();
158
159 let authorization = ExactEvmPayloadAuthorization::new(
160 "0x857b06519E91e3A54538791bDbb0E22373e36b66",
161 "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
162 "1000000",
163 valid_after,
164 valid_before,
165 "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480",
166 );
167
168 assert!(authorization.is_valid_now().unwrap());
169 }
170
171 #[test]
172 fn test_authorization_expired() {
173 let now = chrono::Utc::now().timestamp();
174 let valid_after = (now - 200).to_string();
175 let valid_before = (now - 100).to_string(); let authorization = ExactEvmPayloadAuthorization::new(
178 "0x857b06519E91e3A54538791bDbb0E22373e36b66",
179 "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
180 "1000000",
181 valid_after,
182 valid_before,
183 "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480",
184 );
185
186 assert!(!authorization.is_valid_now().unwrap());
187 }
188
189 #[test]
190 fn test_facilitator_config() {
191 let config = FacilitatorConfig {
192 url: "https://example.com/facilitator".to_string(),
193 timeout: Some(std::time::Duration::from_secs(30)),
194 create_auth_headers: None,
195 };
196
197 assert_eq!(config.url, "https://example.com/facilitator".to_string());
198 assert_eq!(config.timeout, Some(std::time::Duration::from_secs(30)));
199 }
200
201 #[test]
202 fn test_blockchain_facilitator_config() {
203 let config = BlockchainFacilitatorConfig {
204 rpc_url: Some("https://example.com/facilitator".to_string()),
205 network: "base-sepolia".to_string(),
206 verification_timeout: std::time::Duration::from_secs(30),
207 confirmation_blocks: 1,
208 max_retries: 3,
209 retry_delay: std::time::Duration::from_secs(1),
210 };
211
212 assert_eq!(
213 config.rpc_url,
214 Some("https://example.com/facilitator".to_string())
215 );
216 assert_eq!(
217 config.verification_timeout,
218 std::time::Duration::from_secs(30)
219 );
220 }
221
222 #[test]
223 fn test_networks() {
224 assert_eq!(networks::BASE_MAINNET, "base");
225 assert_eq!(networks::BASE_SEPOLIA, "base-sepolia");
226 assert_eq!(networks::AVALANCHE_MAINNET, "avalanche");
227 assert_eq!(networks::AVALANCHE_FUJI, "avalanche-fuji");
228
229 assert!(networks::is_supported("base-sepolia"));
230 assert!(networks::is_supported("base"));
231 assert!(!networks::is_supported("unsupported-network"));
232
233 assert_eq!(
234 networks::get_usdc_address("base-sepolia"),
235 Some("0x036CbD53842c5426634e7929541eC2318f3dCF7e")
236 );
237 assert_eq!(
238 networks::get_usdc_address("base"),
239 Some("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913")
240 );
241 }
242
243 #[test]
244 fn test_schemes() {
245 assert_eq!(schemes::EXACT, "exact");
246 }
247}