mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-04 12:45:55 +01:00
refactor: proofs in localstore
This commit is contained in:
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cashu::nuts::{Id, KeySetInfo, Keys, MintInfo};
|
||||
use cashu::nuts::{Id, KeySetInfo, Keys, MintInfo, Proof, Proofs};
|
||||
use cashu::types::{MeltQuote, MintQuote};
|
||||
use cashu::url::UncheckedUrl;
|
||||
use tokio::sync::Mutex;
|
||||
@@ -16,6 +16,7 @@ pub struct MemoryLocalStore {
|
||||
mint_quotes: Arc<Mutex<HashMap<String, MintQuote>>>,
|
||||
melt_quotes: Arc<Mutex<HashMap<String, MeltQuote>>>,
|
||||
mint_keys: Arc<Mutex<HashMap<Id, Keys>>>,
|
||||
proofs: Arc<Mutex<HashMap<UncheckedUrl, HashSet<Proof>>>>,
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@@ -40,8 +41,8 @@ impl LocalStore for MemoryLocalStore {
|
||||
) -> Result<(), Error> {
|
||||
let mut current_keysets = self.mint_keysets.lock().await;
|
||||
|
||||
let current_keysets = current_keysets.entry(mint_url).or_insert(HashSet::new());
|
||||
current_keysets.extend(keysets);
|
||||
let mint_keysets = current_keysets.entry(mint_url).or_insert(HashSet::new());
|
||||
mint_keysets.extend(keysets);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -107,4 +108,34 @@ impl LocalStore for MemoryLocalStore {
|
||||
self.mint_keys.lock().await.remove(id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Error> {
|
||||
let mut all_proofs = self.proofs.lock().await;
|
||||
|
||||
let mint_proofs = all_proofs.entry(mint_url).or_insert(HashSet::new());
|
||||
mint_proofs.extend(proofs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Error> {
|
||||
Ok(self
|
||||
.proofs
|
||||
.lock()
|
||||
.await
|
||||
.get(&mint_url)
|
||||
.map(|p| p.iter().cloned().collect()))
|
||||
}
|
||||
|
||||
async fn remove_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Error> {
|
||||
let mut mint_proofs = self.proofs.lock().await;
|
||||
|
||||
if let Some(mint_proofs) = mint_proofs.get_mut(&mint_url) {
|
||||
for proof in proofs {
|
||||
mint_proofs.remove(&proof);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
mod memory;
|
||||
use async_trait::async_trait;
|
||||
use cashu::nuts::{Id, KeySetInfo, Keys, MintInfo};
|
||||
use cashu::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs};
|
||||
use cashu::types::{MeltQuote, MintQuote};
|
||||
use cashu::url::UncheckedUrl;
|
||||
use thiserror::Error;
|
||||
@@ -38,4 +38,8 @@ pub trait LocalStore {
|
||||
async fn add_keys(&self, keys: Keys) -> Result<(), Error>;
|
||||
async fn get_keys(&self, id: &Id) -> Result<Option<Keys>, Error>;
|
||||
async fn remove_keys(&self, id: &Id) -> Result<(), Error>;
|
||||
|
||||
async fn add_proofs(&self, mint_url: UncheckedUrl, proof: Proofs) -> Result<(), Error>;
|
||||
async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Error>;
|
||||
async fn remove_proofs(&self, mint_url: UncheckedUrl, proofs: Proofs) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ pub struct BackupInfo {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Wallet<C: Client, L: LocalStore> {
|
||||
backup_info: Option<BackupInfo>,
|
||||
pub client: C,
|
||||
pub localstore: L,
|
||||
localstore: L,
|
||||
backup_info: Option<BackupInfo>,
|
||||
}
|
||||
|
||||
impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
@@ -128,29 +128,32 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
})
|
||||
}
|
||||
|
||||
// Mint a token
|
||||
pub async fn mint_token(
|
||||
&mut self,
|
||||
mint_url: UncheckedUrl,
|
||||
amount: Amount,
|
||||
memo: Option<String>,
|
||||
unit: Option<CurrencyUnit>,
|
||||
) -> Result<Token, Error> {
|
||||
let quote = self
|
||||
.mint_quote(
|
||||
mint_url.clone(),
|
||||
amount,
|
||||
unit.clone()
|
||||
.ok_or(Error::Custom("Unit required".to_string()))?,
|
||||
)
|
||||
.await?;
|
||||
/*
|
||||
// TODO: This should be create token
|
||||
// the requited proofs for the token amount may already be in the wallet and mint is not needed
|
||||
// Mint a token
|
||||
pub async fn mint_token(
|
||||
&mut self,
|
||||
mint_url: UncheckedUrl,
|
||||
amount: Amount,
|
||||
memo: Option<String>,
|
||||
unit: Option<CurrencyUnit>,
|
||||
) -> Result<Token, Error> {
|
||||
let quote = self
|
||||
.mint_quote(
|
||||
mint_url.clone(),
|
||||
amount,
|
||||
unit.clone()
|
||||
.ok_or(Error::Custom("Unit required".to_string()))?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let proofs = self.mint(mint_url.clone(), "e.id).await?;
|
||||
|
||||
let token = Token::new(mint_url.clone(), proofs, memo, unit);
|
||||
Ok(token?)
|
||||
}
|
||||
let proofs = self.mint(mint_url.clone(), "e.id).await?;
|
||||
|
||||
let token = Token::new(mint_url.clone(), proofs, memo, unit);
|
||||
Ok(token?)
|
||||
}
|
||||
*/
|
||||
/// Mint Quote
|
||||
pub async fn mint_quote(
|
||||
&mut self,
|
||||
@@ -225,7 +228,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
}
|
||||
|
||||
/// Mint
|
||||
pub async fn mint(&mut self, mint_url: UncheckedUrl, quote_id: &str) -> Result<Proofs, Error> {
|
||||
pub async fn mint(&mut self, mint_url: UncheckedUrl, quote_id: &str) -> Result<Amount, Error> {
|
||||
let quote_info = self.localstore.get_mint_quote(quote_id).await?;
|
||||
|
||||
let quote_info = if let Some(quote) = quote_info {
|
||||
@@ -271,29 +274,28 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
&keys,
|
||||
)?;
|
||||
|
||||
let minted_amount = proofs.iter().map(|p| p.amount).sum();
|
||||
|
||||
// Remove filled quote from store
|
||||
self.localstore.remove_mint_quote("e_info.id).await?;
|
||||
|
||||
Ok(proofs)
|
||||
// Add new proofs to store
|
||||
self.localstore.add_proofs(mint_url, proofs).await?;
|
||||
|
||||
Ok(minted_amount)
|
||||
}
|
||||
|
||||
/// Receive
|
||||
pub async fn receive(&mut self, encoded_token: &str) -> Result<Proofs, Error> {
|
||||
pub async fn receive(&mut self, encoded_token: &str) -> Result<(), Error> {
|
||||
let token_data = Token::from_str(encoded_token)?;
|
||||
|
||||
let unit = token_data.unit.unwrap_or_default();
|
||||
|
||||
let mut proofs: Vec<Proofs> = vec![vec![]];
|
||||
let mut proofs: HashMap<UncheckedUrl, Proofs> = HashMap::new();
|
||||
for token in token_data.token {
|
||||
if token.proofs.is_empty() {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
let keys = if token.mint.to_string().eq(&self.mint_url.to_string()) {
|
||||
self.mint_keys.clone()
|
||||
} else {
|
||||
self.client.get_mint_keys(token.mint.try_into()?).await?
|
||||
};
|
||||
*/
|
||||
|
||||
let active_keyset_id = self.active_mint_keyset(&token.mint, &unit).await?;
|
||||
|
||||
@@ -305,7 +307,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
let amount: Amount = token.proofs.iter().map(|p| p.amount).sum();
|
||||
|
||||
let pre_swap = self
|
||||
.create_split(&token.mint, &unit, Some(amount), token.proofs)
|
||||
.create_swap(&token.mint, &unit, Some(amount), token.proofs)
|
||||
.await?;
|
||||
|
||||
let swap_response = self
|
||||
@@ -320,13 +322,20 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
pre_swap.pre_mint_secrets.secrets(),
|
||||
&keys.unwrap(),
|
||||
)?;
|
||||
proofs.push(p);
|
||||
let mint_proofs = proofs.entry(token.mint).or_insert(Vec::new());
|
||||
|
||||
mint_proofs.extend(p);
|
||||
}
|
||||
Ok(proofs.iter().flatten().cloned().collect())
|
||||
|
||||
for (mint, proofs) in proofs {
|
||||
self.localstore.add_proofs(mint, proofs).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create Split Payload
|
||||
async fn create_split(
|
||||
async fn create_swap(
|
||||
&mut self,
|
||||
mint_url: &UncheckedUrl,
|
||||
unit: &CurrencyUnit,
|
||||
@@ -363,7 +372,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn process_split_response(
|
||||
pub async fn process_swap_response(
|
||||
&self,
|
||||
blinded_messages: PreMintSecrets,
|
||||
promises: Vec<BlindedSignature>,
|
||||
@@ -412,7 +421,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
}
|
||||
|
||||
let pre_swap = self
|
||||
.create_split(mint_url, unit, Some(amount), proofs)
|
||||
.create_swap(mint_url, unit, Some(amount), proofs)
|
||||
.await?;
|
||||
|
||||
let swap_response = self
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// https://github.com/cashubtc/nuts/blob/main/00.md
|
||||
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -409,6 +410,12 @@ pub struct Proof {
|
||||
pub c: PublicKey,
|
||||
}
|
||||
|
||||
impl Hash for Proof {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.secret.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Proof {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.amount.cmp(&other.amount)
|
||||
|
||||
Reference in New Issue
Block a user