浏览代码

refactor: premintsecrets from p2pk conditions

thesimplekid 1 年之前
父节点
当前提交
2bacda4a56
共有 4 个文件被更改,包括 111 次插入37 次删除
  1. 5 2
      crates/cashu-sdk/src/wallet/mod.rs
  2. 2 0
      crates/cashu/src/error.rs
  3. 54 23
      crates/cashu/src/nuts/nut00.rs
  4. 50 12
      crates/cashu/src/nuts/nut11.rs

+ 5 - 2
crates/cashu-sdk/src/wallet/mod.rs

@@ -385,7 +385,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
         Ok(())
     }
 
-    /// Create Split Payload
+    /// Create Swap Payload
     async fn create_swap(
         &mut self,
         mint_url: &UncheckedUrl,
@@ -393,7 +393,7 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
         amount: Option<Amount>,
         proofs: Proofs,
     ) -> Result<PreSwap, Error> {
-        // Since split is used to get the needed combination of tokens for a specific
+        // Since swap is used to get the needed combination of tokens for a specific
         // amount first blinded messages are created for the amount
 
         let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?.unwrap();
@@ -510,6 +510,9 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
         self.localstore
             .add_pending_proofs(mint_url.clone(), proofs)
             .await?;
+        self.localstore
+            .add_pending_proofs(mint_url.clone(), send_proofs.clone())
+            .await?;
 
         self.localstore
             .add_proofs(mint_url.clone(), keep_proofs)

+ 2 - 0
crates/cashu/src/error.rs

@@ -48,6 +48,8 @@ pub enum Error {
     Key,
     #[error("Invalid signature")]
     InvalidSignature,
+    #[error("Locktime in past")]
+    LocktimeInPast,
     /// Custom error
     #[error("`{0}`")]
     CustomError(String),

+ 54 - 23
crates/cashu/src/nuts/nut00.rs

@@ -100,7 +100,7 @@ pub mod wallet {
     use super::{CurrencyUnit, MintProofs};
     use crate::dhke::blind_message;
     use crate::error::wallet;
-    use crate::nuts::{BlindedMessage, Id, Proofs, SecretKey};
+    use crate::nuts::{BlindedMessage, Id, P2PKConditions, Proofs, SecretKey};
     use crate::secret::Secret;
     use crate::url::UncheckedUrl;
     use crate::{error, Amount};
@@ -134,28 +134,6 @@ pub mod wallet {
         secrets: Vec<PreMint>,
     }
 
-    // Implement Iterator for PreMintSecrets
-    impl Iterator for PreMintSecrets {
-        type Item = PreMint;
-
-        fn next(&mut self) -> Option<Self::Item> {
-            // Use the iterator of the vector
-            self.secrets.pop()
-        }
-    }
-
-    impl Ord for PreMintSecrets {
-        fn cmp(&self, other: &Self) -> Ordering {
-            self.secrets.cmp(&other.secrets)
-        }
-    }
-
-    impl PartialOrd for PreMintSecrets {
-        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-            Some(self.cmp(other))
-        }
-    }
-
     impl PreMintSecrets {
         /// Outputs for speceifed amount with random secret
         pub fn random(keyset_id: Id, amount: Amount) -> Result<Self, wallet::Error> {
@@ -278,6 +256,37 @@ pub mod wallet {
             Ok(pre_mint_secrets)
         }
 
+        #[cfg(feature = "nut11")]
+        pub fn with_p2pk_conditions(
+            keyset_id: Id,
+            amount: Amount,
+            conditions: P2PKConditions,
+        ) -> Result<Self, wallet::Error> {
+            let amount_split = amount.split();
+
+            let mut output = Vec::with_capacity(amount_split.len());
+
+            for amount in amount_split {
+                let secret: Secret = conditions.clone().try_into().unwrap();
+                let (blinded, r) = blind_message(&secret.to_bytes()?, None)?;
+
+                let blinded_message = BlindedMessage {
+                    amount,
+                    b: blinded,
+                    keyset_id,
+                };
+
+                output.push(PreMint {
+                    secret,
+                    blinded_message,
+                    r: r.into(),
+                    amount,
+                });
+            }
+
+            Ok(PreMintSecrets { secrets: output })
+        }
+
         pub fn iter(&self) -> impl Iterator<Item = &PreMint> {
             self.secrets.iter()
         }
@@ -322,6 +331,28 @@ pub mod wallet {
         }
     }
 
+    // Implement Iterator for PreMintSecrets
+    impl Iterator for PreMintSecrets {
+        type Item = PreMint;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            // Use the iterator of the vector
+            self.secrets.pop()
+        }
+    }
+
+    impl Ord for PreMintSecrets {
+        fn cmp(&self, other: &Self) -> Ordering {
+            self.secrets.cmp(&other.secrets)
+        }
+    }
+
+    impl PartialOrd for PreMintSecrets {
+        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+            Some(self.cmp(other))
+        }
+    }
+
     #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
     pub struct Token {
         pub token: Vec<MintProofs>,

+ 50 - 12
crates/cashu/src/nuts/nut11.rs

@@ -80,13 +80,41 @@ impl PartialOrd for Proof {
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct P2PKConditions {
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub locktime: Option<u64>,
     pub pubkeys: Vec<PublicKey>,
-    pub refund_keys: Option<Vec<PublicKey>>,
+    #[serde(default)]
+    #[serde(skip_serializing_if = "Vec::is_empty")]
+    pub refund_keys: Vec<PublicKey>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub num_sigs: Option<u64>,
     pub sig_flag: SigFlag,
 }
 
+impl P2PKConditions {
+    pub fn new(
+        locktime: Option<u64>,
+        pubkeys: Vec<PublicKey>,
+        refund_keys: Vec<PublicKey>,
+        num_sigs: Option<u64>,
+        sig_flag: Option<SigFlag>,
+    ) -> Result<Self, Error> {
+        if let Some(locktime) = locktime {
+            if locktime.lt(&unix_time()) {
+                return Err(Error::LocktimeInPast);
+            }
+        }
+
+        Ok(Self {
+            locktime,
+            pubkeys,
+            refund_keys,
+            num_sigs,
+            sig_flag: sig_flag.unwrap_or_default(),
+        })
+    }
+}
+
 impl TryFrom<P2PKConditions> for Secret {
     type Error = Error;
     fn try_from(conditions: P2PKConditions) -> Result<Secret, Self::Error> {
@@ -119,7 +147,7 @@ impl TryFrom<P2PKConditions> for Secret {
             tags.push(Tag::NSigs(num_sigs).as_vec());
         }
 
-        if let Some(refund_keys) = refund_keys {
+        if !refund_keys.is_empty() {
             tags.push(Tag::Refund(refund_keys).as_vec())
         }
 
@@ -136,6 +164,15 @@ impl TryFrom<P2PKConditions> for Secret {
     }
 }
 
+impl TryFrom<P2PKConditions> for crate::secret::Secret {
+    type Error = Error;
+    fn try_from(conditions: P2PKConditions) -> Result<crate::secret::Secret, Self::Error> {
+        let secret: Secret = conditions.try_into()?;
+
+        secret.try_into()
+    }
+}
+
 impl TryFrom<Secret> for P2PKConditions {
     type Error = Error;
     fn try_from(secret: Secret) -> Result<P2PKConditions, Self::Error> {
@@ -171,11 +208,11 @@ impl TryFrom<Secret> for P2PKConditions {
 
         let refund_keys = if let Some(tag) = tags.get(&TagKind::Refund) {
             match tag {
-                Tag::Refund(keys) => Some(keys.clone()),
-                _ => None,
+                Tag::Refund(keys) => keys.clone(),
+                _ => vec![],
             }
         } else {
-            None
+            vec![]
         };
 
         let sig_flag = if let Some(tag) = tags.get(&TagKind::SigFlag) {
@@ -246,9 +283,9 @@ impl Proof {
         if let Some(locktime) = spending_conditions.locktime {
             // If lock time has passed check if refund witness signature is valid
             if locktime.lt(&unix_time()) {
-                if let Some(refund_pubkeys) = &spending_conditions.refund_keys {
+                if !spending_conditions.refund_keys.is_empty() {
                     for s in &self.witness.signatures {
-                        for v in refund_pubkeys {
+                        for v in &spending_conditions.refund_keys {
                             let sig = Signature::try_from(s.as_bytes())
                                 .map_err(|_| Error::InvalidSignature)?;
                             let v: VerifyingKey = v.clone().try_into()?;
@@ -325,10 +362,11 @@ where
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash)]
+#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash)]
 pub enum SigFlag {
-    SigAll,
+    #[default]
     SigInputs,
+    SigAll,
     Custom(String),
 }
 
@@ -506,10 +544,10 @@ mod tests {
                 )
                 .unwrap(),
             ],
-            refund_keys: Some(vec![PublicKey::from_str(
+            refund_keys: vec![PublicKey::from_str(
                 "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e",
             )
-            .unwrap()]),
+            .unwrap()],
             num_sigs: Some(2),
             sig_flag: SigFlag::SigAll,
         };
@@ -545,7 +583,7 @@ mod tests {
         let conditions = P2PKConditions {
             locktime: None,
             pubkeys: vec![v_key.into()],
-            refund_keys: None,
+            refund_keys: vec![],
             num_sigs: None,
             sig_flag: SigFlag::SigInputs,
         };