Skip to main content

ows_pay/
types.rs

1use serde::{Deserialize, Serialize};
2
3// ===========================================================================
4// Unified public types
5// ===========================================================================
6
7/// Which payment protocol was used.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum Protocol {
10    X402,
11}
12
13impl std::fmt::Display for Protocol {
14    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15        match self {
16            Protocol::X402 => write!(f, "x402"),
17        }
18    }
19}
20
21/// Details about a payment that was made.
22#[derive(Debug, Clone)]
23pub struct PaymentInfo {
24    /// Human-readable amount (e.g. "$0.01").
25    pub amount: String,
26    /// Network/chain name (e.g. "Base", "Tempo").
27    pub network: String,
28    /// Token symbol (e.g. "USDC").
29    pub token: String,
30}
31
32/// Result of a `pay()` call.
33#[derive(Debug, Clone)]
34pub struct PayResult {
35    /// Which protocol handled the payment.
36    pub protocol: Protocol,
37    /// HTTP status of the final response.
38    pub status: u16,
39    /// Response body.
40    pub body: String,
41    /// Payment details. `None` if no payment was required (non-402).
42    pub payment: Option<PaymentInfo>,
43}
44
45/// A discovered payable service, normalized across protocols.
46#[derive(Debug, Clone)]
47pub struct Service {
48    /// Protocol this service uses.
49    pub protocol: Protocol,
50    /// Human-readable name.
51    pub name: String,
52    /// Full endpoint URL.
53    pub url: String,
54    /// Short description.
55    pub description: String,
56    /// Cheapest price display (e.g. "$0.01", "free").
57    pub price: String,
58    /// Network or chain (e.g. "base", "Tempo").
59    pub network: String,
60    /// Categories / tags.
61    pub tags: Vec<String>,
62}
63
64/// Result of a `discover()` call, including pagination info.
65#[derive(Debug, Clone)]
66pub struct DiscoverResult {
67    /// Discovered services on this page.
68    pub services: Vec<Service>,
69    /// Total number of services in the directory.
70    pub total: u64,
71    /// Limit used for this page.
72    pub limit: u64,
73    /// Offset used for this page.
74    pub offset: u64,
75}
76
77// ===========================================================================
78// x402 wire types (internal, used by x402 module)
79// ===========================================================================
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct PaymentRequirements {
84    pub scheme: String,
85    pub network: String,
86    #[serde(alias = "maxAmountRequired")]
87    pub amount: String,
88    pub asset: String,
89    #[serde(alias = "payTo")]
90    pub pay_to: String,
91    #[serde(default = "default_timeout")]
92    pub max_timeout_seconds: u64,
93    #[serde(default, skip_serializing_if = "is_json_null")]
94    pub extra: serde_json::Value,
95    #[serde(default, skip_serializing_if = "Option::is_none")]
96    pub description: Option<String>,
97    #[serde(default, skip_serializing_if = "Option::is_none")]
98    pub resource: Option<String>,
99}
100
101fn default_timeout() -> u64 {
102    30
103}
104
105fn is_json_null(value: &serde_json::Value) -> bool {
106    value.is_null()
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110#[serde(rename_all = "camelCase")]
111pub struct X402Response {
112    #[serde(default)]
113    pub x402_version: Option<u32>,
114    pub accepts: Vec<PaymentRequirements>,
115    #[serde(default)]
116    pub resource: Option<serde_json::Value>,
117}
118
119/// The signed payment payload sent to the server in the payment header.
120#[derive(Debug, Clone, Serialize, Deserialize)]
121#[serde(untagged)]
122pub enum PaymentPayload {
123    V1(PaymentPayloadV1),
124    V2(PaymentPayloadV2),
125}
126
127/// x402 v1 payment payload.
128#[derive(Debug, Clone, Serialize, Deserialize)]
129#[serde(rename_all = "camelCase")]
130pub struct PaymentPayloadV1 {
131    pub x402_version: u32,
132    pub scheme: String,
133    pub network: String,
134    pub payload: serde_json::Value,
135}
136
137/// x402 v2 payment payload.
138#[derive(Debug, Clone, Serialize, Deserialize)]
139#[serde(rename_all = "camelCase")]
140pub struct PaymentPayloadV2 {
141    pub x402_version: u32,
142    pub accepted: PaymentRequirements,
143    pub resource: Option<serde_json::Value>,
144    pub payload: serde_json::Value,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct Eip3009Payload {
149    pub signature: String,
150    pub authorization: Eip3009Authorization,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct Eip3009Authorization {
156    pub from: String,
157    pub to: String,
158    pub value: String,
159    pub valid_after: String,
160    pub valid_before: String,
161    pub nonce: String,
162}
163
164// ===========================================================================
165// x402 discovery wire types
166// ===========================================================================
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169#[serde(rename_all = "camelCase")]
170pub struct DiscoveredService {
171    pub resource: String,
172    #[serde(default)]
173    pub r#type: Option<String>,
174    #[serde(default)]
175    pub x402_version: Option<u32>,
176    #[serde(default)]
177    pub accepts: Vec<PaymentRequirements>,
178    #[serde(default)]
179    pub metadata: Option<ServiceMetadata>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct ServiceMetadata {
184    pub description: Option<String>,
185    #[serde(default)]
186    pub input: Option<serde_json::Value>,
187    #[serde(default)]
188    pub output: Option<serde_json::Value>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct DiscoveryResponse {
193    pub items: Vec<DiscoveredService>,
194    #[serde(default)]
195    pub pagination: Option<Pagination>,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct Pagination {
200    pub limit: u64,
201    pub offset: u64,
202    pub total: u64,
203}
204
205// ===========================================================================
206// MoonPay wire types
207// ===========================================================================
208
209#[derive(Debug, Clone, Serialize)]
210pub struct MoonPayDepositRequest {
211    pub name: String,
212    pub wallet: String,
213    pub chain: String,
214    pub token: String,
215}
216
217#[derive(Debug, Clone, Deserialize)]
218#[serde(rename_all = "camelCase")]
219pub struct MoonPayDepositResponse {
220    pub id: String,
221    pub destination_wallet: String,
222    pub destination_chain: String,
223    pub customer_token: String,
224    pub deposit_url: String,
225    pub wallets: Vec<DepositWallet>,
226    pub instructions: String,
227}
228
229#[derive(Debug, Clone, Deserialize)]
230#[serde(rename_all = "camelCase")]
231pub struct DepositWallet {
232    pub address: String,
233    pub chain: String,
234    pub qr_code: String,
235}
236
237#[derive(Debug, Clone, Serialize)]
238pub struct MoonPayBalanceRequest {
239    pub wallet: String,
240    pub chain: String,
241}
242
243#[derive(Debug, Clone, Deserialize)]
244pub struct MoonPayBalanceResponse {
245    pub items: Vec<TokenBalance>,
246}
247
248#[derive(Debug, Clone, Deserialize)]
249pub struct TokenBalance {
250    pub address: String,
251    pub name: String,
252    pub symbol: String,
253    pub chain: String,
254    pub decimals: u32,
255    pub balance: BalanceInfo,
256}
257
258#[derive(Debug, Clone, Deserialize)]
259pub struct BalanceInfo {
260    pub amount: f64,
261    pub value: f64,
262    pub price: f64,
263}
264
265/// Result of `ows fund`.
266#[derive(Debug, Clone)]
267pub struct FundResult {
268    pub deposit_id: String,
269    pub deposit_url: String,
270    pub wallets: Vec<(String, String)>,
271    pub instructions: String,
272}