mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-05 05:06:14 +01:00
refactor: melt quote and melt to v1 in wallet sdk
This commit is contained in:
@@ -31,8 +31,12 @@ interface Secret {
|
||||
sequence<u8> as_bytes();
|
||||
};
|
||||
|
||||
interface MintQuoteInfo {
|
||||
constructor(string id, Amount amount, string unit, Bolt11Invoice? request, boolean paid, u64 boolean);
|
||||
interface MintQuote {
|
||||
constructor(string id, Amount amount, string unit, Bolt11Invoice request, boolean paid, u64 boolean);
|
||||
};
|
||||
|
||||
interface MeltQuote {
|
||||
constructor(string id, Amount amount, string unit, Bolt11Invoice request, Amount fee_reserve, boolean paid, u64 boolean);
|
||||
};
|
||||
|
||||
// NUT00
|
||||
|
||||
@@ -29,7 +29,7 @@ mod ffi {
|
||||
pub use crate::nuts::nut06::{MintInfo, MintVersion};
|
||||
pub use crate::nuts::nut07::{CheckSpendableRequest, CheckSpendableResponse};
|
||||
pub use crate::nuts::nut08::{MeltBolt11Request, MeltBolt11Response};
|
||||
pub use crate::types::{Amount, Bolt11Invoice, KeySetInfo, MintQuoteInfo, Secret};
|
||||
pub use crate::types::{Amount, Bolt11Invoice, KeySetInfo, MeltQuote, MintQuote, Secret};
|
||||
|
||||
// UDL
|
||||
uniffi::include_scaffolding!("cashu");
|
||||
|
||||
49
bindings/cashu-ffi/src/types/melt_quote.rs
Normal file
49
bindings/cashu-ffi/src/types/melt_quote.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cashu::nuts::CurrencyUnit;
|
||||
use cashu::types::MeltQuote as MeltQuoteSdk;
|
||||
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
|
||||
pub struct MeltQuote {
|
||||
inner: MeltQuoteSdk,
|
||||
}
|
||||
|
||||
impl Deref for MeltQuote {
|
||||
type Target = MeltQuoteSdk;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MeltQuoteSdk> for MeltQuote {
|
||||
fn from(inner: MeltQuoteSdk) -> MeltQuote {
|
||||
MeltQuote { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl MeltQuote {
|
||||
pub fn new(
|
||||
id: String,
|
||||
amount: Arc<Amount>,
|
||||
unit: String,
|
||||
request: Arc<Bolt11Invoice>,
|
||||
fee_reserve: Arc<Amount>,
|
||||
paid: bool,
|
||||
expiry: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: MeltQuoteSdk {
|
||||
id,
|
||||
amount: amount.as_ref().deref().clone(),
|
||||
unit: CurrencyUnit::from_str(&unit).unwrap(),
|
||||
request: request.as_ref().deref().clone(),
|
||||
fee_reserve: fee_reserve.as_ref().deref().clone(),
|
||||
paid,
|
||||
expiry,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
47
bindings/cashu-ffi/src/types/mint_quote.rs
Normal file
47
bindings/cashu-ffi/src/types/mint_quote.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cashu::nuts::CurrencyUnit;
|
||||
use cashu::types::MintQuote as MintQuoteSdk;
|
||||
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
|
||||
pub struct MintQuote {
|
||||
inner: MintQuoteSdk,
|
||||
}
|
||||
|
||||
impl Deref for MintQuote {
|
||||
type Target = MintQuoteSdk;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MintQuoteSdk> for MintQuote {
|
||||
fn from(inner: MintQuoteSdk) -> MintQuote {
|
||||
MintQuote { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl MintQuote {
|
||||
pub fn new(
|
||||
id: String,
|
||||
amount: Arc<Amount>,
|
||||
unit: String,
|
||||
request: Arc<Bolt11Invoice>,
|
||||
paid: bool,
|
||||
expiry: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: MintQuoteSdk {
|
||||
id,
|
||||
amount: amount.as_ref().deref().clone(),
|
||||
unit: CurrencyUnit::from_str(&unit).unwrap(),
|
||||
request: request.as_ref().deref().clone(),
|
||||
paid,
|
||||
expiry,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,42 +3,42 @@ use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cashu::nuts::CurrencyUnit;
|
||||
use cashu::types::MintQuoteInfo as MintQuoteInfoSdk;
|
||||
use cashu::types::MintQuote as MintQuoteSdk;
|
||||
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
|
||||
pub struct MintQuoteInfo {
|
||||
inner: MintQuoteInfoSdk,
|
||||
pub struct MintQuote {
|
||||
inner: MintQuoteSdk,
|
||||
}
|
||||
|
||||
impl Deref for MintQuoteInfo {
|
||||
type Target = MintQuoteInfoSdk;
|
||||
impl Deref for MintQuote {
|
||||
type Target = MintQuoteSdk;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MintQuoteInfoSdk> for MintQuoteInfo {
|
||||
fn from(inner: MintQuoteInfoSdk) -> MintQuoteInfo {
|
||||
MintQuoteInfo { inner }
|
||||
impl From<MintQuoteSdk> for MintQuote {
|
||||
fn from(inner: MintQuoteSdk) -> MintQuote {
|
||||
MintQuote { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl MintQuoteInfo {
|
||||
impl MintQuote {
|
||||
pub fn new(
|
||||
id: String,
|
||||
amount: Arc<Amount>,
|
||||
unit: String,
|
||||
request: Option<Arc<Bolt11Invoice>>,
|
||||
request: Arc<Bolt11Invoice>,
|
||||
paid: bool,
|
||||
expiry: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: MintQuoteInfoSdk {
|
||||
inner: MintQuoteSdk {
|
||||
id,
|
||||
amount: amount.as_ref().deref().clone(),
|
||||
unit: CurrencyUnit::from_str(&unit).unwrap(),
|
||||
request: request.map(|r| r.as_ref().deref().clone()),
|
||||
request: request.as_ref().deref().clone(),
|
||||
paid,
|
||||
expiry,
|
||||
},
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
pub mod amount;
|
||||
pub mod bolt11_invoice;
|
||||
pub mod keyset_info;
|
||||
pub mod mint_quote_info;
|
||||
pub mod melt_quote;
|
||||
pub mod mint_quote;
|
||||
pub mod secret;
|
||||
|
||||
pub use amount::Amount;
|
||||
pub use bolt11_invoice::Bolt11Invoice;
|
||||
pub use keyset_info::KeySetInfo;
|
||||
pub use mint_quote_info::MintQuoteInfo;
|
||||
pub use melt_quote::MeltQuote;
|
||||
pub use mint_quote::MintQuote;
|
||||
pub use secret::Secret;
|
||||
|
||||
@@ -34,8 +34,13 @@ interface Secret {
|
||||
sequence<u8> as_bytes();
|
||||
};
|
||||
|
||||
interface MintQuoteInfo {
|
||||
constructor(string id, Amount amount, string unit, Bolt11Invoice? request, boolean paid, u64 boolean);
|
||||
interface MintQuote {
|
||||
constructor(string id, Amount amount, string unit, Bolt11Invoice request, boolean paid, u64 boolean);
|
||||
};
|
||||
|
||||
|
||||
interface MeltQuote {
|
||||
constructor(string id, Amount amount, string unit, Bolt11Invoice request, Amount fee_reserve, boolean paid, u64 boolean);
|
||||
};
|
||||
|
||||
// NUT00
|
||||
@@ -299,6 +304,7 @@ interface Melted {
|
||||
};
|
||||
|
||||
interface Wallet {
|
||||
constructor(string mint_url, Keys mint_keys, sequence<MintQuote> mint_quotes, sequence<MeltQuote> melt_quotes);
|
||||
// [Throws=CashuSdkError]
|
||||
// ProofsStatus check_proofs_spent(sequence<Proof> proofs);
|
||||
[Throws=CashuSdkError]
|
||||
@@ -312,7 +318,7 @@ interface Wallet {
|
||||
[Throws=CashuSdkError]
|
||||
SendProofs send(Amount amount, sequence<Proof> proofs);
|
||||
[Throws=CashuSdkError]
|
||||
Melted melt(string quote, sequence<Proof> proofs, Amount fee_reserve);
|
||||
Melted melt(string quote_id, sequence<Proof> proofs);
|
||||
[Throws=CashuSdkError]
|
||||
string proofs_to_token(sequence<Proof> proof, CurrencyUnit? unit, string? memo);
|
||||
};
|
||||
|
||||
@@ -7,12 +7,11 @@ mod ffi {
|
||||
pub use cashu_ffi::{
|
||||
Amount, BlindedMessage, BlindedSignature, Bolt11Invoice, CashuError, CheckSpendableRequest,
|
||||
CheckSpendableResponse, CurrencyUnit, Id, InvoiceStatus, KeyPair, KeySet, KeySetInfo,
|
||||
KeySetResponse, Keys, KeysResponse, MeltBolt11Request, MeltBolt11Response,
|
||||
KeySetResponse, Keys, KeysResponse, MeltBolt11Request, MeltBolt11Response, MeltQuote,
|
||||
MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request, MintBolt11Response,
|
||||
MintInfo, MintKeySet, MintProof, MintProofs, MintQuoteBolt11Request,
|
||||
MintQuoteBolt11Response, MintQuoteInfo, MintVersion, Nut05MeltBolt11Request,
|
||||
Nut05MeltBolt11Response, PreMintSecrets, Proof, PublicKey, Secret, SecretKey, SwapRequest,
|
||||
SwapResponse, Token,
|
||||
MintInfo, MintKeySet, MintProof, MintProofs, MintQuote, MintQuoteBolt11Request,
|
||||
MintQuoteBolt11Response, MintVersion, Nut05MeltBolt11Request, Nut05MeltBolt11Response,
|
||||
PreMintSecrets, Proof, PublicKey, Secret, SecretKey, SwapRequest, SwapResponse, Token,
|
||||
};
|
||||
|
||||
pub use crate::error::CashuSdkError;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use cashu_ffi::{BlindedSignature, CurrencyUnit, MintQuoteInfo, PreMintSecrets, Proof, Token};
|
||||
use cashu_ffi::{
|
||||
BlindedSignature, CurrencyUnit, MeltQuote, MintQuote, PreMintSecrets, Proof, Token,
|
||||
};
|
||||
use cashu_sdk::client::minreq_client::HttpClient;
|
||||
use cashu_sdk::types::ProofsStatus;
|
||||
use cashu_sdk::url::UncheckedUrl;
|
||||
@@ -20,13 +22,22 @@ pub struct Wallet {
|
||||
}
|
||||
|
||||
impl Wallet {
|
||||
pub fn new(mint_url: &str, mint_keys: Arc<Keys>, quotes: Vec<Arc<MintQuoteInfo>>) -> Self {
|
||||
pub fn new(
|
||||
mint_url: String,
|
||||
mint_keys: Arc<Keys>,
|
||||
mint_quotes: Vec<Arc<MintQuote>>,
|
||||
melt_quotes: Vec<Arc<MeltQuote>>,
|
||||
) -> Self {
|
||||
let client = HttpClient {};
|
||||
Self {
|
||||
inner: WalletSdk::new(
|
||||
client,
|
||||
UncheckedUrl::new(mint_url),
|
||||
quotes
|
||||
mint_quotes
|
||||
.into_iter()
|
||||
.map(|q| q.as_ref().deref().clone())
|
||||
.collect(),
|
||||
melt_quotes
|
||||
.into_iter()
|
||||
.map(|q| q.as_ref().deref().clone())
|
||||
.collect(),
|
||||
@@ -111,20 +122,14 @@ impl Wallet {
|
||||
Ok(Arc::new(send_proofs.into()))
|
||||
}
|
||||
|
||||
pub fn melt(
|
||||
&self,
|
||||
quote: String,
|
||||
proofs: Vec<Arc<Proof>>,
|
||||
fee_reserve: Arc<Amount>,
|
||||
) -> Result<Arc<Melted>> {
|
||||
pub fn melt(&self, quote_id: String, proofs: Vec<Arc<Proof>>) -> Result<Arc<Melted>> {
|
||||
let melted = RUNTIME.block_on(async {
|
||||
self.inner
|
||||
.write()
|
||||
.unwrap()
|
||||
.melt(
|
||||
quote,
|
||||
"e_id,
|
||||
proofs.iter().map(|p| p.as_ref().deref().clone()).collect(),
|
||||
*fee_reserve.as_ref().deref(),
|
||||
)
|
||||
.await
|
||||
})?;
|
||||
|
||||
@@ -40,7 +40,13 @@ impl JsWallet {
|
||||
let client = HttpClient {};
|
||||
|
||||
JsWallet {
|
||||
inner: Wallet::new(client, mint_url.into(), vec![], mint_keys.deref().clone()),
|
||||
inner: Wallet::new(
|
||||
client,
|
||||
mint_url.into(),
|
||||
vec![],
|
||||
vec![],
|
||||
mint_keys.deref().clone(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,17 +129,12 @@ impl JsWallet {
|
||||
|
||||
/// Melt
|
||||
#[wasm_bindgen(js_name = melt)]
|
||||
pub async fn melt(
|
||||
&self,
|
||||
quote: String,
|
||||
proofs: JsValue,
|
||||
fee_reserve: JsAmount,
|
||||
) -> Result<JsMelted> {
|
||||
pub async fn melt(&self, quote: String, proofs: JsValue) -> Result<JsMelted> {
|
||||
let proofs = serde_wasm_bindgen::from_value(proofs).map_err(into_err)?;
|
||||
|
||||
Ok(self
|
||||
.inner
|
||||
.melt(quote, proofs, *fee_reserve.deref())
|
||||
.melt("e, proofs)
|
||||
.await
|
||||
.map_err(into_err)?
|
||||
.into())
|
||||
|
||||
@@ -7,7 +7,7 @@ use cashu::nuts::{
|
||||
};
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
|
||||
use cashu::Amount;
|
||||
use cashu::{Amount, Bolt11Invoice};
|
||||
use gloo::net::http::Request;
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
@@ -118,6 +118,34 @@ impl Client for HttpClient {
|
||||
}
|
||||
|
||||
/// Melt [NUT-05]
|
||||
async fn post_melt_quote(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
unit: CurrencyUnit,
|
||||
request: Bolt11Invoice,
|
||||
) -> Result<MeltQuoteBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "melt", "quote", "bolt11"])?;
|
||||
|
||||
let request = MeltQuoteBolt11Request { unit, request };
|
||||
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<MeltQuoteBolt11Response, serde_json::Error> =
|
||||
serde_json::from_value(res.clone());
|
||||
|
||||
match response {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_) => Err(Error::from_json(&res.to_string())?),
|
||||
}
|
||||
}
|
||||
|
||||
/// [Nut-08] Lightning fee return if outputs defined
|
||||
async fn post_melt(
|
||||
&self,
|
||||
|
||||
@@ -5,12 +5,13 @@ use std::println;
|
||||
use async_trait::async_trait;
|
||||
use cashu::nuts::{
|
||||
nut00, BlindedMessage, CurrencyUnit, Keys, KeysResponse, KeysetResponse, MeltBolt11Request,
|
||||
MeltBolt11Response, MintBolt11Request, MintBolt11Response, MintInfo, MintQuoteBolt11Request,
|
||||
MintQuoteBolt11Response, PreMintSecrets, Proof, SwapRequest, SwapResponse,
|
||||
MeltBolt11Response, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
|
||||
MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, PreMintSecrets,
|
||||
Proof, SwapRequest, SwapResponse,
|
||||
};
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::nuts::{CheckSpendableRequest, CheckSpendableResponse};
|
||||
use cashu::Amount;
|
||||
use cashu::{Amount, Bolt11Invoice};
|
||||
use serde_json::Value;
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
@@ -103,6 +104,31 @@ impl Client for HttpClient {
|
||||
}
|
||||
}
|
||||
|
||||
/// Melt Quote [NUT-05]
|
||||
async fn post_melt_quote(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
unit: CurrencyUnit,
|
||||
request: Bolt11Invoice,
|
||||
) -> Result<MeltQuoteBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "melt", "quote", "bolt11"])?;
|
||||
|
||||
let request = MeltQuoteBolt11Request { request, unit };
|
||||
|
||||
let value = minreq::post(url)
|
||||
.with_json(&request)?
|
||||
.send()?
|
||||
.json::<Value>()?;
|
||||
|
||||
let response: Result<MeltQuoteBolt11Response, serde_json::Error> =
|
||||
serde_json::from_value(value.clone());
|
||||
|
||||
match response {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_) => Err(Error::from_json(&value.to_string())?),
|
||||
}
|
||||
}
|
||||
|
||||
/// Melt [NUT-05]
|
||||
/// [Nut-08] Lightning fee return if outputs defined
|
||||
async fn post_melt(
|
||||
|
||||
@@ -6,8 +6,9 @@ use cashu::nuts::nut00;
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::nuts::CheckSpendableResponse;
|
||||
use cashu::nuts::{
|
||||
BlindedMessage, CurrencyUnit, Keys, KeysetResponse, MeltBolt11Response, MintBolt11Response,
|
||||
MintInfo, MintQuoteBolt11Response, PreMintSecrets, Proof, SwapRequest, SwapResponse,
|
||||
BlindedMessage, CurrencyUnit, Keys, KeysetResponse, MeltBolt11Response,
|
||||
MeltQuoteBolt11Response, MintBolt11Response, MintInfo, MintQuoteBolt11Response, PreMintSecrets,
|
||||
Proof, SwapRequest, SwapResponse,
|
||||
};
|
||||
use cashu::{utils, Amount};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -101,6 +102,13 @@ pub trait Client {
|
||||
premint_secrets: PreMintSecrets,
|
||||
) -> Result<MintBolt11Response, Error>;
|
||||
|
||||
async fn post_melt_quote(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
unit: CurrencyUnit,
|
||||
request: Bolt11Invoice,
|
||||
) -> Result<MeltQuoteBolt11Response, Error>;
|
||||
|
||||
async fn post_melt(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
|
||||
@@ -13,7 +13,7 @@ use cashu::Amount;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::types::Quote;
|
||||
use crate::types::MeltQuote;
|
||||
|
||||
pub struct Mint {
|
||||
// pub pubkey: PublicKey
|
||||
@@ -23,7 +23,7 @@ pub struct Mint {
|
||||
pub spent_secrets: HashSet<Secret>,
|
||||
pub pending_secrets: HashSet<Secret>,
|
||||
pub fee_reserve: FeeReserve,
|
||||
pub quotes: HashMap<String, Quote>,
|
||||
pub melt_quotes: HashMap<String, MeltQuote>,
|
||||
}
|
||||
|
||||
impl Mint {
|
||||
@@ -31,7 +31,7 @@ impl Mint {
|
||||
secret: &str,
|
||||
keysets_info: HashSet<MintKeySetInfo>,
|
||||
spent_secrets: HashSet<Secret>,
|
||||
quotes: Vec<Quote>,
|
||||
melt_quotes: Vec<MeltQuote>,
|
||||
min_fee_reserve: Amount,
|
||||
percent_fee_reserve: f32,
|
||||
) -> Self {
|
||||
@@ -40,7 +40,7 @@ impl Mint {
|
||||
|
||||
let mut active_units: HashSet<String> = HashSet::default();
|
||||
|
||||
let quotes = quotes.into_iter().map(|q| (q.id.clone(), q)).collect();
|
||||
let melt_quotes = melt_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 {
|
||||
@@ -64,7 +64,7 @@ impl Mint {
|
||||
Self {
|
||||
_secret: secret.to_string(),
|
||||
keysets,
|
||||
quotes,
|
||||
melt_quotes,
|
||||
keysets_info: info,
|
||||
spent_secrets,
|
||||
pending_secrets: HashSet::new(),
|
||||
@@ -235,14 +235,14 @@ impl Mint {
|
||||
}
|
||||
|
||||
pub fn verify_melt_request(&mut self, melt_request: &MeltBolt11Request) -> Result<(), Error> {
|
||||
let quote = self.quotes.get(&melt_request.quote).unwrap();
|
||||
let quote = self.melt_quotes.get(&melt_request.quote).unwrap();
|
||||
let proofs_total = melt_request.proofs_amount();
|
||||
|
||||
let required_total = quote.amount + quote.fee_reserve;
|
||||
|
||||
if proofs_total < required_total.into() {
|
||||
debug!(
|
||||
"Insufficient Proofs: Got: {:?}, Required: {}",
|
||||
"Insufficient Proofs: Got: {}, Required: {}",
|
||||
proofs_total, required_total
|
||||
);
|
||||
return Err(Error::Amount);
|
||||
|
||||
@@ -11,7 +11,7 @@ use cashu::nuts::{
|
||||
};
|
||||
#[cfg(feature = "nut07")]
|
||||
use cashu::types::ProofsStatus;
|
||||
use cashu::types::{Melted, MintQuoteInfo, SendProofs};
|
||||
use cashu::types::{MeltQuote, Melted, MintQuote, SendProofs};
|
||||
use cashu::url::UncheckedUrl;
|
||||
use cashu::Amount;
|
||||
pub use cashu::Bolt11Invoice;
|
||||
@@ -45,7 +45,8 @@ pub enum Error {
|
||||
pub struct Wallet<C: Client> {
|
||||
pub client: C,
|
||||
pub mint_url: UncheckedUrl,
|
||||
pub quotes: HashMap<String, MintQuoteInfo>,
|
||||
pub mint_quotes: HashMap<String, MintQuote>,
|
||||
pub melt_quotes: HashMap<String, MeltQuote>,
|
||||
pub mint_keys: Keys,
|
||||
pub balance: Amount,
|
||||
}
|
||||
@@ -54,14 +55,16 @@ impl<C: Client> Wallet<C> {
|
||||
pub fn new(
|
||||
client: C,
|
||||
mint_url: UncheckedUrl,
|
||||
quotes: Vec<MintQuoteInfo>,
|
||||
mint_quotes: Vec<MintQuote>,
|
||||
melt_quotes: Vec<MeltQuote>,
|
||||
mint_keys: Keys,
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
mint_url,
|
||||
mint_keys,
|
||||
quotes: quotes.into_iter().map(|q| (q.id.clone(), q)).collect(),
|
||||
mint_quotes: mint_quotes.into_iter().map(|q| (q.id.clone(), q)).collect(),
|
||||
melt_quotes: melt_quotes.into_iter().map(|q| (q.id.clone(), q)).collect(),
|
||||
balance: Amount::ZERO,
|
||||
}
|
||||
}
|
||||
@@ -120,29 +123,30 @@ impl<C: Client> Wallet<C> {
|
||||
&mut self,
|
||||
amount: Amount,
|
||||
unit: CurrencyUnit,
|
||||
) -> Result<MintQuoteInfo, Error> {
|
||||
) -> Result<MintQuote, Error> {
|
||||
let quote_res = self
|
||||
.client
|
||||
.post_mint_quote(self.mint_url.clone().try_into()?, amount, unit.clone())
|
||||
.await?;
|
||||
|
||||
let quote = MintQuoteInfo {
|
||||
let quote = MintQuote {
|
||||
id: quote_res.quote.clone(),
|
||||
amount,
|
||||
unit: unit.clone(),
|
||||
request: Some(Bolt11Invoice::from_str("e_res.request).unwrap()),
|
||||
request: Bolt11Invoice::from_str("e_res.request).unwrap(),
|
||||
paid: quote_res.paid,
|
||||
expiry: quote_res.expiry,
|
||||
};
|
||||
|
||||
self.quotes.insert(quote_res.quote.clone(), quote.clone());
|
||||
self.mint_quotes
|
||||
.insert(quote_res.quote.clone(), quote.clone());
|
||||
|
||||
Ok(quote)
|
||||
}
|
||||
|
||||
/// Mint
|
||||
pub async fn mint(&mut self, quote: &str) -> Result<Proofs, Error> {
|
||||
let quote_info = self.quotes.get(quote);
|
||||
pub async fn mint(&mut self, quote_id: &str) -> Result<Proofs, Error> {
|
||||
let quote_info = self.mint_quotes.get(quote_id);
|
||||
|
||||
let quote_info = if let Some(quote) = quote_info {
|
||||
if quote.expiry.le(&unix_time()) {
|
||||
@@ -160,7 +164,7 @@ impl<C: Client> Wallet<C> {
|
||||
.client
|
||||
.post_mint(
|
||||
self.mint_url.clone().try_into()?,
|
||||
quote,
|
||||
quote_id,
|
||||
premint_secrets.clone(),
|
||||
)
|
||||
.await?;
|
||||
@@ -172,7 +176,7 @@ impl<C: Client> Wallet<C> {
|
||||
&self.mint_keys,
|
||||
)?;
|
||||
|
||||
self.quotes.remove("e_info.id);
|
||||
self.mint_quotes.remove("e_info.id);
|
||||
|
||||
Ok(proofs)
|
||||
}
|
||||
@@ -329,19 +333,57 @@ impl<C: Client> Wallet<C> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Melt Quote
|
||||
pub async fn melt_quote(
|
||||
&mut self,
|
||||
unit: CurrencyUnit,
|
||||
request: Bolt11Invoice,
|
||||
) -> Result<MeltQuote, Error> {
|
||||
let quote_res = self
|
||||
.client
|
||||
.post_melt_quote(
|
||||
self.mint_url.clone().try_into()?,
|
||||
unit.clone(),
|
||||
request.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let quote = MeltQuote {
|
||||
id: quote_res.quote,
|
||||
amount: quote_res.amount.into(),
|
||||
request,
|
||||
unit,
|
||||
fee_reserve: quote_res.fee_reserve.into(),
|
||||
paid: quote_res.paid,
|
||||
expiry: quote_res.expiry,
|
||||
};
|
||||
|
||||
self.melt_quotes.insert(quote.id.clone(), quote.clone());
|
||||
|
||||
Ok(quote)
|
||||
}
|
||||
|
||||
/// Melt
|
||||
pub async fn melt(
|
||||
&self,
|
||||
quote: String,
|
||||
proofs: Proofs,
|
||||
fee_reserve: Amount,
|
||||
) -> Result<Melted, Error> {
|
||||
let blinded = PreMintSecrets::blank((&self.mint_keys).into(), fee_reserve)?;
|
||||
pub async fn melt(&self, quote_id: &str, proofs: Proofs) -> Result<Melted, Error> {
|
||||
let quote_info = self.melt_quotes.get(quote_id);
|
||||
|
||||
let quote_info = if let Some(quote) = quote_info {
|
||||
if quote.expiry.le(&unix_time()) {
|
||||
return Err(Error::QuoteExpired);
|
||||
}
|
||||
|
||||
quote.clone()
|
||||
} else {
|
||||
return Err(Error::QuoteUnknown);
|
||||
};
|
||||
|
||||
let blinded = PreMintSecrets::blank((&self.mint_keys).into(), quote_info.fee_reserve)?;
|
||||
|
||||
let melt_response = self
|
||||
.client
|
||||
.post_melt(
|
||||
self.mint_url.clone().try_into()?,
|
||||
quote,
|
||||
quote_id.to_string(),
|
||||
proofs,
|
||||
Some(blinded.blinded_messages()),
|
||||
)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::fmt;
|
||||
|
||||
// https://github.com/clarkmoody/cashu-rs
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -62,6 +64,12 @@ impl std::ops::Sub for Amount {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Amount {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::iter::Sum for Amount {
|
||||
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||
let sats: u64 = iter.map(|amt| amt.0).sum();
|
||||
|
||||
@@ -36,23 +36,23 @@ pub enum InvoiceStatus {
|
||||
|
||||
/// Mint Quote Info
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct MintQuoteInfo {
|
||||
pub struct MintQuote {
|
||||
pub id: String,
|
||||
pub amount: Amount,
|
||||
pub unit: CurrencyUnit,
|
||||
pub request: Option<Bolt11Invoice>,
|
||||
pub request: Bolt11Invoice,
|
||||
pub paid: bool,
|
||||
pub expiry: u64,
|
||||
}
|
||||
|
||||
/// Quote
|
||||
/// Melt Quote Info
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct Quote {
|
||||
pub struct MeltQuote {
|
||||
pub id: String,
|
||||
pub amount: u64,
|
||||
pub amount: Amount,
|
||||
pub request: Bolt11Invoice,
|
||||
pub unit: CurrencyUnit,
|
||||
pub fee_reserve: u64,
|
||||
pub fee_reserve: Amount,
|
||||
pub paid: bool,
|
||||
pub expiry: u64,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user