|
@@ -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")
|