1use std::pin::Pin;
4
5use async_trait::async_trait;
6use cashu::MeltOptions;
7use futures::Stream;
8use lightning_invoice::ParseOrSemanticError;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use thiserror::Error;
12
13use crate::nuts::{CurrencyUnit, MeltQuoteState, MintQuoteState};
14use crate::{mint, Amount};
15
16#[derive(Debug, Error)]
18pub enum Error {
19 #[error("Invoice already paid")]
21 InvoiceAlreadyPaid,
22 #[error("Invoice pay is pending")]
24 InvoicePaymentPending,
25 #[error("Unsupported unit")]
27 UnsupportedUnit,
28 #[error("Unsupported payment option")]
30 UnsupportedPaymentOption,
31 #[error("Payment state is unknown")]
33 UnknownPaymentState,
34 #[error(transparent)]
36 Lightning(Box<dyn std::error::Error + Send + Sync>),
37 #[error(transparent)]
39 Serde(#[from] serde_json::Error),
40 #[error(transparent)]
42 Anyhow(#[from] anyhow::Error),
43 #[error(transparent)]
45 Parse(#[from] ParseOrSemanticError),
46 #[error(transparent)]
48 Amount(#[from] crate::amount::Error),
49 #[error(transparent)]
51 NUT04(#[from] crate::nuts::nut04::Error),
52 #[error(transparent)]
54 NUT05(#[from] crate::nuts::nut05::Error),
55 #[error(transparent)]
57 NUT23(#[from] crate::nuts::nut23::Error),
58 #[error("`{0}`")]
60 Custom(String),
61}
62
63#[async_trait]
65pub trait MintPayment {
66 type Err: Into<Error> + From<Error>;
68
69 async fn get_settings(&self) -> Result<serde_json::Value, Self::Err>;
71
72 async fn create_incoming_payment_request(
74 &self,
75 amount: Amount,
76 unit: &CurrencyUnit,
77 description: String,
78 unix_expiry: Option<u64>,
79 ) -> Result<CreateIncomingPaymentResponse, Self::Err>;
80
81 async fn get_payment_quote(
84 &self,
85 request: &str,
86 unit: &CurrencyUnit,
87 options: Option<MeltOptions>,
88 ) -> Result<PaymentQuoteResponse, Self::Err>;
89
90 async fn make_payment(
92 &self,
93 melt_quote: mint::MeltQuote,
94 partial_amount: Option<Amount>,
95 max_fee_amount: Option<Amount>,
96 ) -> Result<MakePaymentResponse, Self::Err>;
97
98 async fn wait_any_incoming_payment(
101 &self,
102 ) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err>;
103
104 fn is_wait_invoice_active(&self) -> bool;
106
107 fn cancel_wait_invoice(&self);
109
110 async fn check_incoming_payment_status(
112 &self,
113 request_lookup_id: &str,
114 ) -> Result<MintQuoteState, Self::Err>;
115
116 async fn check_outgoing_payment(
118 &self,
119 request_lookup_id: &str,
120 ) -> Result<MakePaymentResponse, Self::Err>;
121}
122
123#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
125pub struct CreateIncomingPaymentResponse {
126 pub request_lookup_id: String,
128 pub request: String,
130 pub expiry: Option<u64>,
132}
133
134#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
136pub struct MakePaymentResponse {
137 pub payment_lookup_id: String,
139 pub payment_proof: Option<String>,
141 pub status: MeltQuoteState,
143 pub total_spent: Amount,
145 pub unit: CurrencyUnit,
147}
148
149#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
151pub struct PaymentQuoteResponse {
152 pub request_lookup_id: String,
154 pub amount: Amount,
156 pub fee: Amount,
158 pub state: MeltQuoteState,
160}
161
162#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
164pub struct Bolt11Settings {
165 pub mpp: bool,
167 pub unit: CurrencyUnit,
169 pub invoice_description: bool,
171 pub amountless: bool,
173}
174
175impl TryFrom<Bolt11Settings> for Value {
176 type Error = crate::error::Error;
177
178 fn try_from(value: Bolt11Settings) -> Result<Self, Self::Error> {
179 serde_json::to_value(value).map_err(|err| err.into())
180 }
181}
182
183impl TryFrom<Value> for Bolt11Settings {
184 type Error = crate::error::Error;
185
186 fn try_from(value: Value) -> Result<Self, Self::Error> {
187 serde_json::from_value(value).map_err(|err| err.into())
188 }
189}