浏览代码

refactor: update send functionality across wallet components (#925)

* refactor: update send functionality across wallet components

---------
Co-authored-by: thesimplekid <tsk@thesimplekid.com>
David Caseria 2 月之前
父节点
当前提交
6ebcbba0c4

+ 1 - 1
crates/cdk-cli/src/sub_commands/pay_request.rs

@@ -92,7 +92,7 @@ pub async fn pay_request(
         )
         .await?;
 
-    let token = matching_wallet.send(prepared_send, None).await?;
+    let token = prepared_send.confirm(None).await?;
 
     // We need the keysets information to properly convert from token proof to proof
     let keysets_info = match matching_wallet

+ 1 - 1
crates/cdk-cli/src/sub_commands/send.rs

@@ -221,7 +221,7 @@ pub async fn send(
             },
         )
         .await?;
-    let token = wallet.send(prepared_send, None).await?;
+    let token = prepared_send.confirm(None).await?;
 
     match sub_command_args.v3 {
         true => {

+ 2 - 5
crates/cdk-integration-tests/tests/integration_tests_pure.rs

@@ -70,11 +70,8 @@ async fn test_swap_to_send() {
                 .expect("Failed to get ys")
         )
     );
-    let token = wallet_alice
-        .send(
-            prepared_send,
-            Some(SendMemo::for_token("test_swapt_to_send")),
-        )
+    let token = prepared_send
+        .confirm(Some(SendMemo::for_token("test_swapt_to_send")))
         .await
         .expect("Failed to send token");
     let keysets_info = wallet_alice.get_mint_keysets().await.unwrap();

+ 1 - 1
crates/cdk-integration-tests/tests/test_fees.rs

@@ -64,7 +64,7 @@ async fn test_swap() {
 
     assert_eq!(fee, 1.into());
 
-    let send = wallet.send(send, None).await.unwrap();
+    let send = send.confirm(None).await.unwrap();
 
     let rec_amount = wallet
         .receive(&send.to_string(), ReceiveOptions::default())

+ 1 - 1
crates/cdk/README.md

@@ -101,7 +101,7 @@ async fn main() {
 
         // Send the token
         let prepared_send = wallet.prepare_send(Amount::ONE, SendOptions::default()).await.unwrap();
-        let token = wallet.send(prepared_send, None).await.unwrap();
+        let token = prepared_send.confirm(None).await.unwrap();
 
         println!("{}", token);
     }

+ 1 - 1
crates/cdk/examples/auth_wallet.rs

@@ -88,7 +88,7 @@ async fn main() -> Result<(), Error> {
     let prepared_send = wallet
         .prepare_send(10.into(), SendOptions::default())
         .await?;
-    let token = wallet.send(prepared_send, None).await?;
+    let token = prepared_send.confirm(None).await?;
 
     println!("Created token: {}", token);
 

+ 1 - 1
crates/cdk/examples/mint-token.rs

@@ -62,7 +62,7 @@ async fn main() -> Result<(), Error> {
 
     // Send a token with the specified amount
     let prepared_send = wallet.prepare_send(amount, SendOptions::default()).await?;
-    let token = wallet.send(prepared_send, None).await?;
+    let token = prepared_send.confirm(None).await?;
     println!("Token:");
     println!("{}", token);
 

+ 1 - 1
crates/cdk/examples/p2pk.rs

@@ -87,7 +87,7 @@ async fn main() -> Result<(), Error> {
         )
         .await?;
     println!("Fee: {}", prepared_send.fee());
-    let token = wallet.send(prepared_send, None).await?;
+    let token = prepared_send.confirm(None).await?;
 
     println!("Created token locked to pubkey: {}", secret.public_key());
     println!("{}", token);

+ 1 - 1
crates/cdk/examples/wallet.rs

@@ -59,7 +59,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
 
     // Send the token
     let prepared_send = wallet.prepare_send(amount, SendOptions::default()).await?;
-    let token = wallet.send(prepared_send, None).await?;
+    let token = prepared_send.confirm(None).await?;
 
     println!("{}", token);
 

+ 1 - 17
crates/cdk/src/wallet/multi_mint_wallet.rs

@@ -15,7 +15,7 @@ use tokio::sync::RwLock;
 use tracing::instrument;
 
 use super::receive::ReceiveOptions;
-use super::send::{PreparedSend, SendMemo, SendOptions};
+use super::send::{PreparedSend, SendOptions};
 use super::Error;
 use crate::amount::SplitTarget;
 use crate::mint_url::MintUrl;
@@ -177,22 +177,6 @@ impl MultiMintWallet {
         wallet.prepare_send(amount, opts).await
     }
 
-    /// Create cashu token
-    #[instrument(skip(self))]
-    pub async fn send(
-        &self,
-        wallet_key: &WalletKey,
-        send: PreparedSend,
-        memo: Option<SendMemo>,
-    ) -> Result<Token, Error> {
-        let wallets = self.wallets.read().await;
-        let wallet = wallets
-            .get(wallet_key)
-            .ok_or(Error::UnknownWallet(wallet_key.clone()))?;
-
-        wallet.send(send, memo).await
-    }
-
     /// Mint quote for wallet
     #[instrument(skip(self))]
     pub async fn mint_quote(

+ 90 - 86
crates/cdk/src/wallet/send.rs

@@ -21,7 +21,7 @@ impl Wallet {
     /// ```no_compile
     /// let send = wallet.prepare_send(Amount::from(10), SendOptions::default()).await?;
     /// assert!(send.fee() <= Amount::from(1));
-    /// let token = wallet.send(send, None).await?;
+    /// let token = send.confirm(None).await?;
     /// ```
     #[instrument(skip(self), err)]
     pub async fn prepare_send(
@@ -188,6 +188,7 @@ impl Wallet {
 
         // Return prepared send
         Ok(PreparedSend {
+            wallet: self.clone(),
             amount,
             options: opts,
             proofs_to_swap,
@@ -196,39 +197,92 @@ impl Wallet {
             send_fee,
         })
     }
+}
 
-    /// Finalize A Send Transaction
-    ///
-    /// This function finalizes a send transaction by constructing a token the [`PreparedSend`].
-    /// See [`Wallet::prepare_send`] for more information.
+/// Prepared send
+pub struct PreparedSend {
+    wallet: Wallet,
+    amount: Amount,
+    options: SendOptions,
+    proofs_to_swap: Proofs,
+    swap_fee: Amount,
+    proofs_to_send: Proofs,
+    send_fee: Amount,
+}
+
+impl PreparedSend {
+    /// Amount
+    pub fn amount(&self) -> Amount {
+        self.amount
+    }
+
+    /// Send options
+    pub fn options(&self) -> &SendOptions {
+        &self.options
+    }
+
+    /// Proofs to swap (i.e., proofs that need to be swapped before constructing the token)
+    pub fn proofs_to_swap(&self) -> &Proofs {
+        &self.proofs_to_swap
+    }
+
+    /// Swap fee
+    pub fn swap_fee(&self) -> Amount {
+        self.swap_fee
+    }
+
+    /// Proofs to send (i.e., proofs that will be included in the token)
+    pub fn proofs_to_send(&self) -> &Proofs {
+        &self.proofs_to_send
+    }
+
+    /// Send fee
+    pub fn send_fee(&self) -> Amount {
+        self.send_fee
+    }
+
+    /// All proofs
+    pub fn proofs(&self) -> Proofs {
+        let mut proofs = self.proofs_to_swap.clone();
+        proofs.extend(self.proofs_to_send.clone());
+        proofs
+    }
+
+    /// Total fee
+    pub fn fee(&self) -> Amount {
+        self.swap_fee + self.send_fee
+    }
+
+    /// Confirm the prepared send and create a token
     #[instrument(skip(self), err)]
-    pub async fn send(&self, send: PreparedSend, memo: Option<SendMemo>) -> Result<Token, Error> {
-        tracing::info!("Sending prepared send");
-        let total_send_fee = send.fee();
-        let mut proofs_to_send = send.proofs_to_send;
+    pub async fn confirm(self, memo: Option<SendMemo>) -> Result<Token, Error> {
+        tracing::info!("Confirming prepared send");
+        let total_send_fee = self.fee();
+        let mut proofs_to_send = self.proofs_to_send;
 
         // Get active keyset ID
-        let active_keyset_id = self.fetch_active_keyset().await?.id;
+        let active_keyset_id = self.wallet.fetch_active_keyset().await?.id;
         tracing::debug!("Active keyset ID: {:?}", active_keyset_id);
 
         // Get keyset fees
-        let keyset_fee_ppk = self.get_keyset_fees_by_id(active_keyset_id).await?;
+        let keyset_fee_ppk = self.wallet.get_keyset_fees_by_id(active_keyset_id).await?;
         tracing::debug!("Keyset fees: {:?}", keyset_fee_ppk);
 
         // Calculate total send amount
-        let total_send_amount = send.amount + send.send_fee;
+        let total_send_amount = self.amount + self.send_fee;
         tracing::debug!("Total send amount: {}", total_send_amount);
 
         // Swap proofs if necessary
-        if !send.proofs_to_swap.is_empty() {
+        if !self.proofs_to_swap.is_empty() {
             let swap_amount = total_send_amount - proofs_to_send.total_amount()?;
             tracing::debug!("Swapping proofs; swap_amount={:?}", swap_amount);
             if let Some(proofs) = self
+                .wallet
                 .swap(
                     Some(swap_amount),
                     SplitTarget::None,
-                    send.proofs_to_swap,
-                    send.options.conditions.clone(),
+                    self.proofs_to_swap,
+                    self.options.conditions.clone(),
                     false, // already included in swap_amount
                 )
                 .await?
@@ -242,15 +296,16 @@ impl Wallet {
         );
 
         // Check if sufficient proofs are available
-        if send.amount > proofs_to_send.total_amount()? {
+        if self.amount > proofs_to_send.total_amount()? {
             return Err(Error::InsufficientFunds);
         }
 
         // Check if proofs are reserved or unspent
         let sendable_proof_ys = self
+            .wallet
             .get_proofs_with(
                 Some(vec![State::Reserved, State::Unspent]),
-                send.options.conditions.clone().map(|c| vec![c]),
+                self.options.conditions.clone().map(|c| vec![c]),
             )
             .await?
             .ys()?;
@@ -268,45 +323,47 @@ impl Wallet {
             "Updating proofs state to pending spent: {:?}",
             proofs_to_send.ys()?
         );
-        self.localstore
+        self.wallet
+            .localstore
             .update_proofs_state(proofs_to_send.ys()?, State::PendingSpent)
             .await?;
 
         // Include token memo
-        let send_memo = send.options.memo.or(memo);
+        let send_memo = self.options.memo.or(memo);
         let memo = send_memo.and_then(|m| if m.include_memo { Some(m.memo) } else { None });
 
         // Add transaction to store
-        self.localstore
+        self.wallet
+            .localstore
             .add_transaction(Transaction {
-                mint_url: self.mint_url.clone(),
+                mint_url: self.wallet.mint_url.clone(),
                 direction: TransactionDirection::Outgoing,
-                amount: send.amount,
+                amount: self.amount,
                 fee: total_send_fee,
-                unit: self.unit.clone(),
+                unit: self.wallet.unit.clone(),
                 ys: proofs_to_send.ys()?,
                 timestamp: unix_time(),
                 memo: memo.clone(),
-                metadata: send.options.metadata,
+                metadata: self.options.metadata,
             })
             .await?;
 
         // Create and return token
         Ok(Token::new(
-            self.mint_url.clone(),
+            self.wallet.mint_url.clone(),
             proofs_to_send,
             memo,
-            self.unit.clone(),
+            self.wallet.unit.clone(),
         ))
     }
 
-    /// Cancel prepared send
-    pub async fn cancel_send(&self, send: PreparedSend) -> Result<(), Error> {
+    /// Cancel the prepared send
+    pub async fn cancel(self) -> Result<(), Error> {
         tracing::info!("Cancelling prepared send");
 
         // Double-check proofs state
-        let reserved_proofs = self.get_reserved_proofs().await?.ys()?;
-        if !send
+        let reserved_proofs = self.wallet.get_reserved_proofs().await?.ys()?;
+        if !self
             .proofs()
             .ys()?
             .iter()
@@ -315,68 +372,15 @@ impl Wallet {
             return Err(Error::UnexpectedProofState);
         }
 
-        self.localstore
-            .update_proofs_state(send.proofs().ys()?, State::Unspent)
+        self.wallet
+            .localstore
+            .update_proofs_state(self.proofs().ys()?, State::Unspent)
             .await?;
 
         Ok(())
     }
 }
 
-/// Prepared send
-pub struct PreparedSend {
-    amount: Amount,
-    options: SendOptions,
-    proofs_to_swap: Proofs,
-    swap_fee: Amount,
-    proofs_to_send: Proofs,
-    send_fee: Amount,
-}
-
-impl PreparedSend {
-    /// Amount
-    pub fn amount(&self) -> Amount {
-        self.amount
-    }
-
-    /// Send options
-    pub fn options(&self) -> &SendOptions {
-        &self.options
-    }
-
-    /// Proofs to swap (i.e., proofs that need to be swapped before constructing the token)
-    pub fn proofs_to_swap(&self) -> &Proofs {
-        &self.proofs_to_swap
-    }
-
-    /// Swap fee
-    pub fn swap_fee(&self) -> Amount {
-        self.swap_fee
-    }
-
-    /// Proofs to send (i.e., proofs that will be included in the token)
-    pub fn proofs_to_send(&self) -> &Proofs {
-        &self.proofs_to_send
-    }
-
-    /// Send fee
-    pub fn send_fee(&self) -> Amount {
-        self.send_fee
-    }
-
-    /// All proofs
-    pub fn proofs(&self) -> Proofs {
-        let mut proofs = self.proofs_to_swap.clone();
-        proofs.extend(self.proofs_to_send.clone());
-        proofs
-    }
-
-    /// Total fee
-    pub fn fee(&self) -> Amount {
-        self.swap_fee + self.send_fee
-    }
-}
-
 impl Debug for PreparedSend {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         f.debug_struct("PreparedSend")