Skip to content

Commit

Permalink
feat: use amount type in ln
Browse files Browse the repository at this point in the history
  • Loading branch information
thesimplekid committed Aug 13, 2024
1 parent 24647a0 commit db94be9
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 58 deletions.
49 changes: 24 additions & 25 deletions crates/cdk-axum/src/router_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -283,8 +283,8 @@ pub async fn post_melt_bolt11(
let quote_msats = to_unit(quote.amount, &quote.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);
Expand All @@ -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, &quote.unit)
.map_err(|_| into_response(Error::UnsupportedUnit))?,
)
}
false => None,
};

let max_fee = to_unit(quote.fee_reserve, &quote.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, &quote.unit)
.map_err(|_| into_response(Error::UnsupportedUnit))?,
};

let input_amount_msats =
to_unit(inputs_amount_quote_unit, &quote.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 {
Expand All @@ -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,
Expand All @@ -358,10 +357,10 @@ pub async fn post_melt_bolt11(
}
};

let amount_spent = to_unit(pre.total_spent_msats, &ln.get_settings().unit, &quote.unit)
let amount_spent = to_unit(pre.total_spent, &ln.get_settings().unit, &quote.unit)
.map_err(|_| into_response(Error::UnsupportedUnit))?;

(pre.payment_preimage, amount_spent.into())
(pre.payment_preimage, amount_spent)
}
};

Expand Down
41 changes: 33 additions & 8 deletions crates/cdk-cln/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();

Expand All @@ -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;

Expand Down Expand Up @@ -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)?;
Expand All @@ -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,
)?,
}
}
_ => {
Expand All @@ -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> {
Expand All @@ -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,
Expand Down
17 changes: 11 additions & 6 deletions crates/cdk-fake-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();

Expand All @@ -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> {
Expand All @@ -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))
Expand Down
14 changes: 8 additions & 6 deletions crates/cdk-strike/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -141,16 +142,16 @@ 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,
})
}

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
Expand All @@ -164,21 +165,22 @@ 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()?;

Ok(PayInvoiceResponse {
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> {
Expand Down
27 changes: 14 additions & 13 deletions crates/cdk/src/cdk_lightning/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand All @@ -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
Expand Down Expand Up @@ -100,8 +101,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
Expand All @@ -110,7 +111,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,
}
Expand Down Expand Up @@ -156,18 +157,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),
}
}

0 comments on commit db94be9

Please sign in to comment.