payment.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. //! CDK Mint Lightning
  2. use std::convert::Infallible;
  3. use std::pin::Pin;
  4. use async_trait::async_trait;
  5. use cashu::util::hex;
  6. use cashu::{Bolt11Invoice, MeltOptions};
  7. #[cfg(feature = "prometheus")]
  8. use cdk_prometheus::METRICS;
  9. use futures::Stream;
  10. use lightning::offers::offer::Offer;
  11. use lightning_invoice::ParseOrSemanticError;
  12. use serde::{Deserialize, Serialize};
  13. use serde_json::Value;
  14. use thiserror::Error;
  15. use crate::mint::MeltPaymentRequest;
  16. use crate::nuts::{CurrencyUnit, MeltQuoteState};
  17. use crate::Amount;
  18. /// CDK Lightning Error
  19. #[derive(Debug, Error)]
  20. pub enum Error {
  21. /// Invoice already paid
  22. #[error("Invoice already paid")]
  23. InvoiceAlreadyPaid,
  24. /// Invoice pay pending
  25. #[error("Invoice pay is pending")]
  26. InvoicePaymentPending,
  27. /// Unsupported unit
  28. #[error("Unsupported unit")]
  29. UnsupportedUnit,
  30. /// Unsupported payment option
  31. #[error("Unsupported payment option")]
  32. UnsupportedPaymentOption,
  33. /// Payment state is unknown
  34. #[error("Payment state is unknown")]
  35. UnknownPaymentState,
  36. /// Amount mismatch
  37. #[error("Amount is not what is expected")]
  38. AmountMismatch,
  39. /// Lightning Error
  40. #[error(transparent)]
  41. Lightning(Box<dyn std::error::Error + Send + Sync>),
  42. /// Serde Error
  43. #[error(transparent)]
  44. Serde(#[from] serde_json::Error),
  45. /// AnyHow Error
  46. #[error(transparent)]
  47. Anyhow(#[from] anyhow::Error),
  48. /// Parse Error
  49. #[error(transparent)]
  50. Parse(#[from] ParseOrSemanticError),
  51. /// Amount Error
  52. #[error(transparent)]
  53. Amount(#[from] crate::amount::Error),
  54. /// NUT04 Error
  55. #[error(transparent)]
  56. NUT04(#[from] crate::nuts::nut04::Error),
  57. /// NUT05 Error
  58. #[error(transparent)]
  59. NUT05(#[from] crate::nuts::nut05::Error),
  60. /// NUT23 Error
  61. #[error(transparent)]
  62. NUT23(#[from] crate::nuts::nut23::Error),
  63. /// Hex error
  64. #[error("Hex error")]
  65. Hex(#[from] hex::Error),
  66. /// Invalid hash
  67. #[error("Invalid hash")]
  68. InvalidHash,
  69. /// Custom
  70. #[error("`{0}`")]
  71. Custom(String),
  72. }
  73. impl From<Infallible> for Error {
  74. fn from(_: Infallible) -> Self {
  75. unreachable!("Infallible cannot be constructed")
  76. }
  77. }
  78. /// Payment identifier types
  79. #[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)]
  80. #[serde(tag = "type", content = "value")]
  81. pub enum PaymentIdentifier {
  82. /// Label identifier
  83. Label(String),
  84. /// Offer ID identifier
  85. OfferId(String),
  86. /// Payment hash identifier
  87. PaymentHash([u8; 32]),
  88. /// Bolt12 payment hash
  89. Bolt12PaymentHash([u8; 32]),
  90. /// Payment id
  91. PaymentId([u8; 32]),
  92. /// Custom Payment ID
  93. CustomId(String),
  94. }
  95. impl PaymentIdentifier {
  96. /// Create new [`PaymentIdentifier`]
  97. pub fn new(kind: &str, identifier: &str) -> Result<Self, Error> {
  98. match kind.to_lowercase().as_str() {
  99. "label" => Ok(Self::Label(identifier.to_string())),
  100. "offer_id" => Ok(Self::OfferId(identifier.to_string())),
  101. "payment_hash" => Ok(Self::PaymentHash(
  102. hex::decode(identifier)?
  103. .try_into()
  104. .map_err(|_| Error::InvalidHash)?,
  105. )),
  106. "bolt12_payment_hash" => Ok(Self::Bolt12PaymentHash(
  107. hex::decode(identifier)?
  108. .try_into()
  109. .map_err(|_| Error::InvalidHash)?,
  110. )),
  111. "custom" => Ok(Self::CustomId(identifier.to_string())),
  112. "payment_id" => Ok(Self::PaymentId(
  113. hex::decode(identifier)?
  114. .try_into()
  115. .map_err(|_| Error::InvalidHash)?,
  116. )),
  117. _ => Err(Error::UnsupportedPaymentOption),
  118. }
  119. }
  120. /// Payment id kind
  121. pub fn kind(&self) -> String {
  122. match self {
  123. Self::Label(_) => "label".to_string(),
  124. Self::OfferId(_) => "offer_id".to_string(),
  125. Self::PaymentHash(_) => "payment_hash".to_string(),
  126. Self::Bolt12PaymentHash(_) => "bolt12_payment_hash".to_string(),
  127. Self::PaymentId(_) => "payment_id".to_string(),
  128. Self::CustomId(_) => "custom".to_string(),
  129. }
  130. }
  131. }
  132. impl std::fmt::Display for PaymentIdentifier {
  133. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  134. match self {
  135. Self::Label(l) => write!(f, "{l}"),
  136. Self::OfferId(o) => write!(f, "{o}"),
  137. Self::PaymentHash(h) => write!(f, "{}", hex::encode(h)),
  138. Self::Bolt12PaymentHash(h) => write!(f, "{}", hex::encode(h)),
  139. Self::PaymentId(h) => write!(f, "{}", hex::encode(h)),
  140. Self::CustomId(c) => write!(f, "{c}"),
  141. }
  142. }
  143. }
  144. /// Options for creating a BOLT11 incoming payment request
  145. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
  146. pub struct Bolt11IncomingPaymentOptions {
  147. /// Optional description for the payment request
  148. pub description: Option<String>,
  149. /// Amount for the payment request in sats
  150. pub amount: Amount,
  151. /// Optional expiry time as Unix timestamp in seconds
  152. pub unix_expiry: Option<u64>,
  153. }
  154. /// Options for creating a BOLT12 incoming payment request
  155. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
  156. pub struct Bolt12IncomingPaymentOptions {
  157. /// Optional description for the payment request
  158. pub description: Option<String>,
  159. /// Optional amount for the payment request in sats
  160. pub amount: Option<Amount>,
  161. /// Optional expiry time as Unix timestamp in seconds
  162. pub unix_expiry: Option<u64>,
  163. }
  164. /// Options for creating a custom incoming payment request
  165. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  166. pub struct CustomIncomingPaymentOptions {
  167. /// Payment method name (e.g., "paypal", "venmo")
  168. pub method: String,
  169. /// Optional description for the payment request
  170. pub description: Option<String>,
  171. /// Amount for the payment request
  172. pub amount: Amount,
  173. /// Optional expiry time as Unix timestamp in seconds
  174. pub unix_expiry: Option<u64>,
  175. /// Extra payment-method-specific fields as JSON string
  176. ///
  177. /// These fields are passed through to the payment processor for
  178. /// method-specific validation (e.g., ehash share).
  179. pub extra_json: Option<String>,
  180. }
  181. /// Options for creating an incoming payment request
  182. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  183. pub enum IncomingPaymentOptions {
  184. /// BOLT11 payment request options
  185. Bolt11(Bolt11IncomingPaymentOptions),
  186. /// BOLT12 payment request options
  187. Bolt12(Box<Bolt12IncomingPaymentOptions>),
  188. /// Custom payment method options
  189. Custom(Box<CustomIncomingPaymentOptions>),
  190. }
  191. /// Options for BOLT11 outgoing payments
  192. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  193. pub struct Bolt11OutgoingPaymentOptions {
  194. /// Bolt11
  195. pub bolt11: Bolt11Invoice,
  196. /// Maximum fee amount allowed for the payment
  197. pub max_fee_amount: Option<Amount>,
  198. /// Optional timeout in seconds
  199. pub timeout_secs: Option<u64>,
  200. /// Melt options
  201. pub melt_options: Option<MeltOptions>,
  202. }
  203. /// Options for BOLT12 outgoing payments
  204. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  205. pub struct Bolt12OutgoingPaymentOptions {
  206. /// Offer
  207. pub offer: Offer,
  208. /// Maximum fee amount allowed for the payment
  209. pub max_fee_amount: Option<Amount>,
  210. /// Optional timeout in seconds
  211. pub timeout_secs: Option<u64>,
  212. /// Melt options
  213. pub melt_options: Option<MeltOptions>,
  214. }
  215. /// Options for custom outgoing payments
  216. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  217. pub struct CustomOutgoingPaymentOptions {
  218. /// Payment method name
  219. pub method: String,
  220. /// Payment request string (method-specific format)
  221. pub request: String,
  222. /// Maximum fee amount allowed for the payment
  223. pub max_fee_amount: Option<Amount>,
  224. /// Optional timeout in seconds
  225. pub timeout_secs: Option<u64>,
  226. /// Melt options
  227. pub melt_options: Option<MeltOptions>,
  228. /// Extra payment-method-specific fields as JSON string
  229. ///
  230. /// These fields are passed through to the payment processor for
  231. /// method-specific validation.
  232. pub extra_json: Option<String>,
  233. }
  234. /// Options for creating an outgoing payment
  235. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  236. pub enum OutgoingPaymentOptions {
  237. /// BOLT11 payment options
  238. Bolt11(Box<Bolt11OutgoingPaymentOptions>),
  239. /// BOLT12 payment options
  240. Bolt12(Box<Bolt12OutgoingPaymentOptions>),
  241. /// Custom payment method options
  242. Custom(Box<CustomOutgoingPaymentOptions>),
  243. }
  244. impl TryFrom<crate::mint::MeltQuote> for OutgoingPaymentOptions {
  245. type Error = Error;
  246. fn try_from(melt_quote: crate::mint::MeltQuote) -> Result<Self, Self::Error> {
  247. let fee_reserve = melt_quote.fee_reserve();
  248. match &melt_quote.request {
  249. MeltPaymentRequest::Bolt11 { bolt11 } => Ok(OutgoingPaymentOptions::Bolt11(Box::new(
  250. Bolt11OutgoingPaymentOptions {
  251. max_fee_amount: Some(fee_reserve.to_owned().into()),
  252. timeout_secs: None,
  253. bolt11: bolt11.clone(),
  254. melt_options: melt_quote.options,
  255. },
  256. ))),
  257. MeltPaymentRequest::Bolt12 { offer } => {
  258. let melt_options = match melt_quote.options {
  259. None => None,
  260. Some(MeltOptions::Mpp { mpp: _ }) => return Err(Error::UnsupportedUnit),
  261. Some(options) => Some(options),
  262. };
  263. Ok(OutgoingPaymentOptions::Bolt12(Box::new(
  264. Bolt12OutgoingPaymentOptions {
  265. max_fee_amount: Some(fee_reserve.clone().into()),
  266. timeout_secs: None,
  267. offer: *offer.clone(),
  268. melt_options,
  269. },
  270. )))
  271. }
  272. MeltPaymentRequest::Custom { method, request } => Ok(OutgoingPaymentOptions::Custom(
  273. Box::new(CustomOutgoingPaymentOptions {
  274. method: method.to_string(),
  275. request: request.to_string(),
  276. max_fee_amount: Some(melt_quote.fee_reserve().into()),
  277. timeout_secs: None,
  278. melt_options: melt_quote.options,
  279. extra_json: None,
  280. }),
  281. )),
  282. }
  283. }
  284. }
  285. /// Mint payment trait
  286. #[async_trait]
  287. pub trait MintPayment {
  288. /// Mint Lightning Error
  289. type Err: Into<Error> + From<Error>;
  290. /// Start the payment processor
  291. /// Called when the mint starts up to initialize the payment processor
  292. async fn start(&self) -> Result<(), Self::Err> {
  293. // Default implementation - do nothing
  294. Ok(())
  295. }
  296. /// Stop the payment processor
  297. /// Called when the mint shuts down to gracefully stop the payment processor
  298. async fn stop(&self) -> Result<(), Self::Err> {
  299. // Default implementation - do nothing
  300. Ok(())
  301. }
  302. /// Base Settings
  303. async fn get_settings(&self) -> Result<SettingsResponse, Self::Err>;
  304. /// Create a new invoice
  305. async fn create_incoming_payment_request(
  306. &self,
  307. unit: &CurrencyUnit,
  308. options: IncomingPaymentOptions,
  309. ) -> Result<CreateIncomingPaymentResponse, Self::Err>;
  310. /// Get payment quote
  311. /// Used to get fee and amount required for a payment request
  312. async fn get_payment_quote(
  313. &self,
  314. unit: &CurrencyUnit,
  315. options: OutgoingPaymentOptions,
  316. ) -> Result<PaymentQuoteResponse, Self::Err>;
  317. /// Pay request
  318. async fn make_payment(
  319. &self,
  320. unit: &CurrencyUnit,
  321. options: OutgoingPaymentOptions,
  322. ) -> Result<MakePaymentResponse, Self::Err>;
  323. /// Listen for invoices to be paid to the mint
  324. /// Returns a stream of request_lookup_id once invoices are paid
  325. async fn wait_payment_event(
  326. &self,
  327. ) -> Result<Pin<Box<dyn Stream<Item = Event> + Send>>, Self::Err>;
  328. /// Is wait invoice active
  329. fn is_wait_invoice_active(&self) -> bool;
  330. /// Cancel wait invoice
  331. fn cancel_wait_invoice(&self);
  332. /// Check the status of an incoming payment
  333. async fn check_incoming_payment_status(
  334. &self,
  335. payment_identifier: &PaymentIdentifier,
  336. ) -> Result<Vec<WaitPaymentResponse>, Self::Err>;
  337. /// Check the status of an outgoing payment
  338. async fn check_outgoing_payment(
  339. &self,
  340. payment_identifier: &PaymentIdentifier,
  341. ) -> Result<MakePaymentResponse, Self::Err>;
  342. }
  343. /// An event emitted which should be handled by the mint
  344. #[derive(Debug, Clone, Hash)]
  345. pub enum Event {
  346. /// A payment has been received.
  347. PaymentReceived(WaitPaymentResponse),
  348. }
  349. impl Default for Event {
  350. fn default() -> Self {
  351. // We use this as a sentinel value for no-op events
  352. // The actual processing will filter these out
  353. Event::PaymentReceived(WaitPaymentResponse {
  354. payment_identifier: PaymentIdentifier::CustomId("default".to_string()),
  355. payment_amount: Amount::new(0, CurrencyUnit::Msat),
  356. payment_id: "default".to_string(),
  357. })
  358. }
  359. }
  360. /// Wait any invoice response
  361. #[derive(Debug, Clone, Hash)]
  362. pub struct WaitPaymentResponse {
  363. /// Request look up id
  364. /// Id that relates the quote and payment request
  365. pub payment_identifier: PaymentIdentifier,
  366. /// Payment amount (typed with unit for compile-time safety)
  367. pub payment_amount: Amount<CurrencyUnit>,
  368. /// Unique id of payment
  369. // Payment hash
  370. pub payment_id: String,
  371. }
  372. impl WaitPaymentResponse {
  373. /// Get the currency unit
  374. pub fn unit(&self) -> &CurrencyUnit {
  375. self.payment_amount.unit()
  376. }
  377. }
  378. /// Create incoming payment response
  379. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
  380. pub struct CreateIncomingPaymentResponse {
  381. /// Id that is used to look up the payment from the ln backend
  382. pub request_lookup_id: PaymentIdentifier,
  383. /// Payment request
  384. pub request: String,
  385. /// Unix Expiry of Invoice
  386. pub expiry: Option<u64>,
  387. /// Extra payment-method-specific fields
  388. ///
  389. /// These fields are flattened into the JSON representation, allowing
  390. /// custom payment methods to include additional data without nesting.
  391. #[serde(flatten, default)]
  392. pub extra_json: Option<serde_json::Value>,
  393. }
  394. /// Payment response
  395. #[derive(Debug, Clone, Hash, PartialEq, Eq)]
  396. pub struct MakePaymentResponse {
  397. /// Payment hash
  398. pub payment_lookup_id: PaymentIdentifier,
  399. /// Payment proof
  400. pub payment_proof: Option<String>,
  401. /// Status
  402. pub status: MeltQuoteState,
  403. /// Total Amount Spent (typed with unit for compile-time safety)
  404. pub total_spent: Amount<CurrencyUnit>,
  405. }
  406. impl MakePaymentResponse {
  407. /// Get the currency unit
  408. pub fn unit(&self) -> &CurrencyUnit {
  409. self.total_spent.unit()
  410. }
  411. }
  412. /// Payment quote response
  413. #[derive(Debug, Clone, Hash, PartialEq, Eq)]
  414. pub struct PaymentQuoteResponse {
  415. /// Request look up id
  416. pub request_lookup_id: Option<PaymentIdentifier>,
  417. /// Amount (typed with unit for compile-time safety)
  418. pub amount: Amount<CurrencyUnit>,
  419. /// Fee required for melt (typed with unit for compile-time safety)
  420. pub fee: Amount<CurrencyUnit>,
  421. /// Status
  422. pub state: MeltQuoteState,
  423. }
  424. impl PaymentQuoteResponse {
  425. /// Get the currency unit
  426. pub fn unit(&self) -> &CurrencyUnit {
  427. self.amount.unit()
  428. }
  429. }
  430. /// BOLT11 settings
  431. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
  432. pub struct Bolt11Settings {
  433. /// Multi-part payment (MPP) supported
  434. pub mpp: bool,
  435. /// Amountless invoice support
  436. pub amountless: bool,
  437. /// Invoice description supported
  438. pub invoice_description: bool,
  439. }
  440. /// BOLT12 settings
  441. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
  442. pub struct Bolt12Settings {
  443. /// Amountless offer support
  444. pub amountless: bool,
  445. }
  446. /// Payment processor settings response
  447. /// Mirrors the proto SettingsResponse structure
  448. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  449. pub struct SettingsResponse {
  450. /// Base unit of backend
  451. pub unit: String,
  452. /// BOLT11 settings (None if not supported)
  453. pub bolt11: Option<Bolt11Settings>,
  454. /// BOLT12 settings (None if not supported)
  455. pub bolt12: Option<Bolt12Settings>,
  456. /// Custom payment methods settings (method name -> settings data)
  457. #[serde(default)]
  458. pub custom: std::collections::HashMap<String, String>,
  459. }
  460. impl From<SettingsResponse> for Value {
  461. fn from(value: SettingsResponse) -> Self {
  462. serde_json::to_value(value).unwrap_or(Value::Null)
  463. }
  464. }
  465. impl TryFrom<Value> for SettingsResponse {
  466. type Error = crate::error::Error;
  467. fn try_from(value: Value) -> Result<Self, Self::Error> {
  468. serde_json::from_value(value).map_err(|err| err.into())
  469. }
  470. }
  471. /// Metrics wrapper for MintPayment implementations
  472. ///
  473. /// This wrapper implements the Decorator pattern to collect metrics on all
  474. /// MintPayment trait methods. It wraps any existing MintPayment implementation
  475. /// and automatically records timing and operation metrics.
  476. #[derive(Debug, Clone)]
  477. #[cfg(feature = "prometheus")]
  478. pub struct MetricsMintPayment<T> {
  479. inner: T,
  480. }
  481. #[cfg(feature = "prometheus")]
  482. impl<T> MetricsMintPayment<T>
  483. where
  484. T: MintPayment,
  485. {
  486. /// Create a new metrics wrapper around a MintPayment implementation
  487. pub fn new(inner: T) -> Self {
  488. Self { inner }
  489. }
  490. /// Get reference to the underlying implementation
  491. pub fn inner(&self) -> &T {
  492. &self.inner
  493. }
  494. /// Consume the wrapper and return the inner implementation
  495. pub fn into_inner(self) -> T {
  496. self.inner
  497. }
  498. }
  499. #[async_trait]
  500. #[cfg(feature = "prometheus")]
  501. impl<T> MintPayment for MetricsMintPayment<T>
  502. where
  503. T: MintPayment + Send + Sync,
  504. {
  505. type Err = T::Err;
  506. async fn get_settings(&self) -> Result<SettingsResponse, Self::Err> {
  507. let start = std::time::Instant::now();
  508. METRICS.inc_in_flight_requests("get_settings");
  509. let result = self.inner.get_settings().await;
  510. let duration = start.elapsed().as_secs_f64();
  511. METRICS.record_mint_operation_histogram("get_settings", result.is_ok(), duration);
  512. METRICS.dec_in_flight_requests("get_settings");
  513. result
  514. }
  515. async fn create_incoming_payment_request(
  516. &self,
  517. unit: &CurrencyUnit,
  518. options: IncomingPaymentOptions,
  519. ) -> Result<CreateIncomingPaymentResponse, Self::Err> {
  520. let start = std::time::Instant::now();
  521. METRICS.inc_in_flight_requests("create_incoming_payment_request");
  522. let result = self
  523. .inner
  524. .create_incoming_payment_request(unit, options)
  525. .await;
  526. let duration = start.elapsed().as_secs_f64();
  527. METRICS.record_mint_operation_histogram(
  528. "create_incoming_payment_request",
  529. result.is_ok(),
  530. duration,
  531. );
  532. METRICS.dec_in_flight_requests("create_incoming_payment_request");
  533. result
  534. }
  535. async fn get_payment_quote(
  536. &self,
  537. unit: &CurrencyUnit,
  538. options: OutgoingPaymentOptions,
  539. ) -> Result<PaymentQuoteResponse, Self::Err> {
  540. let start = std::time::Instant::now();
  541. METRICS.inc_in_flight_requests("get_payment_quote");
  542. let result = self.inner.get_payment_quote(unit, options).await;
  543. let duration = start.elapsed().as_secs_f64();
  544. let success = result.is_ok();
  545. if let Ok(ref quote) = result {
  546. let amount: f64 = quote.amount.value() as f64;
  547. let fee: f64 = quote.fee.value() as f64;
  548. METRICS.record_lightning_payment(amount, fee);
  549. }
  550. METRICS.record_mint_operation_histogram("get_payment_quote", success, duration);
  551. METRICS.dec_in_flight_requests("get_payment_quote");
  552. result
  553. }
  554. async fn wait_payment_event(
  555. &self,
  556. ) -> Result<Pin<Box<dyn Stream<Item = Event> + Send>>, Self::Err> {
  557. let start = std::time::Instant::now();
  558. METRICS.inc_in_flight_requests("wait_payment_event");
  559. let result = self.inner.wait_payment_event().await;
  560. let duration = start.elapsed().as_secs_f64();
  561. let success = result.is_ok();
  562. METRICS.record_mint_operation_histogram("wait_payment_event", success, duration);
  563. METRICS.dec_in_flight_requests("wait_payment_event");
  564. result
  565. }
  566. async fn make_payment(
  567. &self,
  568. unit: &CurrencyUnit,
  569. options: OutgoingPaymentOptions,
  570. ) -> Result<MakePaymentResponse, Self::Err> {
  571. let start = std::time::Instant::now();
  572. METRICS.inc_in_flight_requests("make_payment");
  573. let result = self.inner.make_payment(unit, options).await;
  574. let duration = start.elapsed().as_secs_f64();
  575. let success = result.is_ok();
  576. METRICS.record_mint_operation_histogram("make_payment", success, duration);
  577. METRICS.dec_in_flight_requests("make_payment");
  578. result
  579. }
  580. fn is_wait_invoice_active(&self) -> bool {
  581. self.inner.is_wait_invoice_active()
  582. }
  583. fn cancel_wait_invoice(&self) {
  584. self.inner.cancel_wait_invoice()
  585. }
  586. async fn check_incoming_payment_status(
  587. &self,
  588. payment_identifier: &PaymentIdentifier,
  589. ) -> Result<Vec<WaitPaymentResponse>, Self::Err> {
  590. let start = std::time::Instant::now();
  591. METRICS.inc_in_flight_requests("check_incoming_payment_status");
  592. let result = self
  593. .inner
  594. .check_incoming_payment_status(payment_identifier)
  595. .await;
  596. let duration = start.elapsed().as_secs_f64();
  597. METRICS.record_mint_operation_histogram(
  598. "check_incoming_payment_status",
  599. result.is_ok(),
  600. duration,
  601. );
  602. METRICS.dec_in_flight_requests("check_incoming_payment_status");
  603. result
  604. }
  605. async fn check_outgoing_payment(
  606. &self,
  607. payment_identifier: &PaymentIdentifier,
  608. ) -> Result<MakePaymentResponse, Self::Err> {
  609. let start = std::time::Instant::now();
  610. METRICS.inc_in_flight_requests("check_outgoing_payment");
  611. let result = self.inner.check_outgoing_payment(payment_identifier).await;
  612. let duration = start.elapsed().as_secs_f64();
  613. let success = result.is_ok();
  614. METRICS.record_mint_operation_histogram("check_outgoing_payment", success, duration);
  615. METRICS.dec_in_flight_requests("check_outgoing_payment");
  616. result
  617. }
  618. }
  619. /// Type alias for Mint Payment trait
  620. pub type DynMintPayment = std::sync::Arc<dyn MintPayment<Err = Error> + Send + Sync>;