1use std::marker::PhantomData;
29
30use crate::error::FacilitatorError;
31use crate::facilitator::Facilitator;
32use crate::wire::{SettleRequest, SettleResponse, VerifyRequest, VerifyResponse};
33
34#[derive(Debug, Clone, Copy, Default)]
36pub struct Unverified;
37
38#[derive(Debug, Clone, Copy, Default)]
40pub struct Verified;
41
42#[derive(Debug, Clone, Copy, Default)]
44pub struct Settled;
45
46#[derive(Debug, Clone)]
51pub struct Payment<S> {
52 request: VerifyRequest,
53 state: PhantomData<fn() -> S>,
54}
55
56impl<S> Payment<S> {
57 #[must_use]
60 pub const fn request(&self) -> &VerifyRequest {
61 &self.request
62 }
63}
64
65impl Payment<Unverified> {
66 #[must_use]
68 pub const fn new(request: VerifyRequest) -> Self {
69 Self {
70 request,
71 state: PhantomData,
72 }
73 }
74
75 pub async fn verify<F: Facilitator>(
87 self,
88 facilitator: &F,
89 request: VerifyRequest,
90 ) -> Result<(Payment<Verified>, VerifyResponse), FacilitatorError> {
91 let response = facilitator.verify(request).await?;
92 match &response {
93 VerifyResponse::Valid { .. } => Ok((
94 Payment {
95 request: self.request,
96 state: PhantomData,
97 },
98 response,
99 )),
100 VerifyResponse::Invalid {
101 reason, message, ..
102 } => Err(FacilitatorError::Verification(
103 crate::error::VerificationError::InvalidFormat(format!(
104 "{reason}: {}",
105 message.as_deref().unwrap_or(""),
106 )),
107 )),
108 }
109 }
110}
111
112impl Payment<Verified> {
113 pub async fn settle<F: Facilitator>(
121 self,
122 facilitator: &F,
123 request: SettleRequest,
124 ) -> Result<(Payment<Settled>, SettleResponse), FacilitatorError> {
125 let response = facilitator.settle(request).await?;
126 match &response {
127 SettleResponse::Success { .. } => Ok((
128 Payment {
129 request: self.request,
130 state: PhantomData,
131 },
132 response,
133 )),
134 SettleResponse::Failure { message, .. } => Err(FacilitatorError::Onchain(
135 message.as_deref().unwrap_or("").to_owned(),
136 )),
137 }
138 }
139}
140
141impl Payment<Settled> {
142 #[must_use]
144 pub fn into_request(self) -> VerifyRequest {
145 self.request
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use std::future::Future;
152
153 use super::*;
154 use crate::error_reason::ErrorReason;
155 use crate::wire::{Extensions, SettleResponse, SupportedResponse, VerifyResponse};
156
157 struct AlwaysValid;
158
159 impl Facilitator for AlwaysValid {
160 fn verify(
161 &self,
162 _request: VerifyRequest,
163 ) -> impl Future<Output = Result<VerifyResponse, FacilitatorError>> + Send {
164 std::future::ready(Ok(VerifyResponse::valid("0xPAYER")))
165 }
166
167 fn settle(
168 &self,
169 _request: SettleRequest,
170 ) -> impl Future<Output = Result<SettleResponse, FacilitatorError>> + Send {
171 std::future::ready(Ok(SettleResponse::Success {
172 payer: "0xPAYER".into(),
173 transaction: "0xTX".into(),
174 network: "eip155:1".into(),
175 amount: Some("1000000".into()),
176 extensions: Extensions::new(),
177 }))
178 }
179
180 fn supported(
181 &self,
182 ) -> impl Future<Output = Result<SupportedResponse, FacilitatorError>> + Send {
183 std::future::ready(Ok(SupportedResponse::default()))
184 }
185 }
186
187 struct AlwaysInvalid;
188
189 impl Facilitator for AlwaysInvalid {
190 fn verify(
191 &self,
192 _request: VerifyRequest,
193 ) -> impl Future<Output = Result<VerifyResponse, FacilitatorError>> + Send {
194 std::future::ready(Ok(VerifyResponse::invalid(
195 None,
196 ErrorReason::InvalidPayload,
197 )))
198 }
199
200 fn settle(
201 &self,
202 _request: SettleRequest,
203 ) -> impl Future<Output = Result<SettleResponse, FacilitatorError>> + Send {
204 std::future::ready(Err(FacilitatorError::Onchain("unreachable".into())))
205 }
206
207 fn supported(
208 &self,
209 ) -> impl Future<Output = Result<SupportedResponse, FacilitatorError>> + Send {
210 std::future::ready(Ok(SupportedResponse::default()))
211 }
212 }
213
214 fn dummy_request() -> VerifyRequest {
215 serde_json::json!({}).into()
216 }
217
218 #[tokio::test]
219 async fn verify_then_settle_succeeds() {
220 let facilitator = AlwaysValid;
221 let payment = Payment::new(dummy_request());
222 let (verified, verify_resp) = payment.verify(&facilitator, dummy_request()).await.unwrap();
223 assert!(verify_resp.is_valid());
224 let (_settled, settle_resp) = verified
225 .settle(&facilitator, dummy_request().into())
226 .await
227 .unwrap();
228 assert!(settle_resp.is_success());
229 }
230
231 #[tokio::test]
232 async fn verify_invalid_propagates() {
233 let facilitator = AlwaysInvalid;
234 let payment = Payment::new(dummy_request());
235 let err = payment
236 .verify(&facilitator, dummy_request())
237 .await
238 .unwrap_err();
239 assert!(matches!(err, FacilitatorError::Verification(_)));
240 }
241}