x402_kit/lib.rs
1//! # X402 Kit
2//!
3//! X402 Kit is a fully modular, framework-agnostic, easy-to-extend SDK for building complex X402 payment integrations.
4//!
5//! X402-kit is **not a facilitator** — it's a composable SDK for buyers (signers) and sellers (servers) to build custom business logic.
6//! Future support for modular facilitator components is planned.
7//!
8//! ## Related Crates
9//!
10//! - **[`x402_core`]**: Core traits, types, and transport mechanisms
11//! for the X402 protocol. This crate provides the foundational building blocks that `x402-kit` builds upon.
12//! - **[`x402_paywall`]**: A framework-agnostic HTTP paywall middleware
13//! built on top of `x402-kit`. Use it to protect HTTP resources with X402 payments.
14//!
15//! ## Quick Start
16//!
17//! ```
18//! use alloy::primitives::address;
19//! use axum::{
20//! extract::{Request, State},
21//! middleware::{from_fn_with_state, Next},
22//! response::{IntoResponse, Response},
23//! routing::post,
24//! Router,
25//! };
26//! use url_macro::url;
27//! use x402_kit::{
28//! core::Resource,
29//! facilitator_client::{FacilitatorClient, StandardFacilitatorClient},
30//! networks::evm::assets::UsdcBaseSepolia,
31//! paywall::paywall::PayWall,
32//! schemes::exact_evm::ExactEvm,
33//! };
34//!
35//!
36//! #[derive(Clone)]
37//! struct PayWallState {
38//! facilitator: StandardFacilitatorClient,
39//! }
40//!
41//! let facilitator = FacilitatorClient::from_url(url!("https://facilitator.example.com"));
42//!
43//! async fn paywall_middleware(State(state): State<PayWallState>, req: Request, next: Next) -> Response {
44//! let paywall = PayWall::builder()
45//! .facilitator(state.facilitator)
46//! .accepts(
47//! ExactEvm::builder()
48//! .amount(1000)
49//! .asset(UsdcBaseSepolia)
50//! .pay_to(address!("0x3CB9B3bBfde8501f411bB69Ad3DC07908ED0dE20"))
51//! .build(),
52//! )
53//! .resource(
54//! Resource::builder()
55//! .url(url!("https://example.com/resource"))
56//! .description("Protected resource")
57//! .mime_type("application/json")
58//! .build(),
59//! )
60//! .build();
61//!
62//! paywall
63//! .handle_payment(req, |req| next.run(req))
64//! .await
65//! .unwrap_or_else(|err| err.into_response())
66//! }
67//! ```
68//!
69//! See [`examples/axum_seller.rs`](https://github.com/AIMOverse/x402-kit/blob/main/x402-kit/examples/axum_seller.rs)
70//! for a complete working example.
71//!
72//! ## Accepting Multiple Payment Methods
73//!
74//! You can accept payments from multiple networks (e.g., EVM and SVM) using [`transport::Accepts`]:
75//!
76//! ```
77//! use alloy::primitives::address;
78//! use solana_pubkey::pubkey;
79//! use x402_kit::{
80//! networks::{evm::assets::UsdcBaseSepolia, svm::assets::UsdcSolanaDevnet},
81//! schemes::{exact_evm::ExactEvm, exact_svm::ExactSvm},
82//! transport::Accepts,
83//! };
84//!
85//! let accepts = Accepts::new()
86//! .push(
87//! ExactEvm::builder()
88//! .amount(1000)
89//! .asset(UsdcBaseSepolia)
90//! .pay_to(address!("0x3CB9B3bBfde8501f411bB69Ad3DC07908ED0dE20"))
91//! .build(),
92//! )
93//! .push(
94//! ExactSvm::builder()
95//! .amount(1000)
96//! .asset(UsdcSolanaDevnet)
97//! .pay_to(pubkey!("Ge3jkza5KRfXvaq3GELNLh6V1pjjdEKNpEdGXJgjjKUR"))
98//! .build(),
99//! );
100//! ```
101//!
102//! ## Core Components Overview
103//!
104//! ### For the X402 Protocol
105//!
106//! - **[`core`]**: Core traits and types used across the X402 Kit, including resource configuration.
107//! - **[`transport`]**: Types and traits for defining X402 transport mechanisms and facilitator interactions.
108//! - **[`types`]**: Common re-usable types for defining the X402 protocol.
109//!
110//! ### For Network-Specific Implementations
111//!
112//! - **[`networks`]**: Network-specific implementations, e.g., EVM / SVM assets and addresses.
113//! - **[`schemes`]**: Payment scheme implementations, e.g., Exact EVM / Exact SVM, and their signer logic.
114//!
115//! ### Facilitator Utilities
116//!
117//! - **[`facilitator`]**: Traits and types for building X402 facilitators.
118//! - **[`facilitator_client`]**: Utilities for building X402 facilitator clients.
119//!
120//! ## Extend X402 Kit As You Like
121//!
122//! The main idea is you don't need to wait for the upstream library to support the network or asset in your case.
123//! Adding a new network, asset, or scheme is as simple as implementing a few traits.
124//!
125//! However, we still recommend contributing back any useful implementations to the main repository to help grow the ecosystem!
126//!
127//! ### New Networks
128//!
129//! If you want support for new EVM / SVM networks or assets, just "declare" them anywhere in your codebase:
130//!
131//! #### Custom EVM Network
132//!
133//! ```
134//! use x402_kit::networks::evm::{ExplicitEvmNetwork, EvmNetwork};
135//!
136//! struct MyCustomEvmNetwork;
137//!
138//! impl ExplicitEvmNetwork for MyCustomEvmNetwork {
139//! const NETWORK: EvmNetwork = EvmNetwork {
140//! name: "my-custom-evm-network",
141//! chain_id: 12345,
142//! network_id: "eip155:12345",
143//! };
144//! }
145//!
146//! // Now you can use MyCustomEvmNetwork with any scheme that supports EVM
147//! ```
148//!
149//! #### Custom SVM Network
150//!
151//! ```
152//! use x402_kit::networks::svm::{ExplicitSvmNetwork, SvmNetwork};
153//!
154//! struct MyCustomSvmNetwork;
155//!
156//! impl ExplicitSvmNetwork for MyCustomSvmNetwork {
157//! const NETWORK: SvmNetwork = SvmNetwork {
158//! name: "my-custom-svm-network",
159//! caip_2_id: "solana:BASE58_GENESIS_HASH",
160//! };
161//! }
162//!
163//! // Now you can use MyCustomSvmNetwork with any scheme that supports SVM
164//! ```
165//!
166//! ### New Assets
167//!
168//! Similarly, you can define custom assets for your networks:
169//!
170//! #### Custom EVM Asset
171//!
172//! ```
173//! use alloy_primitives::address;
174//! use x402_kit::networks::evm::{
175//! ExplicitEvmAsset, ExplicitEvmNetwork, EvmNetwork, EvmAsset, EvmAddress, Eip712Domain
176//! };
177//!
178//! struct MyCustomNetwork;
179//! impl ExplicitEvmNetwork for MyCustomNetwork {
180//! const NETWORK: EvmNetwork = EvmNetwork {
181//! name: "my-network",
182//! chain_id: 12345,
183//! network_id: "eip155:12345",
184//! };
185//! }
186//!
187//! struct MyCustomToken;
188//! impl ExplicitEvmAsset for MyCustomToken {
189//! type Network = MyCustomNetwork;
190//!
191//! const ASSET: EvmAsset = EvmAsset {
192//! address: EvmAddress(address!("0x1234567890123456789012345678901234567890")),
193//! decimals: 18,
194//! name: "My Custom Token",
195//! symbol: "MCT",
196//! };
197//!
198//! const EIP712_DOMAIN: Option<Eip712Domain> = Some(Eip712Domain {
199//! name: "My Custom Token",
200//! version: "1",
201//! });
202//! }
203//!
204//! // Now you can use MyCustomToken with ExactEvm or other EVM schemes
205//! ```
206//!
207//! #### Custom SVM Asset
208//!
209//! ```
210//! use solana_pubkey::pubkey;
211//! use x402_kit::networks::svm::{
212//! ExplicitSvmAsset, ExplicitSvmNetwork, SvmNetwork, SvmAsset, SvmAddress
213//! };
214//!
215//! struct MyCustomSvmNetwork;
216//! impl ExplicitSvmNetwork for MyCustomSvmNetwork {
217//! const NETWORK: SvmNetwork = SvmNetwork {
218//! name: "my-svm-network",
219//! caip_2_id: "solana:custom",
220//! };
221//! }
222//!
223//! struct MyCustomSvmToken;
224//! impl ExplicitSvmAsset for MyCustomSvmToken {
225//! type Network = MyCustomSvmNetwork;
226//!
227//! const ASSET: SvmAsset = SvmAsset {
228//! address: SvmAddress(pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")),
229//! decimals: 9,
230//! name: "My Custom SVM Token",
231//! symbol: "MCST",
232//! };
233//! }
234//!
235//! // Now you can use MyCustomSvmToken with ExactSvm or other SVM schemes
236//! ```
237//!
238//! #### Using Custom Assets with Schemes
239//!
240//! Once you've defined your custom asset, you can use it with payment schemes just like built-in assets:
241//!
242//! ```
243//! use alloy_primitives::address;
244//! use x402_kit::{
245//! networks::evm::{ExplicitEvmAsset, ExplicitEvmNetwork, EvmNetwork, EvmAsset, EvmAddress, Eip712Domain},
246//! schemes::exact_evm::ExactEvm,
247//! transport::PaymentRequirements,
248//! };
249//!
250//! // Define your custom network and asset
251//! struct Polygon;
252//! impl ExplicitEvmNetwork for Polygon {
253//! const NETWORK: EvmNetwork = EvmNetwork {
254//! name: "polygon",
255//! chain_id: 137,
256//! network_id: "eip155:137",
257//! };
258//! }
259//!
260//! struct UsdcPolygon;
261//! impl ExplicitEvmAsset for UsdcPolygon {
262//! type Network = Polygon;
263//! const ASSET: EvmAsset = EvmAsset {
264//! address: EvmAddress(address!("0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174")),
265//! decimals: 6,
266//! name: "USD Coin",
267//! symbol: "USDC",
268//! };
269//! const EIP712_DOMAIN: Option<Eip712Domain> = Some(Eip712Domain {
270//! name: "USD Coin",
271//! version: "2",
272//! });
273//! }
274//!
275//! # fn use_custom_asset() {
276//! // Use it in payment requirements
277//! let payment = ExactEvm::builder()
278//! .asset(UsdcPolygon)
279//! .amount(1000000) // 1 USDC
280//! .pay_to(address!("0x3CB9B3bBfde8501f411bB69Ad3DC07908ED0dE20"))
281//! .build();
282//!
283//! // Convert to PaymentRequirements for use with facilitator
284//! let requirements: PaymentRequirements = payment.into();
285//! # }
286//! ```
287//!
288//! ### Defining New Network Families
289//!
290//! If you want to define an entirely new family of networks (beyond EVM or SVM), you need to implement the core traits under [`core`]:
291//!
292//! - [`core::NetworkFamily`]: Represents a blockchain network family
293//! - [`core::Address`]: Represents an address on that network
294//!
295//! The `Address` type should also implement `FromStr`, `Display`, `Copy`, `Debug`, `Clone`, `PartialEq`, `Eq`, and `Hash` for proper serialization/deserialization and usage throughout the SDK.
296//!
297//! Here's a complete example:
298//!
299//! ```
300//! use std::{fmt::Display, str::FromStr};
301//! use x402_kit::core::{Address, Asset, NetworkFamily};
302//!
303//! // Define your network family
304//! struct MyNetworkFamily {
305//! network_name: &'static str,
306//! network_id: &'static str,
307//! }
308//!
309//! impl NetworkFamily for MyNetworkFamily {
310//! fn network_name(&self) -> &str {
311//! self.network_name
312//! }
313//! fn network_id(&self) -> &str {
314//! self.network_id
315//! }
316//! }
317//!
318//! // Define an address type for your network
319//! #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
320//! struct MyAddress(u64);
321//!
322//! impl FromStr for MyAddress {
323//! type Err = std::num::ParseIntError;
324//!
325//! fn from_str(s: &str) -> Result<Self, Self::Err> {
326//! s.parse::<u64>().map(MyAddress)
327//! }
328//! }
329//!
330//! impl Display for MyAddress {
331//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332//! write!(f, "{}", self.0)
333//! }
334//! }
335//!
336//! impl Address for MyAddress {
337//! type Network = MyNetworkFamily;
338//! }
339//!
340//! // Define an asset type for your network
341//! type MyAsset = Asset<MyAddress>;
342//!
343//! # fn use_custom_network_family() {
344//! // Now you can use your custom network family
345//! let network = MyNetworkFamily {
346//! network_name: "my-custom-network",
347//! network_id: "mynet:42",
348//! };
349//!
350//! let address: MyAddress = "12345".parse().unwrap();
351//! assert_eq!(address.to_string(), "12345");
352//!
353//! let asset = MyAsset {
354//! address,
355//! decimals: 18,
356//! name: "My Token",
357//! symbol: "MTK",
358//! };
359//! # }
360//! ```
361//!
362//! Once you have these core types defined, you can build schemes and payment requirements for your custom network family by implementing the [`core::Scheme`] trait.
363//!
364//! ### Defining new Schemes
365//!
366//! To define a new payment scheme, implement the `Scheme` trait from the `core` module. This involves specifying the associated network and payload types.
367//!
368//! Just take how `ExactSvmScheme` is defined for example:
369//!
370//! ```
371//! use serde::{Deserialize, Serialize};
372//! use x402_kit::core::Scheme;
373//! use x402_kit::networks::svm::SvmNetwork;
374//!
375//! pub struct ExactSvmScheme(pub SvmNetwork);
376//!
377//! #[derive(Debug, Clone, Serialize, Deserialize)]
378//! #[serde(rename_all = "camelCase")]
379//! pub struct ExplicitSvmPayload {
380//! pub transaction: String,
381//! }
382//!
383//! impl Scheme for ExactSvmScheme {
384//! type Network = SvmNetwork;
385//! type Payload = ExplicitSvmPayload;
386//! const SCHEME_NAME: &'static str = "exact";
387//! fn network(&self) -> &Self::Network {
388//! &self.0
389//! }
390//! }
391//! ```
392//!
393//! Then you should make an entrypoint to convert the scheme into `PaymentRequirements`.
394//!
395//! Note that `Payment` is a type-safe builder for constructing payment configurations from schemes.
396//!
397//! ```
398//! use bon::Builder;
399//! use x402_kit::core::Payment;
400//! use x402_kit::networks::svm::{ExplicitSvmAsset, ExplicitSvmNetwork, SvmAddress, SvmNetwork};
401//! use x402_kit::schemes::exact_svm::ExactSvmScheme;
402//! use x402_kit::transport::PaymentRequirements;
403//!
404//! #[derive(Builder, Debug, Clone)]
405//! pub struct ExactSvm<A: ExplicitSvmAsset> {
406//! pub asset: A,
407//! #[builder(into)]
408//! pub pay_to: SvmAddress,
409//! pub amount: u64,
410//! pub max_timeout_seconds_override: Option<u64>,
411//! }
412//!
413//! impl<A: ExplicitSvmAsset> From<ExactSvm<A>> for Payment<ExactSvmScheme, SvmAddress> {
414//! fn from(scheme: ExactSvm<A>) -> Self {
415//! Payment {
416//! scheme: ExactSvmScheme(A::Network::NETWORK),
417//! pay_to: scheme.pay_to,
418//! asset: A::ASSET,
419//! amount: scheme.amount.into(),
420//! max_timeout_seconds: scheme.max_timeout_seconds_override.unwrap_or(300),
421//! extra: None,
422//! }
423//! }
424//! }
425//!
426//! // Then implement From for PaymentRequirements
427//! impl<A: ExplicitSvmAsset> From<ExactSvm<A>> for PaymentRequirements {
428//! fn from(scheme: ExactSvm<A>) -> Self {
429//! PaymentRequirements::from(Payment::from(scheme))
430//! }
431//! }
432//! ```
433//!
434
435/// Core components for the X402 protocol.
436pub mod core {
437 pub use x402_core::core::*;
438}
439
440/// Transport mechanisms and facilitator interactions.
441pub mod transport {
442 pub use x402_core::transport::*;
443}
444
445/// Common types used across the X402 protocol.
446pub mod types {
447 pub use x402_core::types::*;
448}
449
450/// Facilitator traits and types.
451pub mod facilitator {
452 pub use x402_core::facilitator::*;
453}
454
455/// Errors used across X402 Kit.
456pub mod errors {
457 pub use x402_core::errors::*;
458}
459
460/// X402 Paywall middleware for protecting HTTP resources.
461#[cfg(feature = "paywall")]
462pub mod paywall {
463 pub use x402_paywall::*;
464}
465
466/// Facilitator client utilities.
467#[cfg(feature = "facilitator-client")]
468pub mod facilitator_client;
469/// Network-specific implementations.
470pub mod networks;
471/// Payment scheme implementations.
472pub mod schemes;