[DO NOT MERGE] fix(commit-stake-v2): per-commitment verifier arbiter opt-in (THREAT_MODEL §8) - #1
Draft
Mnorbert87 wants to merge 2 commits into
Draft
[DO NOT MERGE] fix(commit-stake-v2): per-commitment verifier arbiter opt-in (THREAT_MODEL §8)#1Mnorbert87 wants to merge 2 commits into
Mnorbert87 wants to merge 2 commits into
Conversation
…t griefing Cold-audit finding (griefing, not theft): the §7a surplus burn proves a colluding arbiter can never TAKE the slice, but a staker could still name an only-address- distinct sockpuppet arbiter, have it overturn a CORRECT verdict, and BURN an honest verifier's slice — profitless to the attacker (~gas) but harmful to the verifier. Fix: a verifier must explicitly approve an arbiter address (approveArbiter) before a staker may name it on a commitment that locks the verifier's bond. Mirrors AgentBond's setSlashAllowance consent model — the bonded party now consents to the JUDGE, not just the enforcer. Address-distinctness alone is no longer sufficient. - new state: arbiterApproved[verifier][arbiter]; setter approveArbiter + event - create() requires arbiterApproved[p.verifier][p.arbiter] - revoke blocks NEW commitments only; existing ones keep their arbiter - 7 regression tests; full suite 86/86 green (was 79/79) NOT deployed: this branch is a proof the fix works without touching the verified deployed source on main (arcscan exact-match preserved). Roadmap, per THREAT_MODEL. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e grief-fix tests Completes the §8 griefing fix begun with the per-commitment arbiter opt-in: - Slice leverage cap: verifierSlice <= 3 × (amount + feeDeposit + arbiterFee) (SLICE_ABOVE_LEVERAGE_CAP) — a dust stake can no longer lock a verifier's whole bond behind one job. Defense-in-depth alongside the arbiter opt-in. - THREAT_MODEL.md §8: documents the sockpuppet-arbiter griefing vector, the shipped-release mitigation (revocable allowance), the branch fix, and why it is not deployed (Arcscan exact-match preserved). - Renamed regression suite -> CommitStakeV2GriefFix.t.sol (+2 slice-cap tests). - Adjusted test_Create_RevertInsufficientVerifierBond to stay within the cap. Full suite 88/88 green; Halmos §7a routing spec unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mnorbert87
pushed a commit
that referenced
this pull request
Jun 19, 2026
#1 Makes the documented limitation discoverable on the default branch: §8 describes the griefing vector, the deployed-release mitigation, and points to the implemented+tested fix (Draft PR #1, not deployed to preserve Arcscan exact-match verification). README trust-boundary note now links §8 and the PR. Deployed contract source untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mnorbert87
pushed a commit
that referenced
this pull request
Jul 31, 2026
…tracts The address sweep matched address strings, but a tx hash does not contain the address of the contract it called, so it could not see that the cited transactions still pointed at the replaced contracts. Classifying every cited hash by the target read back from the chain found 17 of 32 on old contracts, including both burn transactions JUDGES.md leads with, and the live state made it visible: the new CommitStakeV2, StreamPay and AgentBond all read nextId() = 1, so a judge following the links saw an empty stack. Re-ran all four CommitStakeV2 branches against the hardened contract. Terminal outcomes read back from get(id): id 1 CleanPass, id 2 LivenessSlash, id 3 OverturnedToPass, id 4 SilenceFail. Both surplus burns to 0x…dEaD reproduce the original amounts exactly, 1.50 USDC on the liveness branch and 1.45 on the overturn branch, confirmed from the Transfer logs in the receipts rather than from the script's own output. Re-ran the commerce scenario (obligation #5, stream #1) and the agent lifecycle (obligation #6, stream #2) on the new AgentBond and StreamPay, and re-executed the AgentBond.deposit leg of the CCTP flow. The two bridge legs are Base Sepolia and CCTP transactions, unaffected by the redeploy, and are now labelled as such. Two things the target-based sweep still could not see on its own: - the two USDC.approve transactions target USDC, so they classified as current, but their spender argument named the old contracts. Both re-earned. - agent/demo-agent.js built its provider without batchMaxCount, and the public Arc RPC rejects batched JSON RPC, so the "run it yourself" script failed on the first read with "missing revert data". Fixed; the run in the README is from the fixed script. SEED_RESULT.json regenerated from the real run, with the superseded run recorded. The commit-stake page gains the fourth branch and the four routing cases it was missing (SilenceFail, SilencePass, UpheldPass, UpheldFail previously fell through to a blank row). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mnorbert87
pushed a commit
that referenced
this pull request
Aug 2, 2026
…exist Two claims on the deck were written against the pre-redeploy state and were never re-measured after 2026-07-31. Both are corrected against the live chain, not against the old text. - Slide 6 claimed "AgentBond #7 was released by the enforcer, #8 was slashed and the creditor received the 2 USDC". Neither obligation exists on the deployed AgentBond (0x4383Ea48...51702c): nextObligationId() returns 7, so the ledger holds #1 through #6 only. A judge following the claim would have found nothing. Measured field by field instead: #1 Released 1.5 USDC, #2 Slashed 1.5 USDC, #3 Slashed 1.5, #4 Released 1.5, #5 Released 0.5, #6 Released 1.0. The story the slide tells is true, the identifiers and the amount were not. The same sentence also listed creditor and enforcer as separate addresses. On these obligations they are the same address, because the enforcer is CommitStakeV2 itself. Saying so is more informative than hiding it. - Slide 8 said the param-bounds fix carries 109 tests. commit-stake-v2 runs 125 today (forge 1.7.1, 226 across the four projects, 0 failed). Both burn transaction hashes on slide 4 were re-checked on chain and are still valid: status 0x1, both to the current CommitStakeV2 0xf3457ABf...af1474. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mnorbert87
pushed a commit
that referenced
this pull request
Aug 5, 2026
Pre-submission hard audit round, two lanes: Forge on fresh-clone reproducibility and on-chain truth, this one on claim-by-claim honesty. Every number below was re-measured, not read back from a doc. - use-case: the live page headlined "obligation #6 and stream #15" while its own linked transactions said #5 and #1. Chain: the Locked event carries id=5 and StreamPay.nextId() is 4, so #15 does not exist. Those were the pre-redeploy ids. The Acme address was already right. - JUDGES: "48 and 25 tests" for agent-bond; forge test says 51. The 08-05 sweep fixed the count in four places and missed this one, so the page whose whole argument is "run it yourself" shipped a number the run disagrees with. Suite total measured today: 51+25+28+125 = 229 green. - verify-claims: that miss was the checker's, not the reader's. The count regex only sees a number sitting next to the word "tests", and in a coordinated list ("48 and 25 tests") only the last one does. Added the fourth spelling and proved it by mutation: 48 fails, 51 passes. - GAS_PROFILE: the on-chain anchor was the creation tx of the pre-redeploy CommitStakeV2. Re-measured the live one (0xd26d8942): 3,279,071 gas at 23.6 gwei, 0.0774 USDC actual. The table keeps 40 gwei as the conservative constant, so it overstates rather than flatters, and the old number stays as a dated footnote. - x402-demo/run.sh: dies with a raw shell error when .env is absent. Guarded with the fix instead; mutation-tested, exit 1 and a usage line. verify-claims.sh: 121 checks, all matched. Still open, needs an on-chain write: the ERC-8004 tokenURI of both identity NFTs points at the pre-rebrand Pages path, which 404s, while the README claims it resolves to the agent metadata. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
What
Closes the §8 griefing vector: a staker-chosen sockpuppet arbiter could burn an
honest verifier's bonded slice at ≈ gas cost. The verifier must now
approveArbiterbefore any staker can name that arbiter over its bond — mirroring AgentBond's
setSlashAllowanceconsent model (the bonded party now consents to the JUDGE, not justthe enforcer). Revoke blocks only NEW commitments; existing ones are untouched.
verifierSlice <= 3 × (amount + feeDeposit + arbiterFee)): a duststake can no longer lock a verifier's whole bond.
Tests
Full suite 88/88 green (was 79/79); 9 new regression tests in
CommitStakeV2GriefFix.t.sol.Halmos §7a spec unaffected — no routing math changed.
Why this is a Draft / NOT merged — INTENTIONAL
The deployed CommitStakeV2 (
0x1f1C…8CA9) is exact-match verified on Arcscan. Merging +redeploying would invalidate that verification this close to judging. This branch is the
proof the fix is real and green; the on-chain contract stays byte-identical. Theft is
already mathematically + symbolically excluded on
main; this removes the residual griefing.DO NOT MERGE without a deliberate redeploy + re-verify of the on-chain contract.
See THREAT_MODEL.md §8 for the full write-up.