1use std::collections::HashMap;
4use std::future::Future;
5
6use compact_str::CompactString;
7use r402_facilitator::BoxFuture;
8use r402_protocol::error::FacilitatorError;
9use r402_protocol::network::ChainId;
10use r402_protocol::payment::{
11 PaymentRequired, PaymentRequirements, ResourceInfo, SupportedPaymentKind, SupportedResponse,
12};
13use serde_json::{Map, Value};
14
15use crate::hooks::{
16 SettleContext, SettleResultContext, VerifiedPaymentCanceledContext, WirePaymentPayload,
17};
18use crate::payment_flow::PaymentFlowConfig;
19
20#[derive(Debug)]
22#[non_exhaustive]
23pub struct SchemePaymentRequiredContext<'a> {
24 pub requirements: &'a [PaymentRequirements],
26 pub payment_payload: Option<&'a WirePaymentPayload>,
28 pub resource: &'a ResourceInfo,
30 pub error: Option<&'a str>,
32 pub payment_required_response: &'a PaymentRequired,
34 pub supported: &'a SupportedResponse,
36}
37
38impl<'a> SchemePaymentRequiredContext<'a> {
39 #[must_use]
41 pub const fn new(
42 requirements: &'a [PaymentRequirements],
43 resource: &'a ResourceInfo,
44 payment_required_response: &'a PaymentRequired,
45 supported: &'a SupportedResponse,
46 ) -> Self {
47 Self {
48 requirements,
49 payment_payload: None,
50 resource,
51 error: None,
52 payment_required_response,
53 supported,
54 }
55 }
56}
57
58pub trait SchemeNetworkServer: Send + Sync {
62 fn scheme(&self) -> &str;
64
65 fn default_asset_transfer_method(&self) -> &str;
67
68 fn payment_flows(&self) -> &HashMap<String, PaymentFlowConfig>;
70
71 fn dynamic_extra_fields(&self) -> &[&str] {
73 &[]
74 }
75
76 fn enrich_payment_required_response<'a>(
78 &'a self,
79 _ctx: &'a SchemePaymentRequiredContext<'a>,
80 ) -> impl Future<Output = Option<Vec<PaymentRequirements>>> + Send + 'a {
81 async { None }
82 }
83
84 fn enrich_settlement_payload<'a>(
89 &'a self,
90 _ctx: &'a SettleContext,
91 ) -> impl Future<Output = Result<Option<Map<String, Value>>, FacilitatorError>> + Send + 'a
92 {
93 async { Ok(None) }
94 }
95
96 fn enrich_settlement_response<'a>(
98 &'a self,
99 _ctx: &'a SettleResultContext,
100 ) -> impl Future<Output = Option<Map<String, Value>>> + Send + 'a {
101 async { None }
102 }
103
104 fn settle_on_cancel<'a>(
108 &'a self,
109 _ctx: &'a VerifiedPaymentCanceledContext,
110 ) -> impl Future<Output = Option<PaymentRequirements>> + Send + 'a {
111 async { None }
112 }
113
114 fn settles_on_cancel(&self) -> bool {
118 false
119 }
120
121 fn validate_facilitator_support(
127 &self,
128 network: &ChainId,
129 kind: &SupportedPaymentKind,
130 facilitator_extensions: &[CompactString],
131 ) -> Result<(), FacilitatorSupportError> {
132 let _ = (network, kind, facilitator_extensions);
133 Ok(())
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
139pub enum FacilitatorSupportError {
140 #[error("{scheme} on {network}: facilitator does not advertise this kind")]
142 KindMissing {
143 scheme: CompactString,
145 network: ChainId,
147 },
148 #[error("{scheme} on {network}: missing extra.feePayer")]
150 MissingFeePayer {
151 scheme: CompactString,
153 network: ChainId,
155 },
156 #[error("{scheme} on {network}: invalid extra.feePayer")]
158 InvalidFeePayer {
159 scheme: CompactString,
161 network: ChainId,
163 },
164 #[error("{scheme} on {network}: missing extra.receiverAuthorizer")]
166 MissingReceiverAuthorizer {
167 scheme: CompactString,
169 network: ChainId,
171 },
172 #[error("{scheme} on {network}: extra.receiverAuthorizer is the zero address")]
174 ZeroReceiverAuthorizer {
175 scheme: CompactString,
177 network: ChainId,
179 },
180 #[error("{scheme} on {network}: invalid extra.receiverAuthorizer")]
182 InvalidReceiverAuthorizer {
183 scheme: CompactString,
185 network: ChainId,
187 },
188}
189
190impl FacilitatorSupportError {
191 #[must_use]
193 pub const fn reason(&self) -> &'static str {
194 match self {
195 Self::KindMissing { .. } => "kind_missing",
196 Self::MissingFeePayer { .. } => "missing_fee_payer",
197 Self::InvalidFeePayer { .. } => "invalid_fee_payer",
198 Self::MissingReceiverAuthorizer { .. } => "missing_receiver_authorizer",
199 Self::ZeroReceiverAuthorizer { .. } => "zero_receiver_authorizer",
200 Self::InvalidReceiverAuthorizer { .. } => "invalid_receiver_authorizer",
201 }
202 }
203}
204
205pub trait DynSchemeNetworkServer: Send + Sync {
207 fn scheme(&self) -> &str;
209
210 fn default_asset_transfer_method(&self) -> &str;
212
213 fn payment_flows(&self) -> &HashMap<String, PaymentFlowConfig>;
215
216 fn dynamic_extra_fields(&self) -> &[&str];
218
219 fn enrich_payment_required_response<'a>(
221 &'a self,
222 ctx: &'a SchemePaymentRequiredContext<'a>,
223 ) -> BoxFuture<'a, Option<Vec<PaymentRequirements>>>;
224
225 fn enrich_settlement_payload<'a>(
227 &'a self,
228 ctx: &'a SettleContext,
229 ) -> BoxFuture<'a, Result<Option<Map<String, Value>>, FacilitatorError>>;
230
231 fn enrich_settlement_response<'a>(
233 &'a self,
234 ctx: &'a SettleResultContext,
235 ) -> BoxFuture<'a, Option<Map<String, Value>>>;
236
237 fn settle_on_cancel<'a>(
239 &'a self,
240 ctx: &'a VerifiedPaymentCanceledContext,
241 ) -> BoxFuture<'a, Option<PaymentRequirements>>;
242
243 fn settles_on_cancel(&self) -> bool;
245
246 fn validate_facilitator_support(
252 &self,
253 network: &ChainId,
254 kind: &SupportedPaymentKind,
255 facilitator_extensions: &[CompactString],
256 ) -> Result<(), FacilitatorSupportError>;
257}
258
259impl<T: SchemeNetworkServer + ?Sized> DynSchemeNetworkServer for T {
260 fn scheme(&self) -> &str {
261 <Self as SchemeNetworkServer>::scheme(self)
262 }
263
264 fn default_asset_transfer_method(&self) -> &str {
265 <Self as SchemeNetworkServer>::default_asset_transfer_method(self)
266 }
267
268 fn payment_flows(&self) -> &HashMap<String, PaymentFlowConfig> {
269 <Self as SchemeNetworkServer>::payment_flows(self)
270 }
271
272 fn dynamic_extra_fields(&self) -> &[&str] {
273 <Self as SchemeNetworkServer>::dynamic_extra_fields(self)
274 }
275
276 fn enrich_payment_required_response<'a>(
277 &'a self,
278 ctx: &'a SchemePaymentRequiredContext<'a>,
279 ) -> BoxFuture<'a, Option<Vec<PaymentRequirements>>> {
280 Box::pin(<Self as SchemeNetworkServer>::enrich_payment_required_response(self, ctx))
281 }
282
283 fn enrich_settlement_payload<'a>(
284 &'a self,
285 ctx: &'a SettleContext,
286 ) -> BoxFuture<'a, Result<Option<Map<String, Value>>, FacilitatorError>> {
287 Box::pin(<Self as SchemeNetworkServer>::enrich_settlement_payload(
288 self, ctx,
289 ))
290 }
291
292 fn enrich_settlement_response<'a>(
293 &'a self,
294 ctx: &'a SettleResultContext,
295 ) -> BoxFuture<'a, Option<Map<String, Value>>> {
296 Box::pin(<Self as SchemeNetworkServer>::enrich_settlement_response(
297 self, ctx,
298 ))
299 }
300
301 fn settle_on_cancel<'a>(
302 &'a self,
303 ctx: &'a VerifiedPaymentCanceledContext,
304 ) -> BoxFuture<'a, Option<PaymentRequirements>> {
305 Box::pin(<Self as SchemeNetworkServer>::settle_on_cancel(self, ctx))
306 }
307
308 fn settles_on_cancel(&self) -> bool {
309 <Self as SchemeNetworkServer>::settles_on_cancel(self)
310 }
311
312 fn validate_facilitator_support(
313 &self,
314 network: &ChainId,
315 kind: &SupportedPaymentKind,
316 facilitator_extensions: &[CompactString],
317 ) -> Result<(), FacilitatorSupportError> {
318 <Self as SchemeNetworkServer>::validate_facilitator_support(
319 self,
320 network,
321 kind,
322 facilitator_extensions,
323 )
324 }
325}