thesimplekid 1 yıl önce
ebeveyn
işleme
92c3b69c47
5 değiştirilmiş dosya ile 86 ekleme ve 2 silme
  1. 1 0
      src/cashu_mint.rs
  2. 58 2
      src/cashu_wallet.rs
  3. 3 0
      src/error.rs
  4. 7 0
      src/types.rs
  5. 17 0
      tests/integration_test.rs

+ 1 - 0
src/cashu_mint.rs

@@ -109,6 +109,7 @@ impl CashuMint {
 
         // TODO: need to handle response error
         // specfically token already spent
+        println!("{:?}", res);
 
         Ok(serde_json::from_value(res).unwrap())
     }

+ 58 - 2
src/cashu_wallet.rs

@@ -7,8 +7,8 @@ use crate::{
     dhke::construct_proof,
     error::Error,
     types::{
-        BlindedMessages, MintKeys, Proof, ProofsStatus, RequestMintResponse, SplitPayload,
-        SplitRequest, TokenData,
+        BlindedMessages, MintKeys, Proof, ProofsStatus, RequestMintResponse, SendProofs,
+        SplitPayload, SplitRequest, TokenData,
     },
 };
 
@@ -102,6 +102,7 @@ impl CashuWallet {
         Ok(proofs.iter().flatten().cloned().collect())
     }
 
+    /// Create Split Payload
     pub async fn create_split(
         &self,
         keep_amount: Amount,
@@ -128,4 +129,59 @@ impl CashuWallet {
             split_payload,
         })
     }
+
+    /// Send
+    pub async fn send(&self, amount: Amount, proofs: Vec<Proof>) -> Result<SendProofs, Error> {
+        let mut amount_avaliable = Amount::ZERO;
+        let mut send_proofs = SendProofs::default();
+
+        for proof in proofs {
+            amount_avaliable += proof.amount;
+            if amount_avaliable > amount {
+                send_proofs.change_proofs.push(proof);
+                break;
+            } else {
+                send_proofs.send_proofs.push(proof);
+            }
+        }
+
+        if amount_avaliable.lt(&amount) {
+            return Err(Error::InsufficantFunds);
+        }
+
+        // If amount avaliable is EQUAL to send amount no need to split
+        if amount_avaliable.eq(&amount) {
+            return Ok(send_proofs);
+        }
+
+        let amount_to_keep = amount_avaliable - amount;
+        let amount_to_send = amount;
+
+        let split_payload = self
+            .create_split(amount_to_keep, amount_to_send, send_proofs.send_proofs)
+            .await?;
+
+        let split_response = self.mint.split(split_payload.split_payload).await?;
+
+        // Proof to keep
+        let keep_proofs = construct_proof(
+            split_response.fst,
+            split_payload.keep_blinded_messages.rs,
+            split_payload.keep_blinded_messages.secrets,
+            &self.keys,
+        )?;
+
+        // Proofs to send
+        let send_proofs = construct_proof(
+            split_response.snd,
+            split_payload.send_blinded_messages.rs,
+            split_payload.send_blinded_messages.secrets,
+            &self.keys,
+        )?;
+
+        Ok(SendProofs {
+            change_proofs: keep_proofs,
+            send_proofs,
+        })
+    }
 }

+ 3 - 0
src/error.rs

@@ -23,4 +23,7 @@ pub enum Error {
     /// Base64 error
     #[error("Base64 error: {0}")]
     Base64Error(#[from] base64::DecodeError),
+    /// Insufficaint Funds
+    #[error("Not enough funds")]
+    InsufficantFunds,
 }

+ 7 - 0
src/types.rs

@@ -147,6 +147,7 @@ pub struct PostMintResponse {
 }
 
 /// Check Fees Response [NUT-05]
+
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct CheckFeesResponse {
     /// Expected Mac Fee in satoshis    
@@ -219,6 +220,12 @@ pub struct ProofsStatus {
     pub spent: Vec<Proof>,
 }
 
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SendProofs {
+    pub change_proofs: Vec<Proof>,
+    pub send_proofs: Vec<Proof>,
+}
+
 /// Mint Version
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct MintVersion {

+ 17 - 0
tests/integration_test.rs

@@ -83,6 +83,23 @@ async fn test_receive() {
     println!("{:?}", prom);
 }
 
+// #[ignore]
+#[tokio::test]
+async fn test_send() {
+    let url = Url::from_str(MINTURL).unwrap();
+    let mint = CashuMint::new(url);
+    let mint_keys = mint.get_keys().await.unwrap();
+
+    let wallet = CashuWallet::new(mint, mint_keys);
+    // FIXME: Have to manully paste an unspent token
+    let token = "cashuAeyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6Im9DV2NkWXJyeVRrUiIsImFtb3VudCI6MSwiQyI6IjAyMjRhMjU5NGY5NWMyMmRiZTA2YjZlN2YzMDNkYTdiZWYwNmM1YzI5YTBjMDU3ZWYyNmNhOWU3ZDVlYzc3MTYzZiIsInNlY3JldCI6IncyL1FpZjZFdlBRYWRtUlYxZzQyTWMrZWVVZ1V3TVZtSC9ndlVlaHhZTXM9In0seyJpZCI6Im9DV2NkWXJyeVRrUiIsImFtb3VudCI6NCwiQyI6IjAyMWEwYTIwYTZmOGEwY2JmMWY2Njc5OTIzNWE5N2U4ZTgxNjkxZWExMTFkMWVjYWJiOWZlZjE5OWRhMzYxNmU0YiIsInNlY3JldCI6InFYazRGbjZKdFBaUnVIRWlFMVVBUDB4MCtEcjd4Y21yNWRwTUVRRldDZ2s9In1dLCJtaW50IjoiaHR0cHM6Ly9sZWdlbmQubG5iaXRzLmNvbS9jYXNodS9hcGkvdjEvU0t2SFJ1czlkbWpXSGhzdEhyc2F6VyJ9XX0=";
+
+    let prom = wallet.receive(token).await.unwrap();
+    let send = wallet.send(Amount::from_sat(1), prom).await.unwrap();
+
+    println!("{:?}", send);
+}
+
 #[ignore]
 #[tokio::test]
 async fn test_get_mint_info() {