mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-20 22:24:54 +01:00
refactor: v1 MeltRequest
TODO: ffi bindings
This commit is contained in:
@@ -4,13 +4,12 @@ use async_trait::async_trait;
|
||||
#[cfg(feature = "nut09")]
|
||||
use cashu::nuts::MintInfo;
|
||||
use cashu::nuts::{
|
||||
BlindedMessage, CheckFeesRequest, CheckFeesResponse, Keys, MeltRequest, MeltResponse,
|
||||
MintRequest, PostMintResponse, PreMintSecrets, Proof, RequestMintResponse, SplitRequest,
|
||||
SplitResponse, *,
|
||||
BlindedMessage, Keys, MeltBolt11Request, MeltBolt11Response, MintRequest, PostMintResponse,
|
||||
PreMintSecrets, Proof, RequestMintResponse, SplitRequest, SplitResponse, *,
|
||||
};
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
|
||||
use cashu::{Amount, Bolt11Invoice};
|
||||
use cashu::Amount;
|
||||
use gloo::net::http::Request;
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
@@ -118,49 +117,20 @@ impl Client for HttpClient {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check Max expected fee [NUT-05]
|
||||
async fn post_check_fees(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
invoice: Bolt11Invoice,
|
||||
) -> Result<CheckFeesResponse, Error> {
|
||||
let url = join_url(mint_url, "checkfees")?;
|
||||
|
||||
let request = CheckFeesRequest { pr: invoice };
|
||||
|
||||
let res = Request::post(url.as_str())
|
||||
.json(&request)
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?
|
||||
.json::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<CheckFeesResponse, serde_json::Error> =
|
||||
serde_json::from_value(res.clone());
|
||||
|
||||
match response {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_) => Err(Error::from_json(&res.to_string())?),
|
||||
}
|
||||
}
|
||||
|
||||
/// Melt [NUT-05]
|
||||
/// [Nut-08] Lightning fee return if outputs defined
|
||||
async fn post_melt(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
proofs: Vec<Proof>,
|
||||
invoice: Bolt11Invoice,
|
||||
quote: String,
|
||||
inputs: Vec<Proof>,
|
||||
outputs: Option<Vec<BlindedMessage>>,
|
||||
) -> Result<MeltResponse, Error> {
|
||||
) -> Result<MeltBolt11Response, Error> {
|
||||
let url = join_url(mint_url, "melt")?;
|
||||
|
||||
let request = MeltRequest {
|
||||
proofs,
|
||||
pr: invoice,
|
||||
let request = MeltBolt11Request {
|
||||
quote,
|
||||
inputs,
|
||||
outputs,
|
||||
};
|
||||
|
||||
@@ -174,7 +144,7 @@ impl Client for HttpClient {
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<MeltResponse, serde_json::Error> =
|
||||
let response: Result<MeltBolt11Response, serde_json::Error> =
|
||||
serde_json::from_value(value.clone());
|
||||
|
||||
match response {
|
||||
|
||||
@@ -6,13 +6,12 @@ use async_trait::async_trait;
|
||||
#[cfg(feature = "nut09")]
|
||||
use cashu::nuts::MintInfo;
|
||||
use cashu::nuts::{
|
||||
BlindedMessage, CheckFeesRequest, CheckFeesResponse, Keys, MeltRequest, MeltResponse,
|
||||
MintRequest, PostMintResponse, PreMintSecrets, Proof, RequestMintResponse, SplitRequest,
|
||||
SplitResponse, *,
|
||||
BlindedMessage, Keys, MeltBolt11Request, MeltBolt11Response, MintRequest, PostMintResponse,
|
||||
PreMintSecrets, Proof, RequestMintResponse, SplitRequest, SplitResponse, *,
|
||||
};
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
|
||||
use cashu::{Amount, Bolt11Invoice};
|
||||
use cashu::Amount;
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
@@ -96,44 +95,20 @@ impl Client for HttpClient {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check Max expected fee [NUT-05]
|
||||
async fn post_check_fees(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
invoice: Bolt11Invoice,
|
||||
) -> Result<CheckFeesResponse, Error> {
|
||||
let url = join_url(mint_url, "checkfees")?;
|
||||
|
||||
let request = CheckFeesRequest { pr: invoice };
|
||||
|
||||
let res = minreq::post(url)
|
||||
.with_json(&request)?
|
||||
.send()?
|
||||
.json::<Value>()?;
|
||||
|
||||
let response: Result<CheckFeesResponse, serde_json::Error> =
|
||||
serde_json::from_value(res.clone());
|
||||
|
||||
match response {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_) => Err(Error::from_json(&res.to_string())?),
|
||||
}
|
||||
}
|
||||
|
||||
/// Melt [NUT-05]
|
||||
/// [Nut-08] Lightning fee return if outputs defined
|
||||
async fn post_melt(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
proofs: Vec<Proof>,
|
||||
invoice: Bolt11Invoice,
|
||||
quote: String,
|
||||
inputs: Vec<Proof>,
|
||||
outputs: Option<Vec<BlindedMessage>>,
|
||||
) -> Result<MeltResponse, Error> {
|
||||
) -> Result<MeltBolt11Response, Error> {
|
||||
let url = join_url(mint_url, "melt")?;
|
||||
|
||||
let request = MeltRequest {
|
||||
proofs,
|
||||
pr: invoice,
|
||||
let request = MeltBolt11Request {
|
||||
quote,
|
||||
inputs,
|
||||
outputs,
|
||||
};
|
||||
|
||||
@@ -142,7 +117,7 @@ impl Client for HttpClient {
|
||||
.send()?
|
||||
.json::<Value>()?;
|
||||
|
||||
let response: Result<MeltResponse, serde_json::Error> =
|
||||
let response: Result<MeltBolt11Response, serde_json::Error> =
|
||||
serde_json::from_value(value.clone());
|
||||
|
||||
match response {
|
||||
|
||||
@@ -8,8 +8,8 @@ use cashu::nuts::CheckSpendableResponse;
|
||||
#[cfg(feature = "nut09")]
|
||||
use cashu::nuts::MintInfo;
|
||||
use cashu::nuts::{
|
||||
BlindedMessage, CheckFeesResponse, Keys, KeysetResponse, MeltResponse, PostMintResponse,
|
||||
PreMintSecrets, Proof, RequestMintResponse, SplitRequest, SplitResponse,
|
||||
BlindedMessage, Keys, KeysetResponse, MeltBolt11Response, PostMintResponse, PreMintSecrets,
|
||||
Proof, RequestMintResponse, SplitRequest, SplitResponse,
|
||||
};
|
||||
use cashu::{utils, Amount};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -103,19 +103,13 @@ pub trait Client {
|
||||
hash: &str,
|
||||
) -> Result<PostMintResponse, Error>;
|
||||
|
||||
async fn post_check_fees(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
invoice: Bolt11Invoice,
|
||||
) -> Result<CheckFeesResponse, Error>;
|
||||
|
||||
async fn post_melt(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
proofs: Vec<Proof>,
|
||||
invoice: Bolt11Invoice,
|
||||
quote: String,
|
||||
inputs: Vec<Proof>,
|
||||
outputs: Option<Vec<BlindedMessage>>,
|
||||
) -> Result<MeltResponse, Error>;
|
||||
) -> Result<MeltBolt11Response, Error>;
|
||||
|
||||
// REVIEW: Should be consistent aboue passing in the Request struct or the
|
||||
// compnatants and making it within the function. Here the struct is passed
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use cashu::dhke::{sign_message, verify_message};
|
||||
pub use cashu::error::mint::Error;
|
||||
use cashu::nuts::{
|
||||
BlindedMessage, BlindedSignature, MeltRequest, MeltResponse, Proof, SplitRequest,
|
||||
BlindedMessage, BlindedSignature, MeltBolt11Request, MeltBolt11Response, Proof, SplitRequest,
|
||||
SplitResponse, *,
|
||||
};
|
||||
#[cfg(feature = "nut07")]
|
||||
@@ -13,6 +13,8 @@ use cashu::Amount;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::types::Quote;
|
||||
|
||||
pub struct Mint {
|
||||
// pub pubkey: PublicKey
|
||||
secret: String,
|
||||
@@ -21,6 +23,7 @@ pub struct Mint {
|
||||
pub spent_secrets: HashSet<Secret>,
|
||||
pub pending_secrets: HashSet<Secret>,
|
||||
pub fee_reserve: FeeReserve,
|
||||
pub quotes: HashMap<String, Quote>,
|
||||
}
|
||||
|
||||
impl Mint {
|
||||
@@ -28,6 +31,7 @@ impl Mint {
|
||||
secret: &str,
|
||||
keysets_info: HashSet<MintKeySetInfo>,
|
||||
spent_secrets: HashSet<Secret>,
|
||||
quotes: Vec<Quote>,
|
||||
min_fee_reserve: Amount,
|
||||
percent_fee_reserve: f32,
|
||||
) -> Self {
|
||||
@@ -36,6 +40,8 @@ impl Mint {
|
||||
|
||||
let mut active_units: HashSet<String> = HashSet::default();
|
||||
|
||||
let quotes = quotes.into_iter().map(|q| (q.id.clone(), q)).collect();
|
||||
|
||||
// Check that there is only one active keyset per unit
|
||||
for keyset_info in keysets_info {
|
||||
if keyset_info.active && !active_units.insert(keyset_info.unit.clone()) {
|
||||
@@ -58,6 +64,7 @@ impl Mint {
|
||||
Self {
|
||||
secret: secret.to_string(),
|
||||
keysets,
|
||||
quotes,
|
||||
keysets_info: info,
|
||||
spent_secrets,
|
||||
pending_secrets: HashSet::new(),
|
||||
@@ -222,41 +229,28 @@ impl Mint {
|
||||
Ok(CheckSpendableResponse { spendable, pending })
|
||||
}
|
||||
|
||||
pub fn verify_melt_request(&mut self, melt_request: &MeltRequest) -> Result<(), Error> {
|
||||
let proofs_total = melt_request.proofs_amount();
|
||||
pub fn verify_melt_request(&mut self, melt_request: &MeltBolt11Request) -> Result<(), Error> {
|
||||
let quote = self.quotes.get(&melt_request.quote).unwrap();
|
||||
let proofs_total = melt_request.proofs_amount().to_sat();
|
||||
|
||||
let percent_fee_reserve = Amount::from_sat(
|
||||
(proofs_total.to_sat() as f32 * self.fee_reserve.percent_fee_reserve) as u64,
|
||||
);
|
||||
|
||||
let fee_reserve = if percent_fee_reserve > self.fee_reserve.min_fee_reserve {
|
||||
percent_fee_reserve
|
||||
} else {
|
||||
self.fee_reserve.min_fee_reserve
|
||||
};
|
||||
|
||||
let required_total = melt_request
|
||||
.invoice_amount()
|
||||
.map_err(|_| Error::InvoiceAmountUndefined)?
|
||||
+ fee_reserve;
|
||||
let required_total = quote.amount + quote.fee_reserve;
|
||||
|
||||
if proofs_total < required_total {
|
||||
debug!(
|
||||
"Insufficient Proofs: Got: {}, Required: {}",
|
||||
proofs_total.to_sat().to_string(),
|
||||
required_total.to_sat().to_string()
|
||||
proofs_total, required_total
|
||||
);
|
||||
return Err(Error::Amount);
|
||||
}
|
||||
|
||||
let secrets: HashSet<&Secret> = melt_request.proofs.iter().map(|p| &p.secret).collect();
|
||||
let secrets: HashSet<&Secret> = melt_request.inputs.iter().map(|p| &p.secret).collect();
|
||||
|
||||
// Ensure proofs are unique and not being double spent
|
||||
if melt_request.proofs.len().ne(&secrets.len()) {
|
||||
if melt_request.inputs.len().ne(&secrets.len()) {
|
||||
return Err(Error::DuplicateProofs);
|
||||
}
|
||||
|
||||
for proof in &melt_request.proofs {
|
||||
for proof in &melt_request.inputs {
|
||||
self.verify_proof(proof)?
|
||||
}
|
||||
|
||||
@@ -265,13 +259,13 @@ impl Mint {
|
||||
|
||||
pub fn process_melt_request(
|
||||
&mut self,
|
||||
melt_request: &MeltRequest,
|
||||
melt_request: &MeltBolt11Request,
|
||||
preimage: &str,
|
||||
total_spent: Amount,
|
||||
) -> Result<MeltResponse, Error> {
|
||||
) -> Result<MeltBolt11Response, Error> {
|
||||
self.verify_melt_request(melt_request)?;
|
||||
|
||||
let secrets = Vec::with_capacity(melt_request.proofs.len());
|
||||
let secrets = Vec::with_capacity(melt_request.inputs.len());
|
||||
for secret in secrets {
|
||||
self.spent_secrets.insert(secret);
|
||||
}
|
||||
@@ -312,9 +306,9 @@ impl Mint {
|
||||
);
|
||||
}
|
||||
|
||||
Ok(MeltResponse {
|
||||
Ok(MeltBolt11Response {
|
||||
paid: true,
|
||||
preimage: Some(preimage.to_string()),
|
||||
proof: preimage.to_string(),
|
||||
change,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ use cashu::dhke::{construct_proofs, unblind_message};
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::nuts::nut00::mint;
|
||||
use cashu::nuts::{
|
||||
BlindedSignature, Keys, PreMintSecrets, PreSplit, Proof, Proofs, RequestMintResponse,
|
||||
SplitRequest, Token,
|
||||
BlindedSignature, CurrencyUnit, Keys, PreMintSecrets, PreSplit, Proof, Proofs,
|
||||
RequestMintResponse, SplitRequest, Token,
|
||||
};
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::types::ProofsStatus;
|
||||
@@ -95,12 +95,12 @@ impl<C: Client> Wallet<C> {
|
||||
&self,
|
||||
amount: Amount,
|
||||
hash: &str,
|
||||
unit: Option<String>,
|
||||
memo: Option<String>,
|
||||
unit: Option<CurrencyUnit>,
|
||||
) -> Result<Token, Error> {
|
||||
let proofs = self.mint(amount, hash).await?;
|
||||
|
||||
let token = Token::new(self.mint_url.clone(), proofs, unit, memo);
|
||||
let token = Token::new(self.mint_url.clone(), proofs, memo, unit);
|
||||
Ok(token?)
|
||||
}
|
||||
|
||||
@@ -127,15 +127,6 @@ impl<C: Client> Wallet<C> {
|
||||
Ok(proofs)
|
||||
}
|
||||
|
||||
/// Check fee
|
||||
pub async fn check_fee(&self, invoice: Bolt11Invoice) -> Result<Amount, Error> {
|
||||
Ok(self
|
||||
.client
|
||||
.post_check_fees(self.mint_url.clone().try_into()?, invoice)
|
||||
.await?
|
||||
.fee)
|
||||
}
|
||||
|
||||
/// Receive
|
||||
pub async fn receive(&self, encoded_token: &str) -> Result<Proofs, Error> {
|
||||
let token_data = Token::from_str(encoded_token)?;
|
||||
@@ -300,7 +291,7 @@ impl<C: Client> Wallet<C> {
|
||||
|
||||
pub async fn melt(
|
||||
&self,
|
||||
invoice: Bolt11Invoice,
|
||||
quote: String,
|
||||
proofs: Proofs,
|
||||
fee_reserve: Amount,
|
||||
) -> Result<Melted, Error> {
|
||||
@@ -309,8 +300,8 @@ impl<C: Client> Wallet<C> {
|
||||
.client
|
||||
.post_melt(
|
||||
self.mint_url.clone().try_into()?,
|
||||
quote,
|
||||
proofs,
|
||||
invoice,
|
||||
Some(blinded.blinded_messages()),
|
||||
)
|
||||
.await?;
|
||||
@@ -327,7 +318,7 @@ impl<C: Client> Wallet<C> {
|
||||
|
||||
let melted = Melted {
|
||||
paid: true,
|
||||
preimage: melt_response.preimage,
|
||||
preimage: Some(melt_response.proof),
|
||||
change: change_proofs,
|
||||
};
|
||||
|
||||
@@ -337,10 +328,10 @@ impl<C: Client> Wallet<C> {
|
||||
pub fn proofs_to_token(
|
||||
&self,
|
||||
proofs: Proofs,
|
||||
unit: Option<String>,
|
||||
memo: Option<String>,
|
||||
unit: Option<CurrencyUnit>,
|
||||
) -> Result<String, Error> {
|
||||
Ok(Token::new(self.mint_url.clone(), proofs, unit, memo)?.to_string())
|
||||
Ok(Token::new(self.mint_url.clone(), proofs, memo, unit)?.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ pub mod nut09;
|
||||
|
||||
#[cfg(feature = "wallet")]
|
||||
pub use nut00::wallet::{PreMint, PreMintSecrets, Token};
|
||||
pub use nut00::{BlindedMessage, BlindedSignature, Proof};
|
||||
pub use nut00::{BlindedMessage, BlindedSignature, CurrencyUnit, Proof};
|
||||
pub use nut01::{Keys, KeysResponse, PublicKey, SecretKey};
|
||||
pub use nut02::mint::KeySet as MintKeySet;
|
||||
pub use nut02::{Id, KeySet, KeySetInfo, KeysetResponse};
|
||||
@@ -21,14 +21,14 @@ pub use nut02::{Id, KeySet, KeySetInfo, KeysetResponse};
|
||||
pub use nut03::PreSplit;
|
||||
pub use nut03::{RequestMintResponse, SplitRequest, SplitResponse};
|
||||
pub use nut04::{MintRequest, PostMintResponse};
|
||||
pub use nut05::{CheckFeesRequest, CheckFeesResponse};
|
||||
#[cfg(not(feature = "nut08"))]
|
||||
pub use nut05::{MeltRequest, MeltResponse};
|
||||
pub use nut05::{MeltBolt11Request, MeltBolt11Response};
|
||||
pub use nut05::{MeltQuoteBolt11Request, MeltQuoteBolt11Response};
|
||||
#[cfg(feature = "wallet")]
|
||||
#[cfg(feature = "nut07")]
|
||||
pub use nut07::{CheckSpendableRequest, CheckSpendableResponse};
|
||||
#[cfg(feature = "nut08")]
|
||||
pub use nut08::{MeltRequest, MeltResponse};
|
||||
pub use nut08::{MeltBolt11Request, MeltBolt11Response};
|
||||
#[cfg(feature = "nut09")]
|
||||
pub use nut09::MintInfo;
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
//! Notation and Models
|
||||
// https://github.com/cashubtc/nuts/blob/main/00.md
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Id, Proofs, PublicKey};
|
||||
use crate::error::Error;
|
||||
use crate::secret::Secret;
|
||||
use crate::url::UncheckedUrl;
|
||||
use crate::Amount;
|
||||
@@ -20,6 +24,33 @@ pub struct BlindedMessage {
|
||||
pub keyset_id: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum CurrencyUnit {
|
||||
#[default]
|
||||
Sat,
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl FromStr for CurrencyUnit {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"sat" => Ok(Self::Sat),
|
||||
_ => Ok(Self::Custom(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CurrencyUnit {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
CurrencyUnit::Sat => write!(f, "sat"),
|
||||
CurrencyUnit::Custom(unit) => write!(f, "{}", unit),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wallet")]
|
||||
pub mod wallet {
|
||||
use std::cmp::Ordering;
|
||||
@@ -31,7 +62,7 @@ pub mod wallet {
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use super::MintProofs;
|
||||
use super::{CurrencyUnit, MintProofs};
|
||||
use crate::dhke::blind_message;
|
||||
use crate::error::wallet;
|
||||
use crate::nuts::{BlindedMessage, Id, Proofs, SecretKey};
|
||||
@@ -201,8 +232,9 @@ pub mod wallet {
|
||||
/// Memo for token
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub memo: Option<String>,
|
||||
/// Token Unit
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unit: Option<String>,
|
||||
pub unit: Option<CurrencyUnit>,
|
||||
}
|
||||
|
||||
impl Token {
|
||||
@@ -210,7 +242,7 @@ pub mod wallet {
|
||||
mint_url: UncheckedUrl,
|
||||
proofs: Proofs,
|
||||
memo: Option<String>,
|
||||
unit: Option<String>,
|
||||
unit: Option<CurrencyUnit>,
|
||||
) -> Result<Self, wallet::Error> {
|
||||
if proofs.is_empty() {
|
||||
return Err(wallet::Error::ProofsRequired);
|
||||
|
||||
@@ -3,48 +3,54 @@
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
use super::CurrencyUnit;
|
||||
use crate::nuts::Proofs;
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
|
||||
/// Check Fees Response [NUT-05]
|
||||
/// Melt quote request [NUT-05]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CheckFeesResponse {
|
||||
/// Expected Mac Fee in satoshis
|
||||
pub fee: Amount,
|
||||
pub struct MeltQuoteBolt11Request {
|
||||
/// Bolt11 invoice to be paid
|
||||
pub request: Bolt11Invoice,
|
||||
/// Unit wallet would like to pay with
|
||||
pub unit: CurrencyUnit,
|
||||
}
|
||||
|
||||
/// Check Fees request [NUT-05]
|
||||
/// Melt quote response [NUT-05]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CheckFeesRequest {
|
||||
/// Lighting Invoice
|
||||
pub pr: Bolt11Invoice,
|
||||
pub struct MeltQuoteBolt11Response {
|
||||
/// Quote Id
|
||||
pub quote: String,
|
||||
/// The amount that needs to be provided
|
||||
pub amount: u64,
|
||||
/// The fee reserve that is required
|
||||
pub fee_reserve: u64,
|
||||
/// Whether the the request haas be paid
|
||||
pub paid: bool,
|
||||
/// Unix timestamp until the quote is valid
|
||||
pub expiry: u64,
|
||||
}
|
||||
|
||||
/// Melt Request [NUT-05]
|
||||
/// Melt Bolt11 Request [NUT-05]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MeltRequest {
|
||||
pub proofs: Proofs,
|
||||
/// bollt11
|
||||
pub pr: Bolt11Invoice,
|
||||
pub struct MeltBolt11Request {
|
||||
/// Quote ID
|
||||
pub quote: String,
|
||||
/// Proofs
|
||||
pub inputs: Proofs,
|
||||
}
|
||||
|
||||
impl MeltRequest {
|
||||
impl MeltBolt11Request {
|
||||
pub fn proofs_amount(&self) -> Amount {
|
||||
self.proofs.iter().map(|proof| proof.amount).sum()
|
||||
}
|
||||
|
||||
pub fn invoice_amount(&self) -> Result<Amount, Error> {
|
||||
match self.pr.amount_milli_satoshis() {
|
||||
Some(value) => Ok(Amount::from_sat(value)),
|
||||
None => Err(Error::InvoiceAmountUndefined),
|
||||
}
|
||||
self.inputs.iter().map(|proof| proof.amount).sum()
|
||||
}
|
||||
}
|
||||
|
||||
/// Melt Response [NUT-05]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MeltResponse {
|
||||
pub struct MeltBolt11Response {
|
||||
/// Indicate if payment was successful
|
||||
pub paid: bool,
|
||||
pub preimage: Option<String>,
|
||||
/// Bolt11 preimage
|
||||
pub payment_preimage: String,
|
||||
}
|
||||
|
||||
@@ -1,51 +1,49 @@
|
||||
//! Lightning fee return
|
||||
// https://github.com/cashubtc/nuts/blob/main/08.md
|
||||
|
||||
use lightning_invoice::Bolt11Invoice;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{BlindedMessage, BlindedSignature, Proofs};
|
||||
use crate::error::Error;
|
||||
use crate::Amount;
|
||||
|
||||
/// Melt Request [NUT-08]
|
||||
/// Melt Bolt11 Request [NUT-08]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MeltRequest {
|
||||
pub proofs: Proofs,
|
||||
/// bollt11
|
||||
pub pr: Bolt11Invoice,
|
||||
pub struct MeltBolt11Request {
|
||||
/// Quote ID
|
||||
pub quote: String,
|
||||
/// Proofs
|
||||
pub inputs: Proofs,
|
||||
/// Blinded Message that can be used to return change [NUT-08]
|
||||
/// Amount field of blindedMessages `SHOULD` be set to zero
|
||||
pub outputs: Option<Vec<BlindedMessage>>,
|
||||
}
|
||||
|
||||
impl MeltRequest {
|
||||
impl MeltBolt11Request {
|
||||
pub fn proofs_amount(&self) -> Amount {
|
||||
self.proofs.iter().map(|proof| proof.amount).sum()
|
||||
self.inputs.iter().map(|proof| proof.amount).sum()
|
||||
}
|
||||
|
||||
pub fn invoice_amount(&self) -> Result<Amount, Error> {
|
||||
match self.pr.amount_milli_satoshis() {
|
||||
Some(value) => Ok(Amount::from_msat(value)),
|
||||
None => Err(Error::InvoiceAmountUndefined),
|
||||
}
|
||||
pub fn output_amount(&self) -> Option<Amount> {
|
||||
self.outputs
|
||||
.as_ref()
|
||||
.map(|o| o.iter().map(|proof| proof.amount).sum())
|
||||
}
|
||||
}
|
||||
|
||||
/// Melt Response [NUT-08]
|
||||
/// Lightning fee return [NUT-08] if change is defined
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MeltResponse {
|
||||
pub struct MeltBolt11Response {
|
||||
pub paid: bool,
|
||||
pub preimage: Option<String>,
|
||||
// REVIEW: https://github.com/cashubtc/nuts/pull/55#discussion_r1419991818
|
||||
pub proof: String,
|
||||
pub change: Option<Vec<BlindedSignature>>,
|
||||
}
|
||||
|
||||
impl MeltResponse {
|
||||
pub fn change_amount(&self) -> Amount {
|
||||
match &self.change {
|
||||
Some(change) => change.iter().map(|c| c.amount).sum(),
|
||||
None => Amount::ZERO,
|
||||
}
|
||||
impl MeltBolt11Response {
|
||||
pub fn change_amount(&self) -> Option<Amount> {
|
||||
self.change
|
||||
.as_ref()
|
||||
.map(|c| c.iter().map(|b| b.amount).sum())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::nuts::{Id, KeySetInfo, Proofs};
|
||||
use crate::nuts::{CurrencyUnit, Proofs};
|
||||
use crate::Bolt11Invoice;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ProofsStatus {
|
||||
@@ -32,3 +33,15 @@ pub enum InvoiceStatus {
|
||||
Expired,
|
||||
InFlight,
|
||||
}
|
||||
|
||||
/// Quote
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct Quote {
|
||||
pub id: String,
|
||||
pub amount: u64,
|
||||
pub request: Bolt11Invoice,
|
||||
pub unit: CurrencyUnit,
|
||||
pub fee_reserve: u64,
|
||||
pub paid: bool,
|
||||
pub expiry: u64,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user