Repository navigation
trade: accurate refusals for wrong-network, expired and zero-amount requests - #1130
Merged
Merged
Conversation
…curate messages
- withdraw: parse the BOLT11 network and expiry before any quote, reservation or
journal entry; refuse non-mainnet ('invoice is for <network>; this mint pays Bitcoin
mainnet invoices; nothing was journaled or sent') and expired / expiring-within-30s
invoices ('invoice expired at <utc>; nothing was journaled or sent').
- fund/send/list/take/withdraw: a zero amount is refused up front with 'amount must be
at least 1 sat' instead of the misleading 'funding cap exceeds 100,000 sats'.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
maxie-agent
marked this pull request as ready for review
October 12, 2026 05:12
maxie-agent
added a commit
that referenced
this pull request
Oct 12, 2026
# Conflicts: # crates/maxplayer-trade/tests/nostr.rs
maxie-agent
added a commit
that referenced
this pull request
Oct 12, 2026
# Conflicts: # crates/maxplayer-trade/src/dryrun.rs # crates/maxplayer-trade/src/money.rs
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes three misleading
maxplayer-tradeerror messages found in live testing (binary from mainbc41510). Approved by Bob, 2026-10-11 20:32 UTC (resumed 22:32 UTC).withdraw <mint> --invoice <lntb…>insufficient unreserved funds for melt, reserve and provable changeinvoice is for testnet; this mint pays Bitcoin mainnet invoices; nothing was journaled or sent(also regtest/signet/simnet)withdrawwith an expired invoiceunpaid_released(exit 1)invoice expired at 2026-10-11T19:00:00Z; nothing was journaled or sent; within 30 s of expiry:invoice expires at <utc>, within 30 s; nothing was journaled or sentsend/list/take/withdrawwith a zero amount flag… cap exceeds …or a later misleading refusalamount must be at least 1 sat (<flag> 0)fund <mint> --amount 0funding cap exceeds 100,000 satsamount must be at least 1 sat (--amount 0)Change
money::check_invoice(new, pub) checks the BOLT11 currency andtimestamp + expiryagainst now + 30 s margin.withdraw_boundedcalls it for a new authorization only (after the payment-hash dedupe, so resuming an already-journaled withdrawal is unchanged), before the amount/cap checks, the journal write, preflight and the melt quote.main.rs: a zero--amount(fund/send),--give/--want(list, incl.--dry-run),--max-give(take) or--max-debit(withdraw) is refused right after argument parsing, before cap checks, home creation, owner.lock, relays or mint traffic.--min-receive 0and--max-fees 0remain valid (they are lower/upper bounds, not amounts).money::fund,send::sendandwithdraw_boundedsplit theiramount > 0 && amount <= CAPchecks so 0 saysamount must be at least 1 sat; a zero-amount invoice now saysinvoice amount must be at least 1 sat. Cap messages are unchanged.references/commands.md: documents the new withdraw refusals and the zero-amount refusal.Tests (
tests/money.rs, loopback fake mint; no real mint contacted)withdraw_refuses_non_mainnet_invoice_before_quote_or_journal: testnet/regtest/signet/simnet invoices signed with a test key → exact message, no mint request (fixture request counter unchanged), no melt request, nowithdrawaljournal row, balance unchanged; plus the CLI path (exit 1, stderr message, no request).withdraw_refuses_expired_invoice_before_quote_or_journal: expired an hour ago and expiring in 20 s (inside the margin; fresh clock read so slow CI cannot turn it into the expired case) → exact messages, same no-side-effect assertions; a fresh mainnet invoice still pays (done).zero_amounts_are_refused_before_caps_journal_or_mint: six CLI cases → exit 1, exact message, home never created, zero mint requests;money::fund(…, 0)andsend::send(…, 0, …)→ exact message, no journal row, no token file; a zero-amount invoice →invoice amount must be at least 1 sat, no journal row, no request.Mutation checks
Each refusal was mutated in turn and the focused
tests/money.rstest rerun (file restored after each); all 9 KILLED, baseline 19/19 green afterwards:network.filter(|_| false))withdraw_refuses_non_mainnet…check_invoicecall removed fromwithdraw_boundedwithdraw_refuses_expired…truewithdraw_refuses_expired…expires > now)withdraw_refuses_expired…zero_amounts…--want 0arm removedzero_amounts…money::fundzero ensure removedzero_amounts…send::sendzero ensure removedzero_amounts…zero_amounts…Local gates (
crates/maxplayer-trade,--test-threads=1)cargo fmt --checkOK at the head; clippy-D warnings(CI allow-list) OK without and withlab; default tests 187 passed / 0 failed;--features labtests (TRADE_LAB_SECONDS=1) 253 passed / 0 failed. The three new tests ran (and passed) in the money, default and lab runs.Likely conflicts
Diff kept minimal. Open PRs touching this crate: #1127 (wallet receive/docs:
commands.md, possiblymain.rs), #1128 (per-mint backoff:money.rs,main.rs) and the nostr-fix PRs (main.rs,money.rs). Expect small textual conflicts inmain.rs(earlyexecute()checks),money.rs(withdraw_bounded), and thecommands.mdwithdrawal section; all are additive.Draft; not for merge without an explicit go-ahead.