AUDIT4-G2 fix: client-side min_utxo guard on ada-only wallet_send

wallet_send now rejects sub-min-utxo (1 ADA) ada-only sends with a
clear local error before any koios round-trip. Asset-bearing sends
still go through to chain so the dynamic per-asset min computation
is what surfaces in the error — no static guard would be right
there.

Saves the chain round-trip + the bewildering "tx submitted... wait
30 seconds... actually it failed" UX. Surfaced 2026-05-04 audit-4
phase G2 against the deployed container.
This commit is contained in:
Kayos 2026-05-04 21:22:28 -07:00
parent d5fb00c9f5
commit 30761039ea

View file

@ -417,6 +417,20 @@ impl WalletService {
if lovelace == 0 {
return Err("lovelace must be > 0".into());
}
// AUDIT4-G2 fix: catch sub-min-utxo ada-only sends client-side
// before the chain rejects them (saves a koios round-trip + the
// user's mental model of "tx submitted" → "tx failed minutes later").
// Asset-bearing sends have a dynamic min driven by asset count +
// name lengths — let those reach chain so the real number is in
// the error.
let default_min = ProtocolParams::default().min_utxo_lovelace;
if assets.is_empty() && lovelace < default_min {
return Err(format!(
"lovelace {lovelace} below min-utxo {default_min}; \
the chain would reject this output. Send {default_min} \
(1 ADA), or pass assets to use the dynamic asset-aware min."
));
}
self.enforce_value_cap(lovelace, force)?;
let utxos = self