refactor: signing keys as part of wallet

This commit is contained in:
thesimplekid
2024-06-01 00:21:28 +01:00
parent 163b165d76
commit 6103bb1d87
2 changed files with 57 additions and 39 deletions

View File

@@ -3,7 +3,7 @@ use std::str::FromStr;
use std::sync::Arc;
use cdk::amount::SplitTarget;
use cdk::nuts::{Proofs, SecretKey};
use cdk::nuts::Proofs;
use cdk::url::UncheckedUrl;
use cdk::wallet::Wallet;
use cdk::Amount;
@@ -11,6 +11,7 @@ use cdk_rexie::RexieWalletDatabase;
use wasm_bindgen::prelude::*;
use crate::error::{into_err, Result};
use crate::nuts::nut01::JsSecretKey;
use crate::nuts::nut04::JsMintQuoteBolt11Response;
use crate::nuts::nut05::JsMeltQuoteBolt11Response;
use crate::nuts::nut11::JsP2PKSpendingConditions;
@@ -40,10 +41,18 @@ impl From<Wallet> for JsWallet {
#[wasm_bindgen(js_class = Wallet)]
impl JsWallet {
#[wasm_bindgen(constructor)]
pub async fn new(seed: Vec<u8>) -> Self {
pub async fn new(seed: Vec<u8>, p2pk_signing_keys: Vec<JsSecretKey>) -> Self {
let db = RexieWalletDatabase::new().await.unwrap();
Wallet::new(Arc::new(db), &seed).into()
Wallet::new(
Arc::new(db),
&seed,
p2pk_signing_keys
.into_iter()
.map(|s| s.deref().clone())
.collect(),
)
.into()
}
#[wasm_bindgen(js_name = unitBalance)]
@@ -253,23 +262,12 @@ impl JsWallet {
}
#[wasm_bindgen(js_name = receive)]
pub async fn receive(
&mut self,
encoded_token: String,
signing_keys: JsValue,
preimages: JsValue,
) -> Result<JsAmount> {
let signing_keys: Option<Vec<SecretKey>> = serde_wasm_bindgen::from_value(signing_keys)?;
pub async fn receive(&mut self, encoded_token: String, preimages: JsValue) -> Result<JsAmount> {
let preimages: Option<Vec<String>> = serde_wasm_bindgen::from_value(preimages)?;
Ok(self
.inner
.receive(
&encoded_token,
&SplitTarget::default(),
signing_keys,
preimages,
)
.receive(&encoded_token, &SplitTarget::default(), preimages)
.await
.map_err(into_err)?
.into())

View File

@@ -2,18 +2,21 @@
use std::collections::{HashMap, HashSet};
use std::num::ParseIntError;
use std::ops::Deref;
use std::str::FromStr;
use std::sync::Arc;
use bitcoin::bip32::ExtendedPrivKey;
use bitcoin::hashes::sha256::Hash as Sha256Hash;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::XOnlyPublicKey;
use bitcoin::Network;
#[cfg(feature = "nostr")]
use nostr_sdk::nips::nip04;
#[cfg(feature = "nostr")]
use nostr_sdk::{Filter, Timestamp};
use thiserror::Error;
use tokio::sync::RwLock;
use tracing::instrument;
use crate::amount::SplitTarget;
@@ -107,6 +110,7 @@ pub struct Wallet {
pub client: HttpClient,
pub localstore: Arc<dyn WalletDatabase<Err = cdk_database::Error> + Send + Sync>,
xpriv: ExtendedPrivKey,
p2pk_signing_keys: Arc<RwLock<HashMap<XOnlyPublicKey, SecretKey>>>,
#[cfg(feature = "nostr")]
nostr_client: nostr_sdk::Client,
}
@@ -115,6 +119,7 @@ impl Wallet {
pub fn new(
localstore: Arc<dyn WalletDatabase<Err = cdk_database::Error> + Send + Sync>,
seed: &[u8],
p2pk_signing_keys: Vec<SecretKey>,
) -> Self {
let xpriv = ExtendedPrivKey::new_master(Network::Bitcoin, seed)
.expect("Could not create master key");
@@ -123,11 +128,38 @@ impl Wallet {
client: HttpClient::new(),
localstore,
xpriv,
p2pk_signing_keys: Arc::new(RwLock::new(
p2pk_signing_keys
.into_iter()
.map(|s| (s.public_key().x_only_public_key(), s))
.collect(),
)),
#[cfg(feature = "nostr")]
nostr_client: nostr_sdk::Client::default(),
}
}
/// Add P2PK signing key to wallet
#[instrument(skip_all)]
pub async fn add_p2pk_signing_key(&self, signing_key: SecretKey) {
self.p2pk_signing_keys
.write()
.await
.insert(signing_key.public_key().x_only_public_key(), signing_key);
}
/// Remove P2PK signing key from wallet
#[instrument(skip_all)]
pub async fn remove_p2pk_signing_key(&self, x_only_pubkey: &XOnlyPublicKey) {
self.p2pk_signing_keys.write().await.remove(x_only_pubkey);
}
/// P2PK keys available in wallet
#[instrument(skip(self))]
pub async fn available_p2pk_signing_keys(&self) -> HashMap<XOnlyPublicKey, SecretKey> {
self.p2pk_signing_keys.read().await.deref().clone()
}
/// Add nostr relays to client
#[cfg(feature = "nostr")]
#[instrument(skip(self))]
@@ -1299,7 +1331,6 @@ impl Wallet {
&self,
encoded_token: &str,
amount_split_target: &SplitTarget,
signing_keys: Option<Vec<SecretKey>>,
preimages: Option<Vec<String>>,
) -> Result<Amount, Error> {
let token_data = Token::from_str(encoded_token)?;
@@ -1333,14 +1364,6 @@ impl Wallet {
let mut sig_flag = SigFlag::SigInputs;
let pubkey_secret_key = match &signing_keys {
Some(signing_keys) => signing_keys
.iter()
.map(|s| (s.public_key().x_only_public_key(), s))
.collect(),
None => HashMap::new(),
};
// Map hash of preimage to preimage
let hashed_to_preimage = match preimages {
Some(ref preimages) => preimages
@@ -1353,6 +1376,8 @@ impl Wallet {
None => HashMap::new(),
};
let p2pk_signing_keys = self.p2pk_signing_keys.read().await;
for proof in &mut proofs {
// Verify that proof DLEQ is valid
if proof.dleq.is_some() {
@@ -1386,7 +1411,7 @@ impl Wallet {
}
for pubkey in pubkeys {
if let Some(signing) =
pubkey_secret_key.get(&pubkey.x_only_public_key())
p2pk_signing_keys.get(&pubkey.x_only_public_key())
{
proof.sign_p2pk(signing.to_owned().clone())?;
}
@@ -1412,7 +1437,7 @@ impl Wallet {
if sig_flag.eq(&SigFlag::SigAll) {
for blinded_message in &mut pre_swap.swap_request.outputs {
for signing_key in pubkey_secret_key.values() {
for signing_key in p2pk_signing_keys.values() {
blinded_message.sign_p2pk(signing_key.to_owned().clone())?
}
}
@@ -1463,8 +1488,12 @@ impl Wallet {
let verifying_key = nostr_signing_key.public_key();
let nostr_pubkey =
nostr_sdk::PublicKey::from_hex(verifying_key.x_only_public_key().to_string())?;
let x_only_pubkey = verifying_key.x_only_public_key();
let nostr_pubkey = nostr_sdk::PublicKey::from_hex(x_only_pubkey.to_string())?;
let keys = Keys::from_str(&(nostr_signing_key).to_secret_hex())?;
self.add_p2pk_signing_key(nostr_signing_key).await;
let filter = match self
.localstore
@@ -1484,7 +1513,6 @@ impl Wallet {
let events = self.nostr_client.get_events_of(vec![filter], None).await?;
let keys = Keys::from_str(&nostr_signing_key.to_secret_hex()).unwrap();
let mut tokens: HashSet<String> = HashSet::new();
for event in events {
@@ -1503,15 +1531,7 @@ impl Wallet {
let mut total_received = Amount::ZERO;
for token in tokens.iter() {
match self
.receive(
token,
&amount_split_target,
Some(vec![nostr_signing_key.clone()]),
None,
)
.await
{
match self.receive(token, &amount_split_target, None).await {
Ok(amount) => total_received += amount,
Err(err) => {
tracing::error!("Could not receive token: {}", err);