Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into nostr-nip-60-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
davidcaseria committed Aug 8, 2024
2 parents e705b6c + 885b0ee commit d5cc9fe
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 28 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
- cdk(cdk-database/wallet): Change `get_proofs` to return `Vec<ProofInfo>` instead of `Option<Vec<ProofInfo>>` ([thesimplekid]).
- cdk-cli: Receive will add wallet when receiving if mint is unknown ([thesimplekid]).
- cdk(cdk-database/mint): Rename `get_blinded_signatures` to `get_blind_signatures` ([thesimplekid]).
- cdk(cdk-database/mint):rename `get_blinded_signatures_for_keyset` to `get_blind_signatures_for_keyset` ([thesimplekid]).
- cdk(cdk-database/mint): Rename `get_blinded_signatures_for_keyset` to `get_blind_signatures_for_keyset` ([thesimplekid]).
- cdk(mint): typo rename `total_redeame` to `total_redeemed` ([vnprc])
- cdk(mint): Refactored `MintKeySet::generate_from_xpriv` and `MintKeySet::generate_from_seed` methods to accept max_order, currency_unit, and derivation_path parameters directly ([vnrpc]).
- cdk(wallet): Return WalletKey for UnknownWallet error ([davidcaseria]).

### Added
- cdk(NUT-11): Add `Copy` on `SigFlag` ([thesimplekid]).
Expand Down
173 changes: 171 additions & 2 deletions crates/cdk/src/mint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ impl Mint {
let keyset = MintKeySet::generate_from_xpriv(
&secp_ctx,
xpriv,
highest_index_keyset.clone(),
highest_index_keyset.max_order,
highest_index_keyset.unit,
highest_index_keyset.derivation_path.clone(),
);
active_keysets.insert(id, keyset);
let mut keyset_info = highest_index_keyset;
Expand Down Expand Up @@ -1156,7 +1158,13 @@ impl Mint {
/// Generate [`MintKeySet`] from [`MintKeySetInfo`]
#[instrument(skip_all)]
pub fn generate_keyset(&self, keyset_info: MintKeySetInfo) -> MintKeySet {
MintKeySet::generate_from_xpriv(&self.secp_ctx, self.xpriv, keyset_info)
MintKeySet::generate_from_xpriv(
&self.secp_ctx,
self.xpriv,
keyset_info.max_order,
keyset_info.unit,
keyset_info.derivation_path,
)
}

/// Get the total amount issed by keyset
Expand Down Expand Up @@ -1296,3 +1304,164 @@ fn derivation_path_from_unit(unit: CurrencyUnit, index: u32) -> DerivationPath {
ChildNumber::from_hardened_idx(index).expect("0 is a valid index"),
])
}

#[cfg(test)]
mod tests {
use bitcoin::Network;
use secp256k1::Secp256k1;

use super::*;

#[test]
fn mint_mod_generate_keyset_from_seed() {
let seed = "test_seed".as_bytes();
let keyset = MintKeySet::generate_from_seed(
&Secp256k1::new(),
seed,
2,
CurrencyUnit::Sat,
derivation_path_from_unit(CurrencyUnit::Sat, 0),
);

assert_eq!(keyset.unit, CurrencyUnit::Sat);
assert_eq!(keyset.keys.len(), 2);

let expected_amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = vec![
(
Amount::from(1),
PublicKey::from_hex(
"0257aed43bf2c1cdbe3e7ae2db2b27a723c6746fc7415e09748f6847916c09176e",
)
.unwrap(),
),
(
Amount::from(2),
PublicKey::from_hex(
"03ad95811e51adb6231613f9b54ba2ba31e4442c9db9d69f8df42c2b26fbfed26e",
)
.unwrap(),
),
]
.into_iter()
.collect();

let amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = keyset
.keys
.iter()
.map(|(amount, pair)| (*amount, pair.public_key))
.collect();

assert_eq!(amounts_and_pubkeys, expected_amounts_and_pubkeys);
}

#[test]
fn mint_mod_generate_keyset_from_xpriv() {
let seed = "test_seed".as_bytes();
let network = Network::Bitcoin;
let xpriv = ExtendedPrivKey::new_master(network, seed).expect("Failed to create xpriv");
let keyset = MintKeySet::generate_from_xpriv(
&Secp256k1::new(),
xpriv,
2,
CurrencyUnit::Sat,
derivation_path_from_unit(CurrencyUnit::Sat, 0),
);

assert_eq!(keyset.unit, CurrencyUnit::Sat);
assert_eq!(keyset.keys.len(), 2);

let expected_amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = vec![
(
Amount::from(1),
PublicKey::from_hex(
"0257aed43bf2c1cdbe3e7ae2db2b27a723c6746fc7415e09748f6847916c09176e",
)
.unwrap(),
),
(
Amount::from(2),
PublicKey::from_hex(
"03ad95811e51adb6231613f9b54ba2ba31e4442c9db9d69f8df42c2b26fbfed26e",
)
.unwrap(),
),
]
.into_iter()
.collect();

let amounts_and_pubkeys: HashSet<(Amount, PublicKey)> = keyset
.keys
.iter()
.map(|(amount, pair)| (*amount, pair.public_key))
.collect();

assert_eq!(amounts_and_pubkeys, expected_amounts_and_pubkeys);
}

use cdk_database::mint_memory::MintMemoryDatabase;

#[tokio::test]
async fn mint_mod_new_mint() {
// mock DB settings
let active_keysets: HashMap<CurrencyUnit, Id> = HashMap::new();
let keysets: Vec<MintKeySetInfo> = Vec::new();
let mint_quotes: Vec<MintQuote> = Vec::new();
let melt_quotes: Vec<MeltQuote> = Vec::new();
let pending_proofs: Proofs = Proofs::new();
let spent_proofs: Proofs = Proofs::new();
let blinded_signatures: HashMap<[u8; 33], BlindSignature> = HashMap::new();

// Mock data
let mint_url = "http://example.com";
let seed = b"some_random_seed";
let mint_info = MintInfo::default();
let localstore = Arc::new(
MintMemoryDatabase::new(
active_keysets,
keysets,
mint_quotes,
melt_quotes,
pending_proofs,
spent_proofs,
blinded_signatures,
)
.unwrap(),
);
let supported_units: HashMap<CurrencyUnit, (u64, u8)> = HashMap::new();

// Instantiate a new Mint
let mint = Mint::new(mint_url, seed, mint_info, localstore, supported_units).await;

// Assert the mint was created successfully
assert!(mint.is_ok());
let mint = mint.unwrap();

assert_eq!(mint.get_mint_url().to_string(), "http://example.com");
let info = mint.mint_info();
assert!(info.name.is_none());
assert!(info.pubkey.is_none());
assert_eq!(
mint.pubkeys().await.unwrap(),
KeysResponse {
keysets: Vec::new()
}
);

assert_eq!(
mint.keysets().await.unwrap(),
KeysetResponse {
keysets: Vec::new()
}
);

assert_eq!(
mint.total_issued().await.unwrap(),
HashMap::<nut02::Id, Amount>::new()
);

assert_eq!(
mint.total_redeemed().await.unwrap(),
HashMap::<nut02::Id, Amount>::new()
);
}
}
24 changes: 12 additions & 12 deletions crates/cdk/src/nuts/nut02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use std::array::TryFromSliceError;
#[cfg(feature = "mint")]
use std::collections::BTreeMap;

#[cfg(feature = "mint")]
use bitcoin::bip32::DerivationPath;
#[cfg(feature = "mint")]
use bitcoin::bip32::{ChildNumber, ExtendedPrivKey};
use bitcoin::hashes::sha256::Hash as Sha256;
Expand All @@ -23,8 +25,6 @@ use thiserror::Error;
use super::nut01::Keys;
#[cfg(feature = "mint")]
use super::nut01::{MintKeyPair, MintKeys};
#[cfg(feature = "mint")]
use crate::mint::MintKeySetInfo;
use crate::nuts::nut00::CurrencyUnit;
use crate::util::hex;
#[cfg(feature = "mint")]
Expand Down Expand Up @@ -324,18 +324,18 @@ impl MintKeySet {
pub fn generate_from_seed<C: secp256k1::Signing>(
secp: &Secp256k1<C>,
seed: &[u8],
info: MintKeySetInfo,
max_order: u8,
currency_unit: CurrencyUnit,
derivation_path: DerivationPath,
) -> Self {
let xpriv =
ExtendedPrivKey::new_master(bitcoin::Network::Bitcoin, seed).expect("RNG busted");
let max_order = info.max_order;
let unit = info.unit;
Self::generate(
secp,
xpriv
.derive_priv(secp, &info.derivation_path)
.derive_priv(secp, &derivation_path)
.expect("RNG busted"),
unit,
currency_unit,
max_order,
)
}
Expand All @@ -344,16 +344,16 @@ impl MintKeySet {
pub fn generate_from_xpriv<C: secp256k1::Signing>(
secp: &Secp256k1<C>,
xpriv: ExtendedPrivKey,
info: MintKeySetInfo,
max_order: u8,
currency_unit: CurrencyUnit,
derivation_path: DerivationPath,
) -> Self {
let max_order = info.max_order;
let unit = info.unit;
Self::generate(
secp,
xpriv
.derive_priv(secp, &info.derivation_path)
.derive_priv(secp, &derivation_path)
.expect("RNG busted"),
unit,
currency_unit,
max_order,
)
}
Expand Down
8 changes: 5 additions & 3 deletions crates/cdk/src/wallet/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use thiserror::Error;
use crate::cdk_database;
use crate::error::{ErrorCode, ErrorResponse};

use super::multi_mint_wallet::WalletKey;

/// Wallet Error
#[derive(Debug, Error)]
pub enum Error {
Expand Down Expand Up @@ -76,9 +78,9 @@ pub enum Error {
UnknownErrorResponse(String),
/// Unknown Wallet
#[error("Unknown Wallet: `{0}`")]
UnknownWallet(String),
/// Unknown Wallet
#[error("Unknown Wallet: `{0}`")]
UnknownWallet(WalletKey),
/// Incorrect Wallet
#[error("Incorrect Wallet: `{0}`")]
IncorrectWallet(String),
/// Max Fee Ecxeded
#[error("Max fee exceeded")]
Expand Down
20 changes: 10 additions & 10 deletions crates/cdk/src/wallet/multi_mint_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

wallet
.send(
Expand All @@ -153,7 +153,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

wallet.mint_quote(amount).await
}
Expand All @@ -171,7 +171,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(&wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

let amount = wallet.check_all_mint_quotes().await?;
amount_minted.insert(wallet.unit, amount);
Expand Down Expand Up @@ -202,7 +202,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;
wallet
.mint(quote_id, SplitTarget::default(), conditions)
.await
Expand All @@ -228,14 +228,14 @@ impl MultiMintWallet {
for (mint_url, proofs) in mint_proofs {
let wallet_key = WalletKey::new(mint_url.clone(), unit);
if !self.has(&wallet_key).await {
return Err(Error::UnknownWallet(wallet_key.to_string()));
return Err(Error::UnknownWallet(wallet_key.clone()));
}

let wallet_key = WalletKey::new(mint_url, unit);
let wallet = self
.get_wallet(&wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

let amount = wallet
.receive_proofs(proofs, SplitTarget::default(), p2pk_signing_keys, preimages)
Expand All @@ -258,7 +258,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

let quote = wallet.melt_quote(bolt11.to_string(), None).await?;
if let Some(max_fee) = max_fee {
Expand All @@ -276,7 +276,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

wallet.restore().await
}
Expand All @@ -292,7 +292,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

wallet.verify_token_p2pk(token, conditions)
}
Expand All @@ -307,7 +307,7 @@ impl MultiMintWallet {
let wallet = self
.get_wallet(wallet_key)
.await
.ok_or(Error::UnknownWallet(wallet_key.to_string()))?;
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;

wallet.verify_token_dleq(token).await
}
Expand Down

0 comments on commit d5cc9fe

Please sign in to comment.