mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-23 05:56:02 +01:00
feat: use amount type in ln
This commit is contained in:
@@ -40,6 +40,8 @@
|
||||
- cdk(mint): Refactored `MintKeySet::generate_from_xpriv` and `MintKeySet::generate_from_seed` methods to accept max_order, currency_unit, and derivation_path parameters directly ([vnprc]).
|
||||
- cdk(wallet): Return WalletKey for UnknownWallet error ([davidcaseria]).
|
||||
- cdk(cdk-lightning): `CreateInvoiceResponse` added expiry time to better support backends where it cannot be set ([thesimeplkid]).
|
||||
- cdk(cdk-lightning): Use `Amount` type instead of `u64` ([thesimplekid]).
|
||||
- cdk(cdk-lightning): `CreateInvoice` requires unit argument ([thesimplekid]).
|
||||
|
||||
### Added
|
||||
- cdk(NUT-11): Add `Copy` on `SigFlag` ([thesimplekid]).
|
||||
|
||||
@@ -4,6 +4,7 @@ use anyhow::Result;
|
||||
use axum::extract::{Json, Path, State};
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use cdk::amount::Amount;
|
||||
use cdk::cdk_lightning::to_unit;
|
||||
use cdk::error::{Error, ErrorResponse};
|
||||
use cdk::nuts::nut05::MeltBolt11Response;
|
||||
@@ -70,7 +71,7 @@ pub async fn get_mint_bolt11_quote(
|
||||
let quote_expiry = unix_time() + state.quote_ttl;
|
||||
|
||||
let create_invoice_response = ln
|
||||
.create_invoice(amount, "".to_string(), quote_expiry)
|
||||
.create_invoice(amount, &payload.unit, "".to_string(), quote_expiry)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
tracing::error!("Could not create invoice: {}", err);
|
||||
@@ -156,7 +157,7 @@ pub async fn get_melt_bolt11_quote(
|
||||
.new_melt_quote(
|
||||
payload.request.to_string(),
|
||||
payload.unit,
|
||||
payment_quote.amount.into(),
|
||||
payment_quote.amount,
|
||||
payment_quote.fee.into(),
|
||||
unix_time() + state.quote_ttl,
|
||||
payment_quote.request_lookup_id,
|
||||
@@ -270,8 +271,7 @@ pub async fn post_melt_bolt11(
|
||||
}
|
||||
};
|
||||
|
||||
let mut partial_msats = None;
|
||||
let mut max_fee_msats = None;
|
||||
let mut partial_amount = None;
|
||||
|
||||
// If the quote unit is SAT or MSAT we can check that the expected fees are provided.
|
||||
// We also check if the quote is less then the invoice amount in the case that it is a mmp
|
||||
@@ -283,8 +283,8 @@ pub async fn post_melt_bolt11(
|
||||
let quote_msats = to_unit(quote.amount, "e.unit, &CurrencyUnit::Msat)
|
||||
.expect("Quote unit is checked above that it can convert to msat");
|
||||
|
||||
let invoice_amount_msats = match invoice.amount_milli_satoshis() {
|
||||
Some(amount) => amount,
|
||||
let invoice_amount_msats: Amount = match invoice.amount_milli_satoshis() {
|
||||
Some(amount) => amount.into(),
|
||||
None => {
|
||||
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
||||
tracing::error!("Could not reset melt quote state: {}", err);
|
||||
@@ -293,30 +293,29 @@ pub async fn post_melt_bolt11(
|
||||
}
|
||||
};
|
||||
|
||||
partial_msats = match invoice_amount_msats > quote_msats {
|
||||
true => Some(invoice_amount_msats - quote_msats),
|
||||
partial_amount = match invoice_amount_msats > quote_msats {
|
||||
true => {
|
||||
let partial_msats = invoice_amount_msats - quote_msats;
|
||||
|
||||
Some(
|
||||
to_unit(partial_msats, &CurrencyUnit::Msat, "e.unit)
|
||||
.map_err(|_| into_response(Error::UnsupportedUnit))?,
|
||||
)
|
||||
}
|
||||
false => None,
|
||||
};
|
||||
|
||||
let max_fee = to_unit(quote.fee_reserve, "e.unit, &CurrencyUnit::Msat)
|
||||
.expect("Quote unit is checked above that it can convert to msat");
|
||||
|
||||
max_fee_msats = Some(max_fee);
|
||||
|
||||
let amount_to_pay_msats = match partial_msats {
|
||||
let amount_to_pay = match partial_amount {
|
||||
Some(amount_to_pay) => amount_to_pay,
|
||||
None => invoice_amount_msats,
|
||||
None => to_unit(invoice_amount_msats, &CurrencyUnit::Msat, "e.unit)
|
||||
.map_err(|_| into_response(Error::UnsupportedUnit))?,
|
||||
};
|
||||
|
||||
let input_amount_msats =
|
||||
to_unit(inputs_amount_quote_unit, "e.unit, &CurrencyUnit::Msat)
|
||||
.expect("Quote unit is checked above that it can convert to msat");
|
||||
|
||||
if amount_to_pay_msats + max_fee > input_amount_msats {
|
||||
if amount_to_pay + quote.fee_reserve > inputs_amount_quote_unit {
|
||||
tracing::debug!(
|
||||
"Not enough inuts provided: {} msats needed {} msats",
|
||||
input_amount_msats,
|
||||
amount_to_pay_msats
|
||||
inputs_amount_quote_unit,
|
||||
amount_to_pay
|
||||
);
|
||||
|
||||
if let Err(err) = state.mint.process_unpaid_melt(&payload).await {
|
||||
@@ -339,7 +338,7 @@ pub async fn post_melt_bolt11(
|
||||
};
|
||||
|
||||
let pre = match ln
|
||||
.pay_invoice(quote.clone(), partial_msats, max_fee_msats)
|
||||
.pay_invoice(quote.clone(), partial_amount, Some(quote.fee_reserve))
|
||||
.await
|
||||
{
|
||||
Ok(pay) => pay,
|
||||
@@ -358,10 +357,10 @@ pub async fn post_melt_bolt11(
|
||||
}
|
||||
};
|
||||
|
||||
let amount_spent = to_unit(pre.total_spent_msats, &ln.get_settings().unit, "e.unit)
|
||||
let amount_spent = to_unit(pre.total_spent, &ln.get_settings().unit, "e.unit)
|
||||
.map_err(|_| into_response(Error::UnsupportedUnit))?;
|
||||
|
||||
(pre.payment_preimage, amount_spent.into())
|
||||
(pre.payment_preimage, amount_spent)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cdk::amount::Amount;
|
||||
use cdk::cdk_lightning::{
|
||||
self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
|
||||
PaymentQuoteResponse, Settings,
|
||||
@@ -130,7 +131,8 @@ impl MintLightning for Cln {
|
||||
&melt_quote_request.unit,
|
||||
)?;
|
||||
|
||||
let relative_fee_reserve = (self.fee_reserve.percent_fee_reserve * amount as f32) as u64;
|
||||
let relative_fee_reserve =
|
||||
(self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64;
|
||||
|
||||
let absolute_fee_reserve: u64 = self.fee_reserve.min_fee_reserve.into();
|
||||
|
||||
@@ -149,8 +151,8 @@ impl MintLightning for Cln {
|
||||
async fn pay_invoice(
|
||||
&self,
|
||||
melt_quote: mint::MeltQuote,
|
||||
partial_msats: Option<u64>,
|
||||
max_fee_msats: Option<u64>,
|
||||
partial_amount: Option<Amount>,
|
||||
max_fee: Option<Amount>,
|
||||
) -> Result<PayInvoiceResponse, Self::Err> {
|
||||
let mut cln_client = self.cln_client.lock().await;
|
||||
|
||||
@@ -181,9 +183,24 @@ impl MintLightning for Cln {
|
||||
exemptfee: None,
|
||||
localinvreqid: None,
|
||||
exclude: None,
|
||||
maxfee: max_fee_msats.map(CLN_Amount::from_msat),
|
||||
maxfee: max_fee
|
||||
.map(|a| {
|
||||
let msat = to_unit(a, &melt_quote.unit, &CurrencyUnit::Msat)?;
|
||||
Ok::<cln_rpc::primitives::Amount, Self::Err>(CLN_Amount::from_msat(
|
||||
msat.into(),
|
||||
))
|
||||
})
|
||||
.transpose()?,
|
||||
description: None,
|
||||
partial_msat: partial_msats.map(CLN_Amount::from_msat),
|
||||
partial_msat: partial_amount
|
||||
.map(|a| {
|
||||
let msat = to_unit(a, &melt_quote.unit, &CurrencyUnit::Msat)?;
|
||||
|
||||
Ok::<cln_rpc::primitives::Amount, Self::Err>(CLN_Amount::from_msat(
|
||||
msat.into(),
|
||||
))
|
||||
})
|
||||
.transpose()?,
|
||||
}))
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
@@ -199,7 +216,11 @@ impl MintLightning for Cln {
|
||||
payment_preimage: Some(hex::encode(pay_response.payment_preimage.to_vec())),
|
||||
payment_hash: pay_response.payment_hash.to_string(),
|
||||
status,
|
||||
total_spent_msats: pay_response.amount_sent_msat.msat(),
|
||||
total_spent: to_unit(
|
||||
pay_response.amount_sent_msat.msat(),
|
||||
&CurrencyUnit::Msat,
|
||||
&melt_quote.unit,
|
||||
)?,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -213,7 +234,8 @@ impl MintLightning for Cln {
|
||||
|
||||
async fn create_invoice(
|
||||
&self,
|
||||
amount_msats: u64,
|
||||
amount: Amount,
|
||||
unit: &CurrencyUnit,
|
||||
description: String,
|
||||
unix_expiry: u64,
|
||||
) -> Result<CreateInvoiceResponse, Self::Err> {
|
||||
@@ -223,7 +245,10 @@ impl MintLightning for Cln {
|
||||
let mut cln_client = self.cln_client.lock().await;
|
||||
|
||||
let label = Uuid::new_v4().to_string();
|
||||
let amount_msat = AmountOrAny::Amount(CLN_Amount::from_msat(amount_msats));
|
||||
|
||||
let amount = to_unit(amount, unit, &CurrencyUnit::Msat)?;
|
||||
let amount_msat = AmountOrAny::Amount(CLN_Amount::from_msat(amount.into()));
|
||||
|
||||
let cln_response = cln_client
|
||||
.call(cln_rpc::Request::Invoice(InvoiceRequest {
|
||||
amount_msat,
|
||||
|
||||
@@ -11,6 +11,7 @@ use std::sync::Arc;
|
||||
use async_trait::async_trait;
|
||||
use bitcoin::hashes::{sha256, Hash};
|
||||
use bitcoin::secp256k1::{Secp256k1, SecretKey};
|
||||
use cdk::amount::Amount;
|
||||
use cdk::cdk_lightning::{
|
||||
self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
|
||||
PaymentQuoteResponse, Settings,
|
||||
@@ -96,7 +97,8 @@ impl MintLightning for FakeWallet {
|
||||
&melt_quote_request.unit,
|
||||
)?;
|
||||
|
||||
let relative_fee_reserve = (self.fee_reserve.percent_fee_reserve * amount as f32) as u64;
|
||||
let relative_fee_reserve =
|
||||
(self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64;
|
||||
|
||||
let absolute_fee_reserve: u64 = self.fee_reserve.min_fee_reserve.into();
|
||||
|
||||
@@ -115,20 +117,21 @@ impl MintLightning for FakeWallet {
|
||||
async fn pay_invoice(
|
||||
&self,
|
||||
melt_quote: mint::MeltQuote,
|
||||
_partial_msats: Option<u64>,
|
||||
_max_fee_msats: Option<u64>,
|
||||
_partial_msats: Option<Amount>,
|
||||
_max_fee_msats: Option<Amount>,
|
||||
) -> Result<PayInvoiceResponse, Self::Err> {
|
||||
Ok(PayInvoiceResponse {
|
||||
payment_preimage: Some("".to_string()),
|
||||
payment_hash: "".to_string(),
|
||||
status: MeltQuoteState::Paid,
|
||||
total_spent_msats: melt_quote.amount.into(),
|
||||
total_spent: melt_quote.amount,
|
||||
})
|
||||
}
|
||||
|
||||
async fn create_invoice(
|
||||
&self,
|
||||
amount_msats: u64,
|
||||
amount: Amount,
|
||||
unit: &CurrencyUnit,
|
||||
description: String,
|
||||
unix_expiry: u64,
|
||||
) -> Result<CreateInvoiceResponse, Self::Err> {
|
||||
@@ -149,11 +152,13 @@ impl MintLightning for FakeWallet {
|
||||
let payment_hash = sha256::Hash::from_slice(&[0; 32][..]).unwrap();
|
||||
let payment_secret = PaymentSecret([42u8; 32]);
|
||||
|
||||
let amount = to_unit(amount, unit, &CurrencyUnit::Msat)?;
|
||||
|
||||
let invoice = InvoiceBuilder::new(Currency::Bitcoin)
|
||||
.description(description)
|
||||
.payment_hash(payment_hash)
|
||||
.payment_secret(payment_secret)
|
||||
.amount_milli_satoshis(amount_msats)
|
||||
.amount_milli_satoshis(amount.into())
|
||||
.current_timestamp()
|
||||
.min_final_cltv_expiry_delta(144)
|
||||
.build_signed(|hash| Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
|
||||
|
||||
@@ -9,6 +9,7 @@ use std::sync::Arc;
|
||||
use anyhow::{anyhow, bail};
|
||||
use async_trait::async_trait;
|
||||
use axum::Router;
|
||||
use cdk::amount::Amount;
|
||||
use cdk::cdk_lightning::{
|
||||
self, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
|
||||
PaymentQuoteResponse, Settings,
|
||||
@@ -141,7 +142,7 @@ impl MintLightning for Strike {
|
||||
|
||||
Ok(PaymentQuoteResponse {
|
||||
request_lookup_id: quote.payment_quote_id,
|
||||
amount: from_strike_amount(quote.amount, &melt_quote_request.unit)?,
|
||||
amount: from_strike_amount(quote.amount, &melt_quote_request.unit)?.into(),
|
||||
fee,
|
||||
})
|
||||
}
|
||||
@@ -149,8 +150,8 @@ impl MintLightning for Strike {
|
||||
async fn pay_invoice(
|
||||
&self,
|
||||
melt_quote: mint::MeltQuote,
|
||||
_partial_msats: Option<u64>,
|
||||
_max_fee_msats: Option<u64>,
|
||||
_partial_msats: Option<Amount>,
|
||||
_max_fee_msats: Option<Amount>,
|
||||
) -> Result<PayInvoiceResponse, Self::Err> {
|
||||
let pay_response = self
|
||||
.strike_api
|
||||
@@ -164,7 +165,7 @@ impl MintLightning for Strike {
|
||||
InvoiceState::Pending => MeltQuoteState::Pending,
|
||||
};
|
||||
|
||||
let total_spent_msats = from_strike_amount(pay_response.total_amount, &melt_quote.unit)?;
|
||||
let total_spent = from_strike_amount(pay_response.total_amount, &melt_quote.unit)?.into();
|
||||
|
||||
let bolt11: Bolt11Invoice = melt_quote.request.parse()?;
|
||||
|
||||
@@ -172,13 +173,14 @@ impl MintLightning for Strike {
|
||||
payment_hash: bolt11.payment_hash().to_string(),
|
||||
payment_preimage: None,
|
||||
status: state,
|
||||
total_spent_msats,
|
||||
total_spent,
|
||||
})
|
||||
}
|
||||
|
||||
async fn create_invoice(
|
||||
&self,
|
||||
amount: u64,
|
||||
amount: Amount,
|
||||
_unit: &CurrencyUnit,
|
||||
description: String,
|
||||
unix_expiry: u64,
|
||||
) -> Result<CreateInvoiceResponse, Self::Err> {
|
||||
|
||||
@@ -49,7 +49,8 @@ pub trait MintLightning {
|
||||
/// Create a new invoice
|
||||
async fn create_invoice(
|
||||
&self,
|
||||
amount: u64,
|
||||
amount: Amount,
|
||||
unit: &CurrencyUnit,
|
||||
description: String,
|
||||
unix_expiry: u64,
|
||||
) -> Result<CreateInvoiceResponse, Self::Err>;
|
||||
@@ -65,8 +66,8 @@ pub trait MintLightning {
|
||||
async fn pay_invoice(
|
||||
&self,
|
||||
melt_quote: mint::MeltQuote,
|
||||
partial_msats: Option<u64>,
|
||||
max_fee_msats: Option<u64>,
|
||||
partial_amount: Option<Amount>,
|
||||
max_fee_amount: Option<Amount>,
|
||||
) -> Result<PayInvoiceResponse, Self::Err>;
|
||||
|
||||
/// Listen for invoices to be paid to the mint
|
||||
@@ -102,8 +103,8 @@ pub struct PayInvoiceResponse {
|
||||
pub payment_preimage: Option<String>,
|
||||
/// Status
|
||||
pub status: MeltQuoteState,
|
||||
/// Totoal Amount Spent in msats
|
||||
pub total_spent_msats: u64,
|
||||
/// Totoal Amount Spent
|
||||
pub total_spent: Amount,
|
||||
}
|
||||
|
||||
/// Payment quote response
|
||||
@@ -112,7 +113,7 @@ pub struct PaymentQuoteResponse {
|
||||
/// Request look up id
|
||||
pub request_lookup_id: String,
|
||||
/// Amount
|
||||
pub amount: u64,
|
||||
pub amount: Amount,
|
||||
/// Fee required for melt
|
||||
pub fee: u64,
|
||||
}
|
||||
@@ -158,18 +159,18 @@ pub fn to_unit<T>(
|
||||
amount: T,
|
||||
current_unit: &CurrencyUnit,
|
||||
target_unit: &CurrencyUnit,
|
||||
) -> Result<u64, Error>
|
||||
) -> Result<Amount, Error>
|
||||
where
|
||||
T: Into<u64>,
|
||||
{
|
||||
let amount = amount.into();
|
||||
match (current_unit, target_unit) {
|
||||
(CurrencyUnit::Sat, CurrencyUnit::Sat) => Ok(amount),
|
||||
(CurrencyUnit::Msat, CurrencyUnit::Msat) => Ok(amount),
|
||||
(CurrencyUnit::Sat, CurrencyUnit::Msat) => Ok(amount * MSAT_IN_SAT),
|
||||
(CurrencyUnit::Msat, CurrencyUnit::Sat) => Ok(amount / MSAT_IN_SAT),
|
||||
(CurrencyUnit::Usd, CurrencyUnit::Usd) => Ok(amount),
|
||||
(CurrencyUnit::Eur, CurrencyUnit::Eur) => Ok(amount),
|
||||
(CurrencyUnit::Sat, CurrencyUnit::Sat) => Ok(amount.into()),
|
||||
(CurrencyUnit::Msat, CurrencyUnit::Msat) => Ok(amount.into()),
|
||||
(CurrencyUnit::Sat, CurrencyUnit::Msat) => Ok((amount * MSAT_IN_SAT).into()),
|
||||
(CurrencyUnit::Msat, CurrencyUnit::Sat) => Ok((amount / MSAT_IN_SAT).into()),
|
||||
(CurrencyUnit::Usd, CurrencyUnit::Usd) => Ok(amount.into()),
|
||||
(CurrencyUnit::Eur, CurrencyUnit::Eur) => Ok(amount.into()),
|
||||
_ => Err(Error::CannotConvertUnits),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user