payment.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  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(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. impl std::fmt::Debug for PaymentIdentifier {
  145. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  146. match self {
  147. PaymentIdentifier::PaymentHash(h) => write!(f, "PaymentHash({})", hex::encode(h)),
  148. PaymentIdentifier::Bolt12PaymentHash(h) => {
  149. write!(f, "Bolt12PaymentHash({})", hex::encode(h))
  150. }
  151. PaymentIdentifier::PaymentId(h) => write!(f, "PaymentId({})", hex::encode(h)),
  152. PaymentIdentifier::Label(s) => write!(f, "Label({})", s),
  153. PaymentIdentifier::OfferId(s) => write!(f, "OfferId({})", s),
  154. PaymentIdentifier::CustomId(s) => write!(f, "CustomId({})", s),
  155. }
  156. }
  157. }
  158. /// Options for creating a BOLT11 incoming payment request
  159. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
  160. pub struct Bolt11IncomingPaymentOptions {
  161. /// Optional description for the payment request
  162. pub description: Option<String>,
  163. /// Amount for the payment request in sats
  164. pub amount: Amount,
  165. /// Optional expiry time as Unix timestamp in seconds
  166. pub unix_expiry: Option<u64>,
  167. }
  168. /// Options for creating a BOLT12 incoming payment request
  169. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
  170. pub struct Bolt12IncomingPaymentOptions {
  171. /// Optional description for the payment request
  172. pub description: Option<String>,
  173. /// Optional amount for the payment request in sats
  174. pub amount: Option<Amount>,
  175. /// Optional expiry time as Unix timestamp in seconds
  176. pub unix_expiry: Option<u64>,
  177. }
  178. /// Options for creating a custom incoming payment request
  179. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  180. pub struct CustomIncomingPaymentOptions {
  181. /// Payment method name (e.g., "paypal", "venmo")
  182. pub method: String,
  183. /// Optional description for the payment request
  184. pub description: Option<String>,
  185. /// Amount for the payment request
  186. pub amount: Amount,
  187. /// Optional expiry time as Unix timestamp in seconds
  188. pub unix_expiry: Option<u64>,
  189. /// Extra payment-method-specific fields as JSON string
  190. ///
  191. /// These fields are passed through to the payment processor for
  192. /// method-specific validation (e.g., ehash share).
  193. pub extra_json: Option<String>,
  194. }
  195. /// Options for creating an incoming payment request
  196. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  197. pub enum IncomingPaymentOptions {
  198. /// BOLT11 payment request options
  199. Bolt11(Bolt11IncomingPaymentOptions),
  200. /// BOLT12 payment request options
  201. Bolt12(Box<Bolt12IncomingPaymentOptions>),
  202. /// Custom payment method options
  203. Custom(Box<CustomIncomingPaymentOptions>),
  204. }
  205. /// Options for BOLT11 outgoing payments
  206. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  207. pub struct Bolt11OutgoingPaymentOptions {
  208. /// Bolt11
  209. pub bolt11: Bolt11Invoice,
  210. /// Maximum fee amount allowed for the payment
  211. pub max_fee_amount: Option<Amount>,
  212. /// Optional timeout in seconds
  213. pub timeout_secs: Option<u64>,
  214. /// Melt options
  215. pub melt_options: Option<MeltOptions>,
  216. }
  217. /// Options for BOLT12 outgoing payments
  218. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  219. pub struct Bolt12OutgoingPaymentOptions {
  220. /// Offer
  221. pub offer: Offer,
  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. }
  229. /// Options for custom outgoing payments
  230. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  231. pub struct CustomOutgoingPaymentOptions {
  232. /// Payment method name
  233. pub method: String,
  234. /// Payment request string (method-specific format)
  235. pub request: String,
  236. /// Maximum fee amount allowed for the payment
  237. pub max_fee_amount: Option<Amount>,
  238. /// Optional timeout in seconds
  239. pub timeout_secs: Option<u64>,
  240. /// Melt options
  241. pub melt_options: Option<MeltOptions>,
  242. /// Extra payment-method-specific fields as JSON string
  243. ///
  244. /// These fields are passed through to the payment processor for
  245. /// method-specific validation.
  246. pub extra_json: Option<String>,
  247. }
  248. /// Options for creating an outgoing payment
  249. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  250. pub enum OutgoingPaymentOptions {
  251. /// BOLT11 payment options
  252. Bolt11(Box<Bolt11OutgoingPaymentOptions>),
  253. /// BOLT12 payment options
  254. Bolt12(Box<Bolt12OutgoingPaymentOptions>),
  255. /// Custom payment method options
  256. Custom(Box<CustomOutgoingPaymentOptions>),
  257. }
  258. impl TryFrom<crate::mint::MeltQuote> for OutgoingPaymentOptions {
  259. type Error = Error;
  260. fn try_from(melt_quote: crate::mint::MeltQuote) -> Result<Self, Self::Error> {
  261. let fee_reserve = melt_quote.fee_reserve();
  262. match &melt_quote.request {
  263. MeltPaymentRequest::Bolt11 { bolt11 } => Ok(OutgoingPaymentOptions::Bolt11(Box::new(
  264. Bolt11OutgoingPaymentOptions {
  265. max_fee_amount: Some(fee_reserve.to_owned().into()),
  266. timeout_secs: None,
  267. bolt11: bolt11.clone(),
  268. melt_options: melt_quote.options,
  269. },
  270. ))),
  271. MeltPaymentRequest::Bolt12 { offer } => {
  272. let melt_options = match melt_quote.options {
  273. None => None,
  274. Some(MeltOptions::Mpp { mpp: _ }) => return Err(Error::UnsupportedUnit),
  275. Some(options) => Some(options),
  276. };
  277. Ok(OutgoingPaymentOptions::Bolt12(Box::new(
  278. Bolt12OutgoingPaymentOptions {
  279. max_fee_amount: Some(fee_reserve.clone().into()),
  280. timeout_secs: None,
  281. offer: *offer.clone(),
  282. melt_options,
  283. },
  284. )))
  285. }
  286. MeltPaymentRequest::Custom { method, request } => Ok(OutgoingPaymentOptions::Custom(
  287. Box::new(CustomOutgoingPaymentOptions {
  288. method: method.to_string(),
  289. request: request.to_string(),
  290. max_fee_amount: Some(melt_quote.fee_reserve().into()),
  291. timeout_secs: None,
  292. melt_options: melt_quote.options,
  293. extra_json: None,
  294. }),
  295. )),
  296. }
  297. }
  298. }
  299. /// Mint payment trait
  300. #[async_trait]
  301. pub trait MintPayment {
  302. /// Mint Lightning Error
  303. type Err: Into<Error> + From<Error>;
  304. /// Start the payment processor
  305. /// Called when the mint starts up to initialize the payment processor
  306. async fn start(&self) -> Result<(), Self::Err> {
  307. // Default implementation - do nothing
  308. Ok(())
  309. }
  310. /// Stop the payment processor
  311. /// Called when the mint shuts down to gracefully stop the payment processor
  312. async fn stop(&self) -> Result<(), Self::Err> {
  313. // Default implementation - do nothing
  314. Ok(())
  315. }
  316. /// Base Settings
  317. async fn get_settings(&self) -> Result<SettingsResponse, Self::Err>;
  318. /// Create a new invoice
  319. async fn create_incoming_payment_request(
  320. &self,
  321. unit: &CurrencyUnit,
  322. options: IncomingPaymentOptions,
  323. ) -> Result<CreateIncomingPaymentResponse, Self::Err>;
  324. /// Get payment quote
  325. /// Used to get fee and amount required for a payment request
  326. async fn get_payment_quote(
  327. &self,
  328. unit: &CurrencyUnit,
  329. options: OutgoingPaymentOptions,
  330. ) -> Result<PaymentQuoteResponse, Self::Err>;
  331. /// Pay request
  332. async fn make_payment(
  333. &self,
  334. unit: &CurrencyUnit,
  335. options: OutgoingPaymentOptions,
  336. ) -> Result<MakePaymentResponse, Self::Err>;
  337. /// Listen for invoices to be paid to the mint
  338. /// Returns a stream of request_lookup_id once invoices are paid
  339. async fn wait_payment_event(
  340. &self,
  341. ) -> Result<Pin<Box<dyn Stream<Item = Event> + Send>>, Self::Err>;
  342. /// Is wait invoice active
  343. fn is_wait_invoice_active(&self) -> bool;
  344. /// Cancel wait invoice
  345. fn cancel_wait_invoice(&self);
  346. /// Check the status of an incoming payment
  347. async fn check_incoming_payment_status(
  348. &self,
  349. payment_identifier: &PaymentIdentifier,
  350. ) -> Result<Vec<WaitPaymentResponse>, Self::Err>;
  351. /// Check the status of an outgoing payment
  352. async fn check_outgoing_payment(
  353. &self,
  354. payment_identifier: &PaymentIdentifier,
  355. ) -> Result<MakePaymentResponse, Self::Err>;
  356. }
  357. /// An event emitted which should be handled by the mint
  358. #[derive(Debug, Clone, Hash)]
  359. pub enum Event {
  360. /// A payment has been received.
  361. PaymentReceived(WaitPaymentResponse),
  362. }
  363. impl Default for Event {
  364. fn default() -> Self {
  365. // We use this as a sentinel value for no-op events
  366. // The actual processing will filter these out
  367. Event::PaymentReceived(WaitPaymentResponse {
  368. payment_identifier: PaymentIdentifier::CustomId("default".to_string()),
  369. payment_amount: Amount::new(0, CurrencyUnit::Msat),
  370. payment_id: "default".to_string(),
  371. })
  372. }
  373. }
  374. /// Wait any invoice response
  375. #[derive(Debug, Clone, Hash)]
  376. pub struct WaitPaymentResponse {
  377. /// Request look up id
  378. /// Id that relates the quote and payment request
  379. pub payment_identifier: PaymentIdentifier,
  380. /// Payment amount (typed with unit for compile-time safety)
  381. pub payment_amount: Amount<CurrencyUnit>,
  382. /// Unique id of payment
  383. // Payment hash
  384. pub payment_id: String,
  385. }
  386. impl WaitPaymentResponse {
  387. /// Get the currency unit
  388. pub fn unit(&self) -> &CurrencyUnit {
  389. self.payment_amount.unit()
  390. }
  391. }
  392. /// Create incoming payment response
  393. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
  394. pub struct CreateIncomingPaymentResponse {
  395. /// Id that is used to look up the payment from the ln backend
  396. pub request_lookup_id: PaymentIdentifier,
  397. /// Payment request
  398. pub request: String,
  399. /// Unix Expiry of Invoice
  400. pub expiry: Option<u64>,
  401. /// Extra payment-method-specific fields
  402. ///
  403. /// These fields are flattened into the JSON representation, allowing
  404. /// custom payment methods to include additional data without nesting.
  405. #[serde(flatten, default)]
  406. pub extra_json: Option<serde_json::Value>,
  407. }
  408. /// Payment response
  409. #[derive(Debug, Clone, Hash, PartialEq, Eq)]
  410. pub struct MakePaymentResponse {
  411. /// Payment hash
  412. pub payment_lookup_id: PaymentIdentifier,
  413. /// Payment proof
  414. pub payment_proof: Option<String>,
  415. /// Status
  416. pub status: MeltQuoteState,
  417. /// Total Amount Spent (typed with unit for compile-time safety)
  418. pub total_spent: Amount<CurrencyUnit>,
  419. }
  420. impl MakePaymentResponse {
  421. /// Get the currency unit
  422. pub fn unit(&self) -> &CurrencyUnit {
  423. self.total_spent.unit()
  424. }
  425. }
  426. /// Payment quote response
  427. #[derive(Debug, Clone, Hash, PartialEq, Eq)]
  428. pub struct PaymentQuoteResponse {
  429. /// Request look up id
  430. pub request_lookup_id: Option<PaymentIdentifier>,
  431. /// Amount (typed with unit for compile-time safety)
  432. pub amount: Amount<CurrencyUnit>,
  433. /// Fee required for melt (typed with unit for compile-time safety)
  434. pub fee: Amount<CurrencyUnit>,
  435. /// Status
  436. pub state: MeltQuoteState,
  437. }
  438. impl PaymentQuoteResponse {
  439. /// Get the currency unit
  440. pub fn unit(&self) -> &CurrencyUnit {
  441. self.amount.unit()
  442. }
  443. }
  444. /// BOLT11 settings
  445. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
  446. pub struct Bolt11Settings {
  447. /// Multi-part payment (MPP) supported
  448. pub mpp: bool,
  449. /// Amountless invoice support
  450. pub amountless: bool,
  451. /// Invoice description supported
  452. pub invoice_description: bool,
  453. }
  454. /// BOLT12 settings
  455. #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
  456. pub struct Bolt12Settings {
  457. /// Amountless offer support
  458. pub amountless: bool,
  459. }
  460. /// Payment processor settings response
  461. /// Mirrors the proto SettingsResponse structure
  462. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  463. pub struct SettingsResponse {
  464. /// Base unit of backend
  465. pub unit: String,
  466. /// BOLT11 settings (None if not supported)
  467. pub bolt11: Option<Bolt11Settings>,
  468. /// BOLT12 settings (None if not supported)
  469. pub bolt12: Option<Bolt12Settings>,
  470. /// Custom payment methods settings (method name -> settings data)
  471. #[serde(default)]
  472. pub custom: std::collections::HashMap<String, String>,
  473. }
  474. impl From<SettingsResponse> for Value {
  475. fn from(value: SettingsResponse) -> Self {
  476. serde_json::to_value(value).unwrap_or(Value::Null)
  477. }
  478. }
  479. impl TryFrom<Value> for SettingsResponse {
  480. type Error = crate::error::Error;
  481. fn try_from(value: Value) -> Result<Self, Self::Error> {
  482. serde_json::from_value(value).map_err(|err| err.into())
  483. }
  484. }
  485. /// Metrics wrapper for MintPayment implementations
  486. ///
  487. /// This wrapper implements the Decorator pattern to collect metrics on all
  488. /// MintPayment trait methods. It wraps any existing MintPayment implementation
  489. /// and automatically records timing and operation metrics.
  490. #[derive(Debug, Clone)]
  491. #[cfg(feature = "prometheus")]
  492. pub struct MetricsMintPayment<T> {
  493. inner: T,
  494. }
  495. #[cfg(feature = "prometheus")]
  496. impl<T> MetricsMintPayment<T>
  497. where
  498. T: MintPayment,
  499. {
  500. /// Create a new metrics wrapper around a MintPayment implementation
  501. pub fn new(inner: T) -> Self {
  502. Self { inner }
  503. }
  504. /// Get reference to the underlying implementation
  505. pub fn inner(&self) -> &T {
  506. &self.inner
  507. }
  508. /// Consume the wrapper and return the inner implementation
  509. pub fn into_inner(self) -> T {
  510. self.inner
  511. }
  512. }
  513. #[async_trait]
  514. #[cfg(feature = "prometheus")]
  515. impl<T> MintPayment for MetricsMintPayment<T>
  516. where
  517. T: MintPayment + Send + Sync,
  518. {
  519. type Err = T::Err;
  520. async fn get_settings(&self) -> Result<SettingsResponse, Self::Err> {
  521. let start = std::time::Instant::now();
  522. METRICS.inc_in_flight_requests("get_settings");
  523. let result = self.inner.get_settings().await;
  524. let duration = start.elapsed().as_secs_f64();
  525. METRICS.record_mint_operation_histogram("get_settings", result.is_ok(), duration);
  526. METRICS.dec_in_flight_requests("get_settings");
  527. result
  528. }
  529. async fn create_incoming_payment_request(
  530. &self,
  531. unit: &CurrencyUnit,
  532. options: IncomingPaymentOptions,
  533. ) -> Result<CreateIncomingPaymentResponse, Self::Err> {
  534. let start = std::time::Instant::now();
  535. METRICS.inc_in_flight_requests("create_incoming_payment_request");
  536. let result = self
  537. .inner
  538. .create_incoming_payment_request(unit, options)
  539. .await;
  540. let duration = start.elapsed().as_secs_f64();
  541. METRICS.record_mint_operation_histogram(
  542. "create_incoming_payment_request",
  543. result.is_ok(),
  544. duration,
  545. );
  546. METRICS.dec_in_flight_requests("create_incoming_payment_request");
  547. result
  548. }
  549. async fn get_payment_quote(
  550. &self,
  551. unit: &CurrencyUnit,
  552. options: OutgoingPaymentOptions,
  553. ) -> Result<PaymentQuoteResponse, Self::Err> {
  554. let start = std::time::Instant::now();
  555. METRICS.inc_in_flight_requests("get_payment_quote");
  556. let result = self.inner.get_payment_quote(unit, options).await;
  557. let duration = start.elapsed().as_secs_f64();
  558. let success = result.is_ok();
  559. if let Ok(ref quote) = result {
  560. let amount: f64 = quote.amount.value() as f64;
  561. let fee: f64 = quote.fee.value() as f64;
  562. METRICS.record_lightning_payment(amount, fee);
  563. }
  564. METRICS.record_mint_operation_histogram("get_payment_quote", success, duration);
  565. METRICS.dec_in_flight_requests("get_payment_quote");
  566. result
  567. }
  568. async fn wait_payment_event(
  569. &self,
  570. ) -> Result<Pin<Box<dyn Stream<Item = Event> + Send>>, Self::Err> {
  571. let start = std::time::Instant::now();
  572. METRICS.inc_in_flight_requests("wait_payment_event");
  573. let result = self.inner.wait_payment_event().await;
  574. let duration = start.elapsed().as_secs_f64();
  575. let success = result.is_ok();
  576. METRICS.record_mint_operation_histogram("wait_payment_event", success, duration);
  577. METRICS.dec_in_flight_requests("wait_payment_event");
  578. result
  579. }
  580. async fn make_payment(
  581. &self,
  582. unit: &CurrencyUnit,
  583. options: OutgoingPaymentOptions,
  584. ) -> Result<MakePaymentResponse, Self::Err> {
  585. let start = std::time::Instant::now();
  586. METRICS.inc_in_flight_requests("make_payment");
  587. let result = self.inner.make_payment(unit, options).await;
  588. let duration = start.elapsed().as_secs_f64();
  589. let success = result.is_ok();
  590. METRICS.record_mint_operation_histogram("make_payment", success, duration);
  591. METRICS.dec_in_flight_requests("make_payment");
  592. result
  593. }
  594. fn is_wait_invoice_active(&self) -> bool {
  595. self.inner.is_wait_invoice_active()
  596. }
  597. fn cancel_wait_invoice(&self) {
  598. self.inner.cancel_wait_invoice()
  599. }
  600. async fn check_incoming_payment_status(
  601. &self,
  602. payment_identifier: &PaymentIdentifier,
  603. ) -> Result<Vec<WaitPaymentResponse>, Self::Err> {
  604. let start = std::time::Instant::now();
  605. METRICS.inc_in_flight_requests("check_incoming_payment_status");
  606. let result = self
  607. .inner
  608. .check_incoming_payment_status(payment_identifier)
  609. .await;
  610. let duration = start.elapsed().as_secs_f64();
  611. METRICS.record_mint_operation_histogram(
  612. "check_incoming_payment_status",
  613. result.is_ok(),
  614. duration,
  615. );
  616. METRICS.dec_in_flight_requests("check_incoming_payment_status");
  617. result
  618. }
  619. async fn check_outgoing_payment(
  620. &self,
  621. payment_identifier: &PaymentIdentifier,
  622. ) -> Result<MakePaymentResponse, Self::Err> {
  623. let start = std::time::Instant::now();
  624. METRICS.inc_in_flight_requests("check_outgoing_payment");
  625. let result = self.inner.check_outgoing_payment(payment_identifier).await;
  626. let duration = start.elapsed().as_secs_f64();
  627. let success = result.is_ok();
  628. METRICS.record_mint_operation_histogram("check_outgoing_payment", success, duration);
  629. METRICS.dec_in_flight_requests("check_outgoing_payment");
  630. result
  631. }
  632. }
  633. /// Type alias for Mint Payment trait
  634. pub type DynMintPayment = std::sync::Arc<dyn MintPayment<Err = Error> + Send + Sync>;