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("`{0}`")]
57 Custom(String),
58}
59
60#[async_trait]
62pub trait MintPayment {
63 type Err: Into<Error> + From<Error>;
65
66 async fn get_settings(&self) -> Result<serde_json::Value, Self::Err>;
68
69 async fn create_incoming_payment_request(
71 &self,
72 amount: Amount,
73 unit: &CurrencyUnit,
74 description: String,
75 unix_expiry: Option<u64>,
76 ) -> Result<CreateIncomingPaymentResponse, Self::Err>;
77
78 async fn get_payment_quote(
81 &self,
82 request: &str,
83 unit: &CurrencyUnit,
84 options: Option<MeltOptions>,
85 ) -> Result<PaymentQuoteResponse, Self::Err>;
86
87 async fn make_payment(
89 &self,
90 melt_quote: mint::MeltQuote,
91 partial_amount: Option<Amount>,
92 max_fee_amount: Option<Amount>,
93 ) -> Result<MakePaymentResponse, Self::Err>;
94
95 async fn wait_any_incoming_payment(
98 &self,
99 ) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err>;
100
101 fn is_wait_invoice_active(&self) -> bool;
103
104 fn cancel_wait_invoice(&self);
106
107 async fn check_incoming_payment_status(
109 &self,
110 request_lookup_id: &str,
111 ) -> Result<MintQuoteState, Self::Err>;
112
113 async fn check_outgoing_payment(
115 &self,
116 request_lookup_id: &str,
117 ) -> Result<MakePaymentResponse, Self::Err>;
118}
119
120#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
122pub struct CreateIncomingPaymentResponse {
123 pub request_lookup_id: String,
125 pub request: String,
127 pub expiry: Option<u64>,
129}
130
131#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
133pub struct MakePaymentResponse {
134 pub payment_lookup_id: String,
136 pub payment_proof: Option<String>,
138 pub status: MeltQuoteState,
140 pub total_spent: Amount,
142 pub unit: CurrencyUnit,
144}
145
146#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
148pub struct PaymentQuoteResponse {
149 pub request_lookup_id: String,
151 pub amount: Amount,
153 pub fee: Amount,
155 pub state: MeltQuoteState,
157}
158
159#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
161pub struct Bolt11Settings {
162 pub mpp: bool,
164 pub unit: CurrencyUnit,
166 pub invoice_description: bool,
168}
169
170impl TryFrom<Bolt11Settings> for Value {
171 type Error = crate::error::Error;
172
173 fn try_from(value: Bolt11Settings) -> Result<Self, Self::Error> {
174 serde_json::to_value(value).map_err(|err| err.into())
175 }
176}
177
178impl TryFrom<Value> for Bolt11Settings {
179 type Error = crate::error::Error;
180
181 fn try_from(value: Value) -> Result<Self, Self::Error> {
182 serde_json::from_value(value).map_err(|err| err.into())
183 }
184}