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-paywall`](https://docs.rs/x402-paywall)**: A framework-agnostic HTTP paywall middleware
11//!   built on top of `x402-kit`. Use it to protect HTTP resources with X402 payments.
12//!
13//! ## Core Components Overview
14//!
15//! ### For the X402 Protocol
16//!
17//! - **[`core`]**: Core traits and types used across the X402 Kit, including resource configuration.
18//! - **[`transport`]**: Types and traits for defining X402 transport mechanisms and facilitator interactions.
19//! - **[`types`]**: Common re-usable types for defining the X402 protocol.
20//!
21//! ### For Network-Specific Implementations
22//!
23//! - **[`networks`]**: Network-specific implementations, e.g., EVM / SVM assets and addresses.
24//! - **[`schemes`]**: Payment scheme implementations, e.g., Exact EVM / Exact SVM, and their signer logic.
25//!
26//! ### Facilitator Utilities
27//!
28//! - **[`facilitator`]**: Traits and types for building X402 facilitators.
29//! - **[`facilitator_client`]**: Utilities for building X402 facilitator clients.
30//!
31//! ## Extend X402 Kit As You Like
32//!
33//! The main idea is you don't need to wait for the upstream library to support the network or asset in your case.
34//! Adding a new network, asset, or scheme is as simple as implementing a few traits.
35//!
36//! However, we still recommend contributing back any useful implementations to the main repository to help grow the ecosystem!
37//!
38//! ### New Networks
39//!
40//! If you want support for new EVM / SVM networks or assets, just "declare" them anywhere in your codebase:
41//!
42//! #### Custom EVM Network
43//!
44//! ```
45//! use x402_kit::networks::evm::{ExplicitEvmNetwork, EvmNetwork};
46//!
47//! struct MyCustomEvmNetwork;
48//!
49//! impl ExplicitEvmNetwork for MyCustomEvmNetwork {
50//!     const NETWORK: EvmNetwork = EvmNetwork {
51//!         name: "my-custom-evm-network",
52//!         chain_id: 12345,
53//!         network_id: "eip155:12345",
54//!     };
55//! }
56//!
57//! // Now you can use MyCustomEvmNetwork with any scheme that supports EVM
58//! ```
59//!
60//! #### Custom SVM Network
61//!
62//! ```
63//! use x402_kit::networks::svm::{ExplicitSvmNetwork, SvmNetwork};
64//!
65//! struct MyCustomSvmNetwork;
66//!
67//! impl ExplicitSvmNetwork for MyCustomSvmNetwork {
68//!     const NETWORK: SvmNetwork = SvmNetwork {
69//!         name: "my-custom-svm-network",
70//!         caip_2_id: "solana:BASE58_GENESIS_HASH",
71//!     };
72//! }
73//!
74//! // Now you can use MyCustomSvmNetwork with any scheme that supports SVM
75//! ```
76//!
77//! ### New Assets
78//!
79//! Similarly, you can define custom assets for your networks:
80//!
81//! #### Custom EVM Asset
82//!
83//! ```
84//! use alloy_primitives::address;
85//! use x402_kit::networks::evm::{
86//!     ExplicitEvmAsset, ExplicitEvmNetwork, EvmNetwork, EvmAsset, EvmAddress, Eip712Domain
87//! };
88//!
89//! struct MyCustomNetwork;
90//! impl ExplicitEvmNetwork for MyCustomNetwork {
91//!     const NETWORK: EvmNetwork = EvmNetwork {
92//!         name: "my-network",
93//!         chain_id: 12345,
94//!         network_id: "eip155:12345",
95//!     };
96//! }
97//!
98//! struct MyCustomToken;
99//! impl ExplicitEvmAsset for MyCustomToken {
100//!     type Network = MyCustomNetwork;
101//!
102//!     const ASSET: EvmAsset = EvmAsset {
103//!         address: EvmAddress(address!("0x1234567890123456789012345678901234567890")),
104//!         decimals: 18,
105//!         name: "My Custom Token",
106//!         symbol: "MCT",
107//!     };
108//!
109//!     const EIP712_DOMAIN: Option<Eip712Domain> = Some(Eip712Domain {
110//!         name: "My Custom Token",
111//!         version: "1",
112//!     });
113//! }
114//!
115//! // Now you can use MyCustomToken with ExactEvm or other EVM schemes
116//! ```
117//!
118//! #### Custom SVM Asset
119//!
120//! ```
121//! use solana_pubkey::pubkey;
122//! use x402_kit::networks::svm::{
123//!     ExplicitSvmAsset, ExplicitSvmNetwork, SvmNetwork, SvmAsset, SvmAddress
124//! };
125//!
126//! struct MyCustomSvmNetwork;
127//! impl ExplicitSvmNetwork for MyCustomSvmNetwork {
128//!     const NETWORK: SvmNetwork = SvmNetwork {
129//!         name: "my-svm-network",
130//!         caip_2_id: "solana:custom",
131//!     };
132//! }
133//!
134//! struct MyCustomSvmToken;
135//! impl ExplicitSvmAsset for MyCustomSvmToken {
136//!     type Network = MyCustomSvmNetwork;
137//!
138//!     const ASSET: SvmAsset = SvmAsset {
139//!         address: SvmAddress(pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")),
140//!         decimals: 9,
141//!         name: "My Custom SVM Token",
142//!         symbol: "MCST",
143//!     };
144//! }
145//!
146//! // Now you can use MyCustomSvmToken with ExactSvm or other SVM schemes
147//! ```
148//!
149//! #### Using Custom Assets with Schemes
150//!
151//! Once you've defined your custom asset, you can use it with payment schemes just like built-in assets:
152//!
153//! ```no_run
154//! use alloy_primitives::address;
155//! use x402_kit::{
156//!     networks::evm::{ExplicitEvmAsset, ExplicitEvmNetwork, EvmNetwork, EvmAsset, EvmAddress, Eip712Domain},
157//!     schemes::exact_evm::ExactEvm,
158//!     transport::PaymentRequirements,
159//! };
160//!
161//! // Define your custom network and asset
162//! struct Polygon;
163//! impl ExplicitEvmNetwork for Polygon {
164//!     const NETWORK: EvmNetwork = EvmNetwork {
165//!         name: "polygon",
166//!         chain_id: 137,
167//!         network_id: "eip155:137",
168//!     };
169//! }
170//!
171//! struct UsdcPolygon;
172//! impl ExplicitEvmAsset for UsdcPolygon {
173//!     type Network = Polygon;
174//!     const ASSET: EvmAsset = EvmAsset {
175//!         address: EvmAddress(address!("0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174")),
176//!         decimals: 6,
177//!         name: "USD Coin",
178//!         symbol: "USDC",
179//!     };
180//!     const EIP712_DOMAIN: Option<Eip712Domain> = Some(Eip712Domain {
181//!         name: "USD Coin",
182//!         version: "2",
183//!     });
184//! }
185//!
186//! # fn use_custom_asset() {
187//! // Use it in payment requirements
188//! let payment = ExactEvm::builder()
189//!     .asset(UsdcPolygon)
190//!     .amount(1000000) // 1 USDC
191//!     .pay_to(address!("0x3CB9B3bBfde8501f411bB69Ad3DC07908ED0dE20"))
192//!     .build();
193//!
194//! // Convert to PaymentRequirements for use with facilitator
195//! let requirements: PaymentRequirements = payment.into();
196//! # }
197//! ```
198//!
199//! ### Defining New Network Families
200//!
201//! If you want to define an entirely new family of networks (beyond EVM or SVM), you need to implement the core traits under [`core`]:
202//!
203//! - [`core::NetworkFamily`]: Represents a blockchain network family
204//! - [`core::Address`]: Represents an address on that network
205//!
206//! The `Address` type should also implement `FromStr`, `Display`, `Copy`, `Debug`, `Clone`, `PartialEq`, `Eq`, and `Hash` for proper serialization/deserialization and usage throughout the SDK.
207//!
208//! Here's a complete example:
209//!
210//! ```
211//! use std::{fmt::Display, str::FromStr};
212//! use x402_kit::core::{Address, Asset, NetworkFamily};
213//!
214//! // Define your network family
215//! struct MyNetworkFamily {
216//!     network_name: &'static str,
217//!     network_id: &'static str,
218//! }
219//!
220//! impl NetworkFamily for MyNetworkFamily {
221//!     fn network_name(&self) -> &str {
222//!         self.network_name
223//!     }
224//!     fn network_id(&self) -> &str {
225//!         self.network_id
226//!     }
227//! }
228//!
229//! // Define an address type for your network
230//! #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
231//! struct MyAddress(u64);
232//!
233//! impl FromStr for MyAddress {
234//!     type Err = std::num::ParseIntError;
235//!
236//!     fn from_str(s: &str) -> Result<Self, Self::Err> {
237//!         s.parse::<u64>().map(MyAddress)
238//!     }
239//! }
240//!
241//! impl Display for MyAddress {
242//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243//!         write!(f, "{}", self.0)
244//!     }
245//! }
246//!
247//! impl Address for MyAddress {
248//!     type Network = MyNetworkFamily;
249//! }
250//!
251//! // Define an asset type for your network
252//! type MyAsset = Asset<MyAddress>;
253//!
254//! # fn use_custom_network_family() {
255//! // Now you can use your custom network family
256//! let network = MyNetworkFamily {
257//!     network_name: "my-custom-network",
258//!     network_id: "mynet:42",
259//! };
260//!
261//! let address: MyAddress = "12345".parse().unwrap();
262//! assert_eq!(address.to_string(), "12345");
263//!
264//! let asset = MyAsset {
265//!     address,
266//!     decimals: 18,
267//!     name: "My Token",
268//!     symbol: "MTK",
269//! };
270//! # }
271//! ```
272//!
273//! 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.
274//!
275//! ### Defining new Schemes
276//!
277//! To define a new payment scheme, implement the `Scheme` trait from the `core` module. This involves specifying the associated network and payload types.
278//!
279//! Just take how `ExactSvmScheme` is defined for example:
280//!
281//! ```
282//! use serde::{Deserialize, Serialize};
283//! use x402_kit::core::Scheme;
284//! use x402_kit::networks::svm::SvmNetwork;
285//!
286//! pub struct ExactSvmScheme(pub SvmNetwork);
287//!
288//! #[derive(Debug, Clone, Serialize, Deserialize)]
289//! #[serde(rename_all = "camelCase")]
290//! pub struct ExplicitSvmPayload {
291//!     pub transaction: String,
292//! }
293//!
294//! impl Scheme for ExactSvmScheme {
295//!     type Network = SvmNetwork;
296//!     type Payload = ExplicitSvmPayload;
297//!     const SCHEME_NAME: &'static str = "exact";
298//!     fn network(&self) -> &Self::Network {
299//!         &self.0
300//!     }
301//! }
302//! ```
303//!
304//! Then you should make an entrypoint to convert the scheme into `PaymentRequirements`.
305//!
306//! Note that `Payment` is a type-safe builder for constructing payment configurations from schemes.
307//!
308//! ```
309//! use bon::Builder;
310//! use x402_kit::core::Payment;
311//! use x402_kit::networks::svm::{ExplicitSvmAsset, ExplicitSvmNetwork, SvmAddress, SvmNetwork};
312//! use x402_kit::schemes::exact_svm::ExactSvmScheme;
313//! use x402_kit::transport::PaymentRequirements;
314//!
315//! #[derive(Builder, Debug, Clone)]
316//! pub struct ExactSvm<A: ExplicitSvmAsset> {
317//!     pub asset: A,
318//!     #[builder(into)]
319//!     pub pay_to: SvmAddress,
320//!     pub amount: u64,
321//!     pub max_timeout_seconds_override: Option<u64>,
322//! }
323//!
324//! impl<A: ExplicitSvmAsset> From<ExactSvm<A>> for Payment<ExactSvmScheme, SvmAddress> {
325//!     fn from(scheme: ExactSvm<A>) -> Self {
326//!         Payment {
327//!             scheme: ExactSvmScheme(A::Network::NETWORK),
328//!             pay_to: scheme.pay_to,
329//!             asset: A::ASSET,
330//!             amount: scheme.amount.into(),
331//!             max_timeout_seconds: scheme.max_timeout_seconds_override.unwrap_or(300),
332//!             extra: None,
333//!         }
334//!     }
335//! }
336//!
337//! // Then implement From for PaymentRequirements
338//! impl<A: ExplicitSvmAsset> From<ExactSvm<A>> for PaymentRequirements {
339//!     fn from(scheme: ExactSvm<A>) -> Self {
340//!         PaymentRequirements::from(Payment::from(scheme))
341//!     }
342//! }
343//! ```
344//!
345
346pub mod core;
347pub mod errors;
348pub mod facilitator;
349pub mod networks;
350pub mod schemes;
351pub mod transport;
352pub mod types;
353
354#[cfg(feature = "facilitator-client")]
355pub mod facilitator_client;