strike_rs/
pay_ln.rs

1//! Pay Ln
2
3use anyhow::{bail, Result};
4use reqwest::StatusCode;
5use serde::{Deserialize, Serialize};
6
7use crate::{Amount, ConversionRate, Currency, Error, InvoiceState, Strike};
8
9/// Pay Invoice Request
10#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
11#[serde(rename_all = "camelCase")]
12pub struct PayInvoiceQuoteRequest {
13    /// Bolt11 Invoice
14    pub ln_invoice: String,
15    /// Source Currency
16    pub source_currency: Currency,
17}
18
19/// Pay Invoice Response
20#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
21#[serde(rename_all = "camelCase")]
22pub struct PayInvoiceQuoteResponse {
23    /// Payment quote Id
24    pub payment_quote_id: String,
25    /// Description
26    pub description: Option<String>,
27    /// Quote valid till
28    pub valid_until: String,
29    /// Conversion quote
30    pub conversion_rate: Option<ConversionRate>,
31    /// Amount
32    pub amount: Amount,
33    /// Network fee
34    pub lightning_network_fee: Amount,
35    /// Total amount including fee
36    pub total_amount: Amount,
37}
38
39/// Pay Quote Response
40#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
41#[serde(rename_all = "camelCase")]
42pub struct InvoicePaymentResponse {
43    /// Payment id
44    pub payment_id: String,
45    /// Invoice state
46    pub state: InvoiceState,
47    /// Completed time stamp
48    pub completed: Option<String>,
49    /// Conversion quote
50    pub conversion_rate: Option<ConversionRate>,
51    /// Amount
52    pub amount: Amount,
53    /// Network fee
54    pub lightning_network_fee: Amount,
55    /// Total amount including fee
56    pub total_amount: Amount,
57}
58
59impl Strike {
60    /// Create Payment Quote
61    pub async fn payment_quote(
62        &self,
63        quote_request: PayInvoiceQuoteRequest,
64    ) -> Result<PayInvoiceQuoteResponse> {
65        let url = self.base_url.join("/v1/payment-quotes/lightning")?;
66
67        let res = self
68            .make_post(url, Some(serde_json::to_value(quote_request)?))
69            .await?;
70
71        match serde_json::from_value(res.clone()) {
72            Ok(res) => Ok(res),
73            Err(_) => {
74                log::error!("Api error response on payment quote");
75                log::error!("{}", res);
76                bail!("Could not get payment quote")
77            }
78        }
79    }
80
81    /// Execute quote to pay invoice
82    pub async fn pay_quote(&self, payment_quote_id: &str) -> Result<InvoicePaymentResponse> {
83        let url = self
84            .base_url
85            .join(&format!("/v1/payment-quotes/{payment_quote_id}/execute"))?;
86
87        let res = self.make_patch(url).await?;
88
89        match serde_json::from_value(res.clone()) {
90            Ok(res) => Ok(res),
91            Err(_) => {
92                log::error!("Api error response on payment quote execution");
93                log::error!("{}", res);
94                bail!("Could not execute payment quote")
95            }
96        }
97    }
98
99    /// Get outgoing payment by payment id
100    pub async fn get_outgoing_payment(
101        &self,
102        payment_id: &str,
103    ) -> Result<InvoicePaymentResponse, Error> {
104        let url = self
105            .base_url
106            .join(&format!("/v1/payments/{payment_id}"))
107            .map_err(|_| Error::InvalidUrl)?;
108
109        let res = match self.make_get(url).await {
110            Ok(res) => res,
111            Err(err) => {
112                if let Error::ReqwestError(err) = &err {
113                    if err.status().unwrap_or_default() == StatusCode::NOT_FOUND {
114                        return Err(Error::NotFound);
115                    }
116                }
117                return Err(err);
118            }
119        };
120
121        match serde_json::from_value(res.clone()) {
122            Ok(res) => Ok(res),
123            Err(err) => {
124                log::error!("Api error response getting payment quote");
125                log::error!("{}", res);
126
127                Err(err.into())
128            }
129        }
130    }
131}