fix: the pool takes its fee OUT of a deposit, not on top of it
An independent audit decoded the account's seven mainnet transactions and settled the direction: send 20 to the pool, get 14 credited; unshield 5, pay 11. The ledger only balances that way (20-6, -5-6, +5-6, +5-6, +20-6, -5-6, +5-6 = 3). The widget had it backwards, so the shield-then-pay path was short by exactly one fee at every invoice size: it deposited amount + fee, which credits the amount, and then needed amount + fee. It could not work on mainnet, and the refusal message sent the payer to deposit a figure that lands them back at the same message forever. MockWallet modelled the chain backwards too, which is why a test named "deposits enough to afford the payment that follows" passed. - depositNeededFor / shieldedNeededFor: the two different questions, named. - The confirm box quotes the fee twice when a deposit leg is coming, and recomputes once the wallet reveals a balance. It understated a 5 STRK invoice by 55%. - The arcade starts with shielded funds, which is the flow the product recommends, and no longer breaks on the second coin. Also, from the same audit: - The receipt claimed "Proves this invoice was paid. Does not link the payment to the payer's wallet" - directly above the public deposit hash that names the payer, with the honesty panel hidden at that exact moment. It now states what it records, who confirms, and that a deposit made this close to the payment can be correlated. The panel stays. - The honesty panel gained the RPC operator seeing the payer's IP, the limits on address freshness this page cannot verify, and the note-mode warning that a merchant may never see the payment. - A new deliveryId per event: an underpaid invoice topped up later sent payment.confirmed under the id its payment.underpaid had used, and every merchant deduping as documented discarded the confirmation. - Payments are counted from transfers into the address, not the balance delta, so sweeping the address no longer erases the payer's credit. - localStorage, not sessionStorage: a second tab had no record and paid again. mountCheckout takes a store, which it never could before. - A pending marker is written before the wallet is asked to move anything, so a wallet that submits and never returns cannot be paid twice on reload. - Idempotency-Key is bound to the request, survives a restart, and refuses a concurrent duplicate. - The token label is checked against the token address. - Invoices without a deadline can be cancelled instead of being immortal. - csvCell quotes a lone carriage return, which smuggled a live formula past the leading-character guard from a third-party RPC's tx hash. 102 tests, including fixtures rebuilt against the real economics. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
B
bongbongcrypto committed
c8ccdf69c31a0bf8127b17817532994f750de4d2
Parent: 764ae9e