|
@@ -113,7 +113,7 @@ impl Wallet {
|
|
|
/// Total unspent balance of wallet
|
|
|
#[instrument(skip(self))]
|
|
|
pub async fn total_balance(&self) -> Result<Amount, Error> {
|
|
|
- if let Some(proofs) = self
|
|
|
+ let proofs = self
|
|
|
.localstore
|
|
|
.get_proofs(
|
|
|
Some(self.mint_url.clone()),
|
|
@@ -121,22 +121,16 @@ impl Wallet {
|
|
|
Some(vec![State::Unspent]),
|
|
|
None,
|
|
|
)
|
|
|
- .await?
|
|
|
- {
|
|
|
- let balance = proofs.iter().map(|p| p.proof.amount).sum::<Amount>();
|
|
|
-
|
|
|
- return Ok(balance);
|
|
|
- }
|
|
|
+ .await?;
|
|
|
+ let balance = proofs.iter().map(|p| p.proof.amount).sum::<Amount>();
|
|
|
|
|
|
- Ok(Amount::ZERO)
|
|
|
+ Ok(balance)
|
|
|
}
|
|
|
|
|
|
/// Total pending balance
|
|
|
#[instrument(skip(self))]
|
|
|
pub async fn total_pending_balance(&self) -> Result<HashMap<CurrencyUnit, Amount>, Error> {
|
|
|
- let mut balances = HashMap::new();
|
|
|
-
|
|
|
- if let Some(proofs) = self
|
|
|
+ let proofs = self
|
|
|
.localstore
|
|
|
.get_proofs(
|
|
|
Some(self.mint_url.clone()),
|
|
@@ -144,15 +138,12 @@ impl Wallet {
|
|
|
Some(vec![State::Pending]),
|
|
|
None,
|
|
|
)
|
|
|
- .await?
|
|
|
- {
|
|
|
- for proof in proofs {
|
|
|
- balances
|
|
|
- .entry(proof.unit)
|
|
|
- .and_modify(|ps| *ps += proof.proof.amount)
|
|
|
- .or_insert(proof.proof.amount);
|
|
|
- }
|
|
|
- }
|
|
|
+ .await?;
|
|
|
+
|
|
|
+ let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
|
|
|
+ *acc.entry(proof.unit).or_insert(Amount::ZERO) += proof.proof.amount;
|
|
|
+ acc
|
|
|
+ });
|
|
|
|
|
|
Ok(balances)
|
|
|
}
|
|
@@ -160,9 +151,7 @@ impl Wallet {
|
|
|
/// Total reserved balance
|
|
|
#[instrument(skip(self))]
|
|
|
pub async fn total_reserved_balance(&self) -> Result<HashMap<CurrencyUnit, Amount>, Error> {
|
|
|
- let mut balances = HashMap::new();
|
|
|
-
|
|
|
- if let Some(proofs) = self
|
|
|
+ let proofs = self
|
|
|
.localstore
|
|
|
.get_proofs(
|
|
|
Some(self.mint_url.clone()),
|
|
@@ -170,15 +159,12 @@ impl Wallet {
|
|
|
Some(vec![State::Reserved]),
|
|
|
None,
|
|
|
)
|
|
|
- .await?
|
|
|
- {
|
|
|
- for proof in proofs {
|
|
|
- balances
|
|
|
- .entry(proof.unit)
|
|
|
- .and_modify(|ps| *ps += proof.proof.amount)
|
|
|
- .or_insert(proof.proof.amount);
|
|
|
- }
|
|
|
- }
|
|
|
+ .await?;
|
|
|
+
|
|
|
+ let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
|
|
|
+ *acc.entry(proof.unit).or_insert(Amount::ZERO) += proof.proof.amount;
|
|
|
+ acc
|
|
|
+ });
|
|
|
|
|
|
Ok(balances)
|
|
|
}
|
|
@@ -208,8 +194,9 @@ impl Wallet {
|
|
|
None,
|
|
|
)
|
|
|
.await?
|
|
|
- .map(|p| p.into_iter().map(|p| p.proof).collect())
|
|
|
- .unwrap_or_default())
|
|
|
+ .into_iter()
|
|
|
+ .map(|p| p.proof)
|
|
|
+ .collect())
|
|
|
}
|
|
|
|
|
|
/// Get pending [`Proofs`]
|
|
@@ -224,8 +211,9 @@ impl Wallet {
|
|
|
None,
|
|
|
)
|
|
|
.await?
|
|
|
- .map(|p| p.into_iter().map(|p| p.proof).collect())
|
|
|
- .unwrap_or_default())
|
|
|
+ .into_iter()
|
|
|
+ .map(|p| p.proof)
|
|
|
+ .collect())
|
|
|
}
|
|
|
|
|
|
/// Get reserved [`Proofs`]
|
|
@@ -240,8 +228,9 @@ impl Wallet {
|
|
|
None,
|
|
|
)
|
|
|
.await?
|
|
|
- .map(|p| p.into_iter().map(|p| p.proof).collect())
|
|
|
- .unwrap_or_default())
|
|
|
+ .into_iter()
|
|
|
+ .map(|p| p.proof)
|
|
|
+ .collect())
|
|
|
}
|
|
|
|
|
|
/// Return proofs to unspent allowing them to be selected and spent
|
|
@@ -405,7 +394,7 @@ impl Wallet {
|
|
|
pub async fn check_all_pending_proofs(&self) -> Result<Amount, Error> {
|
|
|
let mut balance = Amount::ZERO;
|
|
|
|
|
|
- if let Some(proofs) = self
|
|
|
+ let proofs = self
|
|
|
.localstore
|
|
|
.get_proofs(
|
|
|
Some(self.mint_url.clone()),
|
|
@@ -413,33 +402,36 @@ impl Wallet {
|
|
|
Some(vec![State::Pending, State::Reserved]),
|
|
|
None,
|
|
|
)
|
|
|
- .await?
|
|
|
- {
|
|
|
- let states = self
|
|
|
- .check_proofs_spent(proofs.clone().into_iter().map(|p| p.proof).collect())
|
|
|
- .await?;
|
|
|
+ .await?;
|
|
|
|
|
|
- // Both `State::Pending` and `State::Unspent` should be included in the pending table.
|
|
|
- // This is because a proof that has been crated to send will be stored in the pending table
|
|
|
- // in order to avoid accidentally double spending but to allow it to be explicitly reclaimed
|
|
|
- let pending_states: HashSet<PublicKey> = states
|
|
|
- .into_iter()
|
|
|
- .filter(|s| s.state.ne(&State::Spent))
|
|
|
- .map(|s| s.y)
|
|
|
- .collect();
|
|
|
+ if proofs.is_empty() {
|
|
|
+ return Ok(Amount::ZERO);
|
|
|
+ }
|
|
|
|
|
|
- let (pending_proofs, non_pending_proofs): (Vec<ProofInfo>, Vec<ProofInfo>) = proofs
|
|
|
- .into_iter()
|
|
|
- .partition(|p| pending_states.contains(&p.y));
|
|
|
+ let states = self
|
|
|
+ .check_proofs_spent(proofs.clone().into_iter().map(|p| p.proof).collect())
|
|
|
+ .await?;
|
|
|
+
|
|
|
+ // Both `State::Pending` and `State::Unspent` should be included in the pending table.
|
|
|
+ // This is because a proof that has been crated to send will be stored in the pending table
|
|
|
+ // in order to avoid accidentally double spending but to allow it to be explicitly reclaimed
|
|
|
+ let pending_states: HashSet<PublicKey> = states
|
|
|
+ .into_iter()
|
|
|
+ .filter(|s| s.state.ne(&State::Spent))
|
|
|
+ .map(|s| s.y)
|
|
|
+ .collect();
|
|
|
|
|
|
- let amount = pending_proofs.iter().map(|p| p.proof.amount).sum();
|
|
|
+ let (pending_proofs, non_pending_proofs): (Vec<ProofInfo>, Vec<ProofInfo>) = proofs
|
|
|
+ .into_iter()
|
|
|
+ .partition(|p| pending_states.contains(&p.y));
|
|
|
|
|
|
- self.localstore
|
|
|
- .remove_proofs(&non_pending_proofs.into_iter().map(|p| p.proof).collect())
|
|
|
- .await?;
|
|
|
+ let amount = pending_proofs.iter().map(|p| p.proof.amount).sum();
|
|
|
|
|
|
- balance += amount;
|
|
|
- }
|
|
|
+ self.localstore
|
|
|
+ .remove_proofs(&non_pending_proofs.into_iter().map(|p| p.proof).collect())
|
|
|
+ .await?;
|
|
|
+
|
|
|
+ balance += amount;
|
|
|
|
|
|
Ok(balance)
|
|
|
}
|
|
@@ -946,10 +938,20 @@ impl Wallet {
|
|
|
Some(vec![State::Unspent]),
|
|
|
None,
|
|
|
)
|
|
|
- .await?
|
|
|
- .ok_or(Error::InsufficientFunds)?;
|
|
|
+ .await?;
|
|
|
|
|
|
- let available_proofs = available_proofs.into_iter().map(|p| p.proof).collect();
|
|
|
+ let (available_proofs, proofs_sum) = available_proofs.into_iter().map(|p| p.proof).fold(
|
|
|
+ (Vec::new(), Amount::ZERO),
|
|
|
+ |(mut acc1, mut acc2), p| {
|
|
|
+ acc2 += p.amount;
|
|
|
+ acc1.push(p);
|
|
|
+ (acc1, acc2)
|
|
|
+ },
|
|
|
+ );
|
|
|
+
|
|
|
+ if proofs_sum < amount {
|
|
|
+ return Err(Error::InsufficientFunds);
|
|
|
+ }
|
|
|
|
|
|
let proofs = self.select_proofs_to_swap(amount, available_proofs).await?;
|
|
|
|
|
@@ -1015,10 +1017,20 @@ impl Wallet {
|
|
|
Some(vec![State::Unspent]),
|
|
|
conditions.clone().map(|c| vec![c]),
|
|
|
)
|
|
|
- .await?
|
|
|
- .unwrap_or_default();
|
|
|
+ .await?;
|
|
|
|
|
|
- let available_proofs = available_proofs.into_iter().map(|p| p.proof).collect();
|
|
|
+ let (available_proofs, proofs_sum) = available_proofs.into_iter().map(|p| p.proof).fold(
|
|
|
+ (Vec::new(), Amount::ZERO),
|
|
|
+ |(mut acc1, mut acc2), p| {
|
|
|
+ acc2 += p.amount;
|
|
|
+ acc1.push(p);
|
|
|
+ (acc1, acc2)
|
|
|
+ },
|
|
|
+ );
|
|
|
+
|
|
|
+ if proofs_sum < amount {
|
|
|
+ return Err(Error::InsufficientFunds);
|
|
|
+ }
|
|
|
|
|
|
let selected = self
|
|
|
.select_proofs_to_send(amount, available_proofs, include_fees)
|