1use std::fmt::Debug;
2
3use base64::{Engine, prelude::BASE64_STANDARD};
4use serde::{Deserialize, Serialize};
5use url::Url;
6
7use crate::{
8 core::{Address, NetworkFamily, Payment, Resource, Scheme},
9 types::{AmountValue, AnyJson, Base64EncodedHeader, Extension, Record, X402V2},
10};
11
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "camelCase")]
14pub struct PaymentRequirements {
15 pub scheme: String,
16 pub network: String,
17 pub amount: AmountValue,
18 pub asset: String,
19 pub pay_to: String,
20 pub max_timeout_seconds: u64,
21 pub extra: Option<AnyJson>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct PaymentResource {
27 pub url: Url,
28 pub description: String,
29 pub mime_type: String,
30}
31
32impl From<Resource> for PaymentResource {
33 fn from(resource: Resource) -> Self {
34 PaymentResource {
35 url: resource.url,
36 description: resource.description,
37 mime_type: resource.mime_type,
38 }
39 }
40}
41
42#[derive(Clone, Default)]
43pub struct Accepts(Vec<PaymentRequirements>);
44
45impl IntoIterator for Accepts {
46 type Item = PaymentRequirements;
47 type IntoIter = std::vec::IntoIter<PaymentRequirements>;
48
49 fn into_iter(self) -> Self::IntoIter {
50 self.0.into_iter()
51 }
52}
53
54impl<'a> IntoIterator for &'a Accepts {
55 type Item = &'a PaymentRequirements;
56 type IntoIter = std::slice::Iter<'a, PaymentRequirements>;
57
58 fn into_iter(self) -> Self::IntoIter {
59 self.0.iter()
60 }
61}
62
63impl FromIterator<PaymentRequirements> for Accepts {
64 fn from_iter<T: IntoIterator<Item = PaymentRequirements>>(iter: T) -> Self {
65 let vec: Vec<PaymentRequirements> = iter.into_iter().collect();
66 Accepts(vec)
67 }
68}
69
70impl Serialize for Accepts {
71 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
72 where
73 S: serde::Serializer,
74 {
75 self.0.serialize(serializer)
76 }
77}
78
79impl<'de> Deserialize<'de> for Accepts {
80 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
81 where
82 D: serde::Deserializer<'de>,
83 {
84 let vec = Vec::<PaymentRequirements>::deserialize(deserializer)?;
85 Ok(Accepts(vec))
86 }
87}
88
89impl Debug for Accepts {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 format!("{:?}", self.0).fmt(f)
92 }
93}
94
95impl Accepts {
96 pub fn push(mut self, payment: impl Into<PaymentRequirements>) -> Self {
97 self.0.push(payment.into());
98 self
99 }
100
101 pub fn new() -> Self {
102 Accepts(Vec::new())
103 }
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct PaymentRequired {
109 pub x402_version: X402V2,
110 pub error: String,
111 pub resource: PaymentResource,
112 pub accepts: Accepts,
113 pub extensions: Record<Extension>,
114}
115
116impl TryFrom<PaymentRequired> for Base64EncodedHeader {
117 type Error = crate::errors::Error;
118
119 fn try_from(value: PaymentRequired) -> Result<Self, Self::Error> {
121 let json = serde_json::to_string(&value)?;
122 let encoded = BASE64_STANDARD.encode(json);
123 Ok(Base64EncodedHeader(encoded))
124 }
125}
126
127impl TryFrom<Base64EncodedHeader> for PaymentRequired {
128 type Error = crate::errors::Error;
129
130 fn try_from(value: Base64EncodedHeader) -> Result<Self, Self::Error> {
132 let decoded = BASE64_STANDARD.decode(&value.0)?;
133 let json_str = String::from_utf8(decoded)?;
134 let payment_required: PaymentRequired = serde_json::from_str(&json_str)?;
135 Ok(payment_required)
136 }
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140#[serde(rename_all = "camelCase")]
141pub struct PaymentPayload {
142 pub x402_version: X402V2,
143 pub resource: PaymentResource,
144 pub accepted: PaymentRequirements,
145 pub payload: AnyJson,
146 pub extensions: AnyJson,
147}
148
149impl TryFrom<PaymentPayload> for Base64EncodedHeader {
150 type Error = crate::errors::Error;
151
152 fn try_from(value: PaymentPayload) -> Result<Self, Self::Error> {
154 let json = serde_json::to_string(&value)?;
155 let encoded = BASE64_STANDARD.encode(json);
156 Ok(Base64EncodedHeader(encoded))
157 }
158}
159
160impl TryFrom<Base64EncodedHeader> for PaymentPayload {
161 type Error = crate::errors::Error;
162
163 fn try_from(value: Base64EncodedHeader) -> Result<Self, Self::Error> {
165 let decoded_bytes = BASE64_STANDARD.decode(&value.0)?;
166 let json_str = String::from_utf8(decoded_bytes)?;
167 let payload = serde_json::from_str(&json_str)?;
168 Ok(payload)
169 }
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct SettlementResponse {
174 pub success: bool,
175 pub transaction: String,
176 pub network: String,
177 pub payer: String,
178}
179
180impl TryFrom<SettlementResponse> for Base64EncodedHeader {
181 type Error = crate::errors::Error;
182
183 fn try_from(value: SettlementResponse) -> Result<Self, Self::Error> {
185 let json = serde_json::to_string(&value)?;
186 let encoded = BASE64_STANDARD.encode(json);
187 Ok(Base64EncodedHeader(encoded))
188 }
189}
190
191impl TryFrom<Base64EncodedHeader> for SettlementResponse {
192 type Error = crate::errors::Error;
193
194 fn try_from(value: Base64EncodedHeader) -> Result<Self, Self::Error> {
196 let decoded_bytes = BASE64_STANDARD.decode(&value.0)?;
197 let json_str = String::from_utf8(decoded_bytes)?;
198 let response = serde_json::from_str(&json_str)?;
199 Ok(response)
200 }
201}
202
203impl<S, A> From<Payment<S, A>> for PaymentRequirements
204where
205 S: Scheme,
206 A: Address<Network = S::Network>,
207{
208 fn from(payment: Payment<S, A>) -> Self {
209 PaymentRequirements {
210 scheme: S::SCHEME_NAME.to_string(),
211 network: payment.scheme.network().network_id().to_string(),
212 amount: payment.amount,
213 asset: payment.asset.address.to_string(),
214 pay_to: payment.pay_to.to_string(),
215 max_timeout_seconds: payment.max_timeout_seconds,
216 extra: payment.extra,
217 }
218 }
219}