Skip to main content

x402_networks/svm/
mod.rs

1use std::{
2    fmt::{Debug, Display},
3    str::FromStr,
4};
5
6use serde::{Deserialize, Serialize};
7use solana_pubkey::{ParsePubkeyError, Pubkey};
8
9use x402_core::core::{Address, NetworkFamily};
10
11pub mod exact;
12
13pub struct SvmNetwork {
14    pub name: &'static str,
15    pub caip_2_id: &'static str,
16}
17
18impl NetworkFamily for SvmNetwork {
19    fn network_name(&self) -> &str {
20        self.name
21    }
22
23    fn network_id(&self) -> &str {
24        self.caip_2_id
25    }
26}
27
28#[derive(Clone, Copy, PartialEq, Eq, Hash)]
29pub struct SvmAddress(pub Pubkey);
30
31impl From<Pubkey> for SvmAddress {
32    fn from(pk: Pubkey) -> Self {
33        SvmAddress(pk)
34    }
35}
36
37impl FromStr for SvmAddress {
38    type Err = ParsePubkeyError;
39
40    fn from_str(s: &str) -> Result<Self, Self::Err> {
41        let pk = Pubkey::from_str(s)?;
42        Ok(SvmAddress(pk))
43    }
44}
45
46impl Display for SvmAddress {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        write!(f, "{}", self.0)
49    }
50}
51
52impl Debug for SvmAddress {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        write!(f, "SvmAddress({})", self.0)
55    }
56}
57
58impl Serialize for SvmAddress {
59    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
60    where
61        S: serde::Serializer,
62    {
63        serializer.serialize_str(&self.to_string())
64    }
65}
66
67impl<'de> Deserialize<'de> for SvmAddress {
68    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
69    where
70        D: serde::Deserializer<'de>,
71    {
72        let s = String::deserialize(deserializer)?;
73        let pk = Pubkey::from_str(&s).map_err(serde::de::Error::custom)?;
74        Ok(SvmAddress(pk))
75    }
76}
77
78#[derive(Clone, Copy, PartialEq, Eq, Hash)]
79pub struct SvmSignature(pub solana_signature::Signature);
80
81impl FromStr for SvmSignature {
82    type Err = solana_signature::ParseSignatureError;
83
84    fn from_str(s: &str) -> Result<Self, Self::Err> {
85        let sig = solana_signature::Signature::from_str(s)?;
86        Ok(SvmSignature(sig))
87    }
88}
89
90impl Debug for SvmSignature {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        write!(f, "SvmSignature({})", self.0)
93    }
94}
95
96impl Display for SvmSignature {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        write!(f, "{}", self.0)
99    }
100}
101
102impl Serialize for SvmSignature {
103    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104    where
105        S: serde::Serializer,
106    {
107        serializer.serialize_str(&self.to_string())
108    }
109}
110
111impl<'de> Deserialize<'de> for SvmSignature {
112    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113    where
114        D: serde::Deserializer<'de>,
115    {
116        let s = String::deserialize(deserializer)?;
117        let sig = solana_signature::Signature::from_str(&s).map_err(serde::de::Error::custom)?;
118        Ok(SvmSignature(sig))
119    }
120}
121
122impl Address for SvmAddress {
123    type Network = SvmNetwork;
124}
125
126pub type SvmAsset = x402_core::core::Asset<SvmAddress>;
127
128pub trait ExplicitSvmNetwork {
129    const NETWORK: SvmNetwork;
130}
131
132pub trait ExplicitSvmAsset {
133    type Network: ExplicitSvmNetwork;
134    const ASSET: SvmAsset;
135}
136
137pub mod networks {
138    use super::*;
139
140    pub struct Solana;
141    impl ExplicitSvmNetwork for Solana {
142        const NETWORK: SvmNetwork = SvmNetwork {
143            name: "solana",
144            caip_2_id: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
145        };
146    }
147
148    pub struct SolanaDevnet;
149    impl ExplicitSvmNetwork for SolanaDevnet {
150        const NETWORK: SvmNetwork = SvmNetwork {
151            name: "solana-devnet",
152            caip_2_id: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
153        };
154    }
155
156    pub struct SolanaTestnet;
157    impl ExplicitSvmNetwork for SolanaTestnet {
158        const NETWORK: SvmNetwork = SvmNetwork {
159            name: "solana-testnet",
160            caip_2_id: "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z",
161        };
162    }
163}
164
165pub mod assets {
166    use solana_pubkey::pubkey;
167
168    use super::*;
169
170    macro_rules! create_usdc {
171        ($addr:expr) => {
172            SvmAsset {
173                address: SvmAddress($addr),
174                decimals: 6,
175                name: "USD Coin",
176                symbol: "USDC",
177            }
178        };
179    }
180
181    pub struct UsdcSolana;
182    impl ExplicitSvmAsset for UsdcSolana {
183        type Network = networks::Solana;
184        const ASSET: SvmAsset =
185            create_usdc!(pubkey!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"));
186    }
187
188    pub struct UsdcSolanaDevnet;
189    impl ExplicitSvmAsset for UsdcSolanaDevnet {
190        type Network = networks::SolanaDevnet;
191        const ASSET: SvmAsset =
192            create_usdc!(pubkey!("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"));
193    }
194}