feat: support custom unit

This commit is contained in:
thesimplekid
2024-10-26 21:39:34 +01:00
parent c62b0b7f11
commit 3db25640dc
35 changed files with 176 additions and 125 deletions

View File

@@ -33,7 +33,7 @@ impl JsMeltQuote {
#[wasm_bindgen(getter)]
pub fn unit(&self) -> JsCurrencyUnit {
self.inner.unit.into()
self.inner.unit.clone().into()
}
#[wasm_bindgen(getter)]

View File

@@ -33,7 +33,7 @@ impl JsMintQuote {
#[wasm_bindgen(getter)]
pub fn unit(&self) -> JsCurrencyUnit {
self.inner.unit.into()
self.inner.unit.clone().into()
}
#[wasm_bindgen(getter)]

View File

@@ -21,7 +21,7 @@ pub async fn pay_request(
) -> Result<()> {
let payment_request = &sub_command_args.payment_request;
let unit = payment_request.unit;
let unit = &payment_request.unit;
let amount = match payment_request.amount {
Some(amount) => amount,
@@ -56,7 +56,7 @@ pub async fn pay_request(
}
if let Some(unit) = unit {
if wallet.unit != unit {
if &wallet.unit != unit {
continue;
}
}
@@ -97,7 +97,7 @@ pub async fn pay_request(
id: payment_request.payment_id.clone(),
memo: None,
mint: matching_wallet.mint_url.clone(),
unit: matching_wallet.unit,
unit: matching_wallet.unit.clone(),
proofs,
};

View File

@@ -81,8 +81,8 @@ impl MintLightning for Cln {
Settings {
mpp: true,
unit: CurrencyUnit::Msat,
mint_settings: self.mint_settings,
melt_settings: self.melt_settings,
mint_settings: self.mint_settings.clone(),
melt_settings: self.melt_settings.clone(),
invoice_description: true,
}
}

View File

@@ -112,8 +112,8 @@ impl MintLightning for FakeWallet {
Settings {
mpp: true,
unit: CurrencyUnit::Msat,
mint_settings: self.mint_settings,
melt_settings: self.melt_settings,
mint_settings: self.mint_settings.clone(),
melt_settings: self.melt_settings.clone(),
invoice_description: true,
}
}

View File

@@ -176,6 +176,7 @@ where
Arc::new(database),
ln_backends,
supported_units,
HashMap::new(),
)
.await?;

View File

@@ -82,6 +82,7 @@ pub async fn start_mint(
Arc::new(MintMemoryDatabase::default()),
ln_backends.clone(),
supported_units,
HashMap::new(),
)
.await?;
let cache_time_to_live = 3600;

View File

@@ -368,16 +368,12 @@ async fn test_fake_melt_change_in_quote() -> Result<()> {
assert!(melt_response.change.is_some());
let check = wallet.melt_quote_status(&melt_quote.id).await?;
let mut melt_change = melt_response.change.unwrap();
melt_change.sort_by(|a, b| a.amount.cmp(&b.amount));
assert_eq!(
melt_response
.change
.unwrap()
.sort_by(|a, b| a.amount.cmp(&b.amount)),
check
.change
.unwrap()
.sort_by(|a, b| a.amount.cmp(&b.amount))
);
let mut check = check.change.unwrap();
check.sort_by(|a, b| a.amount.cmp(&b.amount));
assert_eq!(melt_change, check);
Ok(())
}

View File

@@ -48,6 +48,7 @@ async fn new_mint(fee: u64) -> Mint {
Arc::new(MintMemoryDatabase::default()),
HashMap::new(),
supported_units,
HashMap::new(),
)
.await
.unwrap()
@@ -270,7 +271,8 @@ async fn test_swap_unbalanced() -> Result<()> {
async fn test_swap_overpay_underpay_fee() -> Result<()> {
let mint = new_mint(1).await;
mint.rotate_keyset(CurrencyUnit::Sat, 1, 32, 1).await?;
mint.rotate_keyset(CurrencyUnit::Sat, 1, 32, 1, HashMap::new())
.await?;
let keys = mint.pubkeys().await?.keysets.first().unwrap().clone().keys;
let keyset_id = Id::from(&keys);

View File

@@ -80,8 +80,8 @@ impl MintLightning for LNbits {
Settings {
mpp: false,
unit: CurrencyUnit::Sat,
mint_settings: self.mint_settings,
melt_settings: self.melt_settings,
mint_settings: self.mint_settings.clone(),
melt_settings: self.melt_settings.clone(),
invoice_description: true,
}
}

View File

@@ -88,8 +88,8 @@ impl MintLightning for Lnd {
Settings {
mpp: true,
unit: CurrencyUnit::Msat,
mint_settings: self.mint_settings,
melt_settings: self.melt_settings,
mint_settings: self.mint_settings.clone(),
melt_settings: self.melt_settings.clone(),
invoice_description: true,
}
}

View File

@@ -188,7 +188,7 @@ async fn main() -> anyhow::Result<()> {
api_key.clone(),
MintMethodSettings::default(),
MeltMethodSettings::default(),
unit,
unit.clone(),
Arc::new(Mutex::new(Some(receiver))),
webhook_url.to_string(),
)
@@ -199,7 +199,7 @@ async fn main() -> anyhow::Result<()> {
.await?;
routers.push(router);
let ln_key = LnKey::new(unit, PaymentMethod::Bolt11);
let ln_key = LnKey::new(unit.clone(), PaymentMethod::Bolt11);
ln_backends.insert(ln_key, Arc::new(strike));
@@ -237,7 +237,7 @@ async fn main() -> anyhow::Result<()> {
let unit = CurrencyUnit::Sat;
let ln_key = LnKey::new(unit, PaymentMethod::Bolt11);
let ln_key = LnKey::new(unit.clone(), PaymentMethod::Bolt11);
ln_backends.insert(ln_key, Arc::new(lnbits));
@@ -326,7 +326,7 @@ async fn main() -> anyhow::Result<()> {
let units = settings.fake_wallet.unwrap_or_default().supported_units;
for unit in units {
let ln_key = LnKey::new(unit, PaymentMethod::Bolt11);
let ln_key = LnKey::new(unit.clone(), PaymentMethod::Bolt11);
let wallet = Arc::new(FakeWallet::new(
fee_reserve.clone(),
@@ -361,13 +361,13 @@ async fn main() -> anyhow::Result<()> {
let m = MppMethodSettings {
method: key.method,
unit: key.unit,
unit: key.unit.clone(),
mpp: settings.mpp,
};
let n4 = MintMethodSettings {
method: key.method,
unit: key.unit,
unit: key.unit.clone(),
min_amount: settings.mint_settings.min_amount,
max_amount: settings.mint_settings.max_amount,
description: settings.invoice_description,
@@ -375,7 +375,7 @@ async fn main() -> anyhow::Result<()> {
let n5 = MeltMethodSettings {
method: key.method,
unit: key.unit,
unit: key.unit.clone(),
min_amount: settings.melt_settings.min_amount,
max_amount: settings.melt_settings.max_amount,
};
@@ -438,6 +438,7 @@ async fn main() -> anyhow::Result<()> {
localstore,
ln_backends.clone(),
supported_units,
HashMap::new(),
)
.await?;

View File

@@ -86,8 +86,8 @@ impl MintLightning for Phoenixd {
Settings {
mpp: false,
unit: CurrencyUnit::Sat,
mint_settings: self.mint_settings,
melt_settings: self.melt_settings,
mint_settings: self.mint_settings.clone(),
melt_settings: self.melt_settings.clone(),
invoice_description: true,
}
}

View File

@@ -77,9 +77,9 @@ impl MintLightning for Strike {
fn get_settings(&self) -> Settings {
Settings {
mpp: false,
unit: self.unit,
mint_settings: self.mint_settings,
melt_settings: self.melt_settings,
unit: self.unit.clone(),
mint_settings: self.mint_settings.clone(),
melt_settings: self.melt_settings.clone(),
invoice_description: true,
}
}
@@ -288,7 +288,7 @@ impl MintLightning for Strike {
payment_preimage: None,
status: state,
total_spent: from_strike_amount(invoice.total_amount, &self.unit)?.into(),
unit: self.unit,
unit: self.unit.clone(),
}
}
Err(err) => match err {
@@ -297,7 +297,7 @@ impl MintLightning for Strike {
payment_preimage: None,
status: MeltQuoteState::Unknown,
total_spent: Amount::ZERO,
unit: self.unit,
unit: self.unit.clone(),
},
_ => {
return Err(Error::from(err).into());

View File

@@ -1,5 +1,6 @@
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use bitcoin::bip32::DerivationPath;
use tracing::instrument;
use crate::Error;
@@ -89,14 +90,20 @@ impl Mint {
derivation_path_index: u32,
max_order: u8,
input_fee_ppk: u64,
custom_paths: HashMap<CurrencyUnit, DerivationPath>,
) -> Result<(), Error> {
let derivation_path = derivation_path_from_unit(unit, derivation_path_index);
let derivation_path = match custom_paths.get(&unit) {
Some(path) => path.clone(),
None => derivation_path_from_unit(unit.clone(), derivation_path_index)
.ok_or(Error::UnsupportedUnit)?,
};
let (keyset, keyset_info) = create_new_keyset(
&self.secp_ctx,
self.xpriv,
derivation_path,
Some(derivation_path_index),
unit,
unit.clone(),
max_order,
input_fee_ppk,
);

View File

@@ -74,11 +74,11 @@ impl Mint {
}
};
self.check_melt_request_acceptable(amount, *unit, PaymentMethod::Bolt11)?;
self.check_melt_request_acceptable(amount, unit.clone(), PaymentMethod::Bolt11)?;
let ln = self
.ln
.get(&LnKey::new(*unit, PaymentMethod::Bolt11))
.get(&LnKey::new(unit.clone(), PaymentMethod::Bolt11))
.ok_or_else(|| {
tracing::info!("Could not get ln backend for {}, bolt11 ", unit);
@@ -97,7 +97,7 @@ impl Mint {
let quote = MeltQuote::new(
request.to_string(),
*unit,
unit.clone(),
payment_quote.amount,
payment_quote.fee,
unix_time() + self.quote_ttl.melt_ttl,
@@ -447,7 +447,10 @@ impl Mint {
}
_ => None,
};
let ln = match self.ln.get(&LnKey::new(quote.unit, PaymentMethod::Bolt11)) {
let ln = match self
.ln
.get(&LnKey::new(quote.unit.clone(), PaymentMethod::Bolt11))
{
Some(ln) => ln,
None => {
tracing::info!("Could not get ln backend for {}, bolt11 ", quote.unit);

View File

@@ -12,7 +12,7 @@ impl Mint {
fn check_mint_request_acceptable(
&self,
amount: Amount,
unit: CurrencyUnit,
unit: &CurrencyUnit,
) -> Result<(), Error> {
let nut04 = &self.mint_info.nuts.nut04;
@@ -20,7 +20,7 @@ impl Mint {
return Err(Error::MintingDisabled);
}
match nut04.get_settings(&unit, &PaymentMethod::Bolt11) {
match nut04.get_settings(unit, &PaymentMethod::Bolt11) {
Some(settings) => {
if settings
.max_amount
@@ -64,11 +64,11 @@ impl Mint {
description,
} = mint_quote_request;
self.check_mint_request_acceptable(amount, unit)?;
self.check_mint_request_acceptable(amount, &unit)?;
let ln = self
.ln
.get(&LnKey::new(unit, PaymentMethod::Bolt11))
.get(&LnKey::new(unit.clone(), PaymentMethod::Bolt11))
.ok_or_else(|| {
tracing::info!("Bolt11 mint request for unsupported unit");
@@ -98,7 +98,7 @@ impl Mint {
let quote = MintQuote::new(
self.mint_url.clone(),
create_invoice_response.request.to_string(),
unit,
unit.clone(),
amount,
create_invoice_response.expiry.unwrap_or(0),
create_invoice_response.request_lookup_id.clone(),

View File

@@ -54,6 +54,7 @@ pub struct Mint {
impl Mint {
/// Create new [`Mint`]
#[allow(clippy::too_many_arguments)]
pub async fn new(
mint_url: &str,
seed: &[u8],
@@ -63,6 +64,7 @@ impl Mint {
ln: HashMap<LnKey, Arc<dyn MintLightning<Err = cdk_lightning::Error> + Send + Sync>>,
// Hashmap where the key is the unit and value is (input fee ppk, max_order)
supported_units: HashMap<CurrencyUnit, (u64, u8)>,
custom_paths: HashMap<CurrencyUnit, DerivationPath>,
) -> Result<Self, Error> {
let secp_ctx = Secp256k1::new();
let xpriv = Xpriv::new_master(bitcoin::Network::Bitcoin, seed).expect("RNG busted");
@@ -83,7 +85,7 @@ impl Mint {
let keysets_by_unit: HashMap<CurrencyUnit, Vec<MintKeySetInfo>> =
keysets_infos.iter().fold(HashMap::new(), |mut acc, ks| {
acc.entry(ks.unit).or_default().push(ks.clone());
acc.entry(ks.unit.clone()).or_default().push(ks.clone());
acc
});
@@ -112,7 +114,7 @@ impl Mint {
&secp_ctx,
xpriv,
highest_index_keyset.max_order,
highest_index_keyset.unit,
highest_index_keyset.unit.clone(),
highest_index_keyset.derivation_path.clone(),
);
active_keysets.insert(id, keyset);
@@ -125,37 +127,46 @@ impl Mint {
highest_index_keyset.derivation_path_index.unwrap_or(0) + 1
};
let derivation_path = derivation_path_from_unit(unit, derivation_path_index);
let derivation_path = match custom_paths.get(&unit) {
Some(path) => path.clone(),
None => derivation_path_from_unit(unit.clone(), derivation_path_index)
.ok_or(Error::UnsupportedUnit)?,
};
let (keyset, keyset_info) = create_new_keyset(
&secp_ctx,
xpriv,
derivation_path,
Some(derivation_path_index),
unit,
unit.clone(),
*max_order,
*input_fee_ppk,
);
let id = keyset_info.id;
localstore.add_keyset_info(keyset_info).await?;
localstore.set_active_keyset(unit, id).await?;
localstore.set_active_keyset(unit.clone(), id).await?;
active_keysets.insert(id, keyset);
active_keyset_units.push(unit);
active_keyset_units.push(unit.clone());
}
}
}
for (unit, (fee, max_order)) in supported_units {
if !active_keyset_units.contains(&unit) {
let derivation_path = derivation_path_from_unit(unit, 0);
let derivation_path = match custom_paths.get(&unit) {
Some(path) => path.clone(),
None => {
derivation_path_from_unit(unit.clone(), 0).ok_or(Error::UnsupportedUnit)?
}
};
let (keyset, keyset_info) = create_new_keyset(
&secp_ctx,
xpriv,
derivation_path,
Some(0),
unit,
unit.clone(),
max_order,
fee,
);
@@ -194,7 +205,7 @@ impl Mint {
let mint = Arc::clone(&mint_arc);
let ln = Arc::clone(ln);
let shutdown = Arc::clone(&shutdown);
let key = *key;
let key = key.clone();
join_set.spawn(async move {
if !ln.is_wait_invoice_active() {
loop {
@@ -438,7 +449,8 @@ impl Mint {
Ok(RestoreResponse {
outputs,
signatures,
signatures: signatures.clone(),
promises: Some(signatures),
})
}
@@ -559,7 +571,7 @@ fn create_new_keyset<C: secp256k1::Signing>(
);
let keyset_info = MintKeySetInfo {
id: keyset.id,
unit: keyset.unit,
unit: keyset.unit.clone(),
active: true,
valid_from: unix_time(),
valid_to: None,
@@ -571,12 +583,17 @@ fn create_new_keyset<C: secp256k1::Signing>(
(keyset, keyset_info)
}
fn derivation_path_from_unit(unit: CurrencyUnit, index: u32) -> DerivationPath {
DerivationPath::from(vec![
fn derivation_path_from_unit(unit: CurrencyUnit, index: u32) -> Option<DerivationPath> {
let unit_index = match unit.derivation_index() {
Some(index) => index,
None => return None,
};
Some(DerivationPath::from(vec![
ChildNumber::from_hardened_idx(0).expect("0 is a valid index"),
ChildNumber::from_hardened_idx(unit.derivation_index()).expect("0 is a valid index"),
ChildNumber::from_hardened_idx(unit_index).expect("0 is a valid index"),
ChildNumber::from_hardened_idx(index).expect("0 is a valid index"),
])
]))
}
#[cfg(test)]
@@ -598,7 +615,7 @@ mod tests {
seed,
2,
CurrencyUnit::Sat,
derivation_path_from_unit(CurrencyUnit::Sat, 0),
derivation_path_from_unit(CurrencyUnit::Sat, 0).unwrap(),
);
assert_eq!(keyset.unit, CurrencyUnit::Sat);
@@ -642,7 +659,7 @@ mod tests {
xpriv,
2,
CurrencyUnit::Sat,
derivation_path_from_unit(CurrencyUnit::Sat, 0),
derivation_path_from_unit(CurrencyUnit::Sat, 0).unwrap(),
);
assert_eq!(keyset.unit, CurrencyUnit::Sat);
@@ -722,6 +739,7 @@ mod tests {
localstore,
HashMap::new(),
config.supported_units,
HashMap::new(),
)
.await
}
@@ -777,7 +795,8 @@ mod tests {
assert!(keysets.keysets.is_empty());
// generate the first keyset and set it to active
mint.rotate_keyset(CurrencyUnit::default(), 0, 1, 1).await?;
mint.rotate_keyset(CurrencyUnit::default(), 0, 1, 1, HashMap::new())
.await?;
let keysets = mint.keysets().await.unwrap();
assert!(keysets.keysets.len().eq(&1));
@@ -785,7 +804,8 @@ mod tests {
let first_keyset_id = keysets.keysets[0].id;
// set the first keyset to inactive and generate a new keyset
mint.rotate_keyset(CurrencyUnit::default(), 1, 1, 1).await?;
mint.rotate_keyset(CurrencyUnit::default(), 1, 1, 1, HashMap::new())
.await?;
let keysets = mint.keysets().await.unwrap();

View File

@@ -361,7 +361,7 @@ where
/// Currency Unit
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
pub enum CurrencyUnit {
/// Sat
@@ -373,17 +373,20 @@ pub enum CurrencyUnit {
Usd,
/// Euro
Eur,
/// Custom currency unit
Custom(String),
}
#[cfg(feature = "mint")]
impl CurrencyUnit {
/// Derivation index mint will use for unit
pub fn derivation_index(&self) -> u32 {
pub fn derivation_index(&self) -> Option<u32> {
match self {
Self::Sat => 0,
Self::Msat => 1,
Self::Usd => 2,
Self::Eur => 3,
Self::Sat => Some(0),
Self::Msat => Some(1),
Self::Usd => Some(2),
Self::Eur => Some(3),
_ => None,
}
}
}
@@ -391,12 +394,13 @@ impl CurrencyUnit {
impl FromStr for CurrencyUnit {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"sat" => Ok(Self::Sat),
"msat" => Ok(Self::Msat),
"usd" => Ok(Self::Usd),
"eur" => Ok(Self::Eur),
_ => Err(Error::UnsupportedUnit),
let value = &value.to_uppercase();
match value.as_str() {
"SAT" => Ok(Self::Sat),
"MSAT" => Ok(Self::Msat),
"USD" => Ok(Self::Usd),
"EUR" => Ok(Self::Eur),
c => Ok(Self::Custom(c.to_string())),
}
}
}
@@ -404,15 +408,16 @@ impl FromStr for CurrencyUnit {
impl fmt::Display for CurrencyUnit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
CurrencyUnit::Sat => "sat",
CurrencyUnit::Msat => "msat",
CurrencyUnit::Usd => "usd",
CurrencyUnit::Eur => "eur",
CurrencyUnit::Sat => "SAT",
CurrencyUnit::Msat => "MSAT",
CurrencyUnit::Usd => "USD",
CurrencyUnit::Eur => "EUR",
CurrencyUnit::Custom(unit) => unit,
};
if let Some(width) = f.width() {
write!(f, "{:width$}", s, width = width)
write!(f, "{:width$}", s.to_lowercase(), width = width)
} else {
write!(f, "{}", s)
write!(f, "{}", s.to_lowercase())
}
}
}

View File

@@ -92,8 +92,8 @@ impl Token {
/// Unit
pub fn unit(&self) -> Option<CurrencyUnit> {
match self {
Self::TokenV3(token) => *token.unit(),
Self::TokenV4(token) => Some(token.unit()),
Self::TokenV3(token) => token.unit().clone(),
Self::TokenV4(token) => Some(token.unit().clone()),
}
}
@@ -326,8 +326,8 @@ impl TokenV4 {
/// Unit
#[inline]
pub fn unit(&self) -> CurrencyUnit {
self.unit
pub fn unit(&self) -> &CurrencyUnit {
&self.unit
}
}
@@ -525,7 +525,7 @@ mod tests {
token.token[0].proofs[0].clone().keyset_id,
Id::from_str("009a1f293253e41e").unwrap()
);
assert_eq!(token.unit.unwrap(), CurrencyUnit::Sat);
assert_eq!(token.unit.clone().unwrap(), CurrencyUnit::Sat);
let encoded = &token.to_string();

View File

@@ -137,7 +137,7 @@ pub struct MintBolt11Response {
}
/// Mint Method Settings
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
pub struct MintMethodSettings {
/// Payment Method e.g. bolt11
@@ -179,7 +179,7 @@ impl Settings {
) -> Option<MintMethodSettings> {
for method_settings in self.methods.iter() {
if method_settings.method.eq(method) && method_settings.unit.eq(unit) {
return Some(*method_settings);
return Some(method_settings.clone());
}
}

View File

@@ -235,7 +235,7 @@ impl MeltBolt11Request {
}
/// Melt Method Settings
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
pub struct MeltMethodSettings {
/// Payment Method e.g. bolt11
@@ -264,7 +264,7 @@ impl Settings {
) -> Option<MeltMethodSettings> {
for method_settings in self.methods.iter() {
if method_settings.method.eq(method) && method_settings.unit.eq(unit) {
return Some(*method_settings);
return Some(method_settings.clone());
}
}

View File

@@ -22,6 +22,9 @@ pub struct RestoreResponse {
pub outputs: Vec<BlindedMessage>,
/// Signatures
pub signatures: Vec<BlindSignature>,
/// Promises
// Temp compatibility with cashu-ts
pub promises: Option<Vec<BlindSignature>>,
}
mod test {

View File

@@ -154,7 +154,7 @@ mod tests {
assert_eq!(&req.payment_id.unwrap(), "b7a90176");
assert_eq!(req.amount.unwrap(), 10.into());
assert_eq!(req.unit.unwrap(), CurrencyUnit::Sat);
assert_eq!(req.unit.clone().unwrap(), CurrencyUnit::Sat);
assert_eq!(
req.mints.unwrap(),
vec![MintUrl::from_str("https://nofees.testnut.cashu.space")?]
@@ -190,7 +190,7 @@ mod tests {
assert_eq!(&req.payment_id.unwrap(), "b7a90176");
assert_eq!(req.amount.unwrap(), 10.into());
assert_eq!(req.unit.unwrap(), CurrencyUnit::Sat);
assert_eq!(req.unit.clone().unwrap(), CurrencyUnit::Sat);
assert_eq!(
req.mints.unwrap(),
vec![MintUrl::from_str("https://nofees.testnut.cashu.space")?]

View File

@@ -141,7 +141,7 @@ impl ProofInfo {
/// Key used in hashmap of ln backends to identify what unit and payment method
/// it is for
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct LnKey {
/// Unit of Payment backend
pub unit: CurrencyUnit,

View File

@@ -19,7 +19,7 @@ impl Wallet {
// TODO If only the proofs for this wallet's unit are retrieved, why build a map with key = unit?
let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
*acc.entry(self.unit).or_insert(Amount::ZERO) += proof.amount;
*acc.entry(self.unit.clone()).or_insert(Amount::ZERO) += proof.amount;
acc
});
@@ -33,7 +33,7 @@ impl Wallet {
// TODO If only the proofs for this wallet's unit are retrieved, why build a map with key = unit?
let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
*acc.entry(self.unit).or_insert(Amount::ZERO) += proof.amount;
*acc.entry(self.unit.clone()).or_insert(Amount::ZERO) += proof.amount;
acc
});

View File

@@ -62,7 +62,7 @@ impl Wallet {
let quote_request = MeltQuoteBolt11Request {
request: Bolt11Invoice::from_str(&request)?,
unit: self.unit,
unit: self.unit.clone(),
options,
};
@@ -79,7 +79,7 @@ impl Wallet {
id: quote_res.quote,
amount,
request,
unit: self.unit,
unit: self.unit.clone(),
fee_reserve: quote_res.fee_reserve,
state: quote_res.state,
expiry: quote_res.expiry,
@@ -233,7 +233,7 @@ impl Wallet {
proof,
self.mint_url.clone(),
State::Unspent,
quote_info.unit,
quote_info.unit.clone(),
)
})
.collect::<Result<Vec<ProofInfo>, _>>()?

View File

@@ -46,7 +46,7 @@ impl Wallet {
description: Option<String>,
) -> Result<MintQuote, Error> {
let mint_url = self.mint_url.clone();
let unit = self.unit;
let unit = self.unit.clone();
// If we have a description, we check that the mint supports it.
if description.is_some() {
@@ -67,7 +67,7 @@ impl Wallet {
let request = MintQuoteBolt11Request {
amount,
unit,
unit: unit.clone(),
description,
};
@@ -80,7 +80,7 @@ impl Wallet {
mint_url,
id: quote_res.quote.clone(),
amount,
unit,
unit: unit.clone(),
request: quote_res.request,
state: quote_res.state,
expiry: quote_res.expiry.unwrap_or(0),
@@ -269,7 +269,7 @@ impl Wallet {
proof,
self.mint_url.clone(),
State::Unspent,
quote_info.unit,
quote_info.unit.clone(),
)
})
.collect::<Result<Vec<ProofInfo>, _>>()?;

View File

@@ -330,7 +330,12 @@ impl Wallet {
let unspent_proofs = unspent_proofs
.into_iter()
.map(|proof| {
ProofInfo::new(proof, self.mint_url.clone(), State::Unspent, keyset.unit)
ProofInfo::new(
proof,
self.mint_url.clone(),
State::Unspent,
keyset.unit.clone(),
)
})
.collect::<Result<Vec<ProofInfo>, _>>()?;

View File

@@ -55,7 +55,7 @@ impl MultiMintWallet {
wallets: Arc::new(Mutex::new(
wallets
.into_iter()
.map(|w| (WalletKey::new(w.mint_url.clone(), w.unit), w))
.map(|w| (WalletKey::new(w.mint_url.clone(), w.unit.clone()), w))
.collect(),
)),
}
@@ -64,7 +64,7 @@ impl MultiMintWallet {
/// Add wallet to MultiMintWallet
#[instrument(skip(self, wallet))]
pub async fn add_wallet(&self, wallet: Wallet) {
let wallet_key = WalletKey::new(wallet.mint_url.clone(), wallet.unit);
let wallet_key = WalletKey::new(wallet.mint_url.clone(), wallet.unit.clone());
let mut wallets = self.wallets.lock().await;
@@ -126,7 +126,7 @@ impl MultiMintWallet {
for (WalletKey { mint_url, unit: u }, wallet) in self.wallets.lock().await.iter() {
let wallet_proofs = wallet.get_unspent_proofs().await?;
mint_proofs.insert(mint_url.clone(), (wallet_proofs, *u));
mint_proofs.insert(mint_url.clone(), (wallet_proofs, u.clone()));
}
Ok(mint_proofs)
}
@@ -198,7 +198,7 @@ impl MultiMintWallet {
let amount = wallet.check_all_mint_quotes().await?;
amount_minted
.entry(wallet.unit)
.entry(wallet.unit.clone())
.and_modify(|b| *b += amount)
.or_insert(amount);
}
@@ -246,7 +246,7 @@ impl MultiMintWallet {
let mint_url = token_data.mint_url()?;
// Check that all mints in tokes have wallets
let wallet_key = WalletKey::new(mint_url.clone(), unit);
let wallet_key = WalletKey::new(mint_url.clone(), unit.clone());
if !self.has(&wallet_key).await {
return Err(Error::UnknownWallet(wallet_key.clone()));
}

View File

@@ -41,7 +41,7 @@ impl Wallet {
.localstore
.get_proofs(
Some(self.mint_url.clone()),
Some(self.unit),
Some(self.unit.clone()),
state,
spending_conditions,
)
@@ -115,7 +115,7 @@ impl Wallet {
.localstore
.get_proofs(
Some(self.mint_url.clone()),
Some(self.unit),
Some(self.unit.clone()),
Some(vec![State::Pending, State::Reserved]),
None,
)

View File

@@ -111,7 +111,7 @@ impl Wallet {
let proofs_info = proofs
.clone()
.into_iter()
.map(|p| ProofInfo::new(p, self.mint_url.clone(), State::Pending, self.unit))
.map(|p| ProofInfo::new(p, self.mint_url.clone(), State::Pending, self.unit.clone()))
.collect::<Result<Vec<ProofInfo>, _>>()?;
self.localstore
.update_proofs(proofs_info.clone(), vec![])
@@ -150,7 +150,7 @@ impl Wallet {
let recv_proof_infos = recv_proofs
.into_iter()
.map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent, self.unit))
.map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent, self.unit.clone()))
.collect::<Result<Vec<ProofInfo>, _>>()?;
self.localstore
.update_proofs(

View File

@@ -16,7 +16,12 @@ impl Wallet {
let ys = proofs.ys()?;
self.localstore.reserve_proofs(ys).await?;
Ok(Token::new(self.mint_url.clone(), proofs, memo, self.unit))
Ok(Token::new(
self.mint_url.clone(),
proofs,
memo,
self.unit.clone(),
))
}
/// Send

View File

@@ -111,7 +111,9 @@ impl Wallet {
let send_proofs_info = proofs_to_send
.clone()
.into_iter()
.map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Reserved, *unit))
.map(|proof| {
ProofInfo::new(proof, mint_url.clone(), State::Reserved, unit.clone())
})
.collect::<Result<Vec<ProofInfo>, _>>()?;
added_proofs = send_proofs_info;
@@ -126,7 +128,7 @@ impl Wallet {
let keep_proofs = change_proofs
.into_iter()
.map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent, *unit))
.map(|proof| ProofInfo::new(proof, mint_url.clone(), State::Unspent, unit.clone()))
.collect::<Result<Vec<ProofInfo>, _>>()?;
added_proofs.extend(keep_proofs);
@@ -154,7 +156,7 @@ impl Wallet {
.localstore
.get_proofs(
Some(self.mint_url.clone()),
Some(self.unit),
Some(self.unit.clone()),
Some(vec![State::Unspent]),
None,
)

6
flake.lock generated
View File

@@ -57,11 +57,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1730327045,
"narHash": "sha256-xKel5kd1AbExymxoIfQ7pgcX6hjw9jCgbiBjiUfSVJ8=",
"lastModified": 1730741070,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "080166c15633801df010977d9d7474b4a6c549d7",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {