Skip to main content

x402_types/chain/
mod.rs

1//! Blockchain-specific types and providers for x402 payment processing.
2//!
3//! This module provides abstractions for interacting with different blockchain networks
4//! in the x402 protocol.
5//!
6//! # Architecture
7//!
8//! The module is organized around the concept of chain providers and chain identifiers:
9//!
10//! - [`ChainId`] - A CAIP-2 compliant chain identifier (e.g., `eip155:8453` for Base)
11//! - [`ChainIdPattern`] - Pattern matching for chain IDs (exact, wildcard, or set)
12//! - [`ChainRegistry`] - Registry of configured chain providers
13
14mod chain_id;
15
16pub use chain_id::*;
17
18use std::collections::HashMap;
19use std::sync::Arc;
20
21/// Asynchronously constructs an instance of `Self` from a configuration type.
22///
23/// This trait provides a generic mechanism for initializing structs from their
24/// corresponding configuration types. It is used throughout the x402-rs crate
25/// to build providers, registries, and other components from configuration files.
26///
27/// # Type Parameters
28///
29/// - `TConfig` - The configuration type that `Self` can be constructed from
30///
31/// Return an error if:
32/// - Configuration validation fails
33/// - Required external connections (RPC, etc.) cannot be established
34/// - Configuration values are invalid or missing
35#[async_trait::async_trait]
36pub trait FromConfig<TConfig>
37where
38    Self: Sized,
39{
40    async fn from_config(config: &TConfig) -> Result<Self, Box<dyn std::error::Error>>;
41}
42
43/// Common operations available on all chain providers.
44///
45/// This trait provides a unified interface for querying chain provider metadata
46/// regardless of the underlying blockchain type.
47pub trait ChainProviderOps {
48    /// Returns the addresses of all configured signers for this chain.
49    ///
50    /// For EVM chains, these are Ethereum addresses (0x-prefixed hex).
51    /// For Solana, these are base58-encoded public keys.
52    fn signer_addresses(&self) -> Vec<String>;
53
54    /// Returns the CAIP-2 chain identifier for this provider.
55    fn chain_id(&self) -> ChainId;
56}
57
58impl<T: ChainProviderOps> ChainProviderOps for Arc<T> {
59    fn signer_addresses(&self) -> Vec<String> {
60        (**self).signer_addresses()
61    }
62    fn chain_id(&self) -> ChainId {
63        (**self).chain_id()
64    }
65}
66
67/// Registry of configured chain providers indexed by chain ID.
68///
69/// The registry is built from configuration and provides lookup methods
70/// for finding providers by exact chain ID or by pattern matching.
71///
72/// # Type Parameters
73///
74/// - `P` - The chain provider type (e.g., [`ChainProvider`] or a custom provider type)
75///
76/// # Example
77///
78/// ```ignore
79/// use x402_rs::chain::{ChainRegistry, ChainIdPattern, ChainProvider};
80/// use x402_rs::config::Config;
81///
82/// let config = Config::load()?;
83/// let registry = ChainRegistry::from_config(config.chains()).await?;
84///
85/// // Find provider for a specific chain
86/// let base_provider = registry.by_chain_id(ChainId::new("eip155", "8453"));
87///
88/// // Find provider matching a pattern
89/// let any_evm = registry.by_chain_id_pattern(&ChainIdPattern::wildcard("eip155"));
90/// ```
91#[derive(Debug)]
92pub struct ChainRegistry<P>(HashMap<ChainId, P>);
93
94impl<P> ChainRegistry<P> {
95    pub fn new(providers: HashMap<ChainId, P>) -> Self {
96        Self(providers)
97    }
98}
99
100impl<P> ChainRegistry<P> {
101    /// Looks up a provider by exact chain ID.
102    ///
103    /// Returns `None` if no provider is configured for the given chain.
104    #[allow(dead_code)]
105    pub fn by_chain_id(&self, chain_id: ChainId) -> Option<&P> {
106        self.0.get(&chain_id)
107    }
108
109    /// Looks up providers by chain ID pattern matching.
110    ///
111    /// Returns all providers whose chain IDs match the given pattern.
112    /// The pattern can be:
113    /// - Wildcard: Matches any chain within a namespace (e.g., `eip155:*`)
114    /// - Exact: Matches a specific chain (e.g., `eip155:8453`)
115    /// - Set: Matches any chain from a set of references (e.g., `eip155:{1,8453,137}`)
116    ///
117    /// # Example
118    ///
119    /// ```ignore
120    /// use x402_rs::chain::{ChainRegistry, ChainIdPattern};
121    /// use x402_rs::config::Config;
122    ///
123    /// let config = Config::load()?;
124    /// let registry = ChainRegistry::from_config(config.chains()).await?;
125    ///
126    /// // Find all EVM chain providers
127    /// let evm_providers = registry.by_chain_id_pattern(&ChainIdPattern::wildcard("eip155"));
128    /// assert!(!evm_providers.is_empty());
129    ///
130    /// // Find providers for specific chains
131    /// let mainnet_chains = ChainIdPattern::set("eip155", ["1", "8453", "137"].into_iter().map(String::from).collect());
132    /// let mainnet_providers = registry.by_chain_id_pattern(&mainnet_chains);
133    /// ```
134    pub fn by_chain_id_pattern(&self, pattern: &ChainIdPattern) -> Vec<&P> {
135        self.0
136            .iter()
137            .filter_map(|(chain_id, provider)| pattern.matches(chain_id).then_some(provider))
138            .collect()
139    }
140}
141
142/// A token amount paired with its deployment information.
143///
144/// This type associates a numeric amount with the token deployment it refers to,
145/// enabling type-safe handling of token amounts across different chains and tokens.
146///
147/// # Type Parameters
148///
149/// - `TAmount` - The numeric type for the amount (e.g., `U256` for EVM, `u64` for Solana)
150/// - `TToken` - The token deployment type containing chain and address information
151#[derive(Debug, Clone)]
152#[allow(dead_code)] // Public for consumption by downstream crates.
153pub struct DeployedTokenAmount<TAmount, TToken> {
154    /// The token amount in the token's smallest unit (e.g., wei for ETH, lamports for SOL).
155    pub amount: TAmount,
156    /// The token deployment information including chain, address, and decimals.
157    pub token: TToken,
158}