fix(ecash): change proofs no longer ride along inside sent tokens — double-credit bug #122
@ -632,11 +632,30 @@ pub async fn send_token_at(data_dir: &Path, mint_url: &str, amount_sats: u64) ->
|
||||
// Mark original proofs as spent
|
||||
wallet.mark_spent(&indices);
|
||||
|
||||
// Separate send proofs from change proofs
|
||||
let (send, change): (Vec<_>, Vec<_>) = swap_result
|
||||
.new_proofs
|
||||
.into_iter()
|
||||
.partition(|p| send_denoms.contains(&p.amount));
|
||||
// Separate send proofs from change proofs BY COUNT, not membership:
|
||||
// partition(contains) put EVERY proof whose denomination appeared in
|
||||
// send_denoms into the token — when change shared a denomination with
|
||||
// the send (worst case: spending from a proof worth exactly 2× the
|
||||
// amount, send [n] + change [n]), the change proofs rode along and the
|
||||
// receiver was credited double. Consume exactly one proof per needed
|
||||
// send denomination; everything else is change.
|
||||
let mut send_needed = send_denoms.clone();
|
||||
let mut send: Vec<Proof> = Vec::new();
|
||||
let mut change: Vec<Proof> = Vec::new();
|
||||
for p in swap_result.new_proofs {
|
||||
if let Some(pos) = send_needed.iter().position(|&d| d == p.amount) {
|
||||
send_needed.swap_remove(pos);
|
||||
send.push(p);
|
||||
} else {
|
||||
change.push(p);
|
||||
}
|
||||
}
|
||||
if !send_needed.is_empty() {
|
||||
anyhow::bail!(
|
||||
"Mint swap returned incomplete send denominations (missing {:?})",
|
||||
send_needed
|
||||
);
|
||||
}
|
||||
|
||||
// Add change proofs back to wallet
|
||||
if !change.is_empty() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user