Round-4 money audit: --max-spend ceiling + paid-tool accounting + trading guards (3.29.8) - #91
Merged
Merged
Conversation
added 2 commits
June 24, 2026 00:59
…d-tool accounting; trading guards (3.29.8) Round-4 money audit of the paid-tool surface (beyond the diff-scoped rounds 1-3), 13 adversarially-verified findings + a follow-up on merged PR #89. Wallet spend ceiling (HIGH): - --max-spend was blind to ALL paid-tool USDC (ImageGen/VideoGen/MusicGen, Exa, Surf, RealFace, Voice, Phone, Modal, DeFiLlama, RPC, Prediction) — only LLM token cost counted. New getLiveSpendUsd accumulator in tracker is diffed around tool execution in the loop and folded into sessionCostUsd, ceiling re-checked. - A paid LLM call whose stream then failed (timeout/mid-stream error/Esc) debited USDC but was never counted; the loop catch now folds getLastPaidUsd() before the next attempt resets it (drift previously compounded across --resume). Paid-but-invisible accounting: - DeFiLlama (5), MultiChainRPC, PredictionMarket (now persisted), MusicGen, and panel phone Buy/Renew/List now call recordUsage with the settled amount (parity with surf.ts) — were charging real USDC invisible to franklin stats. Money-safety + correctness: - $5 BuyPhoneNumber/RenewPhoneNumber now confirm via onAskUser (skipped under FRANKLIN_MEDIA_AUTO_APPROVE_ALL) — were ungated while a $0.05 Modal create gates. - VoiceStatus records one telemetry row per invocation, not per 5s poll (was up to 420/call, evicting real spend history at the 1000-row cap). - RiskEngine per-position cap values the held position at cost basis, not the incoming order price (a buy could slip the cap after a price drop). - closePosition clamps an over-sized close to the held qty (flatten) instead of throwing a confusing 'only X held' error. PR #89 (thanks @samsamtrum) merged + refined: floor excess precision to the atomic unit and reject only true dust (instead of rejecting any excess precision), clearer message + unit test. New no-spend tests: live-spend ceiling basis, risk cost-basis cap, close clamp, Jupiter atomic-unit math. Suite 479/479.
…ing + Jupiter floor Independent review of #91 caught two issues in the round-4 fixes: - --max-spend MISSED concurrent paid tools (DeFiLlama/RPC/Prediction): they start mid-stream via onToolReceived and could settle x402 BEFORE the post-stream snapshot, so their spend was baked into the baseline and excluded from the cap. Now snapshot getLiveSpendUsd() BEFORE the stream and net out the LLM's own callCost, so the fold captures concurrent + sequential tools alike. - Jupiter toAtomicUnits: the scientific-notation toFixed path ROUNDED (9.999e-10 → 1 atomic unit — the dust round-up #89 fixed) and threw a raw BigInt error on >=1e21. Now uses toLocaleString (plain decimal, floor-by-truncation) so it floors excess precision and rejects only true dust on all inputs. New boundary tests (exponential dust, 1.9999e-9 floor, 1e21). Suite 479/479.
Contributor
Author
Independent review — 1 real bug + 1 nit found & fixed (
|
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.
Fourth review round, sweeping the paid-tool surface beyond the diff-scoped rounds 1–3. 13 adversarially-verified findings + a follow-up on the just-merged #89. All money-critical; local suite 479/479.
Wallet spend ceiling (HIGH)
--max-spendwas blind to ALL paid-tool USDC (ImageGen/VideoGen/MusicGen, Exa, Surf, RealFace, Voice, Phone, Modal, DeFiLlama, RPC, Prediction) — only LLM token cost counted, sofranklin -p "generate 30 images" --max-spend 0.50could spend multiples with the guard never firing. NewgetLiveSpendUsdaccumulator is diffed around tool execution and folded into the session total; ceiling re-checked after each tool batch.--resume. The loop catch capturesgetLastPaidUsd()before the next attempt resets it.Paid-but-invisible accounting
recordUsagethe settled amount (parity withsurf.ts) — were charging real USDC invisible tofranklin stats(reconciliation couldn't even detect the gap).Money-safety + correctness
onAskUser(skipped underFRANKLIN_MEDIA_AUTO_APPROVE_ALL) — were ungated while a $0.05 Modal create gates.only X held.PR #89 follow-up (thanks @samsamtrum)
Merged #89 (reject sub-precision Jupiter amounts that rounded up to one atomic unit), then refined: floor excess precision to the atomic unit (so agent-computed amounts / float noise still swap) and reject only true dust, with a clearer message + unit test.
New no-spend regression tests: live-spend ceiling basis, risk cost-basis cap, close clamp, Jupiter atomic-unit math.
🤖 Generated with Claude Code