{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"fdbf5e23-3c3f-4e02-9e9b-113ad92bcc7b","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"2c009e7a4b452575e9e699cdf64fbc1900debe5e6593040241deca818ab1c3ce","dependsOn":["build_contract_project","write_foundry_tests","frontend_for_contract","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"89ef76500734b564ec0fab03ff66c5caedff03d7f0915ac26d1c1daf6882c1b9","dependsOn":["build_contract_project","write_foundry_tests","frontend_for_contract","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"4b9be70bfe8f969fa40a532a9c5830d3b9eb36073305dad1ae5a0241615b9d55","dependsOn":["build_contract_project","write_foundry_tests","frontend_for_contract","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"38cd20c887114df5e631be1a454f5732482fb5621de95b2538ab43c2bcc8114c","dependsOn":["build_contract_project","write_foundry_tests","frontend_for_contract","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"3443f8c6c4d66c47efc5999cb331a69fcf212fce744f7447fe70d6d2bffd6b07","dependsOn":["build_contract_project","write_foundry_tests","frontend_for_contract","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"8dd70a5ed928f7b1e7196cff00efb90221314e7eafd0ba48e94319f23c26b8ab","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"b8de14485b80afab964f6096d9af98b7e6f433d4aaef11d14457a61e6081e51d","dependsOn":["write_foundry_tests"],"execution":{"mustProduce":["dist/index.html"],"network":true,"optionalTools":["browser"],"profile":"foundry","requires":["network"],"skillHash":"7a8712ac362fd9796a2d33fcee6ee3ad1adaefb41673944a34b3d34ef78b3e37","skillId":"frontend-for-contract","tools":[]},"key":"frontend_for_contract","kind":"code","role":"implement","skillHash":"7a8712ac362fd9796a2d33fcee6ee3ad1adaefb41673944a34b3d34ef78b3e37","skillId":"frontend-for-contract","state":"accepted"},{"acceptedSubmissionHash":"89bfa1e9d4b2e7cc7312b48b40a92d95ff1e9fa3c35eb682a8d5ab12d1e475e0","dependsOn":["build_contract_project","write_foundry_tests","frontend_for_contract"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"132858940e6f37ecb774557be76f98218d9266a88b42ee558260dc6be96bdf03","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"CROWN - a per-ticker crown registry and Uniswap v4 fee hook. Build the full system, deploy it on Robinhood Chain (chainId 4663), and deliver a working end-to-end demo.\n\nCONCEPT: One canonical token per ticker - the king. A registry contract maps ticker -> {kingToken, beneficiary, reignStartedAt}. A Uniswap v4 hook attached to participating pools skims a cut of every swap and pays it, inside the same transaction, to the current king`s beneficiary wallet (pay-at-source: fees must never be stored in the hook or pooled for claiming). Anyone can challenge the king with a bonded ETH stake-vote; if the challenger out-stakes the king within the window and quorum is met, the registry flips after a timelock and every subsequent swap pays the new king.\n\nCONTRACT 1 - CrownRegistry:\n- ticker is bytes32 = keccak256 of the uppercase symbol string.\n- registerKing(ticker, token, beneficiary): the first registration for a ticker crowns that token.\n- openChallenge(ticker, challengerToken) payable: bond 0.01 ETH; one live challenge per ticker; a king is challengeable only after a 7-day minimum reign; 3-day cooldown per ticker after a failed challenge.\n- stake(challengeId, side) payable in ETH during a 72-hour window (side = king or challenger).\n- finalize(challengeId) after the window plus a 24-hour timelock: the challenger wins iff challenger stake > king stake AND total staked >= 0.05 ETH quorum. On a flip, the registry points to the challenger token and its beneficiary. Losing side: 80% refundable to its stakers (pull pattern), 20% slashed - half of the slash pro-rata to winning-side stakers (pull), half to treasury 0xf19F11Dee16a341671E6Ed3e209b704C1Bbc3E57. Winning side`s stake is fully refundable (pull).\n- Events: Crowned, ChallengeOpened, Staked, Dethroned, ChallengeFailed. Public per-ticker totals.\n- No admin functions after deployment beyond the constructor`s parameter init; resolution is purely rule-based.\n\nCONTRACT 2 - CrownHook (Uniswap v4; afterSwap and afterSwapReturnsDelta permissions):\n- afterInitialize records poolId -> ticker; the deployer registers each pool`s ticker explicitly.\n- On every swap: compute the cut (per-pool bps set at init, default 100, range 0-500) from the swap amount, read registry.king(ticker).beneficiary, take the cut as the hook`s delta and transfer it to the beneficiary within the same settlement. Maintain a public counter crownPaid[ticker][currency] (cumulative).\n- The hook must never revert or block a swap: if the registry read or the transfer fails, the swap proceeds without the cut.\n\nDEMO LAUNCH (this launch`s token): name \"Crown Demo\", symbol CRWN, paired with native ETH on Robinhood Chain, pool wearing CrownHook, registered as genesis king of ticker CRWN with beneficiary = the launch payer wallet. Additionally deploy a second, distinct plain ERC-20 with the same name and symbol CRWN (a deploy script is fine) as the standing challenger candidate, so a full dethrone (challenge, stake, finalize, recipient flip) can be executed end-to-end after launch.\n\nSITE: the canonical ticker page - current king per ticker, crownPaid totals per ticker, live challenge state (window, both stakes, time remaining), stake and challenge actions wired to the contracts, and a plain-English how-it-works section.\n\nTESTS (Foundry, in the repo): registry and challenge math unit tests (bond, quorum, slash split exact to the wei) and a Uniswap v4 integration test executing buy -> challenge -> stake -> finalize -> buy, asserting the fee recipient changed and crownPaid matches the transfers. Contracts must compile with the repo`s pinned settings and be Sourcify-verifiable; record the compiler settings in the README.","parentJobId":null,"planHash":"b11d922db18eaa29f8d9808fe374bae000de7b1d0a9d9acc137c46577f599a65","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"fdbf5e23-3c3f-4e02-9e9b-113ad92bcc7b","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1872-crown-per-ticker-crown"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51891","feedbackHash":"79520411f97a5cf2c6e62dbcaba8a4b49508260a88107787dc7a2d7cd1cf975b","nodeKey":"audit_economics","submissionHash":"2c009e7a4b452575e9e699cdf64fbc1900debe5e6593040241deca818ab1c3ce","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52160","feedbackHash":"387dd808e98b1a37980f8e49459611b945e60a52251912e42189c4ee5b281a63","nodeKey":"audit_flow","submissionHash":"89ef76500734b564ec0fab03ff66c5caedff03d7f0915ac26d1c1daf6882c1b9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52419","feedbackHash":"9cfda6cd7936fd9cb344796bded438c289c69d9e55e8dc3e64627e7458b401ad","nodeKey":"audit_judge","submissionHash":"0d471ba83002820ec63c15f2578f4be813ddf66e8395313fd0f19de02de1b35c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51368","feedbackHash":"578faa984e2b1c3c254693e6d7ca532bf32caa387dcb4b87ff955a9cf4b1868b","nodeKey":"audit_judge","submissionHash":"483a8e547f447ad9df71519c642b627aa9bfc1d69290479f37884a05531b8212","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52210","feedbackHash":"35d1d310b64cef3669ecf5e7f51fdd98c478e0665d6b4bffe7e163064068f0f5","nodeKey":"audit_judge","submissionHash":"4b9be70bfe8f969fa40a532a9c5830d3b9eb36073305dad1ae5a0241615b9d55","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50952","feedbackHash":"e89c88ca9b20c0730b4ac1155454a536f569a4614e884b83b76ba0bb85e83ae4","nodeKey":"audit_math","submissionHash":"38cd20c887114df5e631be1a454f5732482fb5621de95b2538ab43c2bcc8114c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51243","feedbackHash":"b285e5d77f1f07b747b0a7fe916a5dd1e4638ee2ada38198b7ec2be749574e11","nodeKey":"audit_permissions","submissionHash":"3443f8c6c4d66c47efc5999cb331a69fcf212fce744f7447fe70d6d2bffd6b07","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52251","feedbackHash":"a82cfddbfcaddfd9e18d5f6d0381211fd2fccebb5ed3b0beea52907bf3c5f4b4","nodeKey":"build_contract_project","submissionHash":"8dd70a5ed928f7b1e7196cff00efb90221314e7eafd0ba48e94319f23c26b8ab","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51169","feedbackHash":"2acc74fd0b41aabb70904aec8874b63715019254cab7c707e4f6136288941b0c","nodeKey":"build_contract_project","submissionHash":"8da418de8d0146c1e6b4463148f16fb580b212449e5380731413381feaed48b2","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51558","feedbackHash":"7cc8b9629eadb82d30e9d42c7a4c5491ea62198aa27ddd6442261a007ddfcfe1","nodeKey":"frontend_for_contract","submissionHash":"b8de14485b80afab964f6096d9af98b7e6f433d4aaef11d14457a61e6081e51d","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51530","feedbackHash":"5ee1e4059686ec50aafd6ea22cc9f7cbc4cbc8b7e2a849f6e2af8057585fe71a","nodeKey":"frontend_for_contract","submissionHash":"a8f517578495d54c3c16ab7855a5f04dfc7076546f0184b4144c9869456a5077","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"53923","feedbackHash":"938e5d41d9f5bb080d2d86cd7afe4c50729b92a7575dca822baece36421aeb6d","nodeKey":"frontend_for_contract","submissionHash":"208c51b7ebcc8053f1408fc9f8c738a94b50ad36e8c61a26a4956b1c6f6d2bb3","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"50971","feedbackHash":"e66daa8a7c51e634e9f09d4b70dbfd55c6988e2a6b2f3780e217969e8de99dca","nodeKey":"manifest","submissionHash":"8f8c93a4c3aed535ecbf1ead939b36ebede87656e89163c570c1b5b8a92746f3","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51331","feedbackHash":"b9410656d3b97dd5df77cbf498145e1c03a804d2e88999f5b89a494f13806e09","nodeKey":"manifest","submissionHash":"6ecb528cda2cb88722c6baf8832672548b728cf98c451fe3d3bdc26f2a5e2964","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52642","feedbackHash":"30bc2ed162f4e4abb1ab1c9c3ca4793431380897b26a5d3ba5440be9f582f4d6","nodeKey":"manifest","submissionHash":"89bfa1e9d4b2e7cc7312b48b40a92d95ff1e9fa3c35eb682a8d5ab12d1e475e0","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52487","feedbackHash":"859fd0b4af23ddf74f42ab6b61103b1aea1f64f3ca3b7b0ee6353fade44e884c","nodeKey":"write_foundry_tests","submissionHash":"c8af1ee36eac8a45e321c0038d2e29b39d666a886231bb757b6712bf9b7ed4a2","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51285","feedbackHash":"4ffbfa0a98561ab18ebc53e8608c576794cec0211581974f585238aafcae4fb3","nodeKey":"write_foundry_tests","submissionHash":"132858940e6f37ecb774557be76f98218d9266a88b42ee558260dc6be96bdf03","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"5a2de1ca4f00c94e85f952e43b6da240ed4d90714b8a8eb1b090421b6600a044","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7e50667f872c7f5e","findings":[{"citation":"resolved","description":"Residual of my round-1 finding 3cf0264a (same root cause: the beneficiary runs arbitrary code while the PoolManager is unlocked, inside somebody else's swap). The new payout() self-call (src/CrownHook.sol:400-420) detects a payment that leaves an open delta, moves ETH, or syncs a currency. It does not detect a trade the beneficiary settles entirely in ERC-6909 claims: with ETH parked in the manager as claims (one unlock: settle{value} + mint(self, 0, x)), its receive() can call poolManager.swap on the launch pool and close the deltas with burn(self, 0, ethOwed) and mint(self, tokenId, tokensOut). Afterwards getNonzeroDeltaCount is deltasBefore + 1, the hook's delta is -cut, the manager's ETH balance is balanceBefore - cut, and the sync slots are untouched, so payout() returns normally, crownPaid is incremented and the cut is paid. The nested swap costs 96,270 gas, well inside PAYOUT_GAS = 150_000 (the nested afterSwap's own payout attempt sees hookDeltaBefore == -cut, reverts PayoutLeftTraces and is caught, so the nested swap completes). On the beforeSwap path (exact-input buys, exact-output sells) the user's swap has not run yet, so the beneficiary buys ahead of it and moves the price (20 tokens against 1000e18 liquidity moved sqrtPrice from 79.15e27 to 77.49e27, about 4% in output). Any swapper with a slippage bound or price limit then reverts, which reverts the whole transaction including the beneficiary's nested trade: blocking is free and selective (the beneficiary can key it on tx.origin, size or direction). A swapper without a slippage bound is instead sandwiched atomically (the beneficiary keeps the tokens it bought ahead of them as claims, as the test's control variant shows). The afterSwap path (exact-input sells, exact-output buys) is not blockable this way because the swapper's delta is fixed before the payout, but the beneficiary can still back-run inside it. As in round 1, anyone can become beneficiary for a refundable 0.05 ETH against an undefended king, and the pool binding is immutable. Fix that keeps pay-at-source: give the beneficiary no execution while the manager is unlocked. Pay beneficiaries with code (beneficiary.code.length != 0) by poolManager.mint(beneficiary, 0, cut) (same -cut hook delta, no callback) and document redemption (burn + take in the recipient's own unlock), paying only code-less addresses by take; or require the pool's slot0 (sqrtPrice, tick) and liquidity to be unchanged after the take in payout(), which blocks trades on this pool but not on other pools of the same manager. Lowering PAYOUT_GAS below a swap's cost (~96k measured, so ~40k) would also stop it but is a weaker guarantee.","line":409,"path":"src/CrownHook.sol","reproduction":"State: CrownRegistry('CRWN', token, kingWallet); CrownHook with setRegistry(registry) and registerPool(ETH/CRWN key, keccak256('CRWN'), 100); 1000e18 full-range liquidity at price 1. Control: exact-input buy of 1 ETH with minOut = 99% of the quoted output succeeds, kingWallet receives 0.01 ETH. Attack: contract B deposits 50 ETH into the manager as ERC-6909 claims of currency 0 (unlock: settle{value: 50 ether}(); mint(B, 0, 50 ether)); after 7 days B calls openChallenge{value: 0.01 ether}(CRWN, challengerToken) and stake{value: 0.04 ether}(id, Challenger); at finalizeAfter finalize(id) makes B the beneficiary. B's receive(), when msg.sender is the manager, calls swap(key, zeroForOne=true, amountSpecified=+20e18 (exact-output buy), MIN_SQRT_PRICE+1), then burn(B, 0, -amount0) and mint(B, tokenId, amount1). A swapper quotes a 1 ETH exact-input buy, then sends it with minOut = 99% of the quote. Expected (brief: 'the hook must never revert or block a swap'; payout() comment: 'no beneficiary can hold the pool hostage'): the buy executes at the quoted price, with or without the cut. Actual: the hook's payout succeeds (B's nested swap used 96,270 gas and left no delta, balance or sync trace), the pool price is 4% worse when the user's swap runs, the router's slippage check reverts with 'slippage', and the entire transaction, including B's nested trade, is rolled back, so the blockade costs B nothing. forge test --match-path test/scratch/ClaimsSandwich.t.sol fails with [FAIL: exact-input buy with 1% slippage blocked by the king's beneficiary] on this code.","severity":"high","snippet":"        pm.take{gas: PAYOUT_GAS}(CurrencyLibrary.ADDRESS_ZERO, beneficiary, cut);","title":"Not fixed: a contract beneficiary can still trade inside its payout with ERC-6909 claims, leaving no trace payout() checks, and so block (or sandwich) every exact-input buy and exact-output sell"}],"hash":"0d471ba83002820ec63c15f2578f4be813ddf66e8395313fd0f19de02de1b35c","nodeId":"56179a94-15e4-4baf-a86e-0dbf9ccb370e","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds one finding plus a 30-row coverage record.\n\n**Settled from round 1**\n\n- **Hostile beneficiary blocking swaps (high): not fixed.** The earlier proof now passes, because delta-opening re-entries are rolled back. But the new `payout` trace checks miss a trade the beneficiary settles entirely in ERC-6909 claims. With ETH parked in the manager as claims, its `receive` can swap on the launch pool, close the deltas with `burn` and `mint`, and leave the delta count, ETH balance and sync slots exactly as the checks expect. The nested swap costs 96k gas, inside the 150k budget. On the beforeSwap path it buys ahead of the swapper, and any slippage bound then reverts the whole transaction, including the beneficiary's trade, so blocking is free and selective. Proof at `test/scratch/ClaimsSandwich.t.sol` fails on this tree with the swapper's slippage revert. Suggested fix is to pay beneficiaries with code by `poolManager.mint` claims so no code runs while the manager is unlocked.\n- **Challenge-slot lockout (medium): fixed** by displacement at double the bond with full refunds. I verified the sham tie, the doubling ladder, and that the registry balance covers every claim.\n- **Owner-chosen registry (medium): fixed** by the codehash check and the king-equals-pool-token check. A fake registry is refused and ThroneRegistry accepted. The documented two-call setup gap remains and matches the brief.\n- **Partial cut (low): fixed.** The hook pays `min(cut, balance)`.\n- **Rounding dust (low): dropped.** The author's objection is correct: per-staker ceiling refunds could exceed what finalize reserved, so the dust is a documented assumption.\n- **Unchecked ticker binding (low): fixed** in `registerPool`.\n\n**Also checked**: hook creation code is 20,976 bytes despite embedding both registries' runtime code, the manifest matches the constructor and permissions, and all 82 repository tests pass.","treeHash":null,"usage":{"cachedInputTokens":1455765,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":38419,"runtime":"claude","turns":19,"wallClockMs":602551}},{"artifacts":[],"attempt":1,"bundleHash":"976256ce46f33dbc39b8516ce168886d0163c2627dfa91232b003f12bb22d63a","device":"7e929507773df661","findings":[],"hash":"132858940e6f37ecb774557be76f98218d9266a88b42ee558260dc6be96bdf03","nodeId":"94409366-1957-462b-8d1d-4e067b82f894","outcome":"completed","summary":"All 87 tests pass with the verifier's fuzz seed (78 delivered, 9 scratch), `forge build` is clean, and the only modified paths are `test/CrownHook.t.sol`, `test/invariant/CrownHookInvariant.t.sol` and `test/README.md`.\n\n**What I settled**\n\n- **High, fees on unexecuted input: fixed, verified.** The author could not run Foundry, so I ran their four new tests first. They pass. I then attacked the new rehearsal path directly. Partial fills on the two afterSwap shapes pay the cut on executed ETH only. An empty pool charges nothing in any of the four shapes. A hooked pool after a 1 ETH buy lands on the same price, tick, output and LP fee growth as a hook-less pool after a 0.99 ETH buy, so the rehearsal leaves no trace. A random-limit fuzz over all four shapes holds the cut to bps of the ETH actually moved. A gas sweep over the amount forwarded to the swap finds no window where the rehearsal fails but the trade still completes, so the \"no cut on rehearsal failure\" fallback is not a fee bypass.\n- **Medium, malformed 96-byte registry reply: fixed, verified.** The author's dirty-word test passes. I removed the stale exclusion of 96-byte replies from the reply-length fuzz. 96 zero bytes now asserts a \"no king\" skip and every other length a failed-read skip.\n- **Info, unchanged king token: author's answer accepted.** The brief requires the king record to change on a flip. The end-to-end test already asserts the registry address, pool key, traded currency and token code are byte-identical across the dethrone, which is the reading that holds. Not re-reported.\n\n**One observation, recorded in the README rather than reported.** On a full fill of an ETH-specified order the cut is bps of the order, while on partial fills and token-specified orders it is bps of the ETH the pool moved. The two bases differ by the cut itself. The brief leaves the base open, so the tests assert the implemented behaviour exactly and bound the cut between bps of the user's ETH and bps of the pool's ETH.\n\n**Invariants.** The hook handler now mixes price-limited partial buys and sells into the 256 random sequences, with a partial fill forced at the end of every sequence. Payment accounting and zero-custody invariants hold.\n\nNo `.imd-findings.json` was written because no open finding remains. Changes are left uncommitted in the working tree, as in the previous round.","treeHash":"6252b98bea26cccbcd10f2edfad6958e7f28dc08","usage":{"cachedInputTokens":1578160,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":35908,"runtime":"claude","turns":37,"wallClockMs":585691}},{"artifacts":[],"attempt":1,"bundleHash":"b26ba4f79f19aa6838f3298c30e4e56dd03b2691e7f0840923b7248b9d131c78","device":"733f63ff9321d57a","findings":[],"hash":"208c51b7ebcc8053f1408fc9f8c738a94b50ad36e8c61a26a4956b1c6f6d2bb3","nodeId":"516fb97b-4bec-4f44-9c31-266ef557eae1","outcome":"completed","summary":"Implemented the CROWN frontend, source, lockfile and static export under `dist/`.\n\n- Build and typecheck pass.\n- 78 Foundry tests pass.\n- Chromium and WebKit suites pass.\n- All 16 design checks pass.\n- Submission files total approximately 4.82 MB.\n\nNo deployment handoff was supplied, so the app shows “Awaiting launch” and disables financial actions. No live transactions were broadcast.\n\nSetup, design and validation details are documented in `README.md`, `DESIGN.md` and `validation/README.md`.","treeHash":"c679cc7aa0baf0ca67dfef944c243813d62abedc","usage":{"cachedInputTokens":14006400,"inputTokens":276251,"model":"gpt-6-astra","outputTokens":97882,"runtime":"codex","turns":13,"wallClockMs":2874382}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"934ef01306a3cc89","findings":[{"citation":"resolved","description":"Flow gap (execution x periphery x first principles). The hook's stated guarantee is that it never reverts or blocks a swap: a rejecting or gas-burning beneficiary is caught by try/catch and the cut is skipped. But the beneficiary is paid by `poolManager.take`, i.e. by a native `call` made from the PoolManager while its unlock is open, with ~150k gas. A contract beneficiary can accept the ETH (so `take` succeeds, `crownPaid` is incremented, the hook returns +cut) and, inside its receive, call any `onlyWhenUnlocked` function that records a delta for itself and never settle it, e.g. `poolManager.mint(address(this), 0, 1)` (~45k gas). When the swapper's `unlock` returns, `NonzeroDeltaCount != 0` and the whole swap reverts with `CurrencyNotSettled()`. The beneficiary is attacker-chosen: `openChallenge` sets `challengerBeneficiary = msg.sender`, and an undefended king is flipped for a 0.01 ETH bond plus 0.04 ETH of refundable stake. Once crowned, the hostile king can arm/disarm the blockade at will (storage flag), block only other people's trades (e.g. check tx.origin) or only one direction, and holds the pool hostage for at least MIN_REIGN + STAKE_WINDOW + TIMELOCK (11 days) and as long as it can out-stake defenders. The pool's cut binding is immutable and there is no admin, so nothing can unbind the pool. Both the beforeSwap path (exact-input buys, exact-output sells) and the afterSwap path (exact-input sells, exact-output buys) are affected. Fix that preserves pay-at-source: do the payment through a self-call (`try this.payOut(beneficiary, cut)`) that reads `poolManager.getNonzeroDeltaCount()` before the take and reverts if it grew by more than the hook's own one slot (or if `poolManager.currencyDelta(beneficiary, ETH)` became non-zero); the catch then skips the cut and the inner revert undoes the beneficiary's side effects. Alternatively pay contract beneficiaries via an ERC-6909 mint (no external call) and wallets directly.","line":344,"path":"src/CrownHook.sol","reproduction":"State: launch pool ETH/CRWN bound to ticker CRWN with cutBps=100, registry set, liquidity added. 1) swapper exact-input buy 1 ETH -> succeeds, crownPaid = 0.01 ETH. 2) warp 7 days; attacker contract H calls registry.openChallenge{0.01 ETH}(CRWN, otherToken) then stake{0.05 ETH}(id, Challenger); warp 96h; finalize(id) -> king(CRWN).beneficiary == H. 3) H.arm(true): its receive() now calls poolManager.mint(H, 0, 1). 4) swapper exact-input buy 1 ETH. Expected (README 'never reverts a swap', brief 'the hook must never revert or block a swap'): the swap executes, with or without the cut. Actual: hook's take succeeds, CrownPaid emitted, then PoolManager.unlock reverts with CurrencyNotSettled(); the same happens for exact-input sells (afterSwap path). test/scratch/HostileBeneficiaryBlocksSwaps.t.sol fails with [FAIL: CurrencyNotSettled()] on the current code.","severity":"high","snippet":"        try poolManager.take{gas: PAYOUT_GAS}(CurrencyLibrary.ADDRESS_ZERO, beneficiary, cut) {","title":"A king beneficiary that accepts the cut but leaves a dirty PoolManager delta blocks every swap on the pool"},{"citation":"resolved","description":"Economic security / legitimate feature turned against the protocol. The only checks on a challenger are `challengerToken != 0`, `challengerToken != king.token` and the 0.01 ETH bond; the opener names itself beneficiary. The king's own beneficiary can therefore open a challenge against itself with a throwaway token, stake 0.01 ETH on the king side so it fails, and repeat. Each cycle holds the ticker for 72h window + 24h timelock + 3d cooldown = 7 days and costs 0.001 ETH (20% of the 0.01 bond is slashed, half of which returns to the incumbent as the sole king-side staker). Zero-cost variant: the incumbent stakes 0.04 ETH on its own challenger side, 'flips' the crown to its alt token with the same beneficiary, nothing is slashed, every wei is refunded, and `reignStartedAt` resets so MIN_REIGN locks the ticker for another 7 days (11 days per cycle, alternating two alt tokens to pass the SameToken check). In both variants a rival can only ever open a challenge in the one block where the lock expires, where the incumbent is competing to reopen, so 'anyone can challenge the king' degrades to a per-week gas/ordering race the incumbent controls between rounds. A non-king griefer can do the same against any ticker to keep a specific rival from challenging. The fee stream of the pool (1% of all ETH volume) is what is being protected, so the incumbent's cost is negligible against it. Possible mitigations within the design: let a second challenger open during a live challenge only if they out-bond it, or disallow a challenge whose opener is the current beneficiary, or make the cooldown/min-reign not restart when the winning beneficiary is unchanged.","line":188,"path":"src/CrownRegistry.sol","reproduction":"Genesis king CRWN with beneficiary I. warp +7d. I: openChallenge{0.01}(CRWN, altA) -> id; I: stake{0.01}(id, King). Rival R: openChallenge{0.01}(CRWN, rivalToken) at any time up to windowEnd+24h -> reverts ChallengeLive. finalize(id): challenger 0.01 == king 0.01 so king wins, cooldownUntil = now+3d; R: openChallenge -> reverts InCooldown. I: claim(id) recovers 0.01 + 0.008 + 0.001 bonus = 0.019 of 0.02; net cost 0.001 ETH. Repeat with altB. Three cycles cost exactly 0.003 ETH and R never gets in (test_incumbentOccupiesChallengeSlotForever in test/scratch/RegistryEconomics.t.sol). Zero-cost variant: I stakes 0.04 on Challenger instead; finalize flips to altA with beneficiary I, claim returns all 0.05 ETH, treasuryOwed == 0, and R's openChallenge reverts ReignTooYoung(now+7d) (test_incumbentSelfFlipRestartsReignForFree).","severity":"medium","snippet":"        if (hasLiveChallenge(ticker)) revert ChallengeLive(ticker, liveChallenge[ticker]);","title":"Incumbent (or any griefer) can occupy the single challenge slot indefinitely with self-challenges, locking real challengers out"},{"citation":"resolved","description":"Economic incentive note on the auction design. Winning is `challengerStake > kingStake` at a public, fixed `windowEnd`, stakes are visible, and the winning side's stake is fully refunded plus 10% of the losing side's. Whoever can place the last stake before windowEnd (a block builder, or anyone with more capital than the current leader) wins deterministically; the side that committed early loses 20%. Defending a crown is therefore strictly dominated for anyone with less capital than the richest interested party, and the fee stream goes to capital rather than to a vote. This is close to the brief's stake-vote design, so it is reported low as a trust assumption the README should state; a last-minute-stake window extension (anti-sniping) or a commit-reveal would address it without changing the rules otherwise.","line":214,"path":"src/CrownRegistry.sol","reproduction":"Genesis king beneficiary I, rival R. warp +7d; R openChallenge{0.01}(CRWN, rivalToken); I stake{1 ETH}(id, King). At windowEnd-1: R stake{0.99 ETH + 1 wei}(id, Challenger); I cannot respond (next block is >= windowEnd). finalize after timelock: R is beneficiary, claimable(id, R) = 1.1 ETH + 1 wei (own 1 ETH+1 wei back plus 0.1 ETH of I's stake), claimable(id, I) = 0.8 ETH; treasury 0.1 ETH. test_lastSecondOutStakeTakesTenPercentOfDefender in test/scratch/RegistryEconomics.t.sol.","severity":"low","snippet":"        if (block.timestamp >= c.windowEnd) revert WindowClosed(c.windowEnd);","title":"Stake window closes at a fixed timestamp with no extension, so the last staker in the final block decides the crown and takes 10% of the loser"},{"citation":"resolved","description":"State coupling between hook and registry is not checked at binding time. `registerPool(key, ticker, cutBps)` only requires the pool to be initialized through this hook and the ticker to be non-zero; it does not require `registry.king(ticker).token != 0`, let alone that it equals `key.currency1`. `registerKing` is permissionless and first-come (README line 41-42 acknowledges this for the genesis case only). For every pool after the genesis one, if the owner binds the pool before (or in a separate transaction from) the king registration, anyone who sees the binding can call `registerKing(ticker, anyToken, self)` first and collects `cutBps` of all ETH volume on that pool until out-staked in a challenge, which cannot even start for 7 days. The binding is immutable and there is no admin to repair it. Fix: in `registerPool`, require `registry` to be set and `registry.king(ticker).token == Currency.unwrap(key.currency1)` (the pool's own token is the king at binding time), or at least `king(ticker).token != 0`.","line":147,"path":"src/CrownHook.sol","reproduction":"Owner initializes a second native pool ETH/FOO on CrownHook and calls hook.registerPool(keyFoo, keccak256('FOO'), 100) intending to call registry.registerKing(keccak256('FOO'), FOO, fooTeam) next. Attacker A front-runs with registry.registerKing(keccak256('FOO'), 0xjunk, A) -> Crowned; the owner's registerKing reverts AlreadyCrowned. Every swap on ETH/FOO now pays 1% of its ETH side to A (CrownPaid events to A); fooTeam can only open a challenge after 7 days and must out-stake A to recover the stream. Expected: binding a pool to a ticker nobody has crowned (or whose king is not the pool's token) is refused.","severity":"low","snippet":"        if (!p.initialized) revert PoolNotInitialized();","title":"registerPool accepts a ticker with no king, so a front-runner can crown themselves and capture that pool's cut"}],"hash":"2c009e7a4b452575e9e699cdf64fbc1900debe5e6593040241deca818ab1c3ce","nodeId":"ec28c465-28e1-454a-aaca-631d089c98d7","outcome":"completed","summary":"The review is complete. The findings file is written and valid, no repository source was changed, and the scratch tests confirm each reproduction.\n\n**What I found**\n\n- **High, with a failing proof test.** A king whose beneficiary is a contract can block every swap on the pool. The hook pays the cut through `poolManager.take` while the manager's unlock is open. A beneficiary that accepts the ETH and then records a one-wei unsettled delta for itself makes the swapper's unlock revert with `CurrencyNotSettled`. The hook's try/catch sees a success, so the \"never block a swap\" guarantee fails. Anyone becomes beneficiary by winning an undefended challenge for a refundable 0.05 ETH, and the blockade can be armed, disarmed, or made selective. The proof in test/scratch/HostileBeneficiaryBlocksSwaps.t.sol fails on the current code with that exact revert.\n- **Medium.** The incumbent can occupy the single challenge slot forever with self-challenges against a throwaway token. A failing self-challenge costs 0.001 ETH per seven days. A self-flip to its own alt token costs nothing and restarts the seven-day minimum reign. Rivals can only enter in the one block where each lock expires. Reproduced in test/scratch/RegistryEconomics.t.sol.\n- **Low.** The stake window ends at a fixed public timestamp with no extension, so the last staker in the final block wins and takes 10% of the loser. Reported as a design trust assumption with exact numbers.\n- **Low.** `registerPool` does not check that the ticker has a king, so binding a pool before the king registration lets a front-runner crown themselves and collect that pool's cut for at least seven days.\n\n**Coverage**\n\nAll 26 listed entry points have a row. The ERC-20 tokens, owner functions, claim, treasury withdrawal, and the simulateSwap rehearsal hold. The swap callbacks, registry challenge flow, and pool binding carry findings. I verified the escrow conservation and hook zero-delta invariants by trace. One row is marked unreached: a gas-exhaustion divergence between rehearsal and real swap, and reentrant beneficiary swaps inside the payout gas, which I reasoned about but did not execute.\n\n**Suggested fix for the high finding**\n\nRoute the payout through a self-call that reads the manager's nonzero-delta count before the take and reverts if it grew by more than the hook's own slot. The outer catch then skips the cut, and the inner revert undoes the beneficiary's side effects while preserving pay-at-source.","treeHash":null,"usage":{"cachedInputTokens":1233900,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":40492,"runtime":"claude","turns":25,"wallClockMs":535163}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"76e5f9ed417094cc","findings":[{"citation":"resolved","description":"Trust-gap seam (access x economics x asymmetry). Access: CrownRegistry.openChallenge sets challengerBeneficiary = msg.sender with no restriction, so any contract can become the king's beneficiary by winning a challenge; with no defenders that costs 0.05 ETH of stake that is fully refunded (winning side is 100% claimable). Economics/periphery: CrownHook._payCut pays that beneficiary with poolManager.take inside the swap, while the PoolManager is unlocked. The try/catch on line 344 only protects against the payment itself reverting (EthRejecter / GasBurningBeneficiary are tested). It cannot protect against what the beneficiary does with the ~140k gas it receives: any call that leaves a non-zero currency delta on the beneficiary (poolManager.mint(self, 0, 1), or take(ETH, x, 1)) succeeds, the hook records crownPaid and returns normally, and then PoolManager.unlock reverts the entire transaction with CurrencyNotSettled because NonzeroDeltaCount != 0. Both payment paths are affected: beforeSwap (ETH-specified, line 174) and afterSwap (ETH-unspecified, line 198). Result: once a griefing contract holds the crown, no swap of either direction on any pool bound to that ticker can execute until it is dethroned, which takes at least MIN_REIGN (7 days) + 72h window + 24h timelock, and the griefer can keep re-defending with fully refundable stake. The spec says 'The hook must never revert or block a swap: if the registry read or the transfer fails, the swap proceeds without the cut.' The same callback also hands an arbitrary beneficiary execution inside every swap with the manager unlocked (it may trade the same pool before the user's swap in the beforeSwap path), which the pay-at-source design never intended. Minimal fix that preserves pay-at-source: do the take through a self-call (try this.payout(beneficiary, cut)) that, after take, reads poolManager.getNonzeroDeltaCount() (TransientStateLibrary) and reverts if it changed, so a beneficiary that leaves a debit behind is rolled back and the cut is skipped like any other failed payment; alternatively pay contract beneficiaries with poolManager.mint (ERC-6909 claim, no callback) and only EOAs by take.","line":344,"path":"src/CrownHook.sol","reproduction":"State: ETH/CRWN pool bound to keccak256('CRWN') with 100 bps, registry set, genesis beneficiary an EOA. 1) Attacker deploys contract A whose receive() calls poolManager.mint(address(A), 0, 1). 2) At reignStartedAt + 7 days, A calls registry.openChallenge{value: 0.01 ether}(CRWN, anyToken) (A becomes challengerBeneficiary) and registry.stake{value: 0.04 ether}(id, Challenger). 3) 96 hours later anyone calls registry.finalize(id): challengerStake 0.05 > kingStake 0, total >= 0.05 quorum, king(CRWN).beneficiary == A. 4) Any router swap on the pool, e.g. swap(zeroForOne=true, amountSpecified=-1 ether) or swap(false, -1e18): expected (spec) the swap proceeds, with or without the cut; actual the whole transaction reverts with IPoolManager.CurrencyNotSettled(). 5) registry.claimable(id, A) == 0.05 ether: the attack cost nothing but gas. Run: forge test --match-path test/scratch/BeneficiaryBricksSwaps.t.sol (fails on current code with CurrencyNotSettled).","severity":"high","snippet":"        try poolManager.take{gas: PAYOUT_GAS}(CurrencyLibrary.ADDRESS_ZERO, beneficiary, cut) {","title":"A challenge winner that is a contract can make every swap on the pool revert (hook 'never blocks a swap' guarantee broken at zero cost)"},{"citation":"resolved","description":"Trust-gap seam (access x economics x asymmetry). Access: openChallenge accepts any msg.sender and any challengerToken != k.token, including the king's own beneficiary naming a throwaway address, and finalize crowns c.challengerBeneficiary = msg.sender of the opener, so a self-challenge 'flip' keeps the fee recipient unchanged. Economics: a successful challenge is free (the winning side is 100% refundable and there is no losing side to slash when nobody defends), so the incumbent needs 0.05 ETH of working capital and loses nothing. Asymmetry: the one-live-challenge lock on line 188 plus the MIN_REIGN reset in finalize (reignStartedAt = block.timestamp) protect whoever opens first, and the incumbent knows the exact first challengeable second (reignStartedAt + 7 days) and can submit in that block (or sandwich any outsider's openChallenge in the mempool). Cycle: day 0 crowned; day 7 self-challenge opens (outsiders: ReignTooYoung before, ChallengeLive after); day 11 finalize flips to the incumbent's dummy token with the same beneficiary and restarts the 7-day clock; day 18 repeat. Outsiders never get a block in which openChallenge succeeds unless they win a same-block ordering race against a bot, and staking on the challenger side of the sham does nothing for them (the beneficiary is already the incumbent). This defeats the system's core guarantee that 'anyone can challenge the king'. Fix options (design decision): make a challenge cost something even when it succeeds (burn or treasury the bond), do not reset reignStartedAt when the beneficiary is unchanged, or allow a competing challenge to be opened/queued against a live one so the lock cannot be used as a shield.","line":188,"path":"src/CrownRegistry.sol","reproduction":"State: CrownRegistry deployed with genesis CRWN, kingWallet beneficiary. Loop: 1) at reignStartedAt + 7 days - 1 outsider's openChallenge{value: 0.01 ether}(CRWN, outsiderToken) reverts ReignTooYoung. 2) at reignStartedAt + 7 days kingWallet calls openChallenge{value: 0.01 ether}(CRWN, 0x1000) then stake{value: 0.04 ether}(id, Challenger). 3) outsider's openChallenge now reverts ChallengeLive(CRWN, id) for 96 hours. 4) finalize(id): king(CRWN) = {token 0x1000, beneficiary kingWallet, reignStartedAt now}; kingWallet.claim(id) returns the full 0.05 ether (balance unchanged). 5) outsider again gets ReignTooYoung for 7 days. Verified for 3 cycles in a scratch test (test/scratch/SelfChallengeLockout.t.sol): expected an outsider can open a challenge at some point after the first 7 days; actual every outsider call reverts and the incumbent's ETH balance is unchanged after each cycle.","severity":"medium","snippet":"        if (hasLiveChallenge(ticker)) revert ChallengeLive(ticker, liveChallenge[ticker]);\n        uint64 challengeableAt = k.reignStartedAt + MIN_REIGN;\n        if (block.timestamp < challengeableAt) revert ReignTooYoung(challengeableAt);","title":"Incumbent can self-challenge for free in the first challengeable block and keep every other challenger locked out of the ticker indefinitely"},{"citation":"resolved","description":"Trust assumption to document, not a bypass. The brief says the hook reads registry.king(ticker).beneficiary from the rule-based CrownRegistry and that there is no admin after deployment; in the implementation the registry address is not a constructor argument but an owner-set value, and $owner is also the genesis beneficiary. The owner can bind a contract whose king() always returns the owner (or any address), after which no challenge in the real CrownRegistry changes who the pool pays. Nothing on-chain ties the hook to the CrownRegistry that the site and the challenge game refer to. Ownership is one-step (transferOwnership/renounceOwnership from OZ Ownable), and renouncing before setRegistry/registerPool leaves the pool permanently cut-less. Suggested: take the registry as a constructor argument or emit/verify the expected codehash, and document the owner's powers (registry choice, per-pool ticker and cut up to 500 bps) in the README as trust assumptions.","line":131,"path":"src/CrownHook.sol","reproduction":"State: hook deployed, registry unset. Owner deploys contract F { function king(bytes32) external view returns (ICrownRegistry.King memory) { return King(tokenX, owner, 0); } } and calls hook.setRegistry(F) then hook.registerPool(key, keccak256('CRWN'), 500). A real CrownRegistry dethrone of CRWN later changes nothing: every swap on the pool keeps paying 5% of its ETH side to the owner. Expected per brief: the pool pays the current king of the CrownRegistry; actual: it pays whoever F names.","severity":"low","snippet":"    function setRegistry(ICrownRegistry registry_) external onlyOwner {\n        if (address(registry) != address(0)) revert RegistryAlreadySet();\n        if (address(registry_) == address(0) || address(registry_).code.length == 0) revert ZeroAddress();\n        registry = registry_;","title":"Hook owner chooses the registry after launch; any contract with code is accepted, so the fee recipient the pool follows is whatever the owner binds, not necessarily CrownRegistry"},{"citation":"resolved","description":"Asymmetry between what finalize accounts for (slash = losingTotal*20%, split into winnerBonus and treasuryOwed, computed on the side totals) and what claim pays (each staker's 80% refund and bonus share floored individually). The difference is never assigned to anyone: there is no sweep, and treasuryOwed only receives its half of the slash. The stranded amount is bounded (under one wei per staker per term) so impact is dust, but the brief asked for slash accounting 'exact to the wei' and the contract's ETH balance will drift above the sum of all claimables. Fix: compute refunds from the side's total (e.g. refund = loseStake - loseStake*SLASH_BPS/BPS, rounding the slash down per staker) or credit the rounding remainder to treasuryOwed at finalize.","line":167,"path":"src/CrownRegistry.sol","reproduction":"Challenge where the king side loses with two stakers of 3 wei each (kingStake 6) and the challenger side staked 0.05 ether. finalize: slash = 6*2000/10000 = 1, toWinners = 0, toTreasury = 1. Each king staker claims (3*8000)/10000 = 2, total 4. Paid out 4 + 1 (treasury) = 5 of the 6 wei staked by the losers; 1 wei is permanently unclaimable by anyone. Expected: 6 wei fully assigned (4.8 refunds + 1.2 slash); actual: 1 wei stranded.","severity":"low","snippet":"        if (winStake != 0) amount += winStake + (c.winnerBonus * winStake) / winTotal;\n        // Floored per staker, so the refunds never sum to more than the side's unslashed 80%.\n        if (loseStake != 0) amount += (loseStake * (BPS - SLASH_BPS)) / BPS;","title":"Per-staker floor rounding strands the slash and refund remainders in the registry forever"},{"citation":"resolved","description":"By the brief's own rule ('the first registration for a ticker crowns that token'), so reported as an access-control trust assumption rather than a bypass. The genesis CRWN crown is set in the constructor and is safe. For every other ticker the hook owner might later bind with registerPool, an unprivileged bot can call registerKing(ticker, anyAddress, bot) first (ticker is an arbitrary bytes32; nothing checks it is keccak256 of an upper-cased symbol or that token is a contract). Because the hook pays registry.king(ticker).beneficiary from the first swap, a pool bound to a squatted ticker pays the squatter until a challenge completes (7-day MIN_REIGN + 72h + 24h), and the squatter can defend with refundable stake. Document that pools must be bound only to tickers the deployer crowned itself, or crown in the same transaction as the binding.","line":175,"path":"src/CrownRegistry.sol","reproduction":"Bot calls registry.registerKing(keccak256('ETH'), 0x1234..., bot) on a fresh registry. Later the hook owner registers an ETH/WETH-ticker pool with registerPool(key, keccak256('ETH'), 100). Expected: the deployer's chosen token/beneficiary is king; actual: every swap pays 1% of its ETH side to bot for at least 11 days and the deployer's own registerKing reverts AlreadyCrowned.","severity":"info","snippet":"    function registerKing(bytes32 ticker, address token, address beneficiary) external {\n        if (_kings[ticker].token != address(0)) revert AlreadyCrowned(ticker);\n        _crown(ticker, token, beneficiary);","title":"registerKing is first-come with no cost or ownership check, so any ticker the owner may later bind can be squatted and its fees redirected for at least 11 days"}],"hash":"3443f8c6c4d66c47efc5999cb331a69fcf212fce744f7447fe70d6d2bffd6b07","nodeId":"0a28185b-a5c9-41cc-b5b6-47c047167770","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds 5 findings and a 28-row coverage record (all 26 listed entry points plus two invariants), and no repository file was changed. The scratch directory is gitignored.\n\n**Findings, by severity**\n\n- **High: a contract that wins a challenge can brick every swap on the pool.** `CrownRegistry.openChallenge` makes any `msg.sender` the future beneficiary, and winning with no defenders costs 0.05 ETH that is fully refunded. `CrownHook._payCut` then pays that contract with `poolManager.take` while the manager is unlocked. The try/catch at `src/CrownHook.sol:344` only catches a reverting payment. A beneficiary that instead leaves a 1 wei unsettled delta on itself (one `mint` call) returns normally, and the PoolManager rejects the whole unlock with `CurrencyNotSettled`. Buys and sells both fail, for at least 11 days per cycle, at zero cost. The proof test fails on the current code with exactly that error.\n- **Medium: the incumbent can lock every outsider out of challenges forever.** In the first challengeable second the king's beneficiary opens a challenge against itself with a throwaway token and stakes quorum. Outsiders get `ReignTooYoung` before and `ChallengeLive` after. The \"flip\" names the same beneficiary, restarts the 7-day clock, and the full stake is refunded. Verified across three cycles with the incumbent's balance unchanged.\n- **Low: the hook owner picks the registry after launch.** `setRegistry` accepts any contract with code, so the fee recipient the pool follows is whatever the owner binds, not necessarily the rule-based CrownRegistry. Reported as a trust assumption with the one-step ownership noted.\n- **Low: per-staker floor rounding strands wei permanently.** Two losing stakers of 3 wei each leave 1 wei nobody can claim. Confirmed numerically.\n- **Info: `registerKing` is first-come with no cost**, so any ticker not crowned in the constructor can be squatted ahead of a pool binding. By the brief's rule, so documented rather than counted as a bypass.\n\n**Coverage.** Every hook callback, owner function, and registry action is traced. The ERC-20s are unmodified OpenZeppelin code and hold. `simulateSwap`, `registerPool`, `stake`, `finalize`, and `withdrawTreasury` hold against the Access Control, Asymmetry, and Trust Gap checklists. I did not have budget to exercise the web frontend or the deploy script's broadcast path, which fall outside the assigned area.","treeHash":null,"usage":{"cachedInputTokens":1465536,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":41933,"runtime":"claude","turns":31,"wallClockMs":605922}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ce6eaff570c608ab","findings":[{"citation":"resolved","description":"Boundary: the native `call` inside `poolManager.take` runs the beneficiary's receive() while the PoolManager is unlocked and the swap is mid-flight. The hook assumes the only way the payout can hurt the swap is by reverting or burning gas, both caught by try/catch and the 150k gas cap. The actual behaviour: a beneficiary that is a contract can, within far less than 150k gas, call any unlocked PoolManager function that creates a delta on itself (`mint(address(this), 0, 1)`, `take(ETH, other, 1)`, `burn`, ...) and return normally. `take` succeeds, the hook books the cut and returns, but at the end of `unlock` the PoolManager finds NonzeroDeltaCount != 0 and reverts with CurrencyNotSettled. The swap, not just the cut, fails, and it fails in both callbacks (beforeSwap for ETH-specified orders, afterSwap for token-specified orders), so no order shape on the pool trades. The beneficiary address is set by whoever opens a winning challenge (`c.challengerBeneficiary = msg.sender`), so an attacker contract can obtain it for the price of a bond plus 0.05 ETH of stake, all of which is refunded when the challenge wins against an undefended king; once crowned it holds a 7-day minimum reign plus a 4-day challenge cycle, 11+ days during which it can block or selectively allow swaps on every pool bound to the ticker. The existing tests cover a reverting and a gas-burning beneficiary but not one that re-enters the PoolManager. Fix while keeping pay-at-source: pay contracts through an ERC-6909 claim (`poolManager.mint(beneficiary, 0, cut)`), or do the `take` through a self-call that reads `poolManager.getNonzeroDeltaCount()` before and after and reverts (caught by the catch, cut skipped) when it changed, or only push ETH when `beneficiary.code.length == 0` and mint a claim otherwise.","line":344,"path":"src/CrownHook.sol","reproduction":"State: pool ETH/CRWN with CrownHook registered at 100 bps, registry genesis king CRWN. 1) attacker contract A (receive() calls poolManager.mint(address(this), 0, 1)) calls registry.openChallenge{value: 0.01 ether}(keccak256('CRWN'), rivalToken) after 7 days, then stake{value: 0.05 ether}(id, Challenger); after 96 hours anyone calls finalize(id): king(CRWN).beneficiary == A. 2) Any swapper does an exact-input buy of 1 ETH (or an exact-input sell of 1 token). Expected per the contract's own guarantee: the swap completes, with the 0.01 ETH cut skipped or paid. Actual: PoolManager.unlock reverts with CurrencyNotSettled(); the proof test fails with exactly that error. The honest-beneficiary control test in the same file completes and pays 0.01 ETH.","severity":"high","snippet":"        try poolManager.take{gas: PAYOUT_GAS}(CurrencyLibrary.ADDRESS_ZERO, beneficiary, cut) {\n            crownPaid[ticker][CurrencyLibrary.ADDRESS_ZERO] += cut;\n            emit CrownPaid(id, ticker, beneficiary, cut);\n            return cut;\n        } catch {","title":"Beneficiary paid by poolManager.take can leave an unsettled delta and revert every fee-bearing swap, defeating the never-block guarantee"},{"citation":"resolved","description":"Boundary x invariant seam: the one-live-challenge rule and the 3-day cooldown are keyed on the ticker alone, while nothing constrains who opens a challenge or what token they name (only `challengerToken != k.token`). The guarantee 'anyone can challenge the king' therefore holds only when nobody is running a cheaper challenge first. The king's own wallet (or any third party) opens a challenge with a throwaway token for the 0.01 ETH bond and immediately stakes 0.01 ETH on the king side. The challenge is now a tie, and `challengerStake > kingStake` is strict, so it fails at finalize unless an outsider stakes on the puppet challenger side, which only flips the crown to a token whose beneficiary is the same king wallet (`c.challengerBeneficiary = msg.sender`), so no outsider has a reason to. For 96 hours the ticker is `ChallengeLive`, then for 72 hours it is `InCooldown`: a 7-day lockout per cycle, repeatable forever since the reign requirement is already met. Net cost per cycle: bond 0.01 ETH -> 0.008 refund, 0.002 slash of which 0.001 returns to the king-side staker (the same wallet) as winnerBonus, king stake 0.01 fully refunded: 0.001 ETH. The cooldown and liveness checks are implemented exactly as the brief words them, so this is a defect in the rule set rather than a coding slip; a fix changes the agreed rules and needs a scope decision: e.g. apply the cooldown to the failed challenger's address/token instead of the ticker, let a new challenge with a larger opening bond replace a live tied one, or forbid king-side staking by the challenge opener. The existing tests never open a challenge from the king's beneficiary or stake on both sides of a tie.","line":188,"path":"src/CrownRegistry.sol","reproduction":"State: registry with genesis king CRWN (token 0xBEEF, beneficiary K), 7 days elapsed. Loop: K calls openChallenge{value: 0.01 ether}(CRWN, 0x1000+i) -> id; K calls stake{value: 0.01 ether}(id, King). Honest H calling openChallenge{value: 0.01 ether}(CRWN, 0xCAFE) reverts ChallengeLive(CRWN, id). After 96 h anyone calls finalize(id): kingStake 0.01 == challengerStake 0.01 so the challenge fails, cooldownUntil = now + 3 days, H's openChallenge reverts InCooldown. K calls claim(id) and receives 0.01 + 0.001 (winner) + 0.008 (loser) = 0.019 ETH. After 3 days K repeats. The scratch test test/scratch/TickerLockout.t.sol runs 4 cycles: H is rejected on every attempt for 28 days and K's balance falls by exactly 0.004 ether. Expected: a solvent honest challenger can open a challenge against a king whose reign exceeds 7 days; actual: never, while K keeps cycling.","severity":"medium","snippet":"        if (hasLiveChallenge(ticker)) revert ChallengeLive(ticker, liveChallenge[ticker]);\n        uint64 challengeableAt = k.reignStartedAt + MIN_REIGN;\n        if (block.timestamp < challengeableAt) revert ReignTooYoung(challengeableAt);\n        if (block.timestamp < cooldownUntil[ticker]) revert InCooldown(cooldownUntil[ticker]);","title":"Incumbent (or any griefer) can keep a ticker permanently unchallengeable for 0.001 ETH per week with self-defeating challenges"},{"citation":"resolved","description":"Boundary x precision seam on the payout funding. Because the cut is pushed from the manager's existing ETH in beforeSwap, before the swapper's input is settled, the hook skips the whole cut whenever cut > manager.balance instead of paying what it can or deferring the rest as an ERC-6909 claim. The manager's ETH is at most the ETH reserves of all its pools, so any exact-input buy larger than 100x (at 100 bps; 20x at 500 bps) the manager's total ETH pays nothing, while a buy 1 wei smaller pays the full 1%. On a thin launch pool and a young chain (Robinhood Chain's manager holds only what its pools hold) that threshold is low and the amount forgone is the single largest fee event the king will see. The README documents the fresh-manager first buy but not that the condition recurs for every sufficiently large buy; the reference design for IMD fee hooks is to mint a claim for the uncovered part. Fix without changing pay-at-source semantics: pay `min(cut, balance)` directly and `poolManager.mint(beneficiary, 0, cut - paid)` for the remainder, or take the ETH-specified cut in afterSwap once the input has been settled.","line":340,"path":"src/CrownHook.sol","reproduction":"State: CrownHook pool ETH/CRWN at 100 bps, full-range liquidity 1000e18 at price 1, so the manager holds ~1000 ETH (999999999999999999946 wei in the scratch run). A 1 ETH exact-input buy pays 0.01 ETH to the beneficiary. Then an exact-input buy of (balance + 1) * 100 = 100098999999999999994700 wei: cut = 1000989999999999999947 wei > balance, CutSkipped(MANAGER_SHORT_OF_ETH) is emitted, the pool moves the full 100,099 ETH (delta.amount0 = -100098999999999999994700) and beneficiary balance and crownPaid stay at 0.01 ETH. Expected: ~1,000.99 ETH paid (or credited) to the king; actual: 0. test/scratch/WhaleSkip.t.sol shows these numbers.","severity":"low","snippet":"        if (address(poolManager).balance < cut) {\n            emit CutSkipped(id, ticker, cut, \"MANAGER_SHORT_OF_ETH\");\n            return 0;\n        }","title":"A buy whose cut exceeds the PoolManager's ETH balance pays no cut at all, so the largest buys are fee-free"},{"citation":"resolved","description":"The brief says the per-pool cut is 'set at init, default 100, range 0-500'. The constant exists but no code path reads it; registerPool(key, ticker, cutBps) stores whatever the owner passes, including 0, and the binding is immutable afterwards. Not a vulnerability, but a pool registered with a typo'd 0 is permanently fee-free and the constant gives a false sense that 100 applies. Either apply DEFAULT_CUT_BPS when cutBps == 0 and use a sentinel for an intended zero cut, or drop the constant and the 'default' wording.","line":44,"path":"src/CrownHook.sol","reproduction":"Owner calls registerPool(key, keccak256('CRWN'), 0) on an initialized native pool: pools[id].cutBps == 0, quoteCut(id, 1 ether) == 0, every swap emits no CrownPaid; registerPool(key, ...) again reverts PoolAlreadyRegistered, so the pool can never carry a cut. Expected from the brief's wording: a default of 100 bps unless set otherwise.","severity":"info","snippet":"    uint16 public constant DEFAULT_CUT_BPS = 100;","title":"DEFAULT_CUT_BPS is declared but never applied: registerPool has no default and accepts 0"}],"hash":"38cd20c887114df5e631be1a454f5732482fb5621de95b2538ab43c2bcc8114c","nodeId":"48ae19f7-73f6-4a1c-91ac-0a8478515258","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds 4 findings and 29 coverage rows, and no repository file was changed. Git shows nothing tracked as modified; the findings file and `test/scratch/` are ignored.\n\n**What I audited.** The Math Precision, Boundary and Numerical Gap guides against `CrownRegistry`, `CrownHook`, `ThroneRegistry` and the two tokens. All 78 existing tests pass. The slash split, quorum, strict lead, per-staker flooring, escrow conservation, the `_abs`/`MAX_AMOUNT`/int128 casts, and the beforeSwap rehearsal for partial fills in all four order shapes all hold under concrete values. The aderyn \"unsafe casting\" and slither reentrancy leads are not defects as reported, but the reentrancy lead pointed at the real issue below.\n\n**Findings, most severe first:**\n\n1. **High, `src/CrownHook.sol:344`.** The beneficiary's `receive()` runs inside the PoolManager unlock. A contract beneficiary can call `poolManager.mint(address(this), 0, 1)` within the 150k gas cap and return normally, so `take` succeeds but the unlock then reverts with `CurrencyNotSettled`. Every swap on the pool fails, in both callbacks. An attacker gets the beneficiary slot by winning a challenge against an undefended king with fully refundable stake, then holds it for at least 11 days. Proof in `test/scratch/BeneficiaryBlocksSwap.t.sol` fails with exactly that error, and the honest-beneficiary control passes.\n\n2. **Medium, `src/CrownRegistry.sol:188`.** Liveness and cooldown are keyed on the ticker only. The king opens a puppet challenge and ties it from the king side; honest challengers are rejected for 96 hours of window plus 72 hours of cooldown, repeatable forever. Net cost per 7-day cycle is 0.001 ETH. The scratch test runs four cycles and shows the honest challenger rejected for 28 days. This is a rule-set defect and a fix needs a scope decision.\n\n3. **Low, `src/CrownHook.sol:340`.** When the cut exceeds the manager's ETH balance, the whole cut is skipped rather than partially paid or minted as a claim. A buy of about 100,099 ETH against a 1,000 ETH manager pays nothing while a 1 ETH buy pays 0.01 ETH.\n\n4. **Info, `src/CrownHook.sol:44`.** `DEFAULT_CUT_BPS` is never applied; `registerPool` accepts 0 and the binding is immutable.\n\n**Coverage.** All 26 listed entry points have a row, plus three invariants I checked. Not reached: the site, deploy script, README compiler settings and launch manifest, which are outside the math area.","treeHash":null,"usage":{"cachedInputTokens":1100206,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":45531,"runtime":"claude","turns":22,"wallClockMs":634583}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"efd9a4776ef87cda","findings":[],"hash":"3f22a18cf7d7ee5d8f6f471be53903e236c4e4752decda6e861fb35d6ba3cb34","nodeId":"0841d62d-e6c8-4a7a-82ca-a69d8010ad9e","outcome":"failed","summary":"This content was flagged for possible cybersecurity risk. If this seems wrong, try rephrasing your request. If you’re doing authorized security work that requires more cyber permissive safeguards, apply for Daybreak access via https://platform.openai.com/settings/organization/status-and-access before retrying.","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":8,"wallClockMs":3007604}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bf4c5b8707945096","findings":[{"citation":"resolved","description":"Merged from audit_economics, audit_flow, audit_permissions and audit_math, which all report the same root cause. _payCut pays the cut with poolManager.take while the swapper's unlock is still open. take() makes a native call to the beneficiary with up to PAYOUT_GAS. The try/catch only covers a payout that reverts or runs out of gas. A beneficiary contract can instead accept the ETH and, inside receive(), call an onlyWhenUnlocked PoolManager function that books a delta on itself and never settle it, for example poolManager.mint(address(this), 0, 1) or take(ETH, x, 1). The hook's take then returns normally, crownPaid is incremented and the hook returns the delta. When the swapper's unlock ends, NonzeroDeltaCount != 0 and the whole transaction reverts with CurrencyNotSettled. This hits both payment paths: beforeSwap (exact-input buys, exact-output sells) and afterSwap (exact-input sells, exact-output buys). The brief says 'The hook must never revert or block a swap'. Anyone can become the beneficiary: openChallenge sets challengerBeneficiary = msg.sender (src/CrownRegistry.sol:198), and against an undefended king a win costs a 0.01 ETH bond plus 0.04 ETH of stake, all of which can be claimed back. The attacker then holds the pool hostage for at least MIN_REIGN + window + timelock (11 days) and can defend its crown with stake that comes back to it plus the slash bonus. The pool binding is immutable and there is no admin who can unbind it. A side effect: the beneficiary also runs arbitrary code mid-swap with the manager unlocked, for example trading the same pool inside a user's beforeSwap. Fix that keeps pay-at-source: make the payout an external self-call (try this.payout(...)) that does the take and then requires poolManager.getNonzeroDeltaCount() to have grown only by the hook's own entry and poolManager.currencyDelta(beneficiary, ETH) == 0, reverting otherwise. The catch then rolls back both the transfer and the beneficiary's re-entry, and the swap proceeds without the cut.","line":344,"path":"src/CrownHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams, ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\nimport {CrownHook} from \"src/CrownHook.sol\";\nimport {CrownRegistry} from \"src/CrownRegistry.sol\";\nimport {CrownToken} from \"src/CrownToken.sol\";\nimport {CrownChallengerToken} from \"src/CrownChallengerToken.sol\";\n\ncontract Router is IUnlockCallback {\n    IPoolManager immutable manager;\n\n    constructor(IPoolManager m) {\n        manager = m;\n    }\n\n    function liquidity(PoolKey memory key, int256 liq) external {\n        manager.unlock(abi.encode(true, key, liq, false));\n    }\n\n    function swap(PoolKey memory key, bool zeroForOne, int256 amountSpecified) external {\n        manager.unlock(abi.encode(false, key, amountSpecified, zeroForOne));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (bool isLiq, PoolKey memory key, int256 v, bool zeroForOne) = abi.decode(data, (bool, PoolKey, int256, bool));\n        BalanceDelta d;\n        if (isLiq) {\n            (d,) = manager.modifyLiquidity(\n                key,\n                ModifyLiquidityParams({\n                    tickLower: TickMath.minUsableTick(60), tickUpper: TickMath.maxUsableTick(60), liquidityDelta: v, salt: 0\n                }),\n                \"\"\n            );\n        } else {\n            d = manager.swap(\n                key,\n                SwapParams({\n                    zeroForOne: zeroForOne,\n                    amountSpecified: v,\n                    sqrtPriceLimitX96: zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1\n                }),\n                \"\"\n            );\n        }\n        _settle(key.currency0, d.amount0());\n        _settle(key.currency1, d.amount1());\n        return \"\";\n    }\n\n    function _settle(Currency c, int128 a) internal {\n        if (a < 0) {\n            uint256 owed = uint256(uint128(-a));\n            manager.sync(c);\n            if (c.isAddressZero()) {\n                manager.settle{value: owed}();\n            } else {\n                IERC20(Currency.unwrap(c)).transfer(address(manager), owed);\n                manager.settle();\n            }\n        } else if (a > 0) {\n            manager.take(c, address(this), uint256(uint128(a)));\n        }\n    }\n\n    receive() external payable {}\n}\n\n/// @dev A challenge winner whose receive() accepts the cut and leaves a 1-wei ERC-6909 debt open.\ncontract HostileBeneficiary {\n    IPoolManager immutable manager;\n    CrownRegistry immutable registry;\n\n    constructor(IPoolManager m, CrownRegistry r) payable {\n        manager = m;\n        registry = r;\n    }\n\n    function challenge(bytes32 ticker, address token) external returns (uint256 id) {\n        id = registry.openChallenge{value: 0.01 ether}(ticker, token);\n        registry.stake{value: 0.04 ether}(id, CrownRegistry.Side.Challenger);\n    }\n\n    receive() external payable {\n        if (msg.sender == address(manager)) manager.mint(address(this), 0, 1);\n    }\n}\n\ncontract HostileBeneficiaryTest is Test {\n    bytes32 constant CRWN = keccak256(\"CRWN\");\n    uint160 constant FLAGS = (1 << 12) | (1 << 7) | (1 << 6) | (1 << 3) | (1 << 2);\n\n    PoolManager manager;\n    CrownToken token;\n    CrownRegistry registry;\n    CrownHook hook;\n    Router router;\n    PoolKey key;\n    address owner = makeAddr(\"owner\");\n    address kingWallet = makeAddr(\"kingWallet\");\n\n    function setUp() public {\n        vm.warp(1_000_000);\n        manager = new PoolManager(address(this));\n        token = new CrownToken();\n        registry = new CrownRegistry(\"CRWN\", address(token), kingWallet);\n        bytes memory code = abi.encodePacked(type(CrownHook).creationCode, abi.encode(manager, owner));\n        bytes32 h = keccak256(code);\n        for (uint256 i;; i++) {\n            address p = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(i), h)))));\n            if (uint160(p) & ((1 << 14) - 1) != FLAGS) continue;\n            address at;\n            assembly {\n                at := create2(0, add(code, 0x20), mload(code), i)\n            }\n            hook = CrownHook(at);\n            break;\n        }\n        key = PoolKey(Currency.wrap(address(0)), Currency.wrap(address(token)), 12_500, 60, IHooks(address(hook)));\n        manager.initialize(key, 79228162514264337593543950336);\n        vm.startPrank(owner);\n        hook.setRegistry(registry);\n        hook.registerPool(key, CRWN, 100);\n        vm.stopPrank();\n        router = new Router(manager);\n        vm.deal(address(router), 2_000 ether);\n        token.transfer(address(router), 2_000 ether);\n        router.liquidity(key, 1_000e18);\n    }\n\n    function test_hostileKingMustNotBlockSwaps() public {\n        // Control: an honest king is paid 1% of a 1 ETH exact-input buy.\n        router.swap(key, true, -1 ether);\n        assertEq(kingWallet.balance, 0.01 ether);\n\n        // Attacker wins an undefended challenge with fully refundable stake.\n        HostileBeneficiary bad = new HostileBeneficiary{value: 1 ether}(manager, registry);\n        vm.warp(block.timestamp + 7 days);\n        uint256 id = bad.challenge(CRWN, address(new CrownChallengerToken(address(this))));\n        vm.warp(registry.challenges(id).finalizeAfter);\n        registry.finalize(id);\n        assertEq(registry.king(CRWN).beneficiary, address(bad));\n        assertEq(registry.claimable(id, address(bad)), 0.05 ether);\n\n        // Spec: \"The hook must never revert or block a swap\". Both payment paths must still trade.\n        uint256 tokensBefore = token.balanceOf(address(router));\n        router.swap(key, true, -1 ether); // exact-input buy: beforeSwap path\n        assertGt(token.balanceOf(address(router)), tokensBefore, \"exact-input buy blocked by king's beneficiary\");\n        uint256 ethBefore = address(router).balance;\n        router.swap(key, false, -1 ether); // exact-input sell: afterSwap path\n        assertGt(address(router).balance, ethBefore, \"exact-input sell blocked by king's beneficiary\");\n    }\n}","reproduction":"State: CrownRegistry('CRWN', token, kingWallet); hook with setRegistry(registry) and registerPool(ETH/CRWN key, keccak256('CRWN'), 100); 1000e18 full-range liquidity. Control: an exact-input buy of 1 ETH succeeds and kingWallet receives 0.01 ETH. Attack: contract H, whose receive() calls manager.mint(address(this), 0, 1) when msg.sender is the manager, waits 7 days and calls openChallenge{value: 0.01 ether}(CRWN, challengerToken) and stake{value: 0.04 ether}(id, Challenger). After finalizeAfter it calls finalize(id): king(CRWN).beneficiary == H and claimable(id, H) == 0.05 ether. Then any exact-input buy of 1 ETH (or an exact-input sell of 1e18 tokens). Expected: the swap executes, with or without the cut. Actual: it reverts with CurrencyNotSettled(). I ran the proof with forge test --match-path test/scratch/HostileBeneficiary.t.sol; it fails with [FAIL: CurrencyNotSettled()] after the control buy succeeded.","severity":"high","snippet":"        try poolManager.take{gas: PAYOUT_GAS}(CurrencyLibrary.ADDRESS_ZERO, beneficiary, cut) {","title":"A contract beneficiary (any challenge winner) can make every swap on the pool revert by leaving an open delta in the unlocked PoolManager during its payout"},{"citation":"resolved","description":"Merged from audit_economics, audit_flow, audit_permissions and audit_math (same root cause). openChallenge is first-come. It checks only challengerToken != 0, challengerToken != king.token and the bond, and the opener names itself beneficiary. A live challenge blocks every other opener, a failed one sets a 3-day ticker cooldown, and a successful one resets reignStartedAt, which brings back the 7-day MIN_REIGN. Tie variant: the king's beneficiary opens a challenge with a throwaway token and stakes the same 0.01 ETH on the King side. challengerStake > kingStake is strict, so the challenge fails. Each cycle locks the ticker for 72h + 24h + 72h = 7 days and costs a net 0.001 ETH: 0.002 is slashed and 0.001 of it comes back as winner bonus. Free variant: the incumbent stakes 0.04 ETH on its own challenger side. The crown flips to its alt token with the same beneficiary, nothing is slashed, all 0.05 ETH is refunded, and MIN_REIGN locks the ticker again for 7 days. An outsider can only get in by winning a same-block ordering race at the exact second the lock expires. Staking on the sham challenge does not help them, because both sides pay the incumbent. This defeats the brief's 'anyone can challenge the king'. Every rule is implemented as the brief words it, so a fix is a rule decision. Options: do not reset reign or cooldown when the beneficiary is unchanged, refuse a challenge whose opener is the current beneficiary, or let a larger bond displace a live challenge.","line":188,"path":"src/CrownRegistry.sol","reproduction":"Registry with genesis king CRWN (beneficiary K). Warp +7 days. K: openChallenge{value: 0.01 ether}(CRWN, address(0x1000)) -> id; K: stake{value: 0.01 ether}(id, King). Honest H: openChallenge{value: 0.01 ether}(CRWN, rival) reverts ChallengeLive(CRWN, id) at any time up to finalize. Warp to finalizeAfter; finalize(id) -> ChallengeFailed (0.01 == 0.01), cooldownUntil = now + 3 days; H's openChallenge reverts InCooldown. K: claim(id) receives 0.01 + 0.001 + 0.008 = 0.019 ETH of the 0.02 ETH it staked. At cooldownUntil K opens again with address(0x1001) in the first block. Free variant: K stakes 0.04 ETH on Challenger instead. finalize gives king(CRWN) = {0x1000, K, now}, claim returns 0.05 ETH, treasuryOwed is unchanged, and H gets ReignTooYoung for 7 more days. Expected: a funded outsider can open a challenge once the king's reign is past 7 days. Actual: never, while K keeps cycling.","severity":"medium","snippet":"        if (hasLiveChallenge(ticker)) revert ChallengeLive(ticker, liveChallenge[ticker]);","title":"The single per-ticker challenge slot plus cooldown/reign reset lets the incumbent (or an ally) lock every outside challenger out for ~0.001 ETH per week, or for free"},{"citation":"resolved","description":"Merged from audit_permissions (owner chooses the registry) and audit_math (DEFAULT_CUT_BPS unused), with my own check of the launch flow. The factory deploys only CrownHook(poolManager, owner) and CrownToken, and initializes the pool. afterInitialize stores only `initialized`; it records no ticker and applies no cut. So right after launch pools[id].ticker == 0, and _payCut returns 0 silently (no CutSkipped event) until the owner deploys a registry by hand and calls setRegistry and registerPool. The brief has afterInitialize record poolId -> ticker with a default 100 bps cut, and DEFAULT_CUT_BPS (line 44) is read by no code path. More importantly, setRegistry accepts any contract with code. The owner ($owner, who is also the genesis beneficiary) can bind a contract whose king() always names the owner. After that, no dethrone in the real CrownRegistry changes who the pool pays, which breaks the brief's 'every subsequent swap pays the new king' and its rule-based, no-admin resolution. The site, which reads CrownRegistry, would then show a king different from the one actually paid. Renouncing ownership before setup leaves the pool cut-less forever. Fix: create the registry in the hook constructor from \"$token\"/\"$owner\" (or take it as a constructor argument), and bind the launch pool's ticker and default cut in afterInitialize so no owner switch is involved.","line":131,"path":"src/CrownHook.sol","reproduction":"Launch exactly as the manifest describes: the factory deploys CrownHook(\"$poolManager\", \"$owner\") and calls initialize(ETH/CRWN/12500/60/hook). Exact-input buy of 1 ETH: no CrownPaid, no CutSkipped, crownPaid[CRWN][ETH] == 0, because pools[id].ticker == bytes32(0) makes _payCut return early at line 307. Then the owner deploys F { function king(bytes32) view returns (King memory) { return King(anyToken, owner, 0); } }, calls hook.setRegistry(F) and registerPool(key, keccak256('CRWN'), 500). A completed CrownRegistry dethrone (challenge, stake, finalize -> king(CRWN).beneficiary == challenger) changes nothing: every swap keeps paying 5% of its ETH side to the owner. Expected: the pool pays CrownRegistry.king(CRWN).beneficiary. Actual: it pays whoever F names.","severity":"medium","snippet":"    function setRegistry(ICrownRegistry registry_) external onlyOwner {","title":"The pool's fee recipient follows whatever registry the hook owner binds after launch, not the rule-based CrownRegistry; the launch pool pays no cut until that manual setup, and DEFAULT_CUT_BPS is neve"},{"citation":"resolved","description":"From audit_math, confirmed. The cut on exact-input buys is pushed in beforeSwap from ETH the manager already holds. When cut > manager balance, the whole cut is skipped rather than paying min(cut, balance). The README (lines 117-120) says only the first buy on a fresh manager is affected and that 'the ETH it settles funds the cut of every later swap'. That is false for any later buy larger than 100x the manager's ETH (20x at 500 bps). On a launch pool seeded with tokens only, that threshold is tiny for the first several buys, so the largest early buys pay nothing while slightly smaller ones pay in full. Fix: pay min(cut, balance) and return that as the delta. Paying part keeps pay-at-source and needs no claims.","line":340,"path":"src/CrownHook.sol","reproduction":"Fresh PoolManager, launch pool seeded with tokens only (a single-sided token-only range), registered at 100 bps. Buy 1: exact-input 0.01 ETH -> CutSkipped(MANAGER_SHORT_OF_ETH), and the manager now holds ~0.01 ETH. Buy 2: exact-input 5 ETH -> cut = 0.05 ETH > ~0.01 ETH balance -> CutSkipped(MANAGER_SHORT_OF_ETH), beneficiary receives 0, crownPaid unchanged, while the pool moves the full 5 ETH. Expected (README: 'funds the cut of every later swap'): ~0.05 ETH, or at least the ~0.01 ETH available, is paid. Actual: 0.","severity":"low","snippet":"        if (address(poolManager).balance < cut) {","title":"A buy whose cut exceeds the PoolManager's ETH balance pays no cut at all, so large early buys on the tokens-only launch pool are fee-free"},{"citation":"resolved","description":"From audit_permissions, confirmed. finalize computes the slash on the losing side's total (floor of 20%). claim floors each loser's 80% refund and each winner's bonus share separately. The leftover belongs to nobody: there is no sweep, and treasuryOwed gets only its half of the slash. The registry's balance therefore ends up permanently above the sum of everything claimable, which is not the 'exact to the wei' accounting the brief asks for. The impact is dust: less than one wei per staker per term. Fix: compute each loser's refund as stake - floor(stake*20%) and credit the rounding remainder to treasuryOwed at finalize.","line":169,"path":"src/CrownRegistry.sol","reproduction":"Challenge where the king side loses: two king stakers with 3 wei each (kingStake = 6) against a challenger side of 0.05 ether. finalize: slash = 6*2000/10000 = 1, toWinners = 0, toTreasury = 1. Each king staker's claimable = 3*8000/10000 = 2, so 4 in total. Paid out: 4 + 1 (treasury) = 5 of the 6 wei the losers staked, and 1 wei is unclaimable forever. Expected: all 6 wei assigned. Actual: 5.","severity":"low","snippet":"        if (loseStake != 0) amount += (loseStake * (BPS - SLASH_BPS)) / BPS;","title":"Per-staker floor rounding leaves refund/slash dust permanently unassigned in the registry"},{"citation":"resolved","description":"Merged from audit_economics (low) and audit_permissions (info). registerKing is permissionless and first-come, as the brief says. registerPool, however, binds any non-zero ticker for good without checking that registry.king(ticker).token is the pool's currency1, or even that the ticker is crowned. For any pool other than the genesis one, which is crowned in the registry constructor, a bot that sees the owner's registerKing or registerPool transaction can crown itself first. From the first swap the pool then pays cutBps of its ETH volume to the bot, and nobody can challenge for 7 days, plus the 96-hour challenge cycle. The binding cannot be undone. Fix: in registerPool, require the registry to be set and registry.king(ticker).token == Currency.unwrap(key.currency1).","line":140,"path":"src/CrownHook.sol","reproduction":"Owner initializes a second native pool ETH/FOO on CrownHook and calls hook.registerPool(keyFoo, keccak256('FOO'), 100), planning to call registry.registerKing(keccak256('FOO'), FOO, fooTeam) next. Attacker A front-runs with registry.registerKing(keccak256('FOO'), address(0x1234), A). The owner's registerKing reverts AlreadyCrowned, and every ETH/FOO swap emits CrownPaid(..., A, 1% of ETH). Expected: registerPool refuses a ticker whose king is not the pool's token. Actual: the binding succeeds and pays A.","severity":"low","snippet":"    function registerPool(PoolKey calldata key, bytes32 ticker, uint16 cutBps) external onlyOwner {","title":"registerPool binds a pool to a ticker without checking its king, so a squatted (or uncrowned) ticker routes the pool's cut to an outsider immutably"}],"hash":"483a8e547f447ad9df71519c642b627aa9bfc1d69290479f37884a05531b8212","nodeId":"56179a94-15e4-4baf-a86e-0dbf9ccb370e","outcome":"completed","summary":"I've written the review to `.imd-findings.json`: 6 findings (1 high, 2 medium, 3 low) and a coverage row for each of the 26 entry points. No repository files were changed. I deleted my scratch test after running it.\n\n**Findings kept**\n1. **High: a challenge winner can block every swap on the pool** (`src/CrownHook.sol:344`). All four specialists reported this. The hook pays the cut while the PoolManager is still open for the swap. A beneficiary contract can accept the ETH and, in the same call, leave a 1-wei debt on itself (for example `poolManager.mint(self, 0, 1)`). The whole swap then reverts with `CurrencyNotSettled`, for buys and sells alike. Anyone can become that beneficiary by winning an undefended challenge, and the 0.05 ETH it costs comes back to them in full. The brief says the hook must never block a swap. I ran a self-contained Foundry proof against the code: the honest-king buy succeeds, and after the flip the buy fails with `[FAIL: CurrencyNotSettled()]`. The proof is attached to the finding.\n2. **Medium: the king can keep every outside challenger locked out** (`src/CrownRegistry.sol:188`). Merged from all four specialists. There is only one challenge slot per ticker, a failed challenge starts a cooldown, and a successful one restarts the 7-day minimum reign. So the king can repeatedly challenge itself with a throwaway token, for about 0.001 ETH a week or for nothing. Every rule is coded as the brief words it, so fixing this means changing a rule.\n3. **Medium: the owner decides who the pool pays** (`src/CrownHook.sol:131`). After launch the pool pays no cut until the owner sets a registry and registers the pool by hand. `setRegistry` accepts any contract, so the owner, who is also the genesis beneficiary, can point it at one that always names themselves. Dethrones in the real registry would then change nothing. Also, `afterInitialize` records no ticker and `DEFAULT_CUT_BPS` is never used.\n4. **Low: large early buys pay no cut** (`src/CrownHook.sol:340`). When the cut is more than the ETH the PoolManager holds, the whole cut is skipped rather than paying what's there. The README says this only affects the first buy, which is wrong.\n5. **Low: rounding dust is stranded** (`src/CrownRegistry.sol:169`). Refunds are rounded down per staker and the slash on the side total, so a few wei per challenge belong to nobody and can never be withdrawn.\n6. **Low: `registerPool` doesn't check the ticker's king** (`src/CrownHook.sol:140`). Someone can claim a ticker first by front-running the owner, and the pool then pays them permanently.\n\n**Dropped:**\n- **Last-minute stake sniping:** this is how the brief's fixed stake window works, not a defect.\n- **A wallet address with no code can be crowned:** it causes no harm beyond crowning any junk token, and the suggested fix is easy to get around.\n\n**Deployability:** both contracts the factory deploys fit the size limits; the hook's runtime is about 8.2 KB. The hook's constructor arguments and permissions match `launch.json`. Its `afterInitialize` callback can only be called by the PoolManager and returns the correct selector. So nothing blocks deployment, though the cut still depends on the manual setup in finding 3.","treeHash":null,"usage":{"cachedInputTokens":992760,"inputTokens":22,"model":"claude-opus-5-5","outputTokens":27050,"runtime":"claude","turns":12,"wallClockMs":289816}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dff6c0d3de4aa913","findings":[],"hash":"4b9be70bfe8f969fa40a532a9c5830d3b9eb36073305dad1ae5a0241615b9d55","nodeId":"56179a94-15e4-4baf-a86e-0dbf9ccb370e","outcome":"completed","summary":"The findings file is valid and nothing in the tree outside my scratch tests and the findings file was touched.\n\n**Outcome: my round-2 finding is fixed, and I found no new defect.** The findings file holds an empty list and a full coverage record.\n\n**What I verified on the revised hook**\n\n- **The claims-trading beneficiary no longer gets execution.** I re-ran the exact round-2 scenario through the real registry flow, not a mock: a contract holding 50 ETH of ERC-6909 claims wins the crown via openChallenge, stake and finalize, with a receive() that trades the pool in claims. The hook now routes any address with code to a claim mint, so its code never runs. A 1 ETH exact-input buy with a 1% slippage bound fills at exactly the quoted output, the beneficiary's call counter stays at zero, it buys no tokens ahead, and its claim grows by exactly the cut. The exact-input sell path behaves the same.\n- **The dirty-delta variants** the specialists raised (a 1 wei mint or take inside receive) also never run and block nothing.\n- **Redemption works and is scoped.** After setting the hook as operator, the beneficiary redeems its claim to a named recipient, and the hook ends with no claim and no ETH. Only the caller's own claims can be burned, and the callback is reachable only through the hook's own unlock.\n- **Factory deployability holds.** Embedding both registry runtime codes for the codehash check leaves the hook at 22,965 bytes of initcode and 12,681 bytes of runtime, inside the limits. The manifest's constructor arguments and permissions match the source.\n\n**Changed code I read as new**\n\n- The registry's new challenge displacement (double the live bond inside the window) refunds both sides in full, refuses stake and finalize on the displaced challenge, blocks displacement after the window, and leaves the contract balance equal to what it owes. I did not find a funds defect in it. It turns the lockout the specialists reported into a capital contest with an exponentially growing bond, which the author documents as the design.\n\n**Results**\n\n| Check | Result |\n|---|---|\n| Seeded suite | 85 passed, 0 failed |\n| My scratch reproduction (4 tests) | all pass on this tree |\n| Displacement conservation scratch test | passes |\n| Coverage rows | 29 entry points plus 3 invariants, all `holds` |\n\nThe scratch tests live under test/scratch and are not part of the submission.","treeHash":null,"usage":{"cachedInputTokens":1486698,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":27324,"runtime":"claude","turns":25,"wallClockMs":421500}},{"artifacts":[],"attempt":1,"bundleHash":"47640035e72663851423d2a2c28f215067b71ba457eab0492fa7db6ebffb2752","device":"d2d5a117dd72f6b4","findings":[],"hash":"6ecb528cda2cb88722c6baf8832672548b728cf98c451fe3d3bdc26f2a5e2964","nodeId":"95a5f5f3-4888-4d49-ae3e-634d4316f175","outcome":"completed","summary":"Revised launch.json. Only its notes changed. Everything else in the manifest already matched the accepted code.\n\n**What I checked against the current tree**\n\n- The constructor is `(IPoolManager poolManager_, address owner_)`, so the arguments stay `$poolManager` and `$owner`.\n- `getHookPermissions` enables afterInitialize, beforeSwap, afterSwap, beforeSwapReturnDelta and afterSwapReturnDelta. The manifest lists exactly those five.\n- Token contract CrownToken, \"Crown Demo\", CRWN, 18 decimals, no constructor arguments. Pool values are the launch's own: native ETH, fee 12500, tickSpacing 60, the given initialPrice.\n- The first key is `\"kind\": \"univ4_hook\"`, the address is lowercase, and the notes are 3731 characters.\n\n**Why the notes needed revising**\n\nAnother contributor's accepted commit changed CrownHook and CrownRegistry after my previous manifest. The old notes described behaviour that no longer holds, so I corrected them to the current code:\n\n- setRegistry accepts only a contract whose runtime code hash matches the compiled CrownRegistry or ThroneRegistry.\n- registerPool requires the registry to be set and the ticker's king to be the pool's own token.\n- A PoolManager holding no ETH skips the cut. One holding less than the cut now pays what it holds, where the old notes said it skipped.\n- The payout runs in a self-call that is rolled back if the beneficiary leaves any trace in the PoolManager.\n- A live challenge inside its window can be displaced by a new challenger bonding twice its bond, with full refunds and no slash, cooldown or crown change.\n\n**Verification**\n\n`forge build` succeeded and `forge test` with the verifier's fuzz seed passed all 82 tests across 7 suites, including both invariant suites. `git status` shows launch.json as the only modified file.","treeHash":"6a486676922a675af6c402c2c2cce10bd5b17b21","usage":{"cachedInputTokens":586472,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":7272,"runtime":"claude","turns":14,"wallClockMs":163686}},{"artifacts":[],"attempt":1,"bundleHash":"dceba87a4ec9653f8777a1b14ceb39965c09da06b95fcacc60914819c277ccf7","device":"d73af718d55ba788","findings":[],"hash":"89bfa1e9d4b2e7cc7312b48b40a92d95ff1e9fa3c35eb682a8d5ab12d1e475e0","nodeId":"95a5f5f3-4888-4d49-ae3e-634d4316f175","outcome":"completed","summary":"Done. I revised only `launch.json`, and only its notes.\n\n**What was stale.** Since the manifest was last written, the accepted hook in `src/CrownHook.sol` changed how it pays beneficiaries that have code. A wallet is still paid ETH by transfer inside the swap. A contract beneficiary is now credited an ERC-6909 claim on native ETH in the PoolManager and redeems it later through the hook's `redeem` function. The old notes said no fee is ever deferred as a claim and that a rejecting beneficiary skips the cut, which no longer describes the accepted code.\n\n**What I changed.** The notes now describe the wallet-versus-contract payout split, the claim redemption path, and that a contract beneficiary's claim is minted in full regardless of the manager's ETH balance. I shortened other sentences to stay under the 4000-character cap without dropping facts.\n\n**What I verified against the source.**\n- Constructor is still `(IPoolManager, address owner)`, written as `$poolManager` and `$owner`.\n- `getHookPermissions` still enables afterInitialize, beforeSwap, afterSwap, beforeSwapReturnDelta and afterSwapReturnDelta, exactly as listed.\n- Token contract `CrownToken` is still named \"Crown Demo\" / CRWN with 18 decimals and no constructor arguments.\n- Pool fields are unchanged: native ETH pair, fee 12500, tickSpacing 60, the given initialPrice.\n- The file parses as JSON, `kind` is the first key, and notes are 3962 characters.\n\n**Checks.** `forge build` succeeded, and `forge test` with the verifier's fuzz seed passed all 85 tests across 7 suites. `git status` shows `launch.json` as the only modified tracked file. I did not commit, since the earlier rounds show the harness making the commits.","treeHash":"f3eddb74b955a07dc732595245dcf47e7be07b1c","usage":{"cachedInputTokens":640372,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":8157,"runtime":"claude","turns":12,"wallClockMs":219114}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"cd8076510aad8b8e","findings":[{"citation":"resolved","description":"_payCut pays the cut with poolManager.take(ETH, beneficiary, cut) from inside beforeSwap/afterSwap, while the PoolManager is unlocked for the swapper's transaction. take() does a native call to the beneficiary with up to PAYOUT_GAS, so a beneficiary contract runs code inside the swap with the manager unlocked. The hook only guards against the call reverting or burning gas (try/catch). It does not guard against the beneficiary succeeding while leaving the manager in a state the swap cannot finish from: in its receive() the beneficiary calls poolManager.take(ETH, <sink>, 1 wei), which books a -1 wei delta on the beneficiary's own account and increments NonzeroDeltaCount. The hook's take returns normally, the hook records crownPaid and CrownPaid, the pool swap runs, the router settles its own deltas, and then PoolManager.unlock reverts with CurrencyNotSettled because the beneficiary's 1 wei debt is still open. Every ETH-cut-bearing swap on every pool bound to that ticker reverts, in both the beforeSwap (ETH-specified) and afterSwap (token-specified) shapes, which breaks the explicit requirement that the hook never reverts or blocks a swap. Anyone can become the beneficiary at zero net cost through the ordinary challenge flow: openChallenge from the griefing contract (msg.sender becomes challengerBeneficiary, src/CrownRegistry.sol:198), stake 0.05 ETH on the challenger side, finalize after 96 hours; the winning stake and the bond are fully refundable, and the griefer can defend later challenges for free since winners also earn the slash bonus. LPs can still withdraw, but the launch pool is untradeable for as long as the griefer is king. Fix: perform the payout through a self-call wrapper (onlySelf external function) that does the take and then requires poolManager.getNonzeroDeltaCount() to be exactly one more than before the take (the hook's own -cut) and poolManager.currencyDelta(beneficiary, ETH) == 0, reverting otherwise; _payCut's try/catch then undoes both the transfer and the beneficiary's re-entry and the swap proceeds without the cut (BENEFICIARY_REJECTED). Alternatively pay with poolManager.mint(beneficiary, 0, cut) (an ERC-6909 claim, no external call into the beneficiary), documenting how a wallet redeems it.","line":344,"path":"src/CrownHook.sol","reproduction":"State: CrownHook with registry set and the ETH/CRWN pool registered at 100 bps, pool funded with liquidity. 1) Deploy GriefingBeneficiary whose receive() calls poolManager.take(address(0), 0xdead, 1). 2) warp +7 days; GriefingBeneficiary calls registry.openChallenge{value: 0.01 ether}(keccak256('CRWN'), rivalToken) and registry.stake{value: 0.05 ether}(id, Challenger); warp to challenges(id).finalizeAfter; finalize(id) -> king(CRWN).beneficiary == GriefingBeneficiary. 3) Any router calls poolManager.unlock -> swap(key, zeroForOne=true, amountSpecified=-1 ether) (or an exact-input sell -1e18 tokens). Expected: the swap completes, with the cut or with CutSkipped. Actual: beforeSwap's take succeeds, crownPaid is incremented, and unlock reverts with CurrencyNotSettled; the same happens for the afterSwap path. test/scratch/BeneficiaryReentryBlocksSwaps.t.sol fails on the current code with 'an exact-input buy must not be blocked by the king's beneficiary'. Before the flip the same swap succeeded and paid 0.01 ETH to the genesis wallet.","severity":"high","snippet":"        try poolManager.take{gas: PAYOUT_GAS}(CurrencyLibrary.ADDRESS_ZERO, beneficiary, cut) {","title":"A king's beneficiary contract can block every swap on the pool by re-entering the unlocked PoolManager during its payout"},{"citation":"resolved","description":"openChallenge is first-come: a ticker with a live challenge rejects every other challenge until finalize, and a failed challenge then locks the ticker for COOLDOWN (3 days). Nothing ties the right to challenge to the quality of the challenge, and nothing lets a second challenger join, outbid or replace a stale one. So whoever lands the first openChallenge in the block the cooldown ends (an ally of the sitting king, or anyone wanting to keep a rival out) holds the ticker for 72h window + 24h timelock + 72h cooldown = 7 days, then repeats. Nobody stakes on the sham, so at finalize challengerWon is false (0.01 < 0.05 quorum), slash = 0.002 ETH goes wholly to the treasury (winningTotal == 0) and the ally claims 0.008 back: the lockout costs 0.002 ETH per 7-day cycle, less if the ally also stakes a wei on the king side to recapture half the slash as winner bonus. The brief's guarantee that 'anyone can challenge the king' and the hook's whole flip mechanism are therefore defeatable by the incumbent for a few dollars a week, while the sham challenger also controls the challengerToken (which may be any address, even an EOA: openChallenge only rejects address(0), src/CrownRegistry.sol:185). Fix preserving the design: allow a new challenge to displace a live one before its window closes when it posts a strictly larger bond (refunding the old bond as a losing stake), or let a later challenger join the live challenge's challenger side with its own token ranked by stake, and apply the cooldown only when the failed challenge reached quorum.","line":188,"path":"src/CrownRegistry.sol","reproduction":"State: CrownRegistry('CRWN', kingToken, kingWallet); warp +MIN_REIGN. Ally A, genuine challenger G, each with 1 ETH. Cycle: 1) A: openChallenge{value: 0.01}(CRWN, anyAddress) -> id. 2) G in the same block: openChallenge{value: 0.01}(CRWN, rival) -> reverts ChallengeLive(CRWN, id). 3) warp to challenges(id).finalizeAfter; finalize(id) -> ChallengeFailed, cooldownUntil = now + 3 days; A: claim(id) receives 0.008 ETH. 4) G: openChallenge -> reverts InCooldown. 5) warp to cooldownUntil; A opens again first. After three cycles (21 days) A has spent exactly 0.006 ETH, king(CRWN).token is still kingToken and G has never been able to open a challenge. Reproduced by test/scratch/ShamChallengeLockout.t.sol (passes, demonstrating the lockout).","severity":"medium","snippet":"        if (hasLiveChallenge(ticker)) revert ChallengeLive(ticker, liveChallenge[ticker]);","title":"One live challenge per ticker plus the cooldown lets an incumbent's ally lock out every genuine challenger for 0.002 ETH per week"},{"citation":"resolved","description":"The registry's purpose is 'one canonical token per ticker', and the hook pays fees for whatever king(ticker) says. openChallenge (and registerKing) only reject the zero address and the sitting king's token: no code-length check, no symbol check. A winning challenge can therefore crown an EOA, the registry itself or the hook as the 'king token' while routing every pool's cut to the opener. The site's own-symbol validation is client-side only and cannot be relied upon. Suggested minimal fix: require challengerToken.code.length != 0 in _crown, and optionally that IERC20Metadata(token).symbol() upper-cases to the ticker when the ticker was created via tickerOf.","line":185,"path":"src/CrownRegistry.sol","reproduction":"registry = CrownRegistry('CRWN', kingToken, kingWallet); warp +7 days; attacker (EOA) calls openChallenge{value: 0.01 ether}(keccak256('CRWN'), 0x1111111111111111111111111111111111111111) (an address with no code) and stake{value: 0.05 ether}(id, Challenger); warp to finalizeAfter; finalize(id). Expected: a non-token cannot become king. Actual: king(CRWN).token == 0x1111..., beneficiary == attacker, and every CrownHook swap cut on CRWN pools now goes to the attacker. test/scratch/ShamChallengeLockout.t.sol opens challenges with makeAddr('sham') and they are accepted.","severity":"low","snippet":"        if (challengerToken == address(0)) revert ZeroAddress();","title":"openChallenge accepts any non-zero address as the challenger token, so an EOA or arbitrary contract can be crowned king of a ticker"}],"hash":"89ef76500734b564ec0fab03ff66c5caedff03d7f0915ac26d1c1daf6882c1b9","nodeId":"e7d4bbab-f8fa-4d4b-a66f-a6dd1793781c","outcome":"completed","summary":"The findings file is written, its three snippets match the tree line for line, and both reproductions ran as described. Here is the recap.\n\n**Outcome:** I audited CROWN's control flow against the Execution Trace, Periphery and First Principles guides and recorded three substantiated defects plus a 29-row coverage record in `.imd-findings.json`. The existing suite of 78 tests passes on the current tree.\n\n**Findings**\n\n- **High. A king's beneficiary contract can brick the pool.** The hook pays the cut with a native `take` to the beneficiary while the PoolManager is unlocked. A beneficiary whose receive function calls `take` for 1 wei to a sink leaves an unsettled delta. The hook's try/catch sees success, records the payment, and the swapper's unlock then reverts with CurrencyNotSettled. Every buy and sell on the ticker's pools fails, against the \"never block a swap\" requirement. Anyone reaches that position through an ordinary challenge at zero net cost, since winning stakes are fully refundable. The proof test under `test/scratch/BeneficiaryReentryBlocksSwaps.t.sol` fails on the current code. The suggested fix wraps the payout in a self-call that checks the nonzero-delta count and the beneficiary's delta after the take, so the existing catch path skips the cut instead.\n- **Medium. Cheap perpetual challenge lockout.** One live challenge per ticker plus the 3-day cooldown lets whoever opens first at each cooldown expiry hold the ticker for 7 days per cycle. With no stakers the sham fails, the opener recovers 0.008 ETH and the lockout costs 0.002 ETH per week. Reproduced over three cycles in `test/scratch/ShamChallengeLockout.t.sol`.\n- **Low. Any non-zero address can be crowned.** The registry never checks that a challenger token has code or matches the symbol, so an EOA can become the \"canonical token\" with fees routed to the opener.\n\n**Coverage:** all 26 listed entry points have rows. The hook's swap callbacks and the registry's openChallenge carry the findings. Everything else, including the delta accounting across all four swap shapes and partial fills, the rehearsal's gas-starvation resistance, and the manifest against the implementation, traced as holding. The frontend's side encoding and the shipped ABI arrays also match the compiled contracts.\n\n**Not reached in depth:** the web application's transaction wiring beyond the side encoding, and the registry invariant suite's handler logic, which I relied on rather than re-derived.","treeHash":null,"usage":{"cachedInputTokens":1610349,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":45860,"runtime":"claude","turns":45,"wallClockMs":711163}},{"artifacts":[],"attempt":2,"bundleHash":"382baf0d96d60b70b5e3bae19be4a447e89564b7783b5cb0bf6c577693a865d2","device":"87804e27e9c9f85a","findings":[],"hash":"8da418de8d0146c1e6b4463148f16fb580b212449e5380731413381feaed48b2","nodeId":"0841d62d-e6c8-4a7a-82ca-a69d8010ad9e","outcome":"completed","summary":"The work is complete and verified. Here is the recap.\n\n**Outcome.** A Foundry project at the repository root with the registry, the hook, both CRWN tokens, a post-launch script, 49 passing tests, and a README. `forge build`, `forge test` (with the verifier's fuzz seed) and `forge fmt --check` all pass on a clean rebuild. I also ran the three protected floor suites against the built hook and token bytecode with the launch environment (chain 4663, native pair, fee 12500, factory probe). All 13 passed, and the copies were removed afterwards.\n\n**What was built**\n\n- `src/CrownRegistry.sol` crowns a ticker at construction (`\"CRWN\"`, `$token`, `$owner`) so the genesis registration cannot be front-run. Challenges, 72-hour staking, 24-hour timelock, quorum and the 80/20 slash with half to winners and half to the treasury are all constants and purely rule-based. Payouts are pull-only. `ThroneRegistry` is the same contract under the assignment's name.\n- `src/CrownHook.sol` takes `($poolManager, $owner)`. It uses `afterInitialize`, `beforeSwap`, `afterSwap` and both swap return deltas so the cut is always ETH: before-swap delta when ETH is the specified amount, after-swap delta when it is not. The cut is paid straight from the PoolManager to the king's beneficiary inside the swap. Every failure path (no registry, read failure, no king, manager short of ETH, beneficiary rejects) skips the cut and emits a reason instead of reverting.\n- `src/CrownToken.sol` is the standard launch token. `src/CrownChallengerToken.sol` is the distinct second CRWN for the dethrone demo, deployed by `script/DeployCrown.s.sol`.\n- `site/index.html` is a static ticker page with king, totals, live challenge timers and stake, challenge, finalize and claim actions.\n\n**Decisions worth knowing**\n\n- The brief's pay-at-source rule won over the reference's ERC-6909 claim fallback. On a fresh PoolManager holding no ETH, the first buy runs without the cut and later buys pay. This is tested and documented.\n- Two owner setters exist on the hook (`setRegistry`, `registerPool`), each set-once and immutable afterwards. They are needed because the registry address and pool key are only known after launch. The README lists them under \"After launch\".\n- Rounding was a real bug found by the conservation fuzz test: losing-side refunds are now floored per staker so the contract never owes more than it holds.\n\n**Not done.** No deployment or on-chain demo was run; the launch is IMD's step and the README gives the manifest arguments and the owner's post-launch checklist. No `launch.json` was written. The root `.gitmodules` entry in `git status` is a pre-existing device file in the sandbox, not a submodule, and `lib/` contains no git metadata.","treeHash":"5dd4ad13b7d6d898cb14f2f0d7ecdcaca4987f35","usage":{"cachedInputTokens":3311844,"inputTokens":802,"model":"claude-fable-5-1","outputTokens":94803,"runtime":"claude","turns":60,"wallClockMs":1187071}},{"artifacts":[],"attempt":1,"bundleHash":"c8693734d343877ce8994bbddc1dd1ec0abaffebe2af9c55ee87bb2a622af698","device":"1731fbfe0c4574fb","findings":[],"hash":"8dd70a5ed928f7b1e7196cff00efb90221314e7eafd0ba48e94319f23c26b8ab","nodeId":"0841d62d-e6c8-4a7a-82ca-a69d8010ad9e","outcome":"completed","summary":"The hook reads cleanly on re-inspection, and the shell is still refused by the sandbox, so I cannot run the compiler here. The work is complete; here is the recap.\n\n**Outcome.** Both reproducible findings are fixed in `src/CrownHook.sol`, the advisory one is disputed, and the answers are in `.imd-responses.json`. I could not run `forge build` or `forge test`: every shell command on this machine, including `true`, fails before starting with this sandbox error:\n\n```\napply-seccomp: write /proc/self/setgroups (nested userns is capability-restricted; caller must provide CAP_SYS_ADMIN): Permission denied\n```\n\nSo the changes were verified by reading the vendored v4-core sources against the two proof scenarios, not by executing them. I say the same in the responses file.\n\n**Finding 1, fee charged on unfilled input (fixed).** The old `beforeSwap` took bps of the order before the pool ran. Now it calls a rehearsal: a new `simulateSwap` self-call runs the exact swap the pool is about to execute through `poolManager.swap` and always reverts, returning the pool's delta in the revert data. v4's `Hooks` library skips a hook's own callbacks when the hook is the swapper, so there is no re-entry and the revert discards everything. If the pool fills the whole rehearsed amount, the cut stays bps of the order, so 1 ETH in still pays 0.01 ETH. If it stops short at a price limit or in an empty pool, the cut is bps of the ETH actually moved, which is zero for no fill, so the caller's delta is zero. A failed rehearsal yields no cut rather than a revert.\n\n**Finding 2, malformed 96-byte registry answer (fixed).** The beneficiary word is now loaded by hand and any bits above the address mark the answer as malformed, which skips the cut with the existing `REGISTRY_READ_FAILED` event. No `abi.decode` of registry data remains.\n\n**Finding 3, unchanged king token (disputed).** The brief's finalize rule requires the registry to point at the challenger token after a flip, and the finding itself says it does not ask otherwise. Nothing changed.\n\n**Tests and docs.** Five tests were added to `test/CrownHook.t.sol`: an empty-pool order that costs and pays nothing, price-limited partial fills on an exact-input buy and an exact-output sell with the cut exact to the executed ETH, the rehearsal refusing outside callers, and the dirty-registry skip in both swap directions. The mock router gained a `swapWithLimit` helper. The README documents the rehearsal, its roughly one-extra-swap gas cost, the strict decode, and the hook's full list of external calls.\n\n**What to check first on a working machine.** Run the two proof files and `forge test` with the given fuzz seed. The one place a compile slip is most likely is the `try this.simulateSwap(...)` block in `_fillableEth`, since I could not compile it here.","treeHash":"8e14e3d959958cc2479e901f12ba7568b1ba5d2f","usage":{"cachedInputTokens":1551747,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":58150,"runtime":"claude","turns":48,"wallClockMs":778215}},{"artifacts":[],"attempt":1,"bundleHash":"9c55005dd2ba79479acc65266f17159a7d228236f72cf72b71885b1391d1ca77","device":"35c52a5b502e847c","findings":[],"hash":"8f8c93a4c3aed535ecbf1ead939b36ebede87656e89163c570c1b5b8a92746f3","nodeId":"95a5f5f3-4888-4d49-ae3e-634d4316f175","outcome":"completed","summary":"Created [launch.json](/home/identitymd5/.identitymd/work/fdbf5e23-3c3f-4e02-9e9b-113ad92bcc7b/95a5f5f3-4888-4d49-ae3e-634d4316f175/launch.json) matching the contracts, constructor arguments, permissions, and required pool values.\n\n`forge build` succeeded; all 78 tests passed with the supplied fuzz seed. Only the manifest is delivered.\n\nNotes document required setup and pending live deployment.","treeHash":"f242b844237188fd9dae326e6e63e57c02a9931b","usage":{"cachedInputTokens":577280,"inputTokens":71368,"model":"gpt-6-astra","outputTokens":4666,"runtime":"codex","turns":4,"wallClockMs":148110}},{"artifacts":[],"attempt":1,"bundleHash":"d9cb057254494c7a114f987988eff4acbfd04e3b40e01c3d15f584935408057b","device":"5ded77c3c883b7b0","findings":[],"hash":"a8f517578495d54c3c16ab7855a5f04dfc7076546f0184b4144c9869456a5077","nodeId":"516fb97b-4bec-4f44-9c31-266ef557eae1","outcome":"completed","summary":"Work is complete and verified. Here is the recap.\n\n**Findings and what changed**\n\n- **High, hostile beneficiary (fixed).** The proof reproduced with `CurrencyNotSettled()`. The hook now pays through an external self-call, `payout`, that snapshots the PoolManager's nonzero-delta count, the hook's own ETH delta, the manager's ETH balance and its sync slots, takes the cut, and reverts unless the only trace is the hook's `-cut` delta. The catch rolls back the payment and everything the beneficiary did, and the swap proceeds without the cut. The proof passes; a permanent test covers mint, take and sync re-entries on all four swap shapes.\n- **Medium, sham-challenge lock (fixed by rule decision).** A live challenge in its staking window can be displaced by bonding exactly twice its bond. The displaced challenge ends with full refunds on both sides, no slash, no cooldown, no crown change. The site reads `requiredBond` and offers \"Displace this challenge\" under the live challenge.\n- **Medium, owner-chosen registry (fixed within the proof's API).** `setRegistry` accepts only a bytecode-identical CrownRegistry or ThroneRegistry (code-hash immutables). `registerPool` requires the registry and that the ticker's king is the pool's token. `afterInitialize` records the default 100 bps cut, and an unbound pool emits `POOL_NOT_REGISTERED`. The constructor and setter signatures stay as the proof harness requires, which the response explains.\n- **Low, short-manager cut (fixed).** The hook pays `min(cut, balance)` and skips only when the manager holds no ETH.\n- **Low, squatted tickers (fixed).** Covered by the king-owns-pool check above.\n- **Low, rounding dust (disputed).** The suggested fix would let refunds exceed what the slash split leaves, so the last claimer could fail. The dust is documented and bounded by the invariant suite.\n\n**Validation**\n\n| Check | Result |\n| --- | --- |\n| Seeded `forge test` | 83 passed, 0 failed (82 in the delivered tree plus the proof copy) |\n| Frontend tests, Chromium | 12 passed, 0 failed |\n| Design probe | 16 of 16 passed, main action on the first screen at 390 wide |\n| Export check | 20 assets verified, manifest regenerated |\n| Submission size | about 4.95 MB, under the 8 MiB limit |\n\n**Documents updated:** README (registry rules, hook payout, owner functions, after-launch list, assumptions), DESIGN.md (new disclosure component), validation/README.md (revision section), and `.imd-responses.json` with all six answers. WebKit and a real wallet on Robinhood Chain were not exercised and are recorded as limitations.","treeHash":"93fb5f8213b19b8bf13c0918348ff50787c19273","usage":{"cachedInputTokens":5468452,"inputTokens":900,"model":"claude-fable-5-1","outputTokens":158607,"runtime":"claude","turns":61,"wallClockMs":2644103}},{"artifacts":[],"attempt":1,"bundleHash":"355b101bbd9a1e5b0244deced7af006a1b2da9aa109dbd684c3cf548828be7fa","device":"323aec17bfc8d652","findings":[],"hash":"b8de14485b80afab964f6096d9af98b7e6f433d4aaef11d14457a61e6081e51d","nodeId":"516fb97b-4bec-4f44-9c31-266ef557eae1","outcome":"completed","summary":"The work is complete. Here is the recap.\n\n**Finding reproduced.** A scratch test built from the reviewer's recipe failed on the starting tree exactly as described. The beneficiary contract traded on the pool from ERC-6909 claims inside its own payout. The bounded buy reverted with a slippage error, the unbounded buy received about 4% less than quoted, and the cut was still counted as paid.\n\n**Fix in `src/CrownHook.sol`.** No beneficiary code runs during a payment any more.\n- A code-less address is paid ETH by `take`, which executes nothing.\n- An address with code is credited the cut as a native-ETH ERC-6909 claim in the PoolManager by `mint`. That runs no callback and needs no manager balance, so a contract's cut is never clamped or skipped.\n- The payment self-call keeps its accounting checks as a defensive invariant and refuses a transfer to an address with code.\n- A new `redeem` function lets a claim holder such as a multisig convert its own claims to ETH in its own transaction, after approving the hook as operator. The hook never holds funds or claims.\n\n**Verification.**\n\n| Check | Result |\n| --- | --- |\n| Seeded `forge test` | 88 passed, 0 failed |\n| Scratch reproduction on the fixed tree | passes |\n| Frontend build, typecheck, 12 Chromium and domain tests | pass |\n| Design probe on the rebuilt export | 16 of 16 |\n| Export manifest check | pass, 20 assets |\n\n**Other changes.** New permanent tests cover the claims-trading beneficiary with a slippage-bound router, a re-entering beneficiary on all four swap shapes, the claim path on a short manager, and redemption. The README, the site's how-it-works copy, the regenerated hook ABI, the rebuilt `dist/` export, and the validation notes are updated. The reviewer response is in `.imd-responses.json` with verdict fixed.\n\n**Limitation.** The page offers no control for `redeem`, since connected browser wallets are code-less accounts paid in ETH directly. That is documented in the validation notes and the README.","treeHash":"bf8d3ea8063a28ede3b35357157126d6b214168d","usage":{"cachedInputTokens":5521887,"inputTokens":1316,"model":"claude-fable-5-1","outputTokens":62469,"runtime":"claude","turns":43,"wallClockMs":1002996}},{"artifacts":[],"attempt":1,"bundleHash":"50d606f96148d228a0610196c720f47c57838cbf7a72ec5b56fab7242bfd962e","device":"4fa6ac0d62fd2e01","findings":[{"description":"The ETH-specified path pays a cut of params.amountSpecified before the AMM executes. Uniswap v4 can partially fill an order at its price limit or execute no volume in a pool without liquidity. The hook never reconciles the fee to actual volume. A buyer can therefore lose ETH to a beneficiary without receiving any tokens, or pay much more than the configured bps of its actual input. This requires a manager holding enough ETH to pay the cut, which the reproduction supplies through a real funded pool. The affected zero-execution/partial-fill behavior is not asserted as correct in the submitted passing suite.","line":163,"path":"src/CrownHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {CrownHook} from \"src/CrownHook.sol\";\nimport {CrownRegistry} from \"src/CrownRegistry.sol\";\nimport {CrownToken} from \"src/CrownToken.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {ModifyLiquidityParams, SwapParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\n\ncontract CrownPartialFillProofTest is Test, IUnlockCallback {\n    uint160 constant PRICE = 79228162514264337593543950336;\n    bytes32 constant TICKER = keccak256(\"CRWN\");\n    PoolManager manager;\n    CrownToken token;\n    CrownHook hook;\n    PoolKey key;\n    address beneficiary = makeAddr(\"partial-fill-beneficiary\");\n\n    function setUp() public {\n        vm.deal(address(this), 10_000 ether);\n        manager = new PoolManager(address(this));\n        token = new CrownToken();\n        CrownRegistry registry = new CrownRegistry(\"CRWN\", address(token), beneficiary);\n        bytes memory code = abi.encodePacked(type(CrownHook).creationCode, abi.encode(manager, address(this)));\n        bytes32 hash = keccak256(code);\n        for (uint256 i; i < 500_000; i++) {\n            address predicted =\n                address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(i), hash)))));\n            if (uint160(predicted) & 0x3fff != 0x10cc) continue;\n            address at;\n            assembly (\"memory-safe\") { at := create2(0, add(code, 32), mload(code), i) }\n            require(at == predicted, \"CREATE2 failed\");\n            hook = CrownHook(at);\n            break;\n        }\n        require(address(hook) != address(0), \"no salt\");\n        hook.setRegistry(registry);\n        key = PoolKey(Currency.wrap(address(0)), Currency.wrap(address(token)), 12_500, 60, IHooks(address(hook)));\n        manager.initialize(key, PRICE);\n        hook.registerPool(key, TICKER, 100);\n        manager.unlock(abi.encode(true, key, PRICE));\n    }\n\n    function test_emptyPoolMustNotChargeForAnUnexecutedTrade() public {\n        PoolKey memory empty = key;\n        empty.fee = 3_000;\n        manager.initialize(empty, PRICE);\n        hook.registerPool(empty, TICKER, 100);\n        uint256 before = beneficiary.balance;\n        BalanceDelta delta =\n            abi.decode(manager.unlock(abi.encode(false, empty, TickMath.MIN_SQRT_PRICE + 1)), (BalanceDelta));\n        assertEq(delta.amount1(), 0, \"there was no executed token trade\");\n        // Actual: a 0.01 ETH transfer and -0.01 ETH caller delta, despite zero execution.\n        assertEq(beneficiary.balance - before, 0, \"a percentage of zero executed volume must be zero\");\n        assertEq(delta.amount0(), 0);\n    }\n\n    function test_priceLimitPartialFillMustNotChargeOnUnusedInput() public {\n        uint256 before = beneficiary.balance;\n        BalanceDelta delta = abi.decode(\n            manager.unlock(abi.encode(false, key, uint160(uint256(PRICE) * 9_999 / 10_000))), (BalanceDelta)\n        );\n        uint256 spent = uint256(uint128(-delta.amount0()));\n        uint256 fee = beneficiary.balance - before;\n        assertGt(delta.amount1(), 0, \"some tokens are bought\");\n        assertLt(spent, 0.2 ether, \"the 1 ETH order was only partially filled\");\n        // A 100 bps cut cannot exceed 1% of the actual gross input debited to the trader.\n        // Actual: fee = 0.01 ETH although gross input is approximately 0.1113 ETH.\n        assertLe(fee, spent / 100, \"fee must follow executed input, not the unfilled 1 ETH order\");\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager), \"only manager\");\n        (bool add, PoolKey memory pool, uint160 limit) = abi.decode(data, (bool, PoolKey, uint160));\n        BalanceDelta delta;\n        if (add) {\n            (delta,) = manager.modifyLiquidity(pool, ModifyLiquidityParams(-887220, 887220, 1_000e18, bytes32(0)), \"\");\n        } else {\n            delta = manager.swap(pool, SwapParams(true, -1 ether, limit), \"\");\n        }\n        _settle(pool.currency0, delta.amount0());\n        _settle(pool.currency1, delta.amount1());\n        return abi.encode(delta);\n    }\n\n    function _settle(Currency currency, int128 amount) internal {\n        if (amount < 0) {\n            uint256 owed = uint256(uint128(-amount));\n            manager.sync(currency);\n            if (Currency.unwrap(currency) == address(0)) {\n                manager.settle{value: owed}();\n            } else {\n                token.transfer(address(manager), owed);\n                manager.settle();\n            }\n        } else if (amount > 0) {\n            manager.take(currency, address(this), uint256(uint128(amount)));\n        }\n    }\n\n    receive() external payable {}\n}","reproduction":"Run the embedded test file with forge test --match-path test/scratch/CrownPartialFillProof.t.sol -vv. It uses an actual PoolManager, a permission-mined hook, 100 bps, price 2**96, and 1000e18 full-range liquidity. Test 1 initializes a second fee=3000 pool with no liquidity, registers it, then submits exact-input -1 ether with a valid price limit. Expected: zero output and zero fee/caller debit. Actual: zero token output, beneficiary receives 10000000000000000 wei, and caller pays that amount. Test 2 swaps -1 ether in the funded pool with sqrtPriceLimitX96=floor(2**96*9999/10000). Expected: fee no greater than 1% of gross consumed input. Actual: 10000000000000000 wei fee versus 1112759503798481 wei as 1% of actual gross input. Both tests were run and failed on those assertions.","severity":"high","title":"beforeSwap charges fees for unfilled input, including zero-execution swaps"},{"description":"The low-level staticcall handles unsuccessful reads and wrong lengths, but abi.decode is outside a protected external call. A 96-byte response with nonzero upper 96 bits in its beneficiary word passes the length check and causes abi.decode to revert, propagating through the callback and reverting the entire swap. setRegistry accepts any contract and can only be set once, so pools configured with this nonconforming dependency cannot recover through that setter. The stock CrownRegistry returns valid ABI, so this is a dependency-failure robustness defect, not an attacker-controlled read of the stock registry.","line":270,"path":"src/CrownHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {CrownHook} from \"src/CrownHook.sol\";\nimport {ICrownRegistry} from \"src/interfaces/ICrownRegistry.sol\";\nimport {CrownToken} from \"src/CrownToken.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {ModifyLiquidityParams, SwapParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\n\n// Exactly 96 bytes, but the beneficiary word contains a nonzero bit above bit 159.\ncontract DirtyCrownRegistry {\n    fallback() external {\n        assembly (\"memory-safe\") {\n            mstore(0, 0)\n            mstore(32, shl(160, 1))\n            mstore(64, 0)\n            return(0, 96)\n        }\n    }\n}\n\ncontract CrownMalformedRegistryProofTest is Test, IUnlockCallback {\n    uint160 constant PRICE = 79228162514264337593543950336;\n    bytes32 constant TICKER = keccak256(\"CRWN\");\n    PoolManager manager;\n    CrownToken token;\n    CrownHook hook;\n    PoolKey key;\n    address beneficiary = makeAddr(\"partial-fill-beneficiary\");\n\n    function setUp() public {\n        vm.deal(address(this), 10_000 ether);\n        manager = new PoolManager(address(this));\n        token = new CrownToken();\n        ICrownRegistry registry = ICrownRegistry(address(new DirtyCrownRegistry()));\n        bytes memory code = abi.encodePacked(type(CrownHook).creationCode, abi.encode(manager, address(this)));\n        bytes32 hash = keccak256(code);\n        for (uint256 i; i < 500_000; i++) {\n            address predicted =\n                address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(i), hash)))));\n            if (uint160(predicted) & 0x3fff != 0x10cc) continue;\n            address at;\n            assembly (\"memory-safe\") { at := create2(0, add(code, 32), mload(code), i) }\n            require(at == predicted, \"CREATE2 failed\");\n            hook = CrownHook(at);\n            break;\n        }\n        require(address(hook) != address(0), \"no salt\");\n        hook.setRegistry(registry);\n        key = PoolKey(Currency.wrap(address(0)), Currency.wrap(address(token)), 12_500, 60, IHooks(address(hook)));\n        manager.initialize(key, PRICE);\n        hook.registerPool(key, TICKER, 100);\n        manager.unlock(abi.encode(true, key, PRICE));\n    }\n\n    function test_malformedRegistryMustSkipFeeWithoutBlockingSwap() public {\n        // Expected: execute the funded swap without a cut because the read is malformed.\n        // Actual: abi.decode in CrownHook._payCut reverts and the whole swap is reverted.\n        BalanceDelta delta =\n            abi.decode(manager.unlock(abi.encode(false, key, TickMath.MIN_SQRT_PRICE + 1)), (BalanceDelta));\n        assertEq(delta.amount0(), -1 ether);\n        assertGt(delta.amount1(), 0);\n        assertEq(hook.crownPaid(TICKER, Currency.wrap(address(0))), 0);\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager), \"only manager\");\n        (bool add, PoolKey memory pool, uint160 limit) = abi.decode(data, (bool, PoolKey, uint160));\n        BalanceDelta delta;\n        if (add) {\n            (delta,) = manager.modifyLiquidity(pool, ModifyLiquidityParams(-887220, 887220, 1_000e18, bytes32(0)), \"\");\n        } else {\n            delta = manager.swap(pool, SwapParams(true, -1 ether, limit), \"\");\n        }\n        _settle(pool.currency0, delta.amount0());\n        _settle(pool.currency1, delta.amount1());\n        return abi.encode(delta);\n    }\n\n    function _settle(Currency currency, int128 amount) internal {\n        if (amount < 0) {\n            uint256 owed = uint256(uint128(-amount));\n            manager.sync(currency);\n            if (Currency.unwrap(currency) == address(0)) {\n                manager.settle{value: owed}();\n            } else {\n                token.transfer(address(manager), owed);\n                manager.settle();\n            }\n        } else if (amount > 0) {\n            manager.take(currency, address(this), uint256(uint128(amount)));\n        }\n    }\n\n    receive() external payable {}\n}","reproduction":"Run the embedded standalone file with forge test --match-path test/scratch/CrownMalformedRegistryProof.t.sol -vv. The owner configures a contract whose king(bytes32) response is three words [0, 1 << 160, 0]. After seeding 1000e18 real full-range liquidity, submit a -1 ether buy. Expected under the never-block-on-registry-failure requirement: amount0=-1 ether, amount1>0, crownPaid=0. Actual: beforeSwap reverts with empty underlying revert data, wrapped by Hooks as WrappedError; the buy cannot execute. This proof was run and observed to fail for that reason.","severity":"medium","title":"A malformed 96-byte king response reverts swaps instead of skipping the fee"},{"description":"This is a specification conflict, not an assertion that the registry should stop replacing the king. The assignment asks for the registry token address to be byte-identical before and after dethroning, while also requiring a successful challenge to point the registry at a distinct challenger token. registry.king(ticker).token cannot meet both conditions. The delivered integration verifies the replacement required by the concept and the byte-exact stability of hook.registry() and the traded pool currency1; it does not silently substitute those assertions for fulfillment of the literal unchanged-king-token condition.","line":246,"path":"src/CrownRegistry.sol","reproduction":"In test/CrownHook.t.sol:test_endToEndDethroneChangesFeeRecipient, deploy distinct CrownToken and CrownChallengerToken, wait seven days, open a 0.01 ETH challenge, stake 0.03 ETH on King and another 0.05 ETH on Challenger, wait 96 hours, and finalize. The registry king token changes from the original token to the distinct rival, as the concept requires. A literal assertion comparing the old and new registry.king(CRWN).token addresses for equality would fail. The registry contract address and original pool token address remain identical.","severity":"info","title":"Unchanged king-token acceptance condition conflicts with the specified dethrone"}],"hash":"c8af1ee36eac8a45e321c0038d2e29b39d666a886231bb757b6712bf9b7ed4a2","nodeId":"94409366-1957-462b-8d1d-4e067b82f894","outcome":"completed","summary":"Added boundary, failure-path, invariant, and v4 dethrone tests. `forge build` and seeded `forge test` pass: **67 tests, zero failures or skips**.\n\nReported two defects with reproducible proofs in `.imd-findings.json`:\n\n- Fees charged on unexecuted input.\n- Malformed registry responses blocking swaps.\n\nAlso documented the contradictory unchanged-king-token requirement. Production contracts and configuration remain untouched.","treeHash":"bae5892449eaf023ce77d405f89c140c43a174b4","usage":{"cachedInputTokens":2430464,"inputTokens":128004,"model":"gpt-6.1-sol","outputTokens":39748,"runtime":"codex","turns":7,"wallClockMs":943777}}],"verification":[{"checks":[{"durationMs":4058,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.96s\nCompiler run successful!\n","passed":true},{"durationMs":7318,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 565.74µs (799.15µs CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 28183201)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 29.54ms (29.38ms CPU time)\n\nRan 24 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1194459, ~: 1195752)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 873677)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 671600)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 730234)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 783183)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1179271)\n[PASS] test_finalizeRespectsTimelock() (gas: 506196)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 327005)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 345781)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 74932)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52558)\n[PASS] test_quorumBoundaryAndTie() (gas: 1247191)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 453631)\n[PASS] test_stakeDuringWindowOnly() (gas: 564799)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 347182)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 661893)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 182.09ms (193.02ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 642073, ~: 649011)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 884726, ~: 890839)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 612009, ~: 607289)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 73481, ~: 73489)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 347649)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1001232)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1252759)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1298798)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1353823)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 713105)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 736724)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 670157)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 193.76ms (729.11ms CPU time)\n\nRan 34 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_anyLengthRegistryResponseSkipsBothCallbacks(uint8) (runs: 1000, μ: 417899, ~: 417823)\n[PASS] testFuzz_cutFollowsExecutedEthUnderAnyPriceLimit(uint256,uint16,uint8) (runs: 1000, μ: 319121, ~: 335634)\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 656528, ~: 681490)\n[PASS] testFuzz_noGasLimitLetsASwapThroughWithoutTheCut(uint256) (runs: 1000, μ: 270802, ~: 343739)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 815660)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 48928998)\n[PASS] test_callbacksRefuseNonManager() (gas: 113485)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 956791)\n[PASS] test_emptyPoolChargesNothingInAnyShape() (gas: 3851217)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1919855)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 322184)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 217315)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 219791)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 268422)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 356947)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 18807951)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 48897625)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1700570)\n[PASS] test_noRegistryNoCut() (gas: 48608243)\n[PASS] test_outOfGasBeneficiaryCannotBlockEitherCallback() (gas: 799661)\n[PASS] test_permissionsAndAddressAgree() (gas: 26175)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 305167)\n[PASS] test_priceLimitPartialExactInputSellPaysCutOnDeliveredOutput() (gas: 217754)\n[PASS] test_priceLimitPartialExactOutputBuyPaysCutOnExecutedInput() (gas: 219998)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 266906)\n[PASS] test_registerPoolFailurePaths() (gas: 1897786)\n[PASS] test_registryReadFailureNoCut() (gas: 48811359)\n[PASS] test_rehearsalLeavesNoTraceOnThePool() (gas: 1116458)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 48169379)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38398)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148732)\n[PASS] test_unknownTickerNoCut() (gas: 616702)\n[PASS] test_unregisteredPoolNoCut() (gas: 590707)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 554608)\nSuite result: ok. 34 passed; 0 failed; 0 skipped; finished in 193.77ms (837.05ms CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.41s (6.40s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 4920  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | buyLimited       | 4912  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 4807  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 4930  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sellLimited      | 5007  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.21s (7.19s CPU time)\n\nRan 7 test suites in 7.21s (14.22s CPU time): 78 tests passed, 0 failed, 0 skipped (78 total tests)\n","passed":true},{"durationMs":55,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"README.md\":242,\"foundry.toml\":22,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":353,\"src/CrownRegistry.sol\":302,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":799,\"test/CrownRegistry.t.sol\":483,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":83,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":339,\"test/invariant/CrownRegistryInvariant.t.sol\":393,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"132858940e6f37ecb774557be76f98218d9266a88b42ee558260dc6be96bdf03","verifiedTreeHash":"6252b98bea26cccbcd10f2edfad6958e7f28dc08","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":4174,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.07s\nCompiler run successful!\n","passed":true},{"durationMs":7519,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 528.45µs (925.95µs CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 28183201)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 22.61ms (22.47ms CPU time)\n\nRan 24 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1194459, ~: 1195752)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 873677)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 671600)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 730234)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 783183)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1179271)\n[PASS] test_finalizeRespectsTimelock() (gas: 506196)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 327005)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 345781)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 74932)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52558)\n[PASS] test_quorumBoundaryAndTie() (gas: 1247191)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 453631)\n[PASS] test_stakeDuringWindowOnly() (gas: 564799)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 347182)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 661893)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 197.85ms (203.64ms CPU time)\n\nRan 34 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_anyLengthRegistryResponseSkipsBothCallbacks(uint8) (runs: 1000, μ: 417899, ~: 417823)\n[PASS] testFuzz_cutFollowsExecutedEthUnderAnyPriceLimit(uint256,uint16,uint8) (runs: 1000, μ: 319121, ~: 335634)\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 656528, ~: 681490)\n[PASS] testFuzz_noGasLimitLetsASwapThroughWithoutTheCut(uint256) (runs: 1000, μ: 270802, ~: 343739)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 815660)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 48928998)\n[PASS] test_callbacksRefuseNonManager() (gas: 113485)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 956791)\n[PASS] test_emptyPoolChargesNothingInAnyShape() (gas: 3851217)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1919855)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 322184)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 217315)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 219791)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 268422)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 356947)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 18807951)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 48897625)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1700570)\n[PASS] test_noRegistryNoCut() (gas: 48608243)\n[PASS] test_outOfGasBeneficiaryCannotBlockEitherCallback() (gas: 799661)\n[PASS] test_permissionsAndAddressAgree() (gas: 26175)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 305167)\n[PASS] test_priceLimitPartialExactInputSellPaysCutOnDeliveredOutput() (gas: 217754)\n[PASS] test_priceLimitPartialExactOutputBuyPaysCutOnExecutedInput() (gas: 219998)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 266906)\n[PASS] test_registerPoolFailurePaths() (gas: 1897786)\n[PASS] test_registryReadFailureNoCut() (gas: 48811359)\n[PASS] test_rehearsalLeavesNoTraceOnThePool() (gas: 1116458)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 48169379)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38398)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148732)\n[PASS] test_unknownTickerNoCut() (gas: 616702)\n[PASS] test_unregisteredPoolNoCut() (gas: 590707)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 554608)\nSuite result: ok. 34 passed; 0 failed; 0 skipped; finished in 198.06ms (820.88ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 642073, ~: 649011)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 884726, ~: 890839)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 612009, ~: 607289)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 73481, ~: 73489)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 347649)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1001232)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1252759)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1298798)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1353823)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 713105)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 736724)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 670157)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 198.11ms (771.05ms CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.37s (6.37s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 4920  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | buyLimited       | 4912  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 4807  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 4930  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sellLimited      | 5007  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.40s (7.36s CPU time)\n\nRan 7 test suites in 7.40s (14.39s CPU time): 78 tests passed, 0 failed, 0 skipped (78 total tests)\n","passed":true},{"durationMs":90,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"DESIGN.md\":87,\"README.md\":302,\"dist/NOTICE.txt\":394,\"dist/abi/CrownChallengerToken.json\":334,\"dist/abi/CrownHook.json\":1448,\"dist/abi/CrownRegistry.json\":960,\"dist/abi/CrownToken.json\":328,\"dist/abi/ThroneRegistry.json\":960,\"dist/assets/ccip-Cp0_HofE.js\":1,\"dist/assets/hooks.module-DE9oX6xH.js\":1,\"dist/assets/index-C2Wbb7G-.css\":1,\"dist/assets/index-NlUkNkPb.js\":7,\"dist/assets/index-i5OnzwSe.js\":54,\"dist/assets/index-iLYAXTGY.js\":7,\"dist/favicon.svg\":1,\"dist/imd-deployment.json\":87,\"dist/index.html\":27,\"dist/share.png\":142,\"dist/share.svg\":1,\"dist/wallets/coinbase.svg\":1,\"dist/wallets/metamask.svg\":1,\"dist/wallets/phantom.svg\":1,\"dist/wallets/rabby.svg\":1,\"foundry.toml\":22,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":353,\"src/CrownRegistry.sol\":302,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":799,\"test/CrownRegistry.t.sol\":483,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":83,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":339,\"test/invariant/CrownRegistryInvariant.t.sol\":393,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31,\"validation/README.md\":107,\"validation/screenshots/mock-staking-390.png\":221,\"validation/screenshots/pending-1440.png\":393,\"validation/screenshots/pending-390.png\":209,\"validation/screenshots/webkit-wallet-390.png\":254,\"validation/taste.json\":116,\"web/NOTICE.md\":11,\"web/index.html\":26,\"web/licenses/BetterInterface.txt\":220,\"web/licenses/EthFrontendUX.txt\":30,\"web/licenses/WalletMarks.txt\":9,\"web/package-lock.json\":7763,\"web/package.json\":29,\"web/public/NOTICE.txt\":394,\"web/public/abi/CrownChallengerToken.json\":334,\"web/public/abi/CrownHook.json\":1448,\"web/public/abi/CrownRegistry.json\":960,\"web/public/abi/CrownToken.json\":328,\"web/public/abi/ThroneRegistry.json\":960,\"web/public/favicon.svg\":1,\"web/public/share.png\":142,\"web/public/share.svg\":1,\"web/public/wallets/coinbase.svg\":1,\"web/public/wallets/metamask.svg\":1,\"web/public/wallets/phantom.svg\":1,\"web/public/wallets/rabby.svg\":1,\"web/scripts/build-worker.mjs\":38,\"web/scripts/check-export.mjs\":105,\"web/scripts/export.mjs\":125,\"web/scripts/render-share.mjs\":16,\"web/src/App.tsx\":347,\"web/src/ChallengePanel.tsx\":389,\"web/src/History.tsx\":184,\"web/src/Management.tsx\":345,\"web/src/Transaction.tsx\":185,\"web/src/TransactionFeed.tsx\":58,\"web/src/Wallet.tsx\":232,\"web/src/config.ts\":228,\"web/src/data.ts\":191,\"web/src/domain.ts\":115,\"web/src/main.tsx\":45,\"web/src/styles.css\":1373,\"web/src/ui.tsx\":166,\"web/tests/browser.test.mjs\":942,\"web/tests/domain.test.mjs\":60,\"web/tests/export.test.mjs\":96,\"web/tsconfig.json\":17,\"web/vite.config.ts\":37},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"208c51b7ebcc8053f1408fc9f8c738a94b50ad36e8c61a26a4956b1c6f6d2bb3","verifiedTreeHash":"c679cc7aa0baf0ca67dfef944c243813d62abedc","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":4787,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.67s\nCompiler run successful!\n","passed":true},{"durationMs":8686,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 877.41µs (1.64ms CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 10426426)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.28ms (3.06ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 673274, ~: 680229)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 929091, ~: 935194)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 643091, ~: 638507)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 75697, ~: 75717)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 374213)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1071943)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1301711)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1329810)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1389197)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 741806)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 789887)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 701232)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 214.36ms (850.04ms CPU time)\n\nRan 25 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1245660, ~: 1246885)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 926786)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 704948)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 761259)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 814207)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1230262)\n[PASS] test_displacementBreaksTheShamChallengeLock() (gas: 1103172)\n[PASS] test_finalizeRespectsTimelock() (gas: 532716)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 487062)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 372312)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 79388)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52530)\n[PASS] test_quorumBoundaryAndTie() (gas: 1300803)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 486744)\n[PASS] test_stakeDuringWindowOnly() (gas: 596029)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 369290)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 693061)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 214.59ms (226.36ms CPU time)\n\nRan 37 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_anyLengthRegistryResponseSkipsBothCallbacks(uint8) (runs: 1000, μ: 417647, ~: 417572)\n[PASS] testFuzz_cutFollowsExecutedEthUnderAnyPriceLimit(uint256,uint16,uint8) (runs: 1000, μ: 326392, ~: 343190)\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 678690, ~: 704288)\n[PASS] testFuzz_noGasLimitLetsASwapThroughWithoutTheCut(uint256) (runs: 1000, μ: 269950, ~: 351308)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 843119)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 87886866)\n[PASS] test_callbacksRefuseNonManager() (gas: 113587)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 969044)\n[PASS] test_emptyPoolChargesNothingInAnyShape() (gas: 3863188)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1993385)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 329731)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 225008)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 227462)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 275969)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 364538)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 16909883)\n[PASS] test_hostileBeneficiaryCannotBlockSwapsAndIsNotPaid() (gas: 3155937)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 87859780)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1751235)\n[PASS] test_outOfGasBeneficiaryCannotBlockEitherCallback() (gas: 807633)\n[PASS] test_partialCutWhenManagerHoldsLessThanTheCut() (gas: 16910741)\n[PASS] test_payoutRefusesEveryoneButTheHook() (gas: 32139)\n[PASS] test_permissionsAndAddressAgree() (gas: 26175)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 312691)\n[PASS] test_priceLimitPartialExactInputSellPaysCutOnDeliveredOutput() (gas: 225447)\n[PASS] test_priceLimitPartialExactOutputBuyPaysCutOnExecutedInput() (gas: 227691)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 274475)\n[PASS] test_registerPoolFailurePaths() (gas: 1934915)\n[PASS] test_registerPoolNeedsRegistryAndUnboundPoolSkipsTheCut() (gas: 87541003)\n[PASS] test_registerPoolRefusesTickersTheKingDoesNotOwn() (gas: 293959)\n[PASS] test_registryReadFailureNoCut() (gas: 87780959)\n[PASS] test_rehearsalLeavesNoTraceOnThePool() (gas: 1131596)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 173316241)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38410)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148568)\n[PASS] test_unregisteredPoolNoCut() (gas: 625895)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 569860)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 214.95ms (1.11s CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.07s (7.07s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 4920  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | buyLimited       | 4912  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 4807  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 4930  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sellLimited      | 5007  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.56s (8.53s CPU time)\n\nRan 7 test suites in 8.56s (16.28s CPU time): 82 tests passed, 0 failed, 0 skipped (82 total tests)\n","passed":true},{"durationMs":106,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.payout(address,uint256)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"DESIGN.md\":87,\"README.md\":354,\"dist/NOTICE.txt\":394,\"dist/abi/CrownChallengerToken.json\":334,\"dist/abi/CrownHook.json\":1534,\"dist/abi/CrownRegistry.json\":1020,\"dist/abi/CrownToken.json\":328,\"dist/abi/ThroneRegistry.json\":1020,\"dist/assets/ccip-DTxdOWV4.js\":1,\"dist/assets/hooks.module-DE9oX6xH.js\":1,\"dist/assets/index-Cx0qEvMU.js\":7,\"dist/assets/index-D1UV8ghm.css\":1,\"dist/assets/index-DU0WTre0.js\":54,\"dist/assets/index-Dlomt_yQ.js\":7,\"dist/favicon.svg\":1,\"dist/imd-deployment.json\":87,\"dist/index.html\":27,\"dist/share.png\":142,\"dist/share.svg\":1,\"dist/wallets/coinbase.svg\":1,\"dist/wallets/metamask.svg\":1,\"dist/wallets/phantom.svg\":1,\"dist/wallets/rabby.svg\":1,\"foundry.toml\":22,\"launch.json\":30,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":421,\"src/CrownRegistry.sol\":348,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":931,\"test/CrownRegistry.t.sol\":552,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":83,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":339,\"test/invariant/CrownRegistryInvariant.t.sol\":396,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31,\"validation/README.md\":150,\"validation/screenshots/mock-staking-390.png\":221,\"validation/screenshots/pending-1440.png\":393,\"validation/screenshots/pending-390.png\":209,\"validation/screenshots/webkit-wallet-390.png\":254,\"validation/taste.json\":4385,\"web/NOTICE.md\":11,\"web/index.html\":26,\"web/licenses/BetterInterface.txt\":220,\"web/licenses/EthFrontendUX.txt\":30,\"web/licenses/WalletMarks.txt\":9,\"web/package-lock.json\":7763,\"web/package.json\":29,\"web/public/NOTICE.txt\":394,\"web/public/abi/CrownChallengerToken.json\":334,\"web/public/abi/CrownHook.json\":1534,\"web/public/abi/CrownRegistry.json\":1020,\"web/public/abi/CrownToken.json\":328,\"web/public/abi/ThroneRegistry.json\":1020,\"web/public/favicon.svg\":1,\"web/public/share.png\":142,\"web/public/share.svg\":1,\"web/public/wallets/coinbase.svg\":1,\"web/public/wallets/metamask.svg\":1,\"web/public/wallets/phantom.svg\":1,\"web/public/wallets/rabby.svg\":1,\"web/scripts/build-worker.mjs\":38,\"web/scripts/check-export.mjs\":105,\"web/scripts/export.mjs\":125,\"web/scripts/render-share.mjs\":16,\"web/src/App.tsx\":354,\"web/src/ChallengePanel.tsx\":421,\"web/src/History.tsx\":184,\"web/src/Management.tsx\":345,\"web/src/Transaction.tsx\":185,\"web/src/TransactionFeed.tsx\":58,\"web/src/Wallet.tsx\":232,\"web/src/config.ts\":228,\"web/src/data.ts\":195,\"web/src/domain.ts\":118,\"web/src/main.tsx\":45,\"web/src/styles.css\":1378,\"web/src/ui.tsx\":166,\"web/tests/browser.test.mjs\":952,\"web/tests/domain.test.mjs\":60,\"web/tests/export.test.mjs\":96,\"web/tsconfig.json\":17,\"web/vite.config.ts\":37},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"6ecb528cda2cb88722c6baf8832672548b728cf98c451fe3d3bdc26f2a5e2964","verifiedTreeHash":"6a486676922a675af6c402c2c2cce10bd5b17b21","verifierVersion":"0.1.0+63e0a393"},{"checks":[{"durationMs":4928,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.81s\nCompiler run successful!\n","passed":true},{"durationMs":8265,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 448.98µs (788.37µs CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 15317402)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 13.82ms (13.66ms CPU time)\n\nRan 40 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_anyLengthRegistryResponseSkipsBothCallbacks(uint8) (runs: 1000, μ: 417557, ~: 417488)\n[PASS] testFuzz_cutFollowsExecutedEthUnderAnyPriceLimit(uint256,uint16,uint8) (runs: 1000, μ: 326800, ~: 343204)\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 679426, ~: 704732)\n[PASS] testFuzz_noGasLimitLetsASwapThroughWithoutTheCut(uint256) (runs: 1000, μ: 269741, ~: 351760)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 843075)\n[PASS] test_callbacksRefuseNonManager() (gas: 113566)\n[PASS] test_claimsTradingBeneficiaryCannotFrontRunOrBlockABoundedBuy() (gas: 2586827)\n[PASS] test_contractBeneficiaryClaimNeedsNoManagerBalance() (gas: 16548883)\n[PASS] test_contractBeneficiaryIsPaidInClaimsNotEth() (gas: 9097421)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 968996)\n[PASS] test_emptyPoolChargesNothingInAnyShape() (gas: 3863023)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1995715)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 330150)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 225393)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 227892)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 276414)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 364969)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 16614703)\n[PASS] test_gasBurningBeneficiaryIsPaidInClaimsWithoutRunning() (gas: 610230)\n[PASS] test_hostileBeneficiaryNeverRunsAndCannotBlockSwaps() (gas: 2834301)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 8968751)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1752556)\n[PASS] test_partialCutWhenManagerHoldsLessThanTheCut() (gas: 16613106)\n[PASS] test_payoutRefusesEveryoneButTheHook() (gas: 58530)\n[PASS] test_permissionsAndAddressAgree() (gas: 26197)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 313136)\n[PASS] test_priceLimitPartialExactInputSellPaysCutOnDeliveredOutput() (gas: 225877)\n[PASS] test_priceLimitPartialExactOutputBuyPaysCutOnExecutedInput() (gas: 228121)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 274942)\n[PASS] test_redeemTurnsClaimsIntoEth() (gas: 1710016)\n[PASS] test_registerPoolFailurePaths() (gas: 1935047)\n[PASS] test_registerPoolNeedsRegistryAndUnboundPoolSkipsTheCut() (gas: 8654659)\n[PASS] test_registerPoolRefusesTickersTheKingDoesNotOwn() (gas: 293981)\n[PASS] test_registryReadFailureNoCut() (gas: 8883548)\n[PASS] test_rehearsalLeavesNoTraceOnThePool() (gas: 1132450)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 20092902)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38432)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148520)\n[PASS] test_unregisteredPoolNoCut() (gas: 625830)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 570735)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 199.86ms (716.31ms CPU time)\n\nRan 25 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1245660, ~: 1246885)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 926786)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 704948)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 761259)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 814207)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1230262)\n[PASS] test_displacementBreaksTheShamChallengeLock() (gas: 1103172)\n[PASS] test_finalizeRespectsTimelock() (gas: 532716)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 487062)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 372312)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 79388)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52530)\n[PASS] test_quorumBoundaryAndTie() (gas: 1300803)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 486744)\n[PASS] test_stakeDuringWindowOnly() (gas: 596029)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 369290)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 693061)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 199.85ms (206.51ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 673274, ~: 680229)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 929091, ~: 935194)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 643091, ~: 638507)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 75697, ~: 75717)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 374213)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1071943)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1301711)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1329810)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1389197)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 741806)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 789887)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 701232)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 200.02ms (787.35ms CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.01s (7.01s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 4920  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | buyLimited       | 4912  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 4807  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 4930  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sellLimited      | 5007  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.15s (8.13s CPU time)\n\nRan 7 test suites in 8.15s (15.77s CPU time): 85 tests passed, 0 failed, 0 skipped (85 total tests)\n","passed":true},{"durationMs":80,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.payout(address,uint256,bool)\",\"CrownHook.redeem(uint256,address)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownHook.unlockCallback(bytes)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"DESIGN.md\":87,\"README.md\":384,\"dist/NOTICE.txt\":394,\"dist/abi/CrownChallengerToken.json\":334,\"dist/abi/CrownHook.json\":1637,\"dist/abi/CrownRegistry.json\":1020,\"dist/abi/CrownToken.json\":328,\"dist/abi/ThroneRegistry.json\":1020,\"dist/assets/ccip-DXU6stvj.js\":1,\"dist/assets/hooks.module-DE9oX6xH.js\":1,\"dist/assets/index-D1UV8ghm.css\":1,\"dist/assets/index-D9geSaZO.js\":7,\"dist/assets/index-DGU-7I6I.js\":7,\"dist/assets/index-DnYnoiAi.js\":54,\"dist/favicon.svg\":1,\"dist/imd-deployment.json\":87,\"dist/index.html\":27,\"dist/share.png\":142,\"dist/share.svg\":1,\"dist/wallets/coinbase.svg\":1,\"dist/wallets/metamask.svg\":1,\"dist/wallets/phantom.svg\":1,\"dist/wallets/rabby.svg\":1,\"foundry.toml\":22,\"launch.json\":30,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":468,\"src/CrownRegistry.sol\":348,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":1151,\"test/CrownRegistry.t.sol\":552,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":83,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":339,\"test/invariant/CrownRegistryInvariant.t.sol\":396,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31,\"validation/README.md\":182,\"validation/screenshots/mock-staking-390.png\":221,\"validation/screenshots/pending-1440.png\":393,\"validation/screenshots/pending-390.png\":209,\"validation/screenshots/webkit-wallet-390.png\":254,\"validation/taste.json\":116,\"web/NOTICE.md\":11,\"web/index.html\":26,\"web/licenses/BetterInterface.txt\":220,\"web/licenses/EthFrontendUX.txt\":30,\"web/licenses/WalletMarks.txt\":9,\"web/package-lock.json\":7763,\"web/package.json\":29,\"web/public/NOTICE.txt\":394,\"web/public/abi/CrownChallengerToken.json\":334,\"web/public/abi/CrownHook.json\":1637,\"web/public/abi/CrownRegistry.json\":1020,\"web/public/abi/CrownToken.json\":328,\"web/public/abi/ThroneRegistry.json\":1020,\"web/public/favicon.svg\":1,\"web/public/share.png\":142,\"web/public/share.svg\":1,\"web/public/wallets/coinbase.svg\":1,\"web/public/wallets/metamask.svg\":1,\"web/public/wallets/phantom.svg\":1,\"web/public/wallets/rabby.svg\":1,\"web/scripts/build-worker.mjs\":38,\"web/scripts/check-export.mjs\":105,\"web/scripts/export.mjs\":125,\"web/scripts/render-share.mjs\":16,\"web/src/App.tsx\":357,\"web/src/ChallengePanel.tsx\":421,\"web/src/History.tsx\":184,\"web/src/Management.tsx\":345,\"web/src/Transaction.tsx\":185,\"web/src/TransactionFeed.tsx\":58,\"web/src/Wallet.tsx\":232,\"web/src/config.ts\":228,\"web/src/data.ts\":195,\"web/src/domain.ts\":118,\"web/src/main.tsx\":45,\"web/src/styles.css\":1378,\"web/src/ui.tsx\":166,\"web/tests/browser.test.mjs\":952,\"web/tests/domain.test.mjs\":60,\"web/tests/export.test.mjs\":96,\"web/tsconfig.json\":17,\"web/vite.config.ts\":37},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"89bfa1e9d4b2e7cc7312b48b40a92d95ff1e9fa3c35eb682a8d5ab12d1e475e0","verifiedTreeHash":"f3eddb74b955a07dc732595245dcf47e7be07b1c","verifierVersion":"0.1.0+63e0a393"},{"checks":[{"durationMs":3082,"exitCode":0,"name":"build","output":"Compiling 88 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.94s\nCompiler run successful!\n","passed":true},{"durationMs":154,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 698.97µs (1.22ms CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 15817492)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 25.89ms (24.71ms CPU time)\n\nRan 24 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 256, μ: 1192533, ~: 1195569)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 873677)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 671600)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 730234)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 783183)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1179271)\n[PASS] test_finalizeRespectsTimelock() (gas: 506196)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 327005)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 345781)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 74932)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52558)\n[PASS] test_quorumBoundaryAndTie() (gas: 1247191)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 453631)\n[PASS] test_stakeDuringWindowOnly() (gas: 564799)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 347182)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 661893)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 34.84ms (41.73ms CPU time)\n\nRan 19 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 256, μ: 611469, ~: 625630)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 815649)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 19950244)\n[PASS] test_callbacksRefuseNonManager() (gas: 113543)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1361730)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 266248)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 217300)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 219799)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 218032)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 16788603)\n[PASS] test_noRegistryNoCut() (gas: 19632320)\n[PASS] test_permissionsAndAddressAgree() (gas: 26086)\n[PASS] test_registerPoolFailurePaths() (gas: 1898070)\n[PASS] test_registryReadFailureNoCut() (gas: 19834515)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 19250683)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 147122)\n[PASS] test_unknownTickerNoCut() (gas: 560846)\n[PASS] test_unregisteredPoolNoCut() (gas: 587943)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 498714)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 44.66ms (133.50ms CPU time)\n\nRan 4 test suites in 45.35ms (106.09ms CPU time): 49 tests passed, 0 failed, 0 skipped (49 total tests)\n","passed":true},{"durationMs":69,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"README.md\":223,\"foundry.toml\":22,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":289,\"src/CrownRegistry.sol\":302,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":446,\"test/CrownRegistry.t.sol\":482,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/floor/OwnerChecks.sol\":21,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":64,\"test/utils/HookDeployer.sol\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1961,"exitCode":0,"name":"slither","output":"[low/medium] reentrancy-benign at src/CrownHook.sol:250: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#250-288):\n[low/medium] reentrancy-events at src/CrownHook.sol:250: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#250-288):\n[low/medium] timestamp at src/CrownRegistry.sol:154: CrownRegistry.hasLiveChallenge(bytes32) (src/CrownRegistry.sol#154-157) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:175: CrownRegistry.registerKing(bytes32,address,address) (src/CrownRegistry.sol#175-178) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:219: CrownRegistry.finalize(uint256) (src/CrownRegistry.sol#219-256) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:210: CrownRegistry.stake(uint256,CrownRegistry.Side) (src/CrownRegistry.sol#210-216) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:182: CrownRegistry.openChallenge(bytes32,address) (src/CrownRegistry.sol#182-207) uses timestamp for comparisons","passed":true},{"durationMs":477,"exitCode":0,"name":"aderyn","output":"[high] eth-send-unchecked-address at src/CrownRegistry.sol:259: ETH transferred without address checks (2 places)\n[high] unsafe-casting at src/CrownHook.sol:165: Unsafe Casting of integers (2 places)\n[low] centralization-risk at src/CrownHook.sol:32: Centralization Risk (3 places)\n[low] internal-function-used-once at src/HookFlags.sol:27: Internal Function Used Only Once\n[low] large-numeric-literal at src/CrownChallengerToken.sol:11: Large Numeric Literal (5 places)\n[low] unused-public-function at src/CrownHook.sol:234: Public Function Not Used Internally (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8da418de8d0146c1e6b4463148f16fb580b212449e5380731413381feaed48b2","verifiedTreeHash":"5dd4ad13b7d6d898cb14f2f0d7ecdcaca4987f35","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":2742,"exitCode":0,"name":"build","output":"Compiling 88 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.65s\nCompiler run successful!\n","passed":true},{"durationMs":167,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 528.47µs (726.50µs CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 28183201)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 20.02ms (19.78ms CPU time)\n\nRan 24 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 256, μ: 1192533, ~: 1195569)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 873677)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 671600)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 730234)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 783183)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1179271)\n[PASS] test_finalizeRespectsTimelock() (gas: 506196)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 327005)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 345781)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 74932)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52558)\n[PASS] test_quorumBoundaryAndTie() (gas: 1247191)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 453631)\n[PASS] test_stakeDuringWindowOnly() (gas: 564799)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 347182)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 661893)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 20.75ms (26.04ms CPU time)\n\nRan 24 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 256, μ: 659542, ~: 681467)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 815660)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 48928931)\n[PASS] test_callbacksRefuseNonManager() (gas: 113507)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 956813)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1483864)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 322184)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 217292)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 219747)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 268411)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 18807862)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 48897614)\n[PASS] test_noRegistryNoCut() (gas: 48608166)\n[PASS] test_permissionsAndAddressAgree() (gas: 26175)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 305133)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 266906)\n[PASS] test_registerPoolFailurePaths() (gas: 1897786)\n[PASS] test_registryReadFailureNoCut() (gas: 48811281)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 48169312)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38398)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148754)\n[PASS] test_unknownTickerNoCut() (gas: 616724)\n[PASS] test_unregisteredPoolNoCut() (gas: 590729)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 554630)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 64.35ms (233.99ms CPU time)\n\nRan 4 test suites in 65.11ms (105.64ms CPU time): 54 tests passed, 0 failed, 0 skipped (54 total tests)\n","passed":true},{"durationMs":51,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"README.md\":242,\"foundry.toml\":22,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":353,\"src/CrownRegistry.sol\":302,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":536,\"test/CrownRegistry.t.sol\":482,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/floor/OwnerChecks.sol\":21,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1782,"exitCode":0,"name":"slither","output":"[low/medium] reentrancy-benign at src/CrownHook.sol:303: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#303-352):\n[low/medium] reentrancy-events at src/CrownHook.sol:303: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#303-352):\n[low/medium] timestamp at src/CrownRegistry.sol:154: CrownRegistry.hasLiveChallenge(bytes32) (src/CrownRegistry.sol#154-157) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:175: CrownRegistry.registerKing(bytes32,address,address) (src/CrownRegistry.sol#175-178) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:219: CrownRegistry.finalize(uint256) (src/CrownRegistry.sol#219-256) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:210: CrownRegistry.stake(uint256,CrownRegistry.Side) (src/CrownRegistry.sol#210-216) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:182: CrownRegistry.openChallenge(bytes32,address) (src/CrownRegistry.sol#182-207) uses timestamp for comparisons","passed":true},{"durationMs":462,"exitCode":0,"name":"aderyn","output":"[high] eth-send-unchecked-address at src/CrownRegistry.sol:259: ETH transferred without address checks (2 places)\n[high] unsafe-casting at src/CrownHook.sol:175: Unsafe Casting of integers (2 places)\n[low] centralization-risk at src/CrownHook.sol:38: Centralization Risk (3 places)\n[low] internal-function-used-once at src/HookFlags.sol:27: Internal Function Used Only Once\n[low] large-numeric-literal at src/CrownChallengerToken.sol:11: Large Numeric Literal (5 places)\n[low] unused-public-function at src/CrownRegistry.sol:136: Public Function Not Used Internally","passed":true},{"durationMs":2221,"exitCode":0,"name":"proof 010bb14adca6","output":"Compiling 83 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.62s\nCompiler run successful!\n\nRan 2 tests for test/imd-proof-9cd8a6ec/Proof_010bb14adca6.t.sol:CrownPartialFillProofTest\n[PASS] test_emptyPoolMustNotChargeForAnUnexecutedTrade() (gas: 942250)\n[PASS] test_priceLimitPartialFillMustNotChargeOnUnusedInput() (gas: 268567)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 13.70ms (1.58ms CPU time)\n\nRan 1 test suite in 14.22ms (13.70ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)\n","passed":true},{"durationMs":1743,"exitCode":0,"name":"proof f31299533f76","output":"2026-10-15T18:36:50.471808Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-EuFDal/repo/test/imd-proof-9cd8a6ec/Proof_010bb14adca6.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.16s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-62de5fd2/Proof_f31299533f76.t.sol:CrownMalformedRegistryProofTest\n[PASS] test_malformedRegistryMustSkipFeeWithoutBlockingSwap() (gas: 204624)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.89ms (245.59µs CPU time)\n\nRan 1 test suite in 13.37ms (12.89ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8dd70a5ed928f7b1e7196cff00efb90221314e7eafd0ba48e94319f23c26b8ab","verifiedTreeHash":"8e14e3d959958cc2479e901f12ba7568b1ba5d2f","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":3920,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.83s\nCompiler run successful!\n","passed":true},{"durationMs":7227,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 478.49µs (758.53µs CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 28183201)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 28.10ms (27.98ms CPU time)\n\nRan 24 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1194459, ~: 1195752)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 873677)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 671600)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 730234)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 783183)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1179271)\n[PASS] test_finalizeRespectsTimelock() (gas: 506196)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 327005)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 345781)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 74932)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52558)\n[PASS] test_quorumBoundaryAndTie() (gas: 1247191)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 453631)\n[PASS] test_stakeDuringWindowOnly() (gas: 564799)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 347182)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 661893)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 187.55ms (193.24ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 642073, ~: 649011)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 884726, ~: 890839)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 612009, ~: 607289)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 73481, ~: 73489)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 347649)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1001232)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1252759)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1298798)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1353823)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 713105)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 736724)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 670157)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 191.16ms (757.77ms CPU time)\n\nRan 34 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_anyLengthRegistryResponseSkipsBothCallbacks(uint8) (runs: 1000, μ: 417899, ~: 417823)\n[PASS] testFuzz_cutFollowsExecutedEthUnderAnyPriceLimit(uint256,uint16,uint8) (runs: 1000, μ: 319121, ~: 335634)\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 656528, ~: 681490)\n[PASS] testFuzz_noGasLimitLetsASwapThroughWithoutTheCut(uint256) (runs: 1000, μ: 270802, ~: 343739)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 815660)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 48928998)\n[PASS] test_callbacksRefuseNonManager() (gas: 113485)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 956791)\n[PASS] test_emptyPoolChargesNothingInAnyShape() (gas: 3851217)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1919855)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 322184)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 217315)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 219791)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 268422)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 356947)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 18807951)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 48897625)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1700570)\n[PASS] test_noRegistryNoCut() (gas: 48608243)\n[PASS] test_outOfGasBeneficiaryCannotBlockEitherCallback() (gas: 799661)\n[PASS] test_permissionsAndAddressAgree() (gas: 26175)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 305167)\n[PASS] test_priceLimitPartialExactInputSellPaysCutOnDeliveredOutput() (gas: 217754)\n[PASS] test_priceLimitPartialExactOutputBuyPaysCutOnExecutedInput() (gas: 219998)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 266906)\n[PASS] test_registerPoolFailurePaths() (gas: 1897786)\n[PASS] test_registryReadFailureNoCut() (gas: 48811359)\n[PASS] test_rehearsalLeavesNoTraceOnThePool() (gas: 1116458)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 48169379)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38398)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148732)\n[PASS] test_unknownTickerNoCut() (gas: 616702)\n[PASS] test_unregisteredPoolNoCut() (gas: 590707)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 554608)\nSuite result: ok. 34 passed; 0 failed; 0 skipped; finished in 193.95ms (780.05ms CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.42s (6.41s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 4920  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | buyLimited       | 4912  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 4807  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 4930  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sellLimited      | 5007  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.12s (7.10s CPU time)\n\nRan 7 test suites in 7.12s (14.13s CPU time): 78 tests passed, 0 failed, 0 skipped (78 total tests)\n","passed":true},{"durationMs":77,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"DESIGN.md\":87,\"README.md\":302,\"dist/NOTICE.txt\":394,\"dist/abi/CrownChallengerToken.json\":334,\"dist/abi/CrownHook.json\":1448,\"dist/abi/CrownRegistry.json\":960,\"dist/abi/CrownToken.json\":328,\"dist/abi/ThroneRegistry.json\":960,\"dist/assets/ccip-Cp0_HofE.js\":1,\"dist/assets/hooks.module-DE9oX6xH.js\":1,\"dist/assets/index-C2Wbb7G-.css\":1,\"dist/assets/index-NlUkNkPb.js\":7,\"dist/assets/index-i5OnzwSe.js\":54,\"dist/assets/index-iLYAXTGY.js\":7,\"dist/favicon.svg\":1,\"dist/imd-deployment.json\":87,\"dist/index.html\":27,\"dist/share.png\":142,\"dist/share.svg\":1,\"dist/wallets/coinbase.svg\":1,\"dist/wallets/metamask.svg\":1,\"dist/wallets/phantom.svg\":1,\"dist/wallets/rabby.svg\":1,\"foundry.toml\":22,\"launch.json\":30,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":353,\"src/CrownRegistry.sol\":302,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":799,\"test/CrownRegistry.t.sol\":483,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":83,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":339,\"test/invariant/CrownRegistryInvariant.t.sol\":393,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31,\"validation/README.md\":107,\"validation/screenshots/mock-staking-390.png\":221,\"validation/screenshots/pending-1440.png\":393,\"validation/screenshots/pending-390.png\":209,\"validation/screenshots/webkit-wallet-390.png\":254,\"validation/taste.json\":116,\"web/NOTICE.md\":11,\"web/index.html\":26,\"web/licenses/BetterInterface.txt\":220,\"web/licenses/EthFrontendUX.txt\":30,\"web/licenses/WalletMarks.txt\":9,\"web/package-lock.json\":7763,\"web/package.json\":29,\"web/public/NOTICE.txt\":394,\"web/public/abi/CrownChallengerToken.json\":334,\"web/public/abi/CrownHook.json\":1448,\"web/public/abi/CrownRegistry.json\":960,\"web/public/abi/CrownToken.json\":328,\"web/public/abi/ThroneRegistry.json\":960,\"web/public/favicon.svg\":1,\"web/public/share.png\":142,\"web/public/share.svg\":1,\"web/public/wallets/coinbase.svg\":1,\"web/public/wallets/metamask.svg\":1,\"web/public/wallets/phantom.svg\":1,\"web/public/wallets/rabby.svg\":1,\"web/scripts/build-worker.mjs\":38,\"web/scripts/check-export.mjs\":105,\"web/scripts/export.mjs\":125,\"web/scripts/render-share.mjs\":16,\"web/src/App.tsx\":347,\"web/src/ChallengePanel.tsx\":389,\"web/src/History.tsx\":184,\"web/src/Management.tsx\":345,\"web/src/Transaction.tsx\":185,\"web/src/TransactionFeed.tsx\":58,\"web/src/Wallet.tsx\":232,\"web/src/config.ts\":228,\"web/src/data.ts\":191,\"web/src/domain.ts\":115,\"web/src/main.tsx\":45,\"web/src/styles.css\":1373,\"web/src/ui.tsx\":166,\"web/tests/browser.test.mjs\":942,\"web/tests/domain.test.mjs\":60,\"web/tests/export.test.mjs\":96,\"web/tsconfig.json\":17,\"web/vite.config.ts\":37},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8f8c93a4c3aed535ecbf1ead939b36ebede87656e89163c570c1b5b8a92746f3","verifiedTreeHash":"f242b844237188fd9dae326e6e63e57c02a9931b","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":4427,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.33s\nCompiler run successful!\n","passed":true},{"durationMs":8103,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 944.07µs (1.46ms CPU time)\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 10426426)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.92ms (4.11ms CPU time)\n\nRan 25 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1245660, ~: 1246885)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 926786)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 704948)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 761259)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 814207)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1230262)\n[PASS] test_displacementBreaksTheShamChallengeLock() (gas: 1103172)\n[PASS] test_finalizeRespectsTimelock() (gas: 532716)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 487062)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 372312)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 79388)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52530)\n[PASS] test_quorumBoundaryAndTie() (gas: 1300803)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 486744)\n[PASS] test_stakeDuringWindowOnly() (gas: 596029)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 369290)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 693061)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 211.96ms (214.92ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 673274, ~: 680229)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 929091, ~: 935194)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 643091, ~: 638507)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 75697, ~: 75717)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 374213)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1071943)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1301711)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1329810)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1389197)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 741806)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 789887)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 701232)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 214.68ms (850.51ms CPU time)\n\nRan 37 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_anyLengthRegistryResponseSkipsBothCallbacks(uint8) (runs: 1000, μ: 417647, ~: 417572)\n[PASS] testFuzz_cutFollowsExecutedEthUnderAnyPriceLimit(uint256,uint16,uint8) (runs: 1000, μ: 326392, ~: 343190)\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 678690, ~: 704288)\n[PASS] testFuzz_noGasLimitLetsASwapThroughWithoutTheCut(uint256) (runs: 1000, μ: 269950, ~: 351308)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 843119)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 87886866)\n[PASS] test_callbacksRefuseNonManager() (gas: 113587)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 969044)\n[PASS] test_emptyPoolChargesNothingInAnyShape() (gas: 3863188)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1993385)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 329731)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 225008)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 227462)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 275969)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 364538)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 16909883)\n[PASS] test_hostileBeneficiaryCannotBlockSwapsAndIsNotPaid() (gas: 3155937)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 87859780)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1751235)\n[PASS] test_outOfGasBeneficiaryCannotBlockEitherCallback() (gas: 807633)\n[PASS] test_partialCutWhenManagerHoldsLessThanTheCut() (gas: 16910741)\n[PASS] test_payoutRefusesEveryoneButTheHook() (gas: 32139)\n[PASS] test_permissionsAndAddressAgree() (gas: 26175)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 312691)\n[PASS] test_priceLimitPartialExactInputSellPaysCutOnDeliveredOutput() (gas: 225447)\n[PASS] test_priceLimitPartialExactOutputBuyPaysCutOnExecutedInput() (gas: 227691)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 274475)\n[PASS] test_registerPoolFailurePaths() (gas: 1934915)\n[PASS] test_registerPoolNeedsRegistryAndUnboundPoolSkipsTheCut() (gas: 87541003)\n[PASS] test_registerPoolRefusesTickersTheKingDoesNotOwn() (gas: 293959)\n[PASS] test_registryReadFailureNoCut() (gas: 87780959)\n[PASS] test_rehearsalLeavesNoTraceOnThePool() (gas: 1131596)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 173316241)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38410)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148568)\n[PASS] test_unregisteredPoolNoCut() (gas: 625895)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 569860)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 215.85ms (1.12s CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.65s (6.65s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 4920  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | buyLimited       | 4912  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 4807  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 4930  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sellLimited      | 5007  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.98s (7.95s CPU time)\n\nRan 7 test suites in 7.98s (15.28s CPU time): 82 tests passed, 0 failed, 0 skipped (82 total tests)\n","passed":true},{"durationMs":84,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.payout(address,uint256)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"DESIGN.md\":87,\"README.md\":354,\"dist/NOTICE.txt\":394,\"dist/abi/CrownChallengerToken.json\":334,\"dist/abi/CrownHook.json\":1534,\"dist/abi/CrownRegistry.json\":1020,\"dist/abi/CrownToken.json\":328,\"dist/abi/ThroneRegistry.json\":1020,\"dist/assets/ccip-DTxdOWV4.js\":1,\"dist/assets/hooks.module-DE9oX6xH.js\":1,\"dist/assets/index-Cx0qEvMU.js\":7,\"dist/assets/index-D1UV8ghm.css\":1,\"dist/assets/index-DU0WTre0.js\":54,\"dist/assets/index-Dlomt_yQ.js\":7,\"dist/favicon.svg\":1,\"dist/imd-deployment.json\":87,\"dist/index.html\":27,\"dist/share.png\":142,\"dist/share.svg\":1,\"dist/wallets/coinbase.svg\":1,\"dist/wallets/metamask.svg\":1,\"dist/wallets/phantom.svg\":1,\"dist/wallets/rabby.svg\":1,\"foundry.toml\":22,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":421,\"src/CrownRegistry.sol\":348,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":931,\"test/CrownRegistry.t.sol\":552,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":83,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":339,\"test/invariant/CrownRegistryInvariant.t.sol\":396,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31,\"validation/README.md\":150,\"validation/screenshots/mock-staking-390.png\":221,\"validation/screenshots/pending-1440.png\":393,\"validation/screenshots/pending-390.png\":209,\"validation/screenshots/webkit-wallet-390.png\":254,\"validation/taste.json\":4385,\"web/NOTICE.md\":11,\"web/index.html\":26,\"web/licenses/BetterInterface.txt\":220,\"web/licenses/EthFrontendUX.txt\":30,\"web/licenses/WalletMarks.txt\":9,\"web/package-lock.json\":7763,\"web/package.json\":29,\"web/public/NOTICE.txt\":394,\"web/public/abi/CrownChallengerToken.json\":334,\"web/public/abi/CrownHook.json\":1534,\"web/public/abi/CrownRegistry.json\":1020,\"web/public/abi/CrownToken.json\":328,\"web/public/abi/ThroneRegistry.json\":1020,\"web/public/favicon.svg\":1,\"web/public/share.png\":142,\"web/public/share.svg\":1,\"web/public/wallets/coinbase.svg\":1,\"web/public/wallets/metamask.svg\":1,\"web/public/wallets/phantom.svg\":1,\"web/public/wallets/rabby.svg\":1,\"web/scripts/build-worker.mjs\":38,\"web/scripts/check-export.mjs\":105,\"web/scripts/export.mjs\":125,\"web/scripts/render-share.mjs\":16,\"web/src/App.tsx\":354,\"web/src/ChallengePanel.tsx\":421,\"web/src/History.tsx\":184,\"web/src/Management.tsx\":345,\"web/src/Transaction.tsx\":185,\"web/src/TransactionFeed.tsx\":58,\"web/src/Wallet.tsx\":232,\"web/src/config.ts\":228,\"web/src/data.ts\":195,\"web/src/domain.ts\":118,\"web/src/main.tsx\":45,\"web/src/styles.css\":1378,\"web/src/ui.tsx\":166,\"web/tests/browser.test.mjs\":952,\"web/tests/domain.test.mjs\":60,\"web/tests/export.test.mjs\":96,\"web/tsconfig.json\":17,\"web/vite.config.ts\":37},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1936,"exitCode":0,"name":"slither","output":"[medium/high] incorrect-equality at src/CrownHook.sol:340: CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#340-393) uses a dangerous strict equality:\n[low/medium] reentrancy-benign at src/CrownHook.sol:340: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#340-393):\n[low/medium] reentrancy-events at src/CrownHook.sol:340: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#340-393):\n[low/medium] timestamp at src/CrownRegistry.sol:177: CrownRegistry.requiredBond(bytes32) (src/CrownRegistry.sol#177-182) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:211: CrownRegistry.openChallenge(bytes32,address) (src/CrownRegistry.sol#211-252) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:169: CrownRegistry.hasLiveChallenge(bytes32) (src/CrownRegistry.sol#169-172) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:265: CrownRegistry.finalize(uint256) (src/CrownRegistry.sol#265-302) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:255: CrownRegistry.stake(uint256,CrownRegistry.Side) (src/CrownRegistry.sol#255-262) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:202: CrownRegistry.registerKing(bytes32,address,address) (src/CrownRegistry.sol#202-205) uses timestamp for comparisons","passed":true},{"durationMs":427,"exitCode":0,"name":"aderyn","output":"[high] eth-send-unchecked-address at src/CrownRegistry.sol:305: ETH transferred without address checks (2 places)\n[high] reentrancy-state-change at src/CrownHook.sol:179: Reentrancy: State change after external call\n[high] strict-equality-contract-balance at src/CrownHook.sol:416: Dangerous strict equality checks on contract balances\n[high] unsafe-casting at src/CrownHook.sol:211: Unsafe Casting of integers (2 places)\n[low] centralization-risk at src/CrownHook.sol:46: Centralization Risk (3 places)\n[low] internal-function-used-once at src/HookFlags.sol:27: Internal Function Used Only Once\n[low] large-numeric-literal at src/CrownChallengerToken.sol:11: Large Numeric Literal (5 places)\n[low] unused-public-function at src/CrownRegistry.sol:151: Public Function Not Used Internally (3 places)","passed":true},{"durationMs":2393,"exitCode":0,"name":"proof 3cf0264adc30","output":"Compiling 84 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.80s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-f3277d48/Proof_3cf0264adc30.t.sol:HostileBeneficiaryTest\n[PASS] test_hostileKingMustNotBlockSwaps() (gas: 1403047)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.37ms (769.99µs CPU time)\n\nRan 1 test suite in 4.15ms (3.37ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a8f517578495d54c3c16ab7855a5f04dfc7076546f0184b4144c9869456a5077","verifiedTreeHash":"93fb5f8213b19b8bf13c0918348ff50787c19273","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":4863,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.77s\nCompiler run successful!\n","passed":true},{"durationMs":8739,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 15317402)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 14.14ms (14.15ms CPU time)\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 203.77ms (2.67ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 673274, ~: 680229)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 929091, ~: 935194)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 643091, ~: 638507)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 75697, ~: 75717)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 374213)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1071943)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1301711)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1329810)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1389197)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 741806)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 789887)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 701232)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 204.74ms (814.44ms CPU time)\n\nRan 40 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_anyLengthRegistryResponseSkipsBothCallbacks(uint8) (runs: 1000, μ: 417557, ~: 417488)\n[PASS] testFuzz_cutFollowsExecutedEthUnderAnyPriceLimit(uint256,uint16,uint8) (runs: 1000, μ: 326800, ~: 343204)\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 679426, ~: 704732)\n[PASS] testFuzz_noGasLimitLetsASwapThroughWithoutTheCut(uint256) (runs: 1000, μ: 269741, ~: 351760)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 843075)\n[PASS] test_callbacksRefuseNonManager() (gas: 113566)\n[PASS] test_claimsTradingBeneficiaryCannotFrontRunOrBlockABoundedBuy() (gas: 2586827)\n[PASS] test_contractBeneficiaryClaimNeedsNoManagerBalance() (gas: 16548883)\n[PASS] test_contractBeneficiaryIsPaidInClaimsNotEth() (gas: 9097421)\n[PASS] test_emptyPoolChargesNothingForAnUnfilledOrder() (gas: 968996)\n[PASS] test_emptyPoolChargesNothingInAnyShape() (gas: 3863023)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1995715)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 330150)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 225393)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 227892)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 276414)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 364969)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 16614703)\n[PASS] test_gasBurningBeneficiaryIsPaidInClaimsWithoutRunning() (gas: 610230)\n[PASS] test_hostileBeneficiaryNeverRunsAndCannotBlockSwaps() (gas: 2834301)\n[PASS] test_malformedRegistryAnswerNoCut() (gas: 8968751)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1752556)\n[PASS] test_partialCutWhenManagerHoldsLessThanTheCut() (gas: 16613106)\n[PASS] test_payoutRefusesEveryoneButTheHook() (gas: 58530)\n[PASS] test_permissionsAndAddressAgree() (gas: 26197)\n[PASS] test_priceLimitPartialBuyPaysCutOnExecutedInput() (gas: 313136)\n[PASS] test_priceLimitPartialExactInputSellPaysCutOnDeliveredOutput() (gas: 225877)\n[PASS] test_priceLimitPartialExactOutputBuyPaysCutOnExecutedInput() (gas: 228121)\n[PASS] test_priceLimitPartialSellPaysCutOnDeliveredOutput() (gas: 274942)\n[PASS] test_redeemTurnsClaimsIntoEth() (gas: 1710016)\n[PASS] test_registerPoolFailurePaths() (gas: 1935047)\n[PASS] test_registerPoolNeedsRegistryAndUnboundPoolSkipsTheCut() (gas: 8654659)\n[PASS] test_registerPoolRefusesTickersTheKingDoesNotOwn() (gas: 293981)\n[PASS] test_registryReadFailureNoCut() (gas: 8883548)\n[PASS] test_rehearsalLeavesNoTraceOnThePool() (gas: 1132450)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 20092902)\n[PASS] test_simulateSwapRefusesEveryoneButTheHook() (gas: 38432)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 148520)\n[PASS] test_unregisteredPoolNoCut() (gas: 625830)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 570735)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 204.86ms (764.50ms CPU time)\n\nRan 25 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1245660, ~: 1246885)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 926786)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 704948)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 761259)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 814207)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1230262)\n[PASS] test_displacementBreaksTheShamChallengeLock() (gas: 1103172)\n[PASS] test_finalizeRespectsTimelock() (gas: 532716)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 487062)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 372312)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 79388)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52530)\n[PASS] test_quorumBoundaryAndTie() (gas: 1300803)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 486744)\n[PASS] test_stakeDuringWindowOnly() (gas: 596029)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 369290)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 693061)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 204.83ms (213.21ms CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.40s (7.39s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 4920  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | buyLimited       | 4912  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 4807  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 4930  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sellLimited      | 5007  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.62s (8.59s CPU time)\n\nRan 7 test suites in 8.62s (16.85s CPU time): 85 tests passed, 0 failed, 0 skipped (85 total tests)\n","passed":true},{"durationMs":105,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.payout(address,uint256,bool)\",\"CrownHook.redeem(uint256,address)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.simulateSwap((address,address,uint24,int24,address),(bool,int256,uint160))\",\"CrownHook.transferOwnership(address)\",\"CrownHook.unlockCallback(bytes)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"DESIGN.md\":87,\"README.md\":384,\"dist/NOTICE.txt\":394,\"dist/abi/CrownChallengerToken.json\":334,\"dist/abi/CrownHook.json\":1637,\"dist/abi/CrownRegistry.json\":1020,\"dist/abi/CrownToken.json\":328,\"dist/abi/ThroneRegistry.json\":1020,\"dist/assets/ccip-DXU6stvj.js\":1,\"dist/assets/hooks.module-DE9oX6xH.js\":1,\"dist/assets/index-D1UV8ghm.css\":1,\"dist/assets/index-D9geSaZO.js\":7,\"dist/assets/index-DGU-7I6I.js\":7,\"dist/assets/index-DnYnoiAi.js\":54,\"dist/favicon.svg\":1,\"dist/imd-deployment.json\":87,\"dist/index.html\":27,\"dist/share.png\":142,\"dist/share.svg\":1,\"dist/wallets/coinbase.svg\":1,\"dist/wallets/metamask.svg\":1,\"dist/wallets/phantom.svg\":1,\"dist/wallets/rabby.svg\":1,\"foundry.toml\":22,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":468,\"src/CrownRegistry.sol\":348,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":1151,\"test/CrownRegistry.t.sol\":552,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":83,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":339,\"test/invariant/CrownRegistryInvariant.t.sol\":396,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":74,\"test/utils/HookDeployer.sol\":31,\"validation/README.md\":182,\"validation/screenshots/mock-staking-390.png\":221,\"validation/screenshots/pending-1440.png\":393,\"validation/screenshots/pending-390.png\":209,\"validation/screenshots/webkit-wallet-390.png\":254,\"validation/taste.json\":116,\"web/NOTICE.md\":11,\"web/index.html\":26,\"web/licenses/BetterInterface.txt\":220,\"web/licenses/EthFrontendUX.txt\":30,\"web/licenses/WalletMarks.txt\":9,\"web/package-lock.json\":7763,\"web/package.json\":29,\"web/public/NOTICE.txt\":394,\"web/public/abi/CrownChallengerToken.json\":334,\"web/public/abi/CrownHook.json\":1637,\"web/public/abi/CrownRegistry.json\":1020,\"web/public/abi/CrownToken.json\":328,\"web/public/abi/ThroneRegistry.json\":1020,\"web/public/favicon.svg\":1,\"web/public/share.png\":142,\"web/public/share.svg\":1,\"web/public/wallets/coinbase.svg\":1,\"web/public/wallets/metamask.svg\":1,\"web/public/wallets/phantom.svg\":1,\"web/public/wallets/rabby.svg\":1,\"web/scripts/build-worker.mjs\":38,\"web/scripts/check-export.mjs\":105,\"web/scripts/export.mjs\":125,\"web/scripts/render-share.mjs\":16,\"web/src/App.tsx\":357,\"web/src/ChallengePanel.tsx\":421,\"web/src/History.tsx\":184,\"web/src/Management.tsx\":345,\"web/src/Transaction.tsx\":185,\"web/src/TransactionFeed.tsx\":58,\"web/src/Wallet.tsx\":232,\"web/src/config.ts\":228,\"web/src/data.ts\":195,\"web/src/domain.ts\":118,\"web/src/main.tsx\":45,\"web/src/styles.css\":1378,\"web/src/ui.tsx\":166,\"web/tests/browser.test.mjs\":952,\"web/tests/domain.test.mjs\":60,\"web/tests/export.test.mjs\":96,\"web/tsconfig.json\":17,\"web/vite.config.ts\":37},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":2127,"exitCode":0,"name":"slither","output":"[medium/high] incorrect-equality at src/CrownHook.sol:352: CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#352-410) uses a dangerous strict equality:\n[medium/medium] unused-return at src/CrownHook.sol:452: CrownHook.redeem(uint256,address) (src/CrownHook.sol#452-457) ignores return value by poolManager.unlock(abi.encode(msg.sender,to,amount)) (src/CrownHook.sol#455)\n[low/medium] reentrancy-benign at src/CrownHook.sol:352: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#352-410):\n[low/medium] reentrancy-events at src/CrownHook.sol:452: Reentrancy in CrownHook.redeem(uint256,address) (src/CrownHook.sol#452-457):\n[low/medium] reentrancy-events at src/CrownHook.sol:352: Reentrancy in CrownHook._payCut(PoolKey,uint256) (src/CrownHook.sol#352-410):\n[low/medium] timestamp at src/CrownRegistry.sol:177: CrownRegistry.requiredBond(bytes32) (src/CrownRegistry.sol#177-182) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:211: CrownRegistry.openChallenge(bytes32,address) (src/CrownRegistry.sol#211-252) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:169: CrownRegistry.hasLiveChallenge(bytes32) (src/CrownRegistry.sol#169-172) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:265: CrownRegistry.finalize(uint256) (src/CrownRegistry.sol#265-302) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:255: CrownRegistry.stake(uint256,CrownRegistry.Side) (src/CrownRegistry.sol#255-262) uses timestamp for comparisons\n[low/medium] timestamp at src/CrownRegistry.sol:202: CrownRegistry.registerKing(bytes32,address,address) (src/CrownRegistry.sol#202-205) uses timestamp for comparisons","passed":true},{"durationMs":587,"exitCode":0,"name":"aderyn","output":"[high] eth-send-unchecked-address at src/CrownRegistry.sol:305: ETH transferred without address checks (2 places)\n[high] reentrancy-state-change at src/CrownHook.sol:191: Reentrancy: State change after external call\n[high] strict-equality-contract-balance at src/CrownHook.sol:440: Dangerous strict equality checks on contract balances\n[high] unsafe-casting at src/CrownHook.sol:223: Unsafe Casting of integers (2 places)\n[low] centralization-risk at src/CrownHook.sol:53: Centralization Risk (3 places)\n[low] internal-function-used-once at src/HookFlags.sol:27: Internal Function Used Only Once\n[low] large-numeric-literal at src/CrownChallengerToken.sol:11: Large Numeric Literal (5 places)\n[low] unchecked-return at src/CrownHook.sol:455: Unchecked Return\n[low] unused-public-function at src/CrownRegistry.sol:151: Public Function Not Used Internally (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b8de14485b80afab964f6096d9af98b7e6f433d4aaef11d14457a61e6081e51d","verifiedTreeHash":"bf8d3ea8063a28ede3b35357157126d6b214168d","verifierVersion":"0.1.0+63e0a393"},{"checks":[{"durationMs":4296,"exitCode":0,"name":"build","output":"Compiling 92 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.18s\nCompiler run successful!\n","passed":true},{"durationMs":7017,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/DeployCrown.t.sol:DeployCrownTest\n[PASS] test_configureHookWiresRegistryAndPool() (gas: 15817492)\n[PASS] test_deployChallengerMintsToRecipient() (gas: 1792667)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 10.73ms (10.55ms CPU time)\n\nRan 24 tests for test/CrownRegistry.t.sol:CrownRegistryTest\n[PASS] testFuzz_conservation(uint96,uint96,uint96,uint96) (runs: 1000, μ: 1194459, ~: 1195752)\n[PASS] test_challengeFailsWhenKingOutStakes() (gas: 873677)\n[PASS] test_challengeFailsWithoutQuorum() (gas: 671600)\n[PASS] test_claimIsPullOnceAndOnlyAfterFinalize() (gas: 730234)\n[PASS] test_claimRevertsForRejectingReceiver() (gas: 783183)\n[PASS] test_constructorRejectsHalfGenesis() (gas: 4086)\n[PASS] test_constructorWithoutGenesis() (gas: 9662)\n[PASS] test_dethroneMathExact() (gas: 1179271)\n[PASS] test_finalizeRespectsTimelock() (gas: 506196)\n[PASS] test_genesisCrown() (gas: 25359)\n[PASS] test_oneLiveChallengePerTicker() (gas: 327005)\n[PASS] test_openChallengeRecordsStateAndBondAsStake() (gas: 345781)\n[PASS] test_openChallengeRejectsUnknownTickerSameTokenAndZero() (gas: 114505)\n[PASS] test_openChallengeRequiresExactBond() (gas: 74932)\n[PASS] test_openChallengeRequiresMinReign() (gas: 52558)\n[PASS] test_quorumBoundaryAndTie() (gas: 1247191)\n[PASS] test_registerKingFirstComeOnly() (gas: 150912)\n[PASS] test_registerKingRejectsZeroes() (gas: 83109)\n[PASS] test_slashGoesToTreasuryWhenWinningSideIsEmpty() (gas: 453631)\n[PASS] test_stakeDuringWindowOnly() (gas: 564799)\n[PASS] test_stakeRejectsZeroAndUnknown() (gas: 347182)\n[PASS] test_stakerOnBothSidesClaimsBoth() (gas: 661893)\n[PASS] test_throneRegistryIsTheSameContract() (gas: 12851)\n[PASS] test_withdrawTreasuryNeedsSomething() (gas: 31599)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 134.98ms (141.73ms CPU time)\n\nRan 4 tests for test/CrownToken.t.sol:CrownTokenTest\n[PASS] test_challengerTokenMintsToRecipient() (gas: 30681)\n[PASS] test_hookFlags() (gas: 719)\n[PASS] test_launchTokenHasNoMint() (gas: 28014)\n[PASS] test_launchTokenSupplyAndTransfer() (gas: 101249)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 135.72ms (4.29ms CPU time)\n\nRan 12 tests for test/CrownRegistryBoundaries.t.sol:CrownRegistryBoundariesTest\n[PASS] testFuzz_quorumWithinOneWei(uint8) (runs: 1000, μ: 642040, ~: 649011)\n[PASS] testFuzz_slashAndRefundsForEitherWinner(uint96,uint96) (runs: 1000, μ: 884726, ~: 890839)\n[PASS] testFuzz_strictLeadWithinOneWei(uint8) (runs: 1000, μ: 611992, ~: 607289)\n[PASS] testFuzz_wrongBondIsAtomic(uint96) (runs: 1000, μ: 73481, ~: 73489)\n[PASS] test_bondOneWeiEitherSideRejected() (gas: 347649)\n[PASS] test_failedChallengeCooldownIsTickerLocal() (gas: 1001232)\n[PASS] test_oddWeiSlashAndPerStakerRounding() (gas: 1252759)\n[PASS] test_reentrantClaimCannotWithdrawTwice() (gas: 1298798)\n[PASS] test_rejectedClaimRollsBackAndCanBeRetried() (gas: 1353823)\n[PASS] test_rejectedTreasuryTransferPreservesDebt() (gas: 713105)\n[PASS] test_successfulFlipRestartsMinimumReign() (gas: 736724)\n[PASS] test_timelockHasNoLateStakeEscape() (gas: 670157)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 141.67ms (559.20ms CPU time)\n\nRan 23 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testFuzz_cutMatchesBpsOnExactInputBuy(uint256,uint16) (runs: 1000, μ: 610456, ~: 625618)\n[PASS] testFuzz_wrongLengthRegistryResponsesSkipBothCallbacks(uint8) (runs: 1000, μ: 356772, ~: 356698)\n[PASS] test_afterInitializeRecordsPoolFromAnySender() (gas: 815694)\n[PASS] test_beneficiaryRejectingEthNoCut() (gas: 19950247)\n[PASS] test_callbacksRefuseNonManager() (gas: 113543)\n[PASS] test_endToEndDethroneChangesFeeRecipient() (gas: 1764428)\n[PASS] test_exactInputBuyPaysCutFromEthInput() (gas: 266248)\n[PASS] test_exactInputSellPaysCutFromEthOutput() (gas: 217300)\n[PASS] test_exactOutputBuyPaysCutOnEthInput() (gas: 219822)\n[PASS] test_exactOutputSellPaysCutOnTopOfEthOutput() (gas: 218032)\n[PASS] test_failedSettlementRollsBackAlreadyAttemptedPayout() (gas: 301058)\n[PASS] test_freshManagerSeededWithTokensOnly() (gas: 16788606)\n[PASS] test_multiplePoolsAggregateOnlyTheirOwnTickerPayments() (gas: 1532836)\n[PASS] test_noRegistryNoCut() (gas: 19632334)\n[PASS] test_outOfGasBeneficiaryCannotBlockEitherCallback() (gas: 743755)\n[PASS] test_permissionsAndAddressAgree() (gas: 26131)\n[PASS] test_registerPoolFailurePaths() (gas: 1898026)\n[PASS] test_registryReadFailureNoCut() (gas: 19834507)\n[PASS] test_setRegistryOnceAndOwnerOnly() (gas: 19250686)\n[PASS] test_tinySwapRoundsCutToZero() (gas: 147122)\n[PASS] test_unknownTickerNoCut() (gas: 560802)\n[PASS] test_unregisteredPoolNoCut() (gas: 587943)\n[PASS] test_zeroLiquidityChangeCollectsWithoutHookDelta() (gas: 498714)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 141.72ms (326.67ms CPU time)\n\nRan 1 test for test/invariant/CrownRegistryInvariant.t.sol:CrownRegistryInvariantTest\n[PASS]\nCrownRegistryInvariantTest invariants:\n[PASS] invariant_escrowEqualsOutstandingLiabilitiesPlusBoundedDust\n[PASS] invariant_ruleBasedResolutionAndImmutableFinishedRounds\n CrownRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| CrownRegistryHandler | advance           | 3109  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | advanceToBoundary | 3170  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | claim             | 3061  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | finalize          | 2989  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | open              | 3063  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | stake             | 6095  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| CrownRegistryHandler | withdrawTreasury  | 3089  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.81s (6.81s CPU time)\n\nRan 1 test for test/invariant/CrownHookInvariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_hookRetainsNoValueOrSettlementDebt\n[PASS] invariant_paidCounterMatchesTransfersAcrossReigns\n CrownHookInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+------------------+-------+---------+----------╮\n| Contract         | Selector         | Calls | Reverts | Discards |\n+==================================================================+\n| CrownHookHandler | buy              | 8211  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | resolveChallenge | 8244  | 0       | 0        |\n|------------------+------------------+-------+---------+----------|\n| CrownHookHandler | sell             | 8121  | 0       | 0        |\n╰------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.89s (6.89s CPU time)\n\nRan 7 test suites in 6.90s (14.27s CPU time): 67 tests passed, 0 failed, 0 skipped (67 total tests)\n","passed":true},{"durationMs":68,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownChallengerToken.approve(address,uint256)\",\"CrownChallengerToken.transfer(address,uint256)\",\"CrownChallengerToken.transferFrom(address,address,uint256)\",\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16)\",\"CrownHook.renounceOwnership()\",\"CrownHook.setRegistry(address)\",\"CrownHook.transferOwnership(address)\",\"CrownRegistry.claim(uint256)\",\"CrownRegistry.finalize(uint256)\",\"CrownRegistry.openChallenge(bytes32,address)\",\"CrownRegistry.registerKing(bytes32,address,address)\",\"CrownRegistry.stake(uint256,uint8)\",\"CrownRegistry.withdrawTreasury()\",\"CrownToken.approve(address,uint256)\",\"CrownToken.transfer(address,uint256)\",\"CrownToken.transferFrom(address,address,uint256)\",\"ThroneRegistry.claim(uint256)\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerKing(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.withdrawTreasury()\"],\"files\":{\".gitignore\":4,\"README.md\":223,\"foundry.toml\":22,\"remappings.txt\":4,\"script/DeployCrown.s.sol\":36,\"site/index.html\":182,\"src/CrownChallengerToken.sol\":16,\"src/CrownHook.sol\":289,\"src/CrownRegistry.sol\":302,\"src/CrownToken.sol\":16,\"src/HookFlags.sol\":35,\"src/ThroneRegistry.sol\":13,\"src/interfaces/ICrownRegistry.sol\":14,\"test/CrownHook.t.sol\":577,\"test/CrownRegistry.t.sol\":483,\"test/CrownRegistryBoundaries.t.sol\":326,\"test/CrownToken.t.sol\":46,\"test/DeployCrown.t.sol\":51,\"test/README.md\":69,\"test/floor/OwnerChecks.sol\":21,\"test/invariant/CrownHookInvariant.t.sol\":265,\"test/invariant/CrownRegistryInvariant.t.sol\":393,\"test/mocks/LiquidityProvider.sol\":57,\"test/mocks/MockERC20.sol\":15,\"test/mocks/Swapper.sol\":64,\"test/utils/HookDeployer.sol\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c8af1ee36eac8a45e321c0038d2e29b39d666a886231bb757b6712bf9b7ed4a2","verifiedTreeHash":"bae5892449eaf023ce77d405f89c140c43a174b4","verifierVersion":"0.1.0+8fbf00a5"}]}