{"assessments":[],"deployments":[{"attestationHash":"4034e5dc953a1a23506050526b750bb3c2794789f1af99e43f83977c855c1183","chainId":1,"contracts":[{"address":"0x3a8514ebb7eb31fc3c2987b326587de5f19d25cd","blockNumber":26269355,"name":"OGClubCreatorPool","role":"other","txHash":"0x542c9a8175312440dc459ba9840173afebeb554b68759d508c8bd97aa2406d23"}],"id":"ff7eecf0-476d-4d5d-85f8-6cd541ac6940","manifestHash":"c4a4aafae6cb300980a1efa8b07e55cf0ce0f93b53612eb4f0b4205f1b3ae84d","status":"live"}],"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":"15e903e0-7074-4cc0-8417-7ad4323c8a12","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"9d22f96ec701d526505094418455f782418acba219ccabd8d18e7a44cec496cb","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":"4cdfb0ddfaf47fbe9d640abda48eb2289dd1634e639e7f2ac894a64f8f3df2f5","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":"fa16f64e9b68fa09a87405703ba5ad880dd09a64f22c16aa5f81cf920fb5707a","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":"e8e0539fb399ed107da952dc648f544ec2bee27d58993313d4ff5321d22b63e1","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":"97a8e0875cc00630de384d63bdc46134329283f00272abe993f7ee215b2d4433","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":"5251303ace131c2df84cabddaf80753333a3187138353849d8421ad13ef71def","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"816fe39c7efd64504a19175b0f4dd9186d61069f37a22684c90358a18c60bddc","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"816fe39c7efd64504a19175b0f4dd9186d61069f37a22684c90358a18c60bddc","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"b5161fe0f8fbb6c0844b0ff547f34cc65c8adec3f0a283b7cb25f85f62ea8a24","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"a696be4aef72b4746c1f3bb780953fa11ed1afb1c80411913d031f998dd25e2a","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"ab3f8f2aa4e7f3b3ada558c0dcf522ba733ca3df3b1da92c707a0fe305816d5f","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"ab3f8f2aa4e7f3b3ada558c0dcf522ba733ca3df3b1da92c707a0fe305816d5f","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Build OGClubCreatorPool: a Solidity contract that pays $OG each month to the developers of games in OG Club World, plus Foundry tests and deploy scripts. Put it in the existing Foundry project with OGClubFarmVault, OGClubStaking and OGClubClubs, in the same style (OpenZeppelin 5, Solidity ^0.8.24, Ownable2Step, ReentrancyGuard, SafeERC20, MerkleProof, custom errors).\n\nSETUP: constructor(IERC20 token, address owner); token immutable; no zero addresses. CLAIM_DELAY = 3 days, CLAIM_PERIOD = 90 days. No ETH, no receive, no proxy.\n\nGAMES: id = keccak256(bytes(kitId)), e.g. \"coin-dash\"; pure helper gameId(string). games[id] = {payout, listed}. listGame(id, payout): owner only, an id can only ever be listed once. delistGame/relistGame: owner only, doesn't stop claims of months already proposed. changePayout(id, to): ONLY the game's current payout wallet; the owner can never change a payout. No zero or self payout.\n\nMONEY IN: plain ERC-20 transfers count (the farm vault pays this contract by listing its address as one account in a vault season, then claim(season, pool, amount, proof)). fund(amount) pulls with safeTransferFrom and checks the exact balance change. free() = balance - reserved.\n\nMONTHS: month id YYYYMM (month%100 in 1..12, year >= 2026). proposeMonth(month, root, total), owner only: root and total nonzero, total <= free(), month > lastMonth (or == lastMonth if that month was cancelled, which overwrites it); opensAt = now + 3 days; reserved += total. cancelMonth(month), owner only, before opensAt: releases what's left. claim(month, game, amount, proof), anyone: open between opensAt and opensAt + 90 days, once per game per month, leaf = keccak256(bytes.concat(keccak256(abi.encode(month, game, amount)))), amount <= remaining, game must have a payout (delisted is fine); pays games[game].payout, never the caller; exact balance check. sweep(month), anyone, after the 90 days: unclaimed goes back to free().\n\nOWNER CAN'T: withdraw, sweep to itself, change a payout, change the token, or touch money owed to a month after its 3-day window. $OG only leaves as claims to game payout wallets.\n\nTESTS: list/delist/payout rules; full months with several games (odd and even leaf counts); anyone can push a claim; payout change before claim pays the new wallet; every revert (early, late, twice, wrong leaf, over budget, bad month, cancel too late, sweep too early); cancel and re-propose; sweep then reuse; fee-on-transfer token reverts; INTEGRATION with the real OGClubFarmVault: a vault season lists the pool's address, the vault claim lands $OG in the pool, then a pool month pays games. Fuzz: paid per month <= total. Invariants: balance >= reserved; reserved = sum of open months' remaining; owner's $OG never rises through this contract.\n\nDEPLOY: Sepolia with a mock $OG and test games from a JSON of [kitId, payout]; mainnet from env OG_TOKEN, OWNER, no games listed. Print address and constructor args for verification.\n\nOUT OF SCOPE: the game side (measuring play, the monthly draft and Merkle list, the claim page, adding the pool to vault seasons).","parentJobId":null,"planHash":"0e6396adf1f94026dc13c7fd6bba4d102b3b1f7f7de6ad377e33d22a14572b29","previousHash":"5ec6706daca2da45d1013c97b81b4c53ed1c0c5514e12f4e9c9260332a7911b5","projectId":"15e903e0-7074-4cc0-8417-7ad4323c8a12","publication":{"commit":"849e2564e470f3705f477bbb6591b0b6de7c2dbb","deliveredAt":"2026-10-25T11:20:17.892Z","repoUrl":"https://github.com/identity-md-launches/launch-2568-build-ogclubcreatorpool-solidity-contrac"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"38cfd6d441be5782de38b10f06b62747e8ce4f2b67ac482a51768b03efc739ba","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"a1d38490d3107a4550767dd1d344de842f8aa0706cb9c1999e0e9f3fa8308f7a","device":"764cd99b4c628a47","findings":[{"description":"The brief says the owner can't withdraw and that the owner's $OG never rises through this contract. listGame only refuses zero and the pool itself as payout. Nothing refuses owner(). So the owner can list a new id with payout = owner, propose a month whose single leaf pays that id the whole free() balance, wait the 3-day delay, and claim. The delay and the public root make this visible, and an owner could still route through a second wallet it controls. Refusing owner() as payout in listGame closes the literal violation of the stated invariant. The invariant suites in this submission never list the owner as a payout, so they do not cover this path.","line":142,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract ProofToken is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @notice The brief: \"Invariants: owner's $OG never rises through this contract\" and \"OWNER CAN'T:\n///         withdraw\". Today the owner lists a game with its own wallet as payout and pays itself the\n///         whole free balance three days later. Expected: listGame refuses owner() as a payout.\ncontract ProofOwnerAsPayoutTest is Test {\n    function test_ownerCannotListItselfAsPayout() public {\n        address owner = makeAddr(\"owner\");\n        ProofToken og = new ProofToken();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n        bytes32 id = keccak256(\"owner-game\");\n\n        vm.prank(owner);\n        try pool.listGame(id, owner) {\n            // Listing succeeded: show the consequence, then fail.\n            bytes32 root = pool.leaf(202_701, id, 1000 ether);\n            vm.prank(owner);\n            pool.proposeMonth(202_701, root, 1000 ether);\n            skip(3 days);\n            pool.claim(202_701, id, 1000 ether, new bytes32[](0));\n            assertEq(og.balanceOf(owner), 0, \"owner drained the pool's free balance to itself\");\n        } catch {}\n    }\n}","reproduction":"pool holds 1000 OG; owner: listGame(keccak256('owner-game'), owner); proposeMonth(202701, leaf(202701, id, 1000e18), 1000e18); warp 3 days; anyone: claim(202701, id, 1000e18, []). Expected: listGame reverts (InvalidPayout). Actual: owner's balance goes from 0 to 1000 OG.","severity":"low","title":"Owner can list a game with its own wallet as payout and pay itself the whole free balance"},{"description":"The contract inherits Ownable2Step and does not override renounceOwnership. Only the owner can proposeMonth, and there is no other exit for $OG. After renouncing, every token in free(), plus every later vault-season payment or plain transfer into the pool, can never be paid to any game. Months already proposed still pay and sweep, but swept remainders also become stuck. The brief says $OG only leaves as claims to game payout wallets, and this freezes it permanently. Suggested fix: override renounceOwnership to revert.","line":24,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract ProofToken2 is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @notice renounceOwnership (inherited from Ownable) leaves every free and future-funded $OG locked\n///         for ever: only the owner can propose a month, and there is no other exit. Expected:\n///         renouncing is refused, so the free balance can always still be paid to games.\ncontract ProofRenounceLocksFundsTest is Test {\n    function test_renounceDoesNotLockFreeBalance() public {\n        address owner = makeAddr(\"owner\");\n        ProofToken2 og = new ProofToken2();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n\n        vm.prank(owner);\n        try pool.renounceOwnership() {} catch {}\n\n        // The owner (a real account) must still be able to propose a month for the free balance.\n        assertEq(pool.owner(), owner, \"ownership renounced: no account can ever propose a month again\");\n        bytes32 root = pool.leaf(202_701, keccak256(\"g\"), 1000 ether);\n        vm.prank(owner);\n        pool.proposeMonth(202_701, root, 1000 ether);\n        assertEq(pool.reserved(), 1000 ether);\n    }\n}","reproduction":"pool holds 1000 OG; owner: renounceOwnership(). Expected: reverts, so the owner can still proposeMonth for the 1000 OG. Actual: owner() == address(0), and no account can ever propose a month again.","severity":"low","title":"renounceOwnership locks the free balance and all future vault payments for good"},{"description":"isValidMonth accepts any year from 2026 to 9999, and proposeMonth needs month > lastMonth, or == lastMonth if that month was cancelled. Proposing a typo such as 207206 (meant 202706) sets lastMonth = 207206. Cancelling it during the 3-day window is exactly what the review window is for, but cancelling does not lower lastMonth. From then on, every real month id below 207206 is refused, so the pool cannot pay any month for decades, short of reusing the id 207206 and later ids. The brief's rule is followed literally, but the cancel path cannot undo the mistake it exists to undo. Possible fixes: restore the previous lastMonth when the cancelled month is lastMonth, or bound proposals near block.timestamp.","line":205,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract ProofToken3 is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @notice One mistyped month id (207206 for 202706: year 2072) is a valid YYYYMM, becomes lastMonth,\n///         and even when cancelled inside the 3-day window it leaves every real month (2027..2071)\n///         unproposable for ever. Expected: after cancelling the typo, the next real month can be proposed.\ncontract ProofFarMonthBricksPoolTest is Test {\n    function test_cancelledTypoMonthDoesNotBlockRealMonths() public {\n        address owner = makeAddr(\"owner\");\n        ProofToken3 og = new ProofToken3();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n\n        vm.startPrank(owner);\n        pool.proposeMonth(207_206, keccak256(\"typo\"), 10 ether); // meant 202706\n        pool.cancelMonth(207_206); // caught inside the review window\n        pool.proposeMonth(202_706, keccak256(\"real\"), 10 ether);\n        vm.stopPrank();\n        assertEq(pool.reserved(), 10 ether);\n    }\n}","reproduction":"owner: proposeMonth(207206, r, 10e18); cancelMonth(207206) before opensAt; proposeMonth(202706, r2, 10e18). Expected: succeeds. Actual: reverts MonthNotAfterLast(202706, 207206).","severity":"low","title":"A mistyped far-future month id permanently blocks all real months, even when cancelled in its review window"},{"description":"The brief asks for integration with the real OGClubFarmVault from the existing OG Club Foundry project. That source is not in this repository and I could not find it published. test/OGClubCreatorPool.integration.t.sol uses a test-support reconstruction written by the builder. The pool only sees a plain ERC-20 transfer, so the pool side is covered. Whether the real vault pays a contract account the same way (for example, no EOA-only or msg.sender == account restriction on claim) is untested.","line":1,"path":"test/support/OGClubFarmVault.sol","reproduction":"No failing input. Replace the import in test/OGClubCreatorPool.integration.t.sol with the real vault source and rerun test_vaultSeasonFundsPoolThenPoolPaysGames.","severity":"info","title":"Integration test runs against a reconstructed OGClubFarmVault, not the real vault"}],"hash":"2cabbc38cb531124d3642119132afd41152bbededbe5fd1c4702517b09b607ee","nodeId":"d6b7f709-17c6-42f0-b851-9e86624f8a8d","outcome":"completed","summary":"I added two new test files alongside the existing suite and found no high or critical defects. I did find three low-severity design problems, which I reported rather than writing tests that treat them as correct. With the verifier's seed, `forge build` succeeds and `forge test` passes all 100 tests (68 existing plus 32 new). I did not change anything in `src/` and did not commit.\n\n**`test/OGClubCreatorPool.adversarial.t.sol`** (31 tests) covers what the existing suite left open:\n- **Exact time limits:** claims one second before opening, at opening, one second before closing, and at closing; cancelling one second before opening and at opening; sweeping before and at closing; sweeping twice; and sweeping or cancelling a month that was already cancelled.\n- **Cancel and re-propose:** the old Merkle root stops working and the new one works, the 3-day delay restarts, and the new version can reserve more. A month id can't be reused without a cancel, and an older cancelled month can't come back once a newer one exists. Also covered: December to January rollover and invalid month ids.\n- **Replayed or forged claims:** a proof can't be reused in another month, even when the owner gives both months the same root, and can't be moved to another game or amount. Also covered: an empty or padded proof, a zero-amount leaf, and a leaf for a game that was never listed.\n- **Who gets paid:** a game's payout wallet that moved twice; the old wallet losing control; changing the payout after a claim doesn't allow a second claim; relisting keeps the current wallet; and several months open at once without affecting each other.\n- **Large trees:** months of 33, 64 and 65 games pay out exactly.\n- **Ownership handover:** a pending owner has no powers, and the old owner loses them after the handover. Months already proposed still pay and sweep after the owner renounces.\n- **Re-entering the pool:** a payout wallet that tries to call back into the pool while being paid is blocked.\n- **Unusual tokens:** a token that returns false is refused and nothing changes; a token that returns nothing works.\n\n**`test/OGClubCreatorPool.actors.invariant.t.sol`** drives the pool with the owner, three relayers and the game wallets. It also tries things that must fail: forged claims, owner-only calls from other accounts, the owner changing a payout, cancelling a month after it opened, sweeping too early, and invalid proposals. Each attempt is checked against an independent model of what the pool should accept. After every step it checks:\n- the balance covers what is reserved, and the balance equals what came in minus what was paid out;\n- the reserved amount equals the sum of what open months still owe;\n- no month pays more than its total;\n- only game payout wallets ever receive $OG, never the owner or the account making the claim.\n\nTo check these tests can actually fail, I temporarily broke `src` in two ways (cancel allowed after opening; a month allowed to overpay), confirmed both were caught, then restored it with git. In 30 simulated runs, 68 claims and 33 sweeps succeeded, so the tests are exercising real payouts.\n\n**Findings in `.imd-findings.json`** (each low one has a proof test that fails on the current code):\n1. **Low:** `listGame` accepts the owner's own wallet as a payout. The owner can then propose a month paying that game the whole free balance and collect it 3 days later. This breaks the brief's rule that the owner's $OG never rises through this contract.\n2. **Low:** the inherited `renounceOwnership` isn't disabled. If the owner renounces, the free balance and all future vault payments are locked in the pool permanently.\n3. **Low:** a mistyped month id far in the future, such as 207206 for 202706, becomes `lastMonth`. Cancelling it during the 3-day review doesn't undo that, so every real month below it can never be proposed.\n4. **Info:** the integration test runs against a stand-in vault the builder wrote in `test/support/`, not the real OGClubFarmVault. That sourc","treeHash":"8defa53246f7841f6164efc3dd00e92570ebc4e6","usage":{"cachedInputTokens":2345570,"inputTokens":57,"model":"claude-opus-5-5","outputTokens":53423,"runtime":"claude","turns":32,"wallClockMs":601684}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3c9b660ee1938912","findings":[{"citation":"resolved","description":"Execution trace across transactions (proposeMonth -> cancelMonth -> proposeMonth). proposeMonth sets lastMonth = month (line 212) and cancelMonth (lines 218-229) never restores it. isValidMonth accepts any year from 2026 to 9999, with no link to block.timestamp. The 3-day cancel window is the owner's only way to undo a bad proposal, but it cannot undo a wrong month id. After cancelling, the only ids that can be proposed are >= the typo. If the typo is 999912, the pool can re-propose 999912 once and then never propose again. Because $OG only leaves through claims, all of free() and every later inflow (farm-vault season payouts keep arriving as plain transfers) is locked permanently. With a smaller typo such as 202711 in place of 202611, the twelve months in between are lost for good. Assumption broken: that cancelling restores the state from before the proposal. Fix without changing the design: on cancel of lastMonth, restore the previous lastMonth (store it per month at proposal time), or cap month ids at the calendar month of block.timestamp plus a small margin. Either way the spec's 'month > lastMonth, or == lastMonth if cancelled' ordering still holds for real proposals.","line":205,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract Tok is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n    function mint(address to, uint256 a) external { _mint(to, a); }\n}\n\ncontract LastMonthCancelTest is Test {\n    function test_cancelledTypoMonthDoesNotBlockEarlierMonths() public {\n        vm.warp(1_800_000_000);\n        address owner = makeAddr(\"owner\");\n        Tok og = new Tok();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n\n        vm.startPrank(owner);\n        // Fat-fingered month id: valid (year 9999, month 12), proposed by mistake.\n        pool.proposeMonth(999912, bytes32(uint256(1)), 100 ether);\n        // The 3-day cancel window exists to undo exactly this; the owner cancels in time.\n        pool.cancelMonth(999912);\n        assertEq(pool.free(), 1000 ether, \"reservation released\");\n        // The intended month must still be proposable after the mistake was cancelled.\n        pool.proposeMonth(202611, bytes32(uint256(1)), 100 ether);\n        vm.stopPrank();\n    }\n}","reproduction":"Pool holds 1000 $OG. owner: proposeMonth(999912, 0x..01, 100e18) succeeds (valid id). owner: cancelMonth(999912) within 3 days succeeds; reserved is back to 0. owner: proposeMonth(202611, 0x..01, 100e18). Expected: succeeds because the mistaken month was cancelled. Actual: reverts MonthNotAfterLast(202611, 999912), and it does so for every id below 999912 forever. After 999912 is proposed once more without cancelling, proposeMonth reverts for every input and the pool's free balance can never leave.","severity":"medium","snippet":"        if (month < lastMonth || (month == lastMonth && !months[month].cancelled)) {\n            revert MonthNotAfterLast(month, lastMonth);\n        }","title":"Cancelling a mistyped month id does not undo it: lastMonth stays advanced, so every earlier month becomes unproposable (999912 bricks the pool for good)"},{"citation":"resolved","description":"Periphery/inherited code: OZ Ownable.renounceOwnership is exposed unchanged. proposeMonth is the only way free() can ever be paid out, and it is onlyOwner. After a renounce, open months can still be claimed, but swept remainders, the current free() and every later farm-vault payout (the vault keeps paying the pool's address each season) become permanently unspendable. Nothing in the brief needs an ownerless pool. Fix: override renounceOwnership to revert. This keeps Ownable2Step handover intact.","line":24,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract Tok is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n    function mint(address to, uint256 a) external { _mint(to, a); }\n}\n\ncontract RenounceTest is Test {\n    function test_renounceCannotStrandFreeBalance() public {\n        address owner = makeAddr(\"owner\");\n        Tok og = new Tok();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n        vm.prank(owner);\n        try pool.renounceOwnership() {} catch {}\n        // With an owner, the free balance can still be scheduled into a month.\n        assertEq(pool.owner(), owner, \"pool lost its only way to schedule its free balance\");\n    }\n}","reproduction":"Pool holds 1000 $OG free. owner calls renounceOwnership(). It succeeds and owner() == address(0). From then on proposeMonth reverts OwnableUnauthorizedAccount for every caller, and the 1000 $OG plus anything later sent by OGClubFarmVault.claim(season, pool, ...) can never leave the contract. Expected: renounce reverts, or the pool keeps a way to schedule its balance.","severity":"low","snippet":"contract OGClubCreatorPool is Ownable2Step, ReentrancyGuard {","title":"Inherited renounceOwnership permanently strands the free balance and all future vault inflows"},{"citation":"resolved","description":"First principles: the brief says the owner cannot withdraw and that the owner's $OG never rises through this contract. _checkPayout rejects only zero and the pool, so listGame(id, owner()) is accepted, as is changePayout(id, owner()) by a game wallet. The owner can then propose a month that gives all of free() to that game and collect it 3 days later. The invariant suite passes only because PoolHandler.changePayout returns early when `to == owner` (test/OGClubCreatorPool.invariant.t.sol) and the handler never lists the owner. The tested property is therefore never challenged. A different wallet the owner controls cannot be stopped on-chain (it is a trust assumption the 3-day delay makes visible), but the stated invariant for owner() itself is cheap to enforce. Fix: in listGame and changePayout, revert when payout == owner(). Optionally also reject pendingOwner, and document the alt-wallet trust assumption.","line":314,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract Tok is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n    function mint(address to, uint256 a) external { _mint(to, a); }\n}\n\ncontract OwnerPayoutTest is Test {\n    function test_ownerCannotBeAPayoutWallet() public {\n        vm.warp(1_800_000_000);\n        address owner = makeAddr(\"owner\");\n        Tok og = new Tok();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n        bytes32 g = pool.gameId(\"owner-game\");\n        vm.startPrank(owner);\n        try pool.listGame(g, owner) {\n            bytes32 lf = pool.leaf(202611, g, 1000 ether);\n            pool.proposeMonth(202611, lf, 1000 ether);\n            vm.stopPrank();\n            vm.warp(block.timestamp + 3 days);\n            pool.claim(202611, g, 1000 ether, new bytes32[](0));\n        } catch {\n            vm.stopPrank();\n        }\n        assertEq(og.balanceOf(owner), 0, \"owner's $OG rose through the pool\");\n    }\n}","reproduction":"Pool holds 1000 $OG. owner: listGame(gameId(\"owner-game\"), owner) succeeds. owner: proposeMonth(202611, leaf(202611, g, 1000e18), 1000e18). warp +3 days. Anyone: claim(202611, g, 1000e18, []). Expected: listGame reverts InvalidPayout(owner). Actual: owner's balance goes 0 -> 1000 $OG.","severity":"low","snippet":"    function _checkPayout(address payout) private view {\n        if (payout == address(0)) revert ZeroAddress();\n        if (payout == address(this)) revert InvalidPayout(payout);","title":"Owner can be listed as (or moved to) a game's payout wallet, so the owner's $OG can rise through the pool; the invariant test skips this case"},{"citation":"resolved","description":"Execution trace (parameter divergence between amount sent and amount received). The brief asks for a fee-on-transfer token to revert. fund() catches it, but plain transfers into the pool are an accepted funding path that bypasses fund(). In claim, the check compares the pool's balance drop with amount. For the usual fee-on-transfer shape (the recipient gets amount - fee), the drop equals amount exactly, so the claim succeeds and the game wallet receives less than its Merkle leaf. The suite's test_feeOnTransfer_claimReverts uses only the non-standard sender-charged variant (FeeOnTransferToken(true)), so this path is untested. Impact is limited because token is immutable and expected to be plain $OG. Fix: also measure token.balanceOf(payout) before and after, and require the increase to equal amount (payout != address(this) is already enforced).","line":251,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\n/// Usual fee-on-transfer shape: recipient receives 1% less.\ncontract Fot is ERC20 {\n    constructor() ERC20(\"FEE\", \"FEE\") {}\n    function mint(address to, uint256 a) external { _mint(to, a); }\n    function _update(address from, address to, uint256 v) internal override {\n        if (from != address(0) && to != address(0)) {\n            uint256 fee = v / 100;\n            super._update(from, address(0), fee);\n            v -= fee;\n        }\n        super._update(from, to, v);\n    }\n}\n\ncontract FotClaimTest is Test {\n    function test_claimRevertsWhenPayoutReceivesLess() public {\n        vm.warp(1_800_000_000);\n        address owner = makeAddr(\"owner\");\n        address dev = makeAddr(\"dev\");\n        Fot t = new Fot();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(t)), owner);\n        t.mint(address(this), 1010 ether);\n        t.transfer(address(pool), 1010 ether); // plain transfer: no fund() balance check\n        bytes32 g = pool.gameId(\"coin-dash\");\n        vm.startPrank(owner);\n        pool.listGame(g, dev);\n        pool.proposeMonth(202611, pool.leaf(202611, g, 100 ether), 100 ether);\n        vm.stopPrank();\n        vm.warp(block.timestamp + 3 days);\n        try pool.claim(202611, g, 100 ether, new bytes32[](0)) {} catch {}\n        // Either the claim reverts (nothing paid) or the game got its full Merkle amount.\n        uint256 got = t.balanceOf(dev);\n        assertTrue(got == 0 || got == 100 ether, \"game paid less than its Merkle amount without a revert\");\n    }\n}","reproduction":"Token: recipient-side 1% fee. Transfer 1010 to the pool, so it holds 1000 free. listGame(g, dev). proposeMonth(202611, leaf(202611, g, 100e18), 100e18). warp +3 days. claim(202611, g, 100e18, []). Expected: revert BalanceMismatch. Actual: succeeds, dev receives 99e18, and claimed[202611][g] = true, so the remaining 1e18 can never be claimed.","severity":"low","snippet":"        uint256 before = token.balanceOf(address(this));\n        token.safeTransfer(payout, amount);\n        uint256 sent = before - token.balanceOf(address(this));\n        if (sent != amount) revert BalanceMismatch(amount, sent);","title":"claim's exact-balance check measures only the pool's side, so a standard fee-on-transfer token pays games less than their Merkle amount without reverting"},{"citation":"resolved","description":"The brief requires integration with the real OGClubFarmVault. The repository has no vault source (src/ contains only OGClubCreatorPool.sol), and the builder wrote a test-only reconstruction, which they disclosed in its natspec. The vault-to-pool leg (plain transfer landing in free()) is therefore proven only against an assumed interface. It is not proven against the deployed vault's real claim signature, leaf encoding or any transfer side effects. This is a test-evidence gap, not a pool defect.","line":18,"path":"test/support/OGClubFarmVault.sol","reproduction":"grep -r 'contract OGClubFarmVault' . finds only test/support/OGClubFarmVault.sol (marked 'TEST SUPPORT ONLY ... reconstruction'). Expected: the integration test imports the real vault source. Actual: it imports ./support/OGClubFarmVault.sol.","severity":"info","snippet":"contract OGClubFarmVault is Ownable2Step, ReentrancyGuard {","title":"Integration test runs against a reconstructed OGClubFarmVault, not the real vault the brief names"}],"hash":"4cdfb0ddfaf47fbe9d640abda48eb2289dd1634e639e7f2ac894a64f8f3df2f5","nodeId":"45a99997-01c8-45f1-8fdb-37b2434ca5f4","outcome":"completed","summary":"I found one medium and three low defects in `OGClubCreatorPool`, plus one test gap. Each of the four defects has a Foundry test that fails on the current code for the stated reason. The existing suite (68 tests) passes. Results are in `.imd-findings.json` with 5 findings and 14 coverage rows, which cover all 12 entry points and 2 invariants. I changed no files: the scratch tests were deleted after their source was copied into the findings, and the tree is clean.\n\n**Findings**\n\n1. **Medium: cancelling a mistyped month id doesn't undo it** (`src/OGClubCreatorPool.sol:205`).\n   - `proposeMonth` advances `lastMonth`, and `cancelMonth` never puts it back.\n   - **Reproduction:** `proposeMonth(999912, r, 100e18)`, then `cancelMonth(999912)`, then `proposeMonth(202611, …)`. The last call reverts with `MonthNotAfterLast` for every id below 999912, permanently.\n   - After 999912 is used once more, no month can ever be proposed. All free $OG, including later farm-vault payouts, is then locked for good.\n   - **Fix:** restore the previous `lastMonth` when the last month is cancelled, or cap month ids near the current date.\n2. **Low: `renounceOwnership` is inherited unchanged.**\n   - One owner call means `proposeMonth` can never run again. The free balance and every later vault inflow can then never leave the pool.\n   - **Fix:** override `renounceOwnership` to revert.\n3. **Low: the owner can be a game's payout wallet** (`_checkPayout`, line 314).\n   - **Reproduction:** `listGame(g, owner)`, propose a month that gives `g` all of the free balance, wait 3 days, then claim. The owner's balance goes from 0 to 1000 $OG. This breaks the brief's rule that the owner's $OG never rises through this contract.\n   - The invariant test misses this because its handler skips any payout change to the owner.\n   - **Fix:** reject the owner as a payout in `listGame` and `changePayout`.\n4. **Low: `claim`'s exact-balance check only measures the pool's side** (line 251).\n   - With a standard fee-on-transfer token (the recipient gets less), funds that arrive by plain transfer can still be claimed. The claim succeeds and the game receives 99 instead of 100.\n   - The existing test only covers a token that charges the sender, so this path is untested.\n   - **Fix:** also check that the payout wallet's balance rises by exactly `amount`.\n5. **Info: the integration test uses a rebuilt vault.** It runs against a copy of `OGClubFarmVault` that the builder reconstructed, not the real contract the brief names. The builder disclosed this; the real vault source isn't in the repo.\n\n**Coverage**\n- **Hold:** `acceptOwnership`, `transferOwnership`, `delistGame`, `relistGame`, `fund`, `sweep`, and both invariants (balance ≥ reserved; reserved equals the sum of what open months still owe).\n- **Have findings:** `proposeMonth` and `cancelMonth` (#1), `renounceOwnership` (#2), `listGame` and `changePayout` (#3), `claim` (#4).\n- I covered all three assigned guides: Execution Trace, Periphery and First Principles.\n- I read the deploy scripts but checked them only briefly and found nothing to report.\n- I left out the five Slither timestamp warnings: each comparison is a deliberate window check, and I found no boundary errors at the edges.","treeHash":null,"usage":{"cachedInputTokens":844204,"inputTokens":32,"model":"claude-opus-5-5","outputTokens":20607,"runtime":"claude","turns":18,"wallClockMs":221477}},{"artifacts":[],"attempt":1,"bundleHash":"1849bf1d22270399db30c1e92d1af321d056389916ad6155908ba6d0c8f24ef7","device":"fa2b7fcb5f53535a","findings":[],"hash":"5251303ace131c2df84cabddaf80753333a3187138353849d8421ad13ef71def","nodeId":"eaa475f8-909f-47a9-a0bc-26ec62fe140b","outcome":"completed","summary":"Both reproducible findings are fixed and their proofs pass, the three advisory findings reproduced on the original code and are fixed too, and all five are answered in `.imd-responses.json`.\n\n**What I verified first**\n\n- The two proofs failed on the starting tree exactly as reported. Both pass on the fixed contract.\n- The three advisory findings also reproduced on the original source with a scratch test. The same scratch test passes on the fixed source.\n\n**Contract changes in `src/OGClubCreatorPool.sol`**\n\n- **Late listing** records a `listedAt` timestamp per game. A claim reverts when the game was listed after the month was proposed, so a month's recipients are fixed when its review starts. Same-block listing and cancel-then-re-propose still work.\n- **Mistyped month id** is undone by cancel. Proposing stores the previous `lastMonth`, and cancelling the highest month walks back to the highest live month. The rule \"month > lastMonth, or equal if cancelled\" is unchanged.\n- **Owner as payout** is refused on list and on payout change, for the owner and the pending owner. A claim also refuses a payout wallet that has since become the owner.\n- **`renounceOwnership`** always reverts, since no owner would mean no way to schedule the free balance.\n- **Recipient-side balance check** in claim, so a fee-on-transfer token now reverts in both shapes.\n\n**Tests and docs**\n\n- Added unit tests for every change, replaced the one test that encoded the old `lastMonth` behaviour, and added two invariants plus a handler action that tries the owner as payout.\n- README natspec and trust statements reworded to match what the contract enforces, with new operational notes on listing order and on checking month ids within the three days.\n\n**Checks run**\n\n```\nforge build          ok (only pre-existing lint warnings)\nforge fmt --check    ok\nforge test           84 passed, 0 failed (verifier seed), proofs included\n```\n\nThe responses file is excluded from git by the harness's own exclude rule, which is how it was set up, so nothing further is needed there. Month-id validation still accepts any year up to 9999. A typo not cancelled within three days remains permanent, which the README now states.","treeHash":"a76de8df317849079bc4705b5a0c300b69ed7d4f","usage":{"cachedInputTokens":1990337,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":39494,"runtime":"claude","turns":53,"wallClockMs":620947}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"d0653dc91b6e2259","findings":[{"citation":"resolved","description":"claim() reads games[game].payout at claim time and only requires it to be nonzero; listGame() is onlyOwner and has no time restriction. A month's root may contain a leaf whose game id is not listed when the month is proposed. During the 3-day review nobody can tell who that leaf will pay, and once opensAt has passed (cancelMonth reverts MonthAlreadyOpen, so the month's money is supposed to be beyond the owner's reach) the owner can still call listGame(id, anyWallet), including its own wallet, and the leaf's amount goes there. This breaks the stated guarantee 'the owner can't touch money owed to a month after its 3-day window' (natspec lines 20-23, README 'Once a month has opened the owner can never touch its money again') and the README's trust statement that 'a leaf for an unknown game is unclaimable'. The builder's own test test_leafForNeverListedGameIsUnclaimableUntilListed stops before the late listing. Merged from audit_economics (medium) and audit_permissions (low); distinct from finding 3 because the set of recipients is not frozen at proposal even if owner() itself were refused as a payout. Minimal fix that keeps the design: record when a game was listed (e.g. uint64 listedAt in Game, set in listGame) and in claim require listedAt != 0 && listedAt < m.opensAt - CLAIM_DELAY (listed before the month was proposed), so the recipients of a month are fixed when the public review starts. Tradeoff: a game listed after a proposal must wait for the next month, which matches the off-chain draft flow.","line":242,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract OG is ERC20(\"OG\", \"OG\") {\n    function mint(address to, uint256 a) external {\n        _mint(to, a);\n    }\n}\n\n/// Money owed to a month must be out of the owner's reach once its 3-day window has passed.\n/// A leaf whose game id is not listed when the month opens lets the owner choose its recipient\n/// afterwards by listing that id with a wallet of its own.\ncontract UnlistedLeafTest is Test {\n    OG og;\n    OGClubCreatorPool pool;\n    address owner = makeAddr(\"owner\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        og = new OG();\n        pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n    }\n\n    function test_ownerCannotRedirectOpenMonthByLateListing() public {\n        bytes32 newGame = pool.gameId(\"new-game\");\n        uint256 month = 202611;\n        bytes32 root = pool.leaf(month, newGame, 1000 ether); // single-leaf tree: root == leaf\n        vm.prank(owner);\n        pool.proposeMonth(month, root, 1000 ether);\n\n        skip(3 days); // open: cancelMonth now reverts, the month is meant to be out of owner reach\n\n        vm.prank(owner);\n        try pool.listGame(newGame, owner) {} catch {}\n        try pool.claim(month, newGame, 1000 ether, new bytes32[](0)) {} catch {}\n\n        assertEq(og.balanceOf(owner), 0, \"owner received money owed to an open month\");\n    }\n}","reproduction":"State: OGClubCreatorPool(og, O) holding 1000e18 OG; gameId('new-game') never listed. (1) O: proposeMonth(202611, leaf(202611, gameId('new-game'), 1000e18), 1000e18) succeeds (single-leaf tree, root == leaf). (2) warp +3 days: month Open; O: cancelMonth(202611) reverts MonthAlreadyOpen. (3) O: listGame(gameId('new-game'), O) succeeds. (4) anyone: claim(202611, gameId('new-game'), 1000e18, []) succeeds. Expected: after opensAt the owner cannot decide who receives the month's money (listing a game into an already-open month's leaf is refused, or the claim is). Actual: og.balanceOf(O) goes 0 -> 1000e18. Proof test fails with 'owner received money owed to an open month: 1000000000000000000000 != 0'.","severity":"medium","snippet":"        address payout = games[game].payout;\n        if (payout == address(0)) revert GameUnknown(game);","title":"Owner can pick the recipient of an open month's leaf after the 3-day window by listing its game id late (README's 'leaf for an unknown game is unclaimable' is false)"},{"citation":"resolved","description":"proposeMonth sets lastMonth = month (line 212) and cancelMonth (lines 218-229) never restores the previous value. isValidMonth accepts any YYYYMM with year 2026..9999 with no relation to block.timestamp. The 3-day cancel window is the owner's only way to undo a bad proposal, but it cannot undo the id: after cancelling, the only proposable ids are >= the typo. With 207206 typed for 202706 the pool cannot pay any real month for 45 years; with 999912 the owner can re-propose 999912 once and never anything again. Because $OG only leaves through month claims and there is deliberately no withdraw path, all of free() plus every later farm-vault season payment (seasons keep listing the pool's address) becomes permanently unspendable after a single owner typo. The implementation follows the brief's ordering rule literally, so this is an operational-safety defect rather than a spec violation; the same mechanism means a pending month that is not lastMonth (e.g. 202611 cancelled after 202612 was proposed) can never be re-proposed under its own id, which the adversarial test documents as intended. Merged from audit_flow (medium), audit_economics (low), write_foundry_tests (low) and audit_permissions (info). Fix that preserves 'month > lastMonth, or == lastMonth if cancelled': store the previous lastMonth when proposing and restore it when the cancelled month is lastMonth, and/or bound month ids to at most one or two calendar months after block.timestamp (a derived constant, no new constructor argument).","line":205,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract Tok is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n    function mint(address to, uint256 a) external { _mint(to, a); }\n}\n\ncontract LastMonthCancelTest is Test {\n    function test_cancelledTypoMonthDoesNotBlockEarlierMonths() public {\n        vm.warp(1_800_000_000);\n        address owner = makeAddr(\"owner\");\n        Tok og = new Tok();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n\n        vm.startPrank(owner);\n        // Fat-fingered month id: valid (year 9999, month 12), proposed by mistake.\n        pool.proposeMonth(999912, bytes32(uint256(1)), 100 ether);\n        // The 3-day cancel window exists to undo exactly this; the owner cancels in time.\n        pool.cancelMonth(999912);\n        assertEq(pool.free(), 1000 ether, \"reservation released\");\n        // The intended month must still be proposable after the mistake was cancelled.\n        pool.proposeMonth(202611, bytes32(uint256(1)), 100 ether);\n        vm.stopPrank();\n    }\n}","reproduction":"State: pool holds 1000e18 OG, lastMonth == 0. (1) owner: proposeMonth(999912, bytes32(uint256(1)), 100e18) succeeds (isValidMonth(999912) is true). (2) owner: cancelMonth(999912) within 3 days succeeds, reserved == 0, free() == 1000e18. (3) owner: proposeMonth(202611, bytes32(uint256(1)), 100e18). Expected: succeeds, since the mistaken month was cancelled inside the window meant for that. Actual: reverts MonthNotAfterLast(202611, 999912), as does every id below 999912. If 999912 is proposed again and not cancelled, proposeMonth reverts for every input and the 1000e18 plus all future inflows can never leave the contract. Proof test fails with 'MonthNotAfterLast(202611, 999912)'.","severity":"medium","snippet":"        if (month < lastMonth || (month == lastMonth && !months[month].cancelled)) {\n            revert MonthNotAfterLast(month, lastMonth);\n        }","title":"cancelMonth cannot undo a mistyped month id: lastMonth is never lowered, so a far-future id (e.g. 999912) permanently blocks every later proposal and locks the free balance forever"},{"citation":"resolved","description":"_checkPayout refuses only address(0) and the pool itself, so listGame(id, owner()) succeeds, as does changePayout(id, owner()) by a game wallet. Since the owner also chooses every month's root and total, it can propose a single-leaf month paying that game the whole free() balance and claim it after CLAIM_DELAY. The natspec (lines 20-23), README ('There is no withdraw ... path') and the brief's invariant overstate what the contract enforces; invariant_ownerNeverGainsOG in test/OGClubCreatorPool.invariant.t.sol passes only because PoolHandler never lists the owner as a payout and returns early when a changePayout target equals the owner (line 139), so the stated property is never challenged. An owner using a second wallet cannot be stopped on chain, so this is primarily a trust assumption the 3-day public review mitigates, which is why it is rated low rather than the medium one specialist gave it. Merged from audit_permissions (medium), audit_flow (low), write_foundry_tests (low) and audit_math (info). Cheap hardening that keeps the design: revert in _checkPayout when payout == owner() or pendingOwner() (and re-check games[game].payout != owner() in claim, since ownership can move after listing), and reword natspec/README to say the owner is trusted with roots and the delay plus the published list are the safeguard.","line":314,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract ScratchOG is ERC20 {\n    constructor() ERC20(\"Mock OG\", \"OG\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @notice The brief and the contract's own natspec say the owner can never withdraw and that the\n///         owner's $OG never rises through this contract. `_checkPayout` only rejects address(0) and\n///         the pool itself, so the owner can list a game whose payout wallet is the owner, propose a\n///         month whose single leaf pays that game the whole free balance, and claim it three days later.\ncontract OwnerSelfPayoutTest is Test {\n    ScratchOG internal og;\n    OGClubCreatorPool internal pool;\n    address internal owner = makeAddr(\"owner\");\n    address internal funder = makeAddr(\"funder\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        og = new ScratchOG();\n        pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(funder, 1_000 ether);\n        vm.startPrank(funder);\n        og.approve(address(pool), 1_000 ether);\n        pool.fund(1_000 ether);\n        vm.stopPrank();\n    }\n\n    function test_ownerCannotBeListedAsPayoutWallet() public {\n        bytes32 id = pool.gameId(\"owner-game\");\n        vm.prank(owner);\n        // Expected: refused, the owner must never be a payout destination.\n        // Actual on this code: succeeds (only address(0) and address(pool) are refused).\n        vm.expectRevert();\n        pool.listGame(id, owner);\n    }\n\n    function test_ownerDrainsFreeBalanceViaSelfListedGame() public {\n        bytes32 id = pool.gameId(\"owner-game\");\n        vm.startPrank(owner);\n        (bool listed,) = address(pool).call(abi.encodeCall(OGClubCreatorPool.listGame, (id, owner)));\n        if (listed) {\n            // Single-leaf tree: root == leaf, empty proof.\n            bytes32 root = pool.leaf(202_701, id, 1_000 ether);\n            pool.proposeMonth(202_701, root, 1_000 ether);\n            skip(3 days);\n            pool.claim(202_701, id, 1_000 ether, new bytes32[](0));\n        }\n        vm.stopPrank();\n        // Expected by the brief's invariant: the owner's $OG never rises through this contract.\n        assertEq(og.balanceOf(owner), 0, \"owner withdrew the whole free balance through a self-listed game\");\n    }\n}","reproduction":"State: pool funded with 1000e18 OG (fund or plain transfer), owner = O, O's balance 0. (1) O: listGame(keccak256('owner-game'), O) succeeds (expected per the stated invariant: refused). (2) O: proposeMonth(202701, leaf(202701, id, 1000e18), 1000e18) succeeds. (3) skip 3 days. (4) anyone: claim(202701, id, 1000e18, []) transfers 1000e18 OG to O. Expected per README/natspec: og.balanceOf(O) stays 0. Actual: og.balanceOf(O) == 1000e18. Proof file fails both tests: 'next call did not revert as expected' and 'owner withdrew the whole free balance through a self-listed game: 1000000000000000000000 != 0'.","severity":"low","snippet":"    function _checkPayout(address payout) private view {\n        if (payout == address(0)) revert ZeroAddress();\n        if (payout == address(this)) revert InvalidPayout(payout);\n    }","title":"Owner may be listed as (or moved to) a game's payout wallet, so 'the owner can never withdraw' and 'owner's $OG never rises through this contract' are enforced only by the test handler, not by the con"},{"citation":"resolved","description":"Ownable2Step keeps Ownable.renounceOwnership(), a one-step irreversible call that sets owner to address(0). proposeMonth is onlyOwner and is the only way tokens become claimable; the brief intentionally provides no withdraw path. After a renounce, months already proposed still pay and sweep, but the current free(), every swept remainder and every later OGClubFarmVault season payment to the pool's address are locked forever. The contract made handover two-step to avoid a mistaken transfer but left this single-step footgun open. Reported identically by all four specialists and the test writer. Fix: override renounceOwnership() to revert (handover via transferOwnership/acceptOwnership stays intact).","line":24,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract Tok is ERC20 {\n    constructor() ERC20(\"OG\", \"OG\") {}\n    function mint(address to, uint256 a) external { _mint(to, a); }\n}\n\ncontract RenounceTest is Test {\n    function test_renounceCannotStrandFreeBalance() public {\n        address owner = makeAddr(\"owner\");\n        Tok og = new Tok();\n        OGClubCreatorPool pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n        vm.prank(owner);\n        try pool.renounceOwnership() {} catch {}\n        // With an owner, the free balance can still be scheduled into a month.\n        assertEq(pool.owner(), owner, \"pool lost its only way to schedule its free balance\");\n    }\n}","reproduction":"State: pool holds 1000e18 OG, reserved == 0. (1) owner: renounceOwnership() succeeds, owner() == address(0). (2) any caller: proposeMonth(202611, root, 1e18) reverts OwnableUnauthorizedAccount. Expected: renounce refused, so the 1000e18 can still be scheduled into a month. Actual: free() == 1000e18 can never be reserved, claimed or moved by anyone. Proof test fails with 'pool lost its only way to schedule its free balance: 0x000...000 != <owner>'.","severity":"low","snippet":"contract OGClubCreatorPool is Ownable2Step, ReentrancyGuard {","title":"Inherited renounceOwnership() permanently strands the free balance and every future vault inflow (no owner means no proposeMonth, and there is no other exit for $OG)"},{"citation":"resolved","description":"The README says 'fee-on-transfer token reverts on fund and claim'. fund() (line 184-185) really does catch the usual shape because it measures the pool as recipient. claim() compares only the pool's balance drop with amount; for the common fee-on-transfer shape (sender debited exactly value, recipient credited value - fee) the drop equals amount, so the claim succeeds, claimed[month][game] is set, remaining and reserved fall by the full amount, and the payout wallet receives amount - fee with no way to retry. test_feeOnTransfer_claimReverts uses only the inverted sender-charged variant (FeeOnTransferToken(true), test/support/FeeOnTransferToken.sol), so the common shape is untested. The launch token is the live $OG, a plain ERC-20 (verified: symbol OG, 18 decimals, token() of the live farm vault), so this cannot trigger in production; it is a documentation and test-coverage gap, rated low. Merged from audit_math (low) and audit_flow (low). Fix if the guarantee is meant to hold for any token: also require token.balanceOf(payout) to rise by exactly amount (payout != address(this) is already enforced); otherwise narrow the README and test claim to 'protects the pool's accounting'.","line":251,"path":"src/OGClubCreatorPool.sol","reproduction":"Token: OpenZeppelin ERC20 whose _update burns value/100 from `from` and credits `to` with value - fee. Deploy OGClubCreatorPool(token, owner); mint 1000e18 to the pool; owner: listGame(gameId('coin-dash'), dev); owner: proposeMonth(202701, leaf(202701, game, 100e18), 100e18); warp +3 days; anyone: claim(202701, game, 100e18, []). Expected per README: revert BalanceMismatch. Actual: succeeds; token.balanceOf(dev) == 99e18, months(202701).remaining == 0, reserved == 0, claimed(202701, game) == true. Verified with a scratch test (test/scratch/FeeRecipient.t.sol): the expectRevert variant fails with 'next call did not revert as expected' and the observing variant logs dev balance 99000000000000000000.","severity":"low","snippet":"        uint256 before = token.balanceOf(address(this));\n        token.safeTransfer(payout, amount);\n        uint256 sent = before - token.balanceOf(address(this));\n        if (sent != amount) revert BalanceMismatch(amount, sent);","title":"claim()'s exact-balance check measures only the pool's side, so the usual recipient-side fee-on-transfer token passes and the game is credited with more than it receives; the README and test overstate"},{"citation":"resolved","description":"The brief requires integration with the real OGClubFarmVault. src/ contains only OGClubCreatorPool.sol, and the vault used is test/support/OGClubFarmVault.sol, whose header states it is a reconstruction of the season interface as the brief describes it. The builder disclosed this in the README. The pool side (a plain ERC-20 transfer lands in free()) is proven, but the real vault's claim signature, leaf encoding and any restriction on paying a contract account are not. Reported by audit_economics, audit_flow and write_foundry_tests; kept as a test-evidence gap, not a pool defect. The live vault at 0x60401e748d6c3a1f2775bE9e6a41bda20eDa0B80 reports token() == the manifest's $OG address, so the token leg is consistent.","line":7,"path":"test/OGClubCreatorPool.integration.t.sol","reproduction":"grep -r 'contract OGClubFarmVault' . finds only test/support/OGClubFarmVault.sol. Expected: test/OGClubCreatorPool.integration.t.sol imports the real vault source. Actual: it imports ./support/OGClubFarmVault.sol. No failing input against the pool itself; replace the import with the real vault and rerun test_vaultSeasonFundsPoolThenPoolPaysGames.","severity":"info","snippet":"import {OGClubFarmVault} from \"./support/OGClubFarmVault.sol\";","title":"Integration test runs against a reconstructed OGClubFarmVault written for the tests, not the real vault the brief names"}],"hash":"90ed0e6d3014deb3f6be3cd330f191a5f899642a68bd379ed6905810b1b16db7","nodeId":"187591fa-0d60-4787-a46f-d59ee0b5fb49","outcome":"completed","summary":"Review complete. The findings file is written and the tree is otherwise unchanged (git status is clean apart from the untracked findings file, and the scratch tests are removed).\n\n**Outcome.** Every specialist finding reproduced; the 15 specialist reports collapse into 6 findings, with four attached proofs that all fail on the current code for the stated reasons. The project's own 100 tests pass. The manifest's $OG address was checked against mainnet: symbol OG, 18 decimals, and it is the live farm vault's token.\n\n**Findings kept, by severity:**\n\n1. **Medium: late listing redirects an open month.** The owner can propose a root containing a leaf for an unlisted game id, wait past the 3-day window, then list that id with any wallet and claim. This contradicts the README's \"a leaf for an unknown game is unclaimable\" and the post-window guarantee. Merged from economics and permissions.\n2. **Medium: cancel cannot undo a mistyped month id.** `lastMonth` is never lowered, so a typo like 999912 locks every future proposal and the whole free balance permanently, since there is no withdraw path. Merged from all four areas and the test writer.\n3. **Low: owner may be a payout wallet.** Only zero and the pool itself are refused, so the \"owner never gains $OG\" invariant is enforced only by the test handler, which skips that case. Rated low because a second wallet is unstoppable on chain anyway and the delay is the real safeguard.\n4. **Low: inherited renounceOwnership strands all funds.**\n5. **Low: claim's balance check is pool-side only.** A recipient-side fee token passes and the game gets less than its leaf. Harmless with the real $OG but the README and the fee test overclaim.\n6. **Info: the integration test uses a reconstructed vault**, not the real OGClubFarmVault.\n\n**Coverage.** All 12 entry points answered, plus rows for the three brief invariants and the manifest. Eight entry points hold; claim, listGame, proposeMonth and renounceOwnership point at findings 1, 1, 2 and 4.\n\n**Nothing new beyond the specialists.** My own pass over Merkle domain separation, reserved accounting across cancel and re-propose, claim and sweep boundaries, reentrancy, the deploy scripts and the launch manifest found no additional defect.","treeHash":null,"usage":{"cachedInputTokens":728188,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":21411,"runtime":"claude","turns":27,"wallClockMs":321295}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f494611affb5524c","findings":[{"citation":"resolved","description":"The brief lists 'OWNER CAN'T: withdraw' and the invariant 'owner's $OG never rises through this contract'; the contract natspec (lines 20-23) repeats that the owner 'can never withdraw'. Nothing enforces it. _checkPayout only refuses address(0) and the pool itself, so listGame(id, owner()) succeeds. Because the owner also chooses every month's Merkle root and total, it can propose a single-leaf month (root == leaf(month, id, free()), empty proof) paying that game the entire free balance and claim it after CLAIM_DELAY. The 3-day delay is the only real protection, and it is only meaningful if the list behind the root is published off-chain for the public to compare. The invariant test invariant_ownerNeverGainsOG passes only because the handler never lists the owner as a payout and skips changePayout targets equal to owner, so the suite does not exercise this case. Access x economics seam: guard (onlyOwner) and economics (claim pays games[game].payout) are each correct in isolation; together the trusted role can extract all idle funds. A full on-chain fix is impossible while the owner picks roots, so this is primarily a trust assumption the docs overstate. Minimal code hardening that preserves the design: refuse owner() and pendingOwner() in _checkPayout (and re-check in claim against the current owner), and reword the natspec/README to say the owner is trusted with roots and the delay plus published lists are the safeguard.","line":315,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract ScratchOG is ERC20 {\n    constructor() ERC20(\"Mock OG\", \"OG\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @notice The brief and the contract's own natspec say the owner can never withdraw and that the\n///         owner's $OG never rises through this contract. `_checkPayout` only rejects address(0) and\n///         the pool itself, so the owner can list a game whose payout wallet is the owner, propose a\n///         month whose single leaf pays that game the whole free balance, and claim it three days later.\ncontract OwnerSelfPayoutTest is Test {\n    ScratchOG internal og;\n    OGClubCreatorPool internal pool;\n    address internal owner = makeAddr(\"owner\");\n    address internal funder = makeAddr(\"funder\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        og = new ScratchOG();\n        pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(funder, 1_000 ether);\n        vm.startPrank(funder);\n        og.approve(address(pool), 1_000 ether);\n        pool.fund(1_000 ether);\n        vm.stopPrank();\n    }\n\n    function test_ownerCannotBeListedAsPayoutWallet() public {\n        bytes32 id = pool.gameId(\"owner-game\");\n        vm.prank(owner);\n        // Expected: refused, the owner must never be a payout destination.\n        // Actual on this code: succeeds (only address(0) and address(pool) are refused).\n        vm.expectRevert();\n        pool.listGame(id, owner);\n    }\n\n    function test_ownerDrainsFreeBalanceViaSelfListedGame() public {\n        bytes32 id = pool.gameId(\"owner-game\");\n        vm.startPrank(owner);\n        (bool listed,) = address(pool).call(abi.encodeCall(OGClubCreatorPool.listGame, (id, owner)));\n        if (listed) {\n            // Single-leaf tree: root == leaf, empty proof.\n            bytes32 root = pool.leaf(202_701, id, 1_000 ether);\n            pool.proposeMonth(202_701, root, 1_000 ether);\n            skip(3 days);\n            pool.claim(202_701, id, 1_000 ether, new bytes32[](0));\n        }\n        vm.stopPrank();\n        // Expected by the brief's invariant: the owner's $OG never rises through this contract.\n        assertEq(og.balanceOf(owner), 0, \"owner withdrew the whole free balance through a self-listed game\");\n    }\n}","reproduction":"State: pool funded with 1000 OG (fund or plain transfer), owner = O. Calls: (1) O: listGame(keccak256('owner-game'), O) -> succeeds (expected: refused). (2) O: proposeMonth(202701, leaf(202701, id, 1000e18), 1000e18) -> succeeds. (3) skip 3 days. (4) anyone: claim(202701, id, 1000e18, []) -> transfers 1000 OG to O. Expected per brief: balanceOf(O) stays 0. Actual: balanceOf(O) == 1000e18. test/scratch/OwnerSelfPayout.t.sol fails on both tests on the current code.","severity":"medium","snippet":"        if (payout == address(0)) revert ZeroAddress();\n        if (payout == address(this)) revert InvalidPayout(payout);","title":"Owner can withdraw the whole free balance by listing a game whose payout wallet is the owner (stated 'owner can't withdraw' invariant not enforced)"},{"citation":"resolved","description":"claim reads games[game].payout at claim time and only requires it to be nonzero. A root may contain a leaf for an id that is not listed when the month is proposed; after opensAt, when the owner is supposed to have no further influence over the month's money, the owner can still call listGame(id, anyWallet) and thereby choose the recipient of that leaf. Combined with the owner's control of the root this is the same trust assumption as finding 1, but it is a distinct code path with its own minimal fix: record when a game was listed (e.g. uint64 listedAt in Game) and in claim require the game to have been listed before the month was proposed (listedAt <= opensAt - CLAIM_DELAY), so the set of possible recipients for a month is frozen at proposal time. Note the leaf does not bind the payout address, so this cannot be enforced through the proof alone.","line":242,"path":"src/OGClubCreatorPool.sol","reproduction":"State: pool holds 500 OG, id = keccak256('late-game') is NOT listed. Calls: (1) owner: proposeMonth(202701, leaf(202701, id, 500e18), 500e18). (2) skip 3 days (month open). (3) owner: listGame(id, W) where W is any wallet -> succeeds. (4) anyone: claim(202701, id, 500e18, []) -> pays W 500 OG. Expected: after opensAt the owner has no way to affect who receives the month's money; actual: owner picked W after the window closed. Shown by test_ownerCanListGameIntoAlreadyProposedMonth in test/scratch/Renounce.t.sol (passes on current code, demonstrating the behaviour).","severity":"low","snippet":"        address payout = games[game].payout;\n        if (payout == address(0)) revert GameUnknown(game);","title":"Owner can decide where an already-open month's leaf pays by listing the game after proposal (weakens 'owner can't touch money owed after the 3-day window')"},{"citation":"resolved","description":"Ownable2Step keeps Ownable.renounceOwnership(), a one-step, irreversible call that sets owner to address(0). proposeMonth is the only way tokens ever become claimable, and there is intentionally no withdraw. After a renounce every unreserved token (current free() plus anything the farm vault pays in later, since vault seasons are configured off-chain and keep listing the pool) is locked forever. Ownership transfer was deliberately made two-step to avoid a mistaken handover, but this single-step footgun was left open. Minimal fix preserving the design: override renounceOwnership to revert (the owner can still hand over via transferOwnership/acceptOwnership).","line":24,"path":"src/OGClubCreatorPool.sol","reproduction":"State: pool holds 500 OG, reserved == 0. Calls: (1) owner: renounceOwnership() -> owner() == address(0). (2) owner or anyone: proposeMonth(202701, root, 1e18) -> reverts OwnableUnauthorizedAccount. Expected: a reversible or guarded handover path only; actual: free() == 500e18 can never be reserved, claimed, or moved by anyone. test_renounceStrandsFreeBalance in test/scratch/Renounce.t.sol.","severity":"low","snippet":"contract OGClubCreatorPool is Ownable2Step, ReentrancyGuard {","title":"Inherited renounceOwnership permanently strands the free balance (no withdraw path, no future months)"},{"citation":"resolved","description":"This matches the brief ('month > lastMonth, or == lastMonth if cancelled'), so it is recorded as an operational consequence rather than a spec violation. cancelMonth releases the reservation but does not roll lastMonth back, so after proposing and cancelling e.g. 202712 by mistake in January 2027 the owner can never propose 202702..202711; those months' payouts would have to be issued under later ids. A design-level option is to let cancelMonth of the current lastMonth restore the previous lastMonth, which requires a scope decision.","line":205,"path":"src/OGClubCreatorPool.sol","reproduction":"State: pool funded. Calls: (1) owner: proposeMonth(202712, root, 1e18). (2) owner: cancelMonth(202712). (3) owner: proposeMonth(202702, root, 1e18) -> reverts MonthNotAfterLast(202702, 202712). test_cancelledTypoMonthBlocksIntermediateMonths in test/scratch/Renounce.t.sol.","severity":"info","snippet":"        if (month < lastMonth || (month == lastMonth && !months[month].cancelled)) {\n            revert MonthNotAfterLast(month, lastMonth);\n        }","title":"A cancelled month still advances lastMonth, so a mistyped future month id permanently blocks every calendar month before it"}],"hash":"97a8e0875cc00630de384d63bdc46134329283f00272abe993f7ee215b2d4433","nodeId":"39d339a7-0571-418e-9e49-98632607a92a","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds four findings and fifteen coverage rows. The existing suite of 68 tests passes, and my scratch tests under `test/scratch/` reproduce every finding.\n\n**Findings**\n\n- **Medium, owner self-payout.** The brief says the owner can never withdraw and that the owner's $OG never rises through the pool. Nothing enforces it: `_checkPayout` at src/OGClubCreatorPool.sol:315 only refuses the zero address and the pool, so the owner can list a game paying itself, propose a single-leaf month for the whole free balance, and claim it after three days. The invariant handler never generates this case, which is why the suite passes. A proof test fails on the current code and passes once owner and pending owner are refused as payouts. The complete guarantee cannot be enforced on-chain while the owner picks roots, so the natspec should state the real safeguard: the delay plus published lists.\n- **Low, late listing into an open month.** `claim` reads the payout at claim time and only needs it nonzero. The owner can propose a root with a leaf for an unlisted id, wait past opensAt, then list that id with any wallet and decide the recipient after the window where the owner is supposed to have no influence. Fix by recording a listing time and requiring it to precede the month's proposal.\n- **Low, renounce strands funds.** The inherited one-step `renounceOwnership` leaves no owner, and proposing months is the only way tokens ever leave. All free balance, including future vault payouts, is locked forever. Override it to revert.\n- **Info, cancelled typo month.** A cancelled month still raises lastMonth, so a mistyped future id permanently blocks the calendar months before it. This matches the brief, so it is recorded as a consequence, not a violation.\n\n**Coverage**\n\nAll twelve entry points have a row. Ownership handover, cancel, changePayout, delist, relist, fund, proposeMonth and sweep hold under the Access Control, Trust Gap and Asymmetry checks. The reserved accounting invariant holds. Slither's timestamp leads are inherent to the window design and were not promoted. Reentrancy, math and token-behaviour passes outside my area were only sampled.","treeHash":null,"usage":{"cachedInputTokens":548082,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":20306,"runtime":"claude","turns":21,"wallClockMs":333395}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bc1e515ca5c78ac4","findings":[{"citation":"resolved","description":"claim() only requires games[game].payout != 0 at claim time, and listGame() can be called at any time. A month's root may contain a leaf for a game id that is not listed when the month opens (a new game in the draft that was not listed yet, or a leaf the owner crafted). During the 3-day delay nobody can tell who that leaf will pay, and once the month is open (cancelMonth reverts, the funds are supposed to be beyond the owner's reach) the owner lists that id with any payout wallet, including its own, and the leaf's amount goes there. This breaks 'the owner can't touch money owed to a month after its 3-day window' and the invariant 'owner's $OG never rises through this contract'. The invariant test (invariant_ownerNeverGainsOG) only holds because its handler never lists an owner wallet, so it does not exercise this. Minimal fix that keeps the design: store the listing timestamp in Game (e.g. uint64 listedAt set in listGame) and in claim require listedAt != 0 && listedAt < m.opensAt, so only games listed before a month opens (visible during the delay) can claim it; optionally also reject payout == owner() in listGame.","line":242,"path":"src/OGClubCreatorPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {OGClubCreatorPool} from \"src/OGClubCreatorPool.sol\";\n\ncontract OG is ERC20(\"OG\", \"OG\") {\n    function mint(address to, uint256 a) external {\n        _mint(to, a);\n    }\n}\n\n/// Money owed to a month must be out of the owner's reach once its 3-day window has passed.\n/// A leaf whose game id is not listed when the month opens lets the owner choose its recipient\n/// afterwards by listing that id with a wallet of its own.\ncontract UnlistedLeafTest is Test {\n    OG og;\n    OGClubCreatorPool pool;\n    address owner = makeAddr(\"owner\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        og = new OG();\n        pool = new OGClubCreatorPool(IERC20(address(og)), owner);\n        og.mint(address(pool), 1000 ether);\n    }\n\n    function test_ownerCannotRedirectOpenMonthByLateListing() public {\n        bytes32 newGame = pool.gameId(\"new-game\");\n        uint256 month = 202611;\n        bytes32 root = pool.leaf(month, newGame, 1000 ether); // single-leaf tree: root == leaf\n        vm.prank(owner);\n        pool.proposeMonth(month, root, 1000 ether);\n\n        skip(3 days); // open: cancelMonth now reverts, the month is meant to be out of owner reach\n\n        vm.prank(owner);\n        try pool.listGame(newGame, owner) {} catch {}\n        try pool.claim(month, newGame, 1000 ether, new bytes32[](0)) {} catch {}\n\n        assertEq(og.balanceOf(owner), 0, \"owner received money owed to an open month\");\n    }\n}","reproduction":"owner=O, pool holds 1000 OG. O: proposeMonth(202611, leaf(202611, gameId(\"new-game\"), 1000e18), 1000e18) with gameId(\"new-game\") unlisted. warp +3 days (month open; cancelMonth reverts MonthAlreadyOpen). O: listGame(gameId(\"new-game\"), O) succeeds. Anyone: claim(202611, gameId(\"new-game\"), 1000e18, []) succeeds. Expected: the owner cannot pick the recipient of an open month's funds (listing/claim rejected). Actual: O's OG balance goes 0 -> 1000e18. Proof test fails with 'owner received money owed to an open month: 1000000000000000000000 != 0'.","severity":"medium","snippet":"        address payout = games[game].payout;\n        if (payout == address(0)) revert GameUnknown(game);","title":"Owner can choose who receives an open month's money by listing an unlisted leaf's game id after the 3-day window"},{"citation":"resolved","description":"proposeMonth only requires month > lastMonth (or == a cancelled lastMonth) and isValidMonth accepts any year up to 9999. lastMonth is never lowered, even by cancelMonth. If the owner proposes a mistyped id (e.g. 202710 instead of 202610, or 999912) and it is not cancelled within 3 days, every earlier id is unusable for good; cancelling only allows re-proposing the same far id. With 999912 open, no month can ever be proposed again, and since there is no withdrawal path, the whole free() balance plus every later vault season payment is locked in the contract forever. Fix preserving the design: bound the month id to the current time (e.g. reject a month whose start is more than ~2 months after block.timestamp), or have cancelMonth restore the previous lastMonth.","line":205,"path":"src/OGClubCreatorPool.sol","reproduction":"Pool holds 1000 OG, owner proposes proposeMonth(999912, root, 1) and 3 days pass (or the cancelled re-proposal of 999912 opens). Then proposeMonth(202612, r, 999) reverts MonthNotAfterLast(202612, 999912), and so does every other id, since none is > 999912 and isValidMonth caps year at 9999. Expected: a recoverable pool. Actual: 999 OG free and all future inflows permanently unspendable.","severity":"low","snippet":"        if (month < lastMonth || (month == lastMonth && !months[month].cancelled)) {\n            revert MonthNotAfterLast(month, lastMonth);\n        }","title":"A single far-future month id permanently stops all future months and locks the pool's free balance"},{"citation":"resolved","description":"Ownable2Step keeps Ownable.renounceOwnership(). Only the owner can propose months, and $OG can leave only through month claims, so once ownership is renounced the free() balance, every swept remainder, and every later farm-vault payment (the vault keeps paying the pool's address) is stuck forever. Since the brief gives no withdrawal path by design, renouncing is never a safe action for this contract. Fix: override renounceOwnership() to revert.","line":24,"path":"src/OGClubCreatorPool.sol","reproduction":"Pool holds 1000 OG free. owner calls renounceOwnership() (succeeds, owner() == 0). Any proposeMonth(202611, r, 1000e18) reverts OwnableUnauthorizedAccount. Later sweeps return remainders to free(), which nobody can ever allocate. Expected: renounce rejected; actual: funds permanently locked.","severity":"low","snippet":"contract OGClubCreatorPool is Ownable2Step, ReentrancyGuard {","title":"renounceOwnership is inherited and permanently locks all free and future $OG"},{"citation":"resolved","description":"The brief requires INTEGRATION with the real OGClubFarmVault. The test uses a contract written for the test from the brief's description, so any difference in the real vault's claim (e.g. leaf encoding, season ids, transfer path) is not covered. The pool side holds for plain ERC-20 transfers, which is what such a claim does. Replace with the real vault source when available.","line":11,"path":"test/support/OGClubFarmVault.sol","reproduction":"test/OGClubCreatorPool.integration.t.sol imports ./support/OGClubFarmVault.sol, whose header states it is a reconstruction; no file from the real vault is in the tree.","severity":"info","snippet":"/// @notice TEST SUPPORT ONLY. The workspace this pool was built in did not contain the deployed","title":"Integration test runs against a reconstructed OGClubFarmVault, not the real one"}],"hash":"9d22f96ec701d526505094418455f782418acba219ccabd8d18e7a44cec496cb","nodeId":"d0d2e213-23d4-4496-b040-c97aa1288c56","outcome":"completed","summary":"I found one medium, two low and one info finding. They are written to `.imd-findings.json` along with a coverage row for each of the 12 entry points and the three requested invariants. The existing suite (68 tests) passes. My proof test fails on the current code for the reason given in finding 1. I then deleted the scratch test and changed no project files.\n\n**Findings**\n1. **Medium: the owner can still redirect money owed to an open month** (`src/OGClubCreatorPool.sol:242`). `claim()` only checks that the game has a payout wallet at claim time, and `listGame()` works at any time. So if a month's Merkle root contains a game id that isn't listed yet, the owner can wait for the month to open (when `cancelMonth` stops working), list that id with their own wallet, and the claim pays them.\n   - **Reproduction:** propose `202611` with a single leaf of 1000 OG for `gameId(\"new-game\")`, wait 3 days, call `listGame(id, owner)`, then `claim(...)`. The owner's balance goes from 0 to 1000e18.\n   - **What it breaks:** the rule that the owner can't touch a month's money after its 3-day window, and the invariant that the owner's $OG never rises. The invariant test only passes because its handler never lists an owner wallet.\n   - **Fix:** store a `listedAt` time for each game and have `claim` require `listedAt < opensAt`.\n2. **Low: one far-future month id locks the pool for good** (`:205`). `lastMonth` never goes back down, and any year up to 9999 is accepted. Once `999912` is proposed and opens, every later `proposeMonth` reverts with `MonthNotAfterLast`. There is no withdrawal, so the free balance and all later vault payments are stuck. **Fix:** cap the month id relative to the current date, or have `cancelMonth` restore the previous `lastMonth`.\n3. **Low: `renounceOwnership()` is inherited and not blocked** (`:24`). After renouncing, nobody can propose a month, so all free and future $OG is stuck forever. **Fix:** override it to revert.\n4. **Info: the integration test doesn't use the real OGClubFarmVault.** It runs against `test/support/OGClubFarmVault.sol`, a stand-in written from the brief because the real vault source isn't in this repository. Its header says so.\n\n**Checked and found sound:** the claim window boundaries, cancel only before a month opens, once-per-game claims, the `amount <= remaining` cap, the exact balance checks on `fund` and `claim` (a fee-on-transfer token reverts), sweep timing, overwriting a cancelled month (no leftover claim flags), and how `reserved` is kept. Balance ≥ reserved and reserved = sum of open months' remaining both hold. The slither timestamp warnings are only the intended day-scale windows, so I didn't report them.\n\n**Not covered in depth:** the deploy scripts outside their economic effect.","treeHash":null,"usage":{"cachedInputTokens":333224,"inputTokens":18,"model":"claude-opus-5-5","outputTokens":11870,"runtime":"claude","turns":9,"wallClockMs":155239}},{"artifacts":[],"attempt":1,"bundleHash":"b6e33d9e4a0e013ff4bce75de3214f366c3b8b9cc12c31a220fa6e1547b1fb08","device":"52c98c0dc01791cd","findings":[],"hash":"a38815fec0099542751dd16a14dc41db13319f714638dbe28f55e13304be9336","nodeId":"eaa475f8-909f-47a9-a0bc-26ec62fe140b","outcome":"completed","summary":"The work is complete and committed. A clean clone of the commit builds, passes all tests with the verifier's fuzz seed, and passes the format check, all offline.\n\n**One deviation to flag first.** The brief says to add the pool to the existing Foundry project and to integrate with the real OGClubFarmVault. The workspace was empty and the vault source is not published anywhere I could find. I built a fresh Foundry project at the root, and the integration test runs against a reconstruction of the vault's season interface in `test/support/OGClubFarmVault.sol`. It is test support only, nothing in src depends on it, and the README explains how to swap in the real vault with a single import change.\n\n**What was delivered**\n\n- `src/OGClubCreatorPool.sol`: the contract as specified. Ownable2Step, ReentrancyGuard, SafeERC20, MerkleProof, custom errors, immutable token, 3-day delay and 90-day claim window, YYYYMM month validation, exact balance checks on fund and claim, sweep back to free. No withdraw, no payout override by owner, no ETH, no proxy. The constructor makes no external call.\n- Tests, 68 in total across five files: unit tests for every listed rule and revert, fuzz tests including paid-per-month ≤ total, four invariants under a handler, the vault integration flow, and direct calls of both deploy functions.\n- `script/DeployCreatorPool.s.sol` for mainnet from env OG_TOKEN and OWNER, listing no games. `script/DeployCreatorPoolSepolia.s.sol` deploys a mock $OG and lists test games from a JSON string. Both print the address and ABI-encoded constructor args.\n- `README.md` with behaviour, trust assumptions, invariants, deployment parameters, and an \"Operations\" section describing the monthly owner workflow.\n- OpenZeppelin 5.4.0 and forge-std 1.11.0 vendored under lib as plain files. The index holds no gitlinks.\n\n| Check | Result |\n| --- | --- |\n| forge build (solc 0.8.26) | success, lint warnings only |\n| forge test with the verifier's seed | 68 passed, 0 failed |\n| forge fmt --check | clean |\n| Pool runtime size | about 14 KB |\n\n**Decisions you may want to review**\n\n- \"No self payout\" was read two ways and both are enforced: a payout cannot be the pool contract, and a payout wallet cannot set itself again.\n- The Sepolia script takes the games JSON as text through the GAMES_JSON variable rather than reading a file, so no filesystem permission is enabled. The example JSON file has placeholder text, not addresses, so it must be filled in before use.\n- Slither was not available here. The code avoids the six outright-reject detectors by construction, which the README states.\n\n**Next steps for the requester**\n\n- Put the real OGClubFarmVault, OGClubStaking and OGClubClubs sources in the repository and point the integration test at the real vault.\n- Supply the live $OG token address for the manifest. The owner argument is $owner.\n- Arrange an independent adversarial review before release, as the contract will hold developers' $OG.","treeHash":"3569224db25eeb2fc38bd5542aafef760574570a","usage":{"cachedInputTokens":2119973,"inputTokens":962,"model":"claude-fable-5-1","outputTokens":71246,"runtime":"claude","turns":52,"wallClockMs":976644}},{"artifacts":[],"attempt":1,"bundleHash":"66db6644856e1c14aa240dca4c3f08b25012e82ab2c36d1780671d7a768d7e89","device":"a7b8747ac077deb9","findings":[{"description":"The brief says proposeMonth needs month > lastMonth, or month == lastMonth if that month was cancelled. Since 638e244, cancelMonth moves lastMonth back to the highest live month, so after cancelling the highest month the owner may propose any lower id above the previous live month. This deviates from the brief's literal rule. It is documented in the README as a way to undo a mistyped id, it moves no money (only months not yet open can be cancelled, and the funds go back to free()), and the invariant suites check that lastMonth always equals the highest live month. Reported so the requester can confirm the change is wanted; the tests assert the implemented behaviour, which is not a money defect.","line":254,"path":"src/OGClubCreatorPool.sol","reproduction":"proposeMonth(202612, r, 1); cancelMonth(202612) before opensAt; proposeMonth(202611, r, 1). Expected by the brief's literal rule: MonthNotAfterLast(202611, 202612). Actual: accepted, lastMonth == 202611.","severity":"info","title":"lastMonth walks back on cancel, which allows proposing a month below a cancelled one; the brief only allows re-proposing the cancelled month"},{"description":"The integration test now runs against the live OGClubFarmVault bytecode (test/support/OGClubFarmVaultBytecode.sol) and test/support/OGClubFarmVault.sol is deleted. README's 'About the vault in the integration test' section and repository layout still point to the reconstruction and to openSeason(season, root, total). The real vault numbers seasons itself (proposeSeason(root, total) returns the id), caps a season at half its free balance and spaces proposals 7 days apart. README is outside the test paths this task may write, so it was left unchanged.","line":1,"path":"README.md","reproduction":"grep -n 'reconstruction' README.md finds the stale section; ls test/support shows OGClubFarmVaultBytecode.sol and no OGClubFarmVault.sol.","severity":"info","title":"README still describes the removed reconstructed vault and the real vault's season rules"}],"hash":"a696be4aef72b4746c1f3bb780953fa11ed1afb1c80411913d031f998dd25e2a","nodeId":"d6b7f709-17c6-42f0-b851-9e86624f8a8d","outcome":"completed","summary":"The reviewer's finding was correct and is now fixed. The integration test runs against the real OGClubFarmVault bytecode instead of the copy the previous round wrote from the brief. `forge build` and `forge test` both pass: 112 tests, run with the verifier's fuzz seed, including both invariant suites.\n\n**The vault finding (`e94d3298…`): fixed**\n- The live vault at `0x60401e74…0B80` has no verified source on Sourcify or Blockscout. Blockscout does have the transaction data that created it, though.\n- `test/support/OGClubFarmVaultBytecode.sol` now holds that creation code and the live contract's code. A new test, `test_vaultBytecodeIsTheLiveContract`, deploys it with the mainnet constructor arguments and checks the result matches the mainnet code byte for byte.\n- The integration tests deploy the same bytes with a mock $OG. They call it through an interface built from the function signatures in its code. With the real vault:\n  - the claim format is the one assumed: season, account, amount;\n  - a vault season can pay the pool's address, and the $OG shows up in the pool's `free()`;\n  - vault claims fail before its 3-day delay.\n- I deleted the old copy, `test/support/OGClubFarmVault.sol`. It got three things wrong about the real vault, none of which affects the pool:\n  - the vault numbers seasons itself (`proposeSeason(root, total)`; there is no `openSeason`);\n  - a season can take at most half the vault's free balance;\n  - proposals must be at least 7 days apart.\n\n**Two of my earlier tests were failing, now fixed.** Another contributor changed the contract after my last round, and two of my tests no longer matched it:\n- `cancelMonth` now moves `lastMonth` back to the highest month that is still live. The invariant handler re-proposes the same month after cancelling the highest one. It now asserts `lastMonth` equals the highest live month, and no longer that every proposed month is at or below it.\n- `renounceOwnership` is now disabled. The test that renounced and then claimed now expects `RenounceDisabled`, and checks that a two-step ownership handover leaves a proposed month claimable.\n\n**Reported in `.imd-findings.json` (both info, no money at risk):**\n- **`lastMonth` steps back on cancel.** The brief only allows re-proposing the cancelled month itself. The contract now also accepts lower months, as long as they are above the previous live one: for example, `202611` after cancelling `202612`. This is documented as a way to undo a mistyped month and moves no money, but the requester should confirm they want it.\n- **The README is out of date.** It still describes the deleted copy of the vault. It's outside the files I'm allowed to change, so I left it alone.\n\nMy answer to the reviewer is in `.imd-responses.json`. I haven't committed anything.","treeHash":"bb8244ce37e613128b68d100d2b0040325783e0f","usage":{"cachedInputTokens":1766515,"inputTokens":59,"model":"claude-opus-5-5","outputTokens":24901,"runtime":"claude","turns":31,"wallClockMs":342484}},{"artifacts":[],"attempt":2,"bundleHash":"ec3b8bac52b2061975003f82533b716c0300e4f9d177ac5684ccd5c4eca0c6d9","device":"cdeffb0cd839cbf7","findings":[],"hash":"af8938cc384abeada4f5d2d45f48cb7dd5cca5d0660901d158fe06c3b1a3c933","nodeId":"53777257-6233-4b84-b393-a32e12622384","outcome":"completed","summary":"Done. `launch.json` is written, and it is the only changed file.\n\n**What was open, and how I decided it.** The previous attempt stopped because the brief gives no mainnet $OG address, and the pool's constructor stores the token immutably. Since no reply comes, I resolved it from the requester's own prior launches rather than inventing anything:\n\n- The accepted OGClubHookDeployer manifest for the same owner, 0x5b95…d06, passes the OG token 0xCe7EB1Ad9e2E1c784ea05F7eA4A0Fe625923D10A and the farm vault 0x60401e748d6c3a1f2775bE9e6a41bda20eDa0B80 as static arguments.\n- On-chain checks over a public mainnet RPC confirm that address: symbol OG, 18 decimals, one billion supply matching the OG token launch, and the live farm vault's `token()` returns it.\n\n**The manifest** names one contract, OGClubCreatorPool, with constructor arguments `[OG token address, \"$owner\"]`, matching `constructor(IERC20 token_, address owner_)` in `src/OGClubCreatorPool.sol:128`. The notes explain the token's provenance and the owner's limits.\n\n**Checks run:**\n\n| Check | Result |\n| --- | --- |\n| `forge build` | ok |\n| `forge test` with the verifier's fuzz seed | 68 passed, 0 failed |\n| Manifest shape (keys, kind, identifier, string args, notes length) | ok |\n\nSources used to resolve the token: [launch-2407 hook README](https://github.com/identity-md-launches/launch-2407-ogclubhook-uniswap-v4-hook), [launch-2160 OG token](https://github.com/identity-md-launches/launch-2160-og-club), [launch-2327 OG Club](https://github.com/identity-md-launches/launch-2327-continue-delivered-og-club).","treeHash":"e9c11729dbc38f461b44cfe80ce70238979efb4f","usage":{"cachedInputTokens":306781,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":6505,"runtime":"claude","turns":15,"wallClockMs":156774}},{"artifacts":[],"attempt":1,"bundleHash":"0af53cd1cfc0a729a231158a2ab19ca31235cd35b1c907dd760cabc73ff44a77","device":"0e3b71e2ffcd200b","findings":[],"hash":"b5161fe0f8fbb6c0844b0ff547f34cc65c8adec3f0a283b7cb25f85f62ea8a24","nodeId":"53777257-6233-4b84-b393-a32e12622384","outcome":"completed","summary":"The manifest is complete and `launch.json` is the only changed file.\n\n**Outcome.** The earlier rejection asked for the mainnet $OG token address. It did not need the requester: the address in the accepted manifest is the requester's own live token, and I confirmed that on chain today rather than guessing.\n\n- **Token argument verified on Ethereum mainnet.** A public RPC read of the token at the manifest's address returned name OG, symbol OG, 18 decimals and a total supply of one billion tokens. The live OG Club farm vault returned that same address from its token() getter, and its owner() is this launch's $owner wallet.\n- **Constructor match.** OGClubCreatorPool's constructor takes an ERC-20 token and an owner, in that order, and only stores the token after a nonzero check. The manifest passes the static token address and `$owner`, so the empty-chain rehearsal cannot revert on a missing contract.\n- **Change made.** Constructor arguments are unchanged from the accepted round. Only the notes were rewritten to record the on-chain evidence and the date it was gathered, so a reviewer can see the address is not a stand-in. Notes are under the 4,000 character limit and the manifest has exactly the kind, contracts and notes keys.\n- **Checks.** The project builds, and the full suite passes with the verifier's fuzz seed.\n\n| Suite | Result |\n| --- | --- |\n| All 5 Foundry suites | 79 passed, 0 failed |\n\nNo `.imd-blocked.json` was written, since the missing value turned out to be resolvable from the requester's deployed contracts. Nothing outside `launch.json` was touched.","treeHash":"5e9ab5b2c265f64852ae05fb7cc5e616fd326c3f","usage":{"cachedInputTokens":260580,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":6247,"runtime":"claude","turns":10,"wallClockMs":165630}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dd3018ab6b18e7bc","findings":[{"citation":"resolved","description":"Boundary (non-standard token) x invariant. The brief and README state that claim() reverts for a fee-on-transfer token ('fee-on-transfer token reverts on fund and claim'). The check at line 253-254 compares only the pool's own balance delta with `amount`. For the common fee-on-transfer shape (the fee is deducted from what the recipient receives, the sender is debited exactly `value`) the pool's balance falls by exactly `amount`, so `sent == amount`, the claim succeeds, `claimed[month][game]` is set, `remaining` and `reserved` drop by the full `amount`, while the payout wallet receives `amount - fee`. The game's claim for that month is consumed at a lower real payout and cannot be retried. Only the inverted shape (sender debited more than `amount`), which test/support/FeeOnTransferToken.sol implements with `chargeSender == true`, is caught; the test `test_feeOnTransfer_claimReverts` therefore demonstrates a property narrower than the README states, and the common shape is untested. Impact depends on $OG being a plain ERC-20, which the brief implies; with a plain token this path cannot trigger. If the guarantee is meant to hold for any token, also compare the payout wallet's balance delta (`token.balanceOf(payout)` before/after == amount), or document that the check only protects the pool's accounting, not the recipient's receipt.","line":253,"path":"src/OGClubCreatorPool.sol","reproduction":"Token: OpenZeppelin ERC20 whose _update burns value/100 from `from` and credits `to` with value - fee (recipient-side fee). Deploy OGClubCreatorPool(token, owner); owner.listGame(gameId('coin-dash'), dev1); mint 1000e18 to the pool; owner.proposeMonth(202701, leaf(202701, game, 100e18), 100e18); warp +3 days; anyone calls claim(202701, game, 100e18, []). Expected (per README/brief): revert BalanceMismatch. Actual: succeeds; token.balanceOf(dev1) == 99e18, months(202701).remaining == 0, reserved == 0, claimed(202701, game) == true. Verified with test/scratch/Repro.t.sol::test_claimPassesWhenRecipientReceivesLess (the test asserts the defective outcome and passes on the current tree).","severity":"low","snippet":"        uint256 sent = before - token.balanceOf(address(this));\n        if (sent != amount) revert BalanceMismatch(amount, sent);","title":"claim()'s exact-balance check only measures the pool side, so the usual fee-on-transfer shape passes and the game is credited with more than it receives"},{"citation":"resolved","description":"Documented as a trust assumption, not a permission bypass: the owner is trusted to publish honest roots, and this route needs no unprivileged amplifier. _checkPayout refuses only the zero address and the pool itself. The owner can therefore listGame(id, owner()) (or any wallet it controls), propose a month whose single leaf pays that game the whole free balance, and claim it after the 3-day delay. The brief's invariant 'owner's $OG never rises through this contract' passes in test/OGClubCreatorPool.invariant.t.sol only because PoolHandler never lists the owner as a payout and skips changePayout targets equal to the owner (`if (to == owner || ...) return;`). The 3-day review window is the only mitigation. If the requester wants the contract rather than the owner's honesty to enforce the guarantee, _checkPayout could also refuse `owner()` and `pendingOwner()` (noting a game wallet could still later changePayout to the owner, so this is a deterrent, not a proof). No change to the agreed design is required; this is for the trust-assumptions section of the report.","line":314,"path":"src/OGClubCreatorPool.sol","reproduction":"Deploy OGClubCreatorPool(og, owner); mint 1000e18 to the pool. owner.listGame(gameId('owner-game'), owner) succeeds (expected per brief's 'no zero or self payout': succeeds; only zero and pool are refused). owner.proposeMonth(202701, leaf(202701, game, 1000e18), 1000e18); warp +3 days; anyone calls claim(202701, game, 1000e18, []). Result: og.balanceOf(owner) == 1000e18. Verified with test/scratch/Repro.t.sol::test_ownerCanBePayoutWallet.","severity":"info","snippet":"    function _checkPayout(address payout) private view {\n        if (payout == address(0)) revert ZeroAddress();\n        if (payout == address(this)) revert InvalidPayout(payout);\n    }","title":"Trust assumption: the owner may list a game whose payout wallet is the owner, so 'owner's $OG never rises through this contract' is enforced only by the test handler, not by the contract"}],"hash":"e8e0539fb399ed107da952dc648f544ec2bee27d58993313d4ff5321d22b63e1","nodeId":"ef178242-6e3e-406d-ad34-c6dc5a4ac96f","outcome":"completed","summary":"The findings file is valid, both snippets match the source exactly, and the coverage record answers all 12 entry points plus five invariant/lead rows. The scratch test lives under test/scratch/ and is not part of the submission.\n\n**Result: the arithmetic and boundaries of OGClubCreatorPool hold. Two low-impact items were substantiated, nothing critical or high.**\n\nWhat I checked in my area (Math Precision, Boundary, Numerical Gap):\n- **No division, scaling or downcast risk.** The only division is in the month-id validator, and the one narrowing cast is of a timestamp into uint64, which cannot truncate.\n- **Reservation accounting is exact.** Every change to `reserved` is paired with an equal change to exactly one month's `remaining`, so balance ≥ reserved and reserved = Σ remaining hold by construction for a plain ERC-20. The existing invariant and fuzz suites confirm this and pass with all 68 tests.\n- **Time edges are consistent.** Claim, cancel and sweep use complementary comparisons at `opensAt` and `opensAt + 90 days`, so there is no gap or overlap. I reproduced this at the exact boundaries in a scratch test. The Slither timestamp leads are intended behaviour.\n- **Cancel-and-repropose is safe.** A cancelled month can only be overwritten before it opened, so the claimed map for it is guaranteed empty.\n\nFindings written to the file:\n1. **Low.** The claim path's exact-balance check only measures the pool's own balance. With the common fee-on-transfer shape, where the recipient receives less, the claim succeeds, the month records the full amount as paid, and the game receives 99% of it. The README's statement that claim reverts on fee-on-transfer tokens is only true for the inverted, sender-charged shape that the test mock implements. This does not trigger with a plain $OG token.\n2. **Info, trust assumption.** The owner can list a game whose payout is the owner's own address and route a whole month to it after the 3-day delay. The \"owner's $OG never rises\" invariant passes only because the test handler never does this. This is the agreed design's reliance on an honest owner, not a bypass.\n\nNot covered: the real OGClubFarmVault, whose source is absent from the repository, so the integration test runs against a reconstruction. That is outside my area and noted in the README by the author.","treeHash":null,"usage":{"cachedInputTokens":753333,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":20422,"runtime":"claude","turns":29,"wallClockMs":316808}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a7581259169534a1","findings":[],"hash":"f818ae67f2c06d204878b99c82642afb5ee922dbf223c7a77d1c8fd6d497c4d3","nodeId":"53777257-6233-4b84-b393-a32e12622384","outcome":"failed","summary":"needs input: The Ethereum mainnet $OG ERC-20 token address is missing. OGClubCreatorPool requires it as its first constructor argument and stores it immutably; the second argument can use $owner. The brief and accepted sources provide no token address, and launch.json cannot resolve OG_TOKEN from the environment or use a token placeholder or test mock. — What is the Ethereum mainnet (chain ID 1) $OG ERC-20 contract address to pass as OGClubCreatorPool's token constructor argument?","treeHash":null,"usage":{"cachedInputTokens":198016,"inputTokens":51686,"model":"gpt-6-astra","outputTokens":1772,"runtime":"codex","turns":3,"wallClockMs":148144}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1188f01303e45ecd","findings":[{"citation":"resolved","description":"Documentation inaccuracy only, no code defect. The fix for the earlier integration finding deleted test/support/OGClubFarmVault.sol and replaced it with test/support/OGClubFarmVaultBytecode.sol, which carries the creation code and runtime of the live OGClubFarmVault at 0x60401e748d6c3a1f2775bE9e6a41bda20eDa0B80. I fetched the live runtime from mainnet (cast code via ethereum-rpc.publicnode.com) and its keccak256 is 0x6c325e836293ca5ea50e0c3f6ab30aaacab272e034d7453ab058fdf51d3ce706, identical to the LIVE_RUNTIME constant the test asserts against, so test_vaultBytecodeIsTheLiveContract really does prove the bytes are the deployed vault's. The README section 'About the vault in the integration test' (lines 126-137) and the layout note still describe the deleted reconstruction and an openSeason(season, root, total) entry point the real vault does not have (it numbers seasons itself via proposeSeason(root, total), caps a season at half its free balance and spaces proposals 7 days apart). The author stated README.md was outside their writable paths in that round. Merged with write_foundry_tests' identical note. Fix: rewrite that section to describe OGClubFarmVaultBytecode.sol and the real vault's interface.","line":131,"path":"README.md","reproduction":"grep -n 'reconstruction' README.md prints line 131 referring to test/support/OGClubFarmVault.sol; ls test/support shows FeeOnTransferToken.sol, Merkle.sol, MockOG.sol, OGClubFarmVaultBytecode.sol and no OGClubFarmVault.sol; test/OGClubCreatorPool.integration.t.sol line 7 imports ./support/OGClubFarmVaultBytecode.sol. Expected: README describes the file the test uses. Actual: it describes a deleted file and an openSeason function the live vault lacks.","severity":"info","snippet":"`test/support/OGClubFarmVault.sol`: a reconstruction of the vault's season interface as the brief","title":"README still says the integration test runs against a reconstructed vault in test/support/OGClubFarmVault.sol, a file that no longer exists; the test now runs the live vault's bytecode"}],"hash":"fa16f64e9b68fa09a87405703ba5ad880dd09a64f22c16aa5f81cf920fb5707a","nodeId":"187591fa-0d60-4787-a46f-d59ee0b5fb49","outcome":"completed","summary":"Review complete. The findings file is written at `.imd-findings.json` with one info-level note and an 18-row coverage record.\n\n**Earlier findings, all confirmed fixed.** I copied the six attached proofs under test/scratch and ran them against the revised code. Every one passes now, and the full suite of 112 tests passes with them.\n\n- **Late listing redirecting an open month's leaf** is closed. The contract records when a game was listed and claim refuses a game listed after the month was proposed.\n- **Cancel not undoing a mistyped month id** is closed. Cancelling the highest month walks lastMonth back to the highest live month. I traced nested and repeated cancel sequences and found no way for it to land on a cancelled month or below an open one.\n- **Owner as payout wallet** is closed. Listing and payout changes refuse the owner and pending owner, and claim re-checks the current owner.\n- **renounceOwnership** now reverts.\n- **Recipient-side fee-on-transfer** is closed. Claim checks the payout wallet's balance rose by exactly the amount.\n- **Integration against the real vault** is closed in code. I fetched the live vault's runtime from mainnet and its keccak matches the constant the test asserts against byte for byte, so the test really drives the deployed vault's bytecode.\n\n**One item kept, as info.** The README section about the vault in the integration test still describes the deleted reconstruction file and an openSeason function the live vault does not have. The author said README was outside their writable paths last round. Documentation only, no code impact.\n\n**Dropped.** The test writer's note that the lastMonth walk-back departs from the brief's literal rule is the fix I asked for, and the brief's rule still holds with lastMonth defined as the highest live month. The static-analysis timestamp and literal leads are intended behaviour.\n\n**Also checked.** The manifest has only the three schema keys, two string constructor arguments, and the live $OG address. Runtime size is 7,870 bytes and the constructor makes no external call, so the CREATE2 rehearsal deploys. Nothing in the tree was modified. The scratch copies were removed.","treeHash":null,"usage":{"cachedInputTokens":592354,"inputTokens":226,"model":"claude-fable-5-1","outputTokens":13939,"runtime":"claude","turns":16,"wallClockMs":221854}}],"verification":[{"checks":[{"durationMs":3270,"exitCode":0,"name":"build","output":"Compiling 49 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.19s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/OGClubCreatorPool.fuzz.t.sol:95:14:\n   |\n95 |         for (uint256 i; i < 3; ++i) {\n   |              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/OGClubCreatorPool.fuzz.t.sol:104:9:\n    |\n104 |         uint256 i = bound(which, 0, 2);\n    |         ^^^^^^^^^\n\n","passed":true},{"durationMs":3515,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/OGClubCreatorPool.integration.t.sol:OGClubCreatorPoolIntegrationTest\n[PASS] test_monthCannotBeProposedBeforeVaultPays() (gas: 482715)\n[PASS] test_vaultPayoutsAcrossSeasonsAccumulateAsFree() (gas: 720303)\n[PASS] test_vaultSeasonFundsPoolThenPoolPaysGames() (gas: 1091603)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 42.11ms (977.33µs CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.fuzz.t.sol:OGClubCreatorPoolFuzzTest\n[PASS] testFuzz_forgedLeafRejected(uint256,uint256,uint8) (runs: 256, μ: 347434, ~: 347557)\nLogs:\n  Bound result 2\n  Bound result 340282366920938463463374607431768211455\n\n[PASS] testFuzz_monthIdValidation(uint256) (runs: 256, μ: 115570, ~: 114966)\n[PASS] testFuzz_paidPerMonthNeverExceedsTotal(uint256,uint8,uint256,uint256) (runs: 256, μ: 955977, ~: 748144)\nLogs:\n  Bound result 1\n  Bound result 11000000000000000000\n  Bound result 6595\n  Bound result 545188853437351037\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 42.15ms (57.09ms CPU time)\n\nRan 54 tests for test/OGClubCreatorPool.t.sol:OGClubCreatorPoolTest\n[PASS] test_anyoneCanPushClaim_payoutWalletReceives() (gas: 788762)\n[PASS] test_cancelMonth_onlyOwnerAndMustExist() (gas: 399252)\n[PASS] test_cancelMonth_releasesAndAllowsRepropose() (gas: 770295)\n[PASS] test_cancelMonth_tooLate() (gas: 420115)\n[PASS] test_cancelledMonthIsNotLastMonthBarrierForOlderMonths() (gas: 510047)\n[PASS] test_changePayout_byPayoutWallet() (gas: 124457)\n[PASS] test_changePayout_ownerCannot() (gas: 38331)\n[PASS] test_changePayout_rejectsZeroSelfAndPool() (gas: 90687)\n[PASS] test_changePayout_strangerCannot() (gas: 38353)\n[PASS] test_changePayout_unknownGame() (gas: 43496)\n[PASS] test_changePayout_worksWhenDelisted() (gas: 83692)\n[PASS] test_claim_cannotPayFromOtherMonthsReserve() (gas: 1078345)\n[PASS] test_claim_revertsEarly() (gas: 511093)\n[PASS] test_claim_revertsLate() (gas: 525514)\n[PASS] test_claim_revertsOverBudget() (gas: 597971)\n[PASS] test_claim_revertsTwice() (gas: 496593)\n[PASS] test_claim_revertsUnknownGame() (gas: 378038)\n[PASS] test_claim_revertsUnknownOrCancelledMonth() (gas: 451797)\n[PASS] test_claim_revertsWrongLeaf() (gas: 810023)\n[PASS] test_constructor() (gas: 48273)\n[PASS] test_constructor_revertsOnZeroOwner() (gas: 6345)\n[PASS] test_constructor_revertsOnZeroToken() (gas: 6090)\n[PASS] test_delistRelist() (gas: 161048)\n[PASS] test_delistRelist_onlyOwner() (gas: 63118)\n[PASS] test_delistRelist_unknownGame() (gas: 70835)\n[PASS] test_delistedGameCanStillClaim() (gas: 493623)\n[PASS] test_feeOnTransfer_claimReverts() (gas: 1022134)\n[PASS] test_feeOnTransfer_fundReverts() (gas: 792524)\n[PASS] test_fullMonth_evenLeaves() (gas: 876715)\n[PASS] test_fullMonth_fiveLeavesAndSurplusFree() (gas: 949466)\n[PASS] test_fullMonth_oddLeaves() (gas: 843304)\n[PASS] test_fund_pullsExactAmount() (gas: 148942)\n[PASS] test_fund_revertsOnZero() (gas: 37270)\n[PASS] test_fund_revertsWithoutAllowance() (gas: 46056)\n[PASS] test_gameId() (gas: 14032)\n[PASS] test_isValidMonth() (gas: 46154)\n[PASS] test_listGame_emits() (gas: 68986)\n[PASS] test_listGame_onlyOnceEver() (gas: 102113)\n[PASS] test_listGame_onlyOwner() (gas: 43560)\n[PASS] test_listGame_revertsOnPoolAsPayout() (gas: 43798)\n[PASS] test_listGame_revertsOnZeroPayout() (gas: 43076)\n[PASS] test_listGame_setsPayoutAndListed() (gas: 12378)\n[PASS] test_noEthAccepted() (gas: 38732)\n[PASS] test_ownerHasNoWayToTakeTokens() (gas: 429659)\n[PASS] test_ownershipIsTwoStep() (gas: 116355)\n[PASS] test_payoutChangedBeforeClaim_paysNewWallet() (gas: 503975)\n[PASS] test_plainTransferCountsAsFree() (gas: 74999)\n[PASS] test_proposeMonth_onlyOwner() (gas: 151491)\n[PASS] test_proposeMonth_reservesAndSchedules() (gas: 379502)\n[PASS] test_proposeMonth_reverts() (gas: 684986)\n[PASS] test_singleLeafMonth() (gas: 398115)\n[PASS] test_sweep_fullyClaimedMonthIsNoop() (gas: 729181)\n[PASS] test_sweep_returnsUnclaimedToFreeAndReuse() (gas: 1098808)\n[PASS] test_sweep_unknownMonth() (gas: 32270)\nSuite result: ok. 54 passed; 0 failed; 0 skipped; finished in 42.24ms (16.45ms CPU time)\n\nRan 31 tests for test/OGClubCreatorPool.adversarial.t.sol:OGClubCreatorPoolAdversarialTest\n[PASS] test_cancel_exactBoundary() (gas: 434527)\n[PASS] test_cancelledMonth_cannotBeCancelledAgainOrSwept() (gas: 437789)\n[PASS] test_cancelledOlderMonthCannotComeBackOnceANewerOneExists() (gas: 735530)\n[PASS] test_claimByAnotherGamesWalletPaysTheClaimedGame() (gas: 472046)\n[PASS] test_claimWindow_exactBoundaries() (gas: 759215)\n[PASS] test_concurrentMonths_areIsolated() (gas: 1394724)\n[PASS] test_firstValidMonthIsJanuary2026() (gas: 311980)\n[PASS] test_fund_exactAllowanceAndOneWei() (gas: 178549)\n[PASS] test_leafForNeverListedGameIsUnclaimableUntilListed() (gas: 356160)\n[PASS] test_manyLeaves_allPaidExactly() (gas: 38672751)\n[PASS] test_monthsAlreadyProposedStillPayAndSweepWithoutAnOwner() (gas: 545697)\n[PASS] test_overwrite_canReserveMoreThanTheCancelledVersion() (gas: 592398)\n[PASS] test_overwrite_oldRootDeadNewRootLive() (gas: 856374)\n[PASS] test_ownerHasNoOtherTokenExit_allPublicSelectorsAccountedFor() (gas: 534328)\n[PASS] test_ownershipHandover_pendingOwnerPowerlessUntilAccept_oldOwnerPowerlessAfter() (gas: 508379)\n[PASS] test_payoutChangeAfterClaimDoesNotAllowSecondClaim() (gas: 528970)\n[PASS] test_payoutMovedTwice_onlyLatestWalletIsPaid_andOldWalletLosesControl() (gas: 569371)\n[PASS] test_proofCannotBeRedirectedToAnotherGameOrAmount() (gas: 564150)\n[PASS] test_proofForOneMonthDoesNotWorkInAnother_evenWithTheSameRoot() (gas: 732471)\n[PASS] test_proposeExactlyFree_thenOneMoreWeiFails() (gas: 544553)\n[PASS] test_proposeSameMonthTwiceWithoutCancelReverts() (gas: 575778)\n[PASS] test_reentrancy_claimFromPayoutHookIsBlocked() (gas: 1828187)\n[PASS] test_reentrancy_fundFromPayoutHookIsBlocked() (gas: 1715706)\n[PASS] test_reentrancy_swallowedReentryLeavesAccountingSound() (gas: 2011627)\n[PASS] test_reentrancy_sweepFromPayoutHookFindsWindowOpen() (gas: 1718861)\n[PASS] test_relistKeepsCurrentPayoutWallet() (gas: 140852)\n[PASS] test_sweep_exactBoundaryOnceAndNotWhilePendingOrOpen() (gas: 698340)\n[PASS] test_tokenReturningFalse_claimAndFundRevertAndRollBack() (gas: 1139536)\n[PASS] test_tokenWithoutReturnValue_worksForFundAndClaim() (gas: 752811)\n[PASS] test_yearRollover() (gas: 842476)\n[PASS] test_zeroAmountLeafIsRefusedEvenIfInTheTree() (gas: 352520)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 42.26ms (47.58ms CPU time)\n\nRan 7 tests for test/DeployScripts.t.sol:DeployScriptsTest\n[PASS] test_mainnetScript_deploysWithTokenAndOwnerAndNoGames() (gas: 4096491)\nLogs:\n  OGClubCreatorPool: 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac\n    token: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    owner: 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266\n    constructor args (abi-encoded, for forge verify-contract --constructor-args):\n  0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000007c8999dc9a822c1f0df42023113edb4fdd543266\n\n[PASS] test_mainnetScript_rejectsZeroToken() (gas: 2142600)\n[PASS] test_sepoliaScript_deploysMockListsGamesAndHandsOver() (gas: 5274686)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_emptyListIsFine() (gas: 5123579)\nLogs:\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_parsesGames() (gas: 3120074)\n[PASS] test_sepoliaScript_rejectsBadPayout() (gas: 5105311)\n[PASS] test_sepoliaScript_sameOwnerSkipsHandover() (gas: 5176067)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 42.45ms (118.35ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.invariant.t.sol:OGClubCreatorPoolInvariantTest\n[PASS]\nOGClubCreatorPoolInvariantTest invariants:\n[PASS] invariant_balanceCoversReserved\n[PASS] invariant_conservation\n[PASS] invariant_ownerNeverGainsOG\n[PASS] invariant_reservedIsSumOfRemaining\n OGClubCreatorPoolInvariantTest invariants (runs: 64, calls: 4096, reverts: 0)\n\n╭-------------+---------------+-------+---------+----------╮\n| Contract    | Selector      | Calls | Reverts | Discards |\n+==========================================================+\n| PoolHandler | cancel        | 448   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | changePayout  | 447   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | claim         | 432   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | fund          | 450   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | propose       | 495   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | sweep         | 457   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | toggleListing | 426   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | transferIn    | 468   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | warp          | 473   | 0       | 0        |\n╰-------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 2\n  Bound result 3\n  Bound result 64\n  Bound result 190\n  Bound result 2\n  Bound result 5\n  Bound result 3856056066\n  Bound result 3\n  Bound result 3\n  Bound result 1226\n  Bound result 246\n  Bound result 3\n  Bound result 123\n  Bound result 0\n  Bound result 0\n  Bound result 467\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1000001\n  Bound result 3\n  Bound result 2057\n  Bound result 223\n  Bound result 887217811883949069578915\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1022\n  Bound result 0\n  Bound result 0\n  Bound result 300000000000000000000\n  Bound result 5\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 12064\n  Bound result 3\n  Bound result 112482188116047074351179\n  Bound result 29361702562790762618404\n  Bound result 25163562213453797463745\n  Bound result 22322099463855044668346\n  Bound result 5\n  Bound result 0\n  Bound result 1\n  Bound result 42000000000000000000\n  Bound result 0\n  Bound result 0\n  Bound result 259200\n  Bound result 3\n  Bound result 7563\n  Bound result 2\n  Bound result 0\n  Bound result 417864309969283415311566\n  Bound result 2112000\n  Bound result 3\n  Bound result 1633\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 5340\n  Bound result 794\n  Bound result 245\n  Bound result 0\n  Bound result 678\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 5094\n  Bound result 482\n  Bound result 543\n  Bound result 999999999999999999999997\n  Bound result 1\n  Bound result 2185686\n  Bound result 0\n  Bound result 1822\n  Bound result 35000000000000000000\n  Bound result 1\n  Bound result 40000000000000000000\n  Bound result 34988501545438359661\n  Bound result 5\n  Bound result 6963\n  Bound result 150\n  Bound result 918\n  Bound result 824\n  Bound result 1226\n  Bound result 831\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 474.35ms (471.84ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.actors.invariant.t.sol:OGClubCreatorPoolActorsInvariantTest\n[PASS]\nOGClubCreatorPoolActorsInvariantTest invariants:\n[PASS] invariant_balanceCoversReservedAndConserves\n[PASS] invariant_onlyPayoutWalletsEverReceive\n[PASS] invariant_ownerAndTokenFixed\n[PASS] invariant_poolAgreesWithModelOnEveryAttempt\n[PASS] invariant_reservedIsSumOfOpenMonthsRemaining_andMonthsNeverOverpay\n OGClubCreatorPoolActorsInvariantTest invariants (runs: 128, calls: 15360, reverts: 13)\n\n╭---------------+--------------------+-------+---------+----------╮\n| Contract      | Selector           | Calls | Reverts | Discards |\n+=================================================================+\n| ActorsHandler | cancel             | 1024  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | changePayout       | 1017  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | claim              | 1007  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | claimOpen          | 1021  | 7       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | forgedClaim        | 1064  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | fund               | 1044  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | ownerChangesPayout | 1013  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | propose            | 1015  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | proposeBad         | 1006  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | strangerOwnerCall  | 999   | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | sweep              | 1048  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | sweepClosed        | 991   | 6       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | toggleListing      | 1023  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | transferIn         | 1054  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | warp               | 1034  | 0       | 0        |\n╰---------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 2\n  Bound result 544562483646282773430272\n  Bound result 10000\n  Bound result 1\n  Bound result 1626\n  Bound result 23\n  Bound result 1\n  Bound result 3\n  Bound result 1790000007\n  Bound result 566286863523773954249006\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 202611\n  Bound result 185287\n  Bound result 83528\n  Bound result 3\n  Bound result 1\n  Bound result 499000000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 99000000000000000000\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 1\n  Bound result 1\n  Bound result 12213\n  Bound result 2\n  Bound result 1\n  Bound result 123000000000000000000\n  Bound result 14387145120094799525\n  Bound result 4\n  Bound result 117300738\n  Bound result 27066323\n  Bound result 58744366\n  Bound result 66252047\n  Bound result 43190715\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 25000000000000000000\n  Bound result 42000000000000000000\n  Bound result 116293\n  Bound result 2\n  Bound result 1\n  Bound result 33\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1638\n  Bound result 14865\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 2\n  Bound result 929\n  Bound result 1985746333\n  Bound result 13\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 3\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 14875\n  Bound result 0\n  Bound result 0\n  Bound result 5300\n  Bound result 4\n  Bound result 128000\n  Bound result 2\n  Bound result 2\n  Bound result 3106\n  Bound result 3\n  Bound result 0\n  Bound result 7105\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 3\n  Bound result 400000000000000000000\n  Bound result 4\n  Bound result 8002\n  Bound result 5\n  Bound result 7775\n  Bound result 7351\n  Bound result 6288\n  Bound result 483\n  Bound result 1144\n  Bound result 5889\n  Bound result 4755323\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 115651\n  Bound result 3\n  Bound result 3\n  Bound result 4\n  Bound result 3\n  Bound result 371\n  Bound result 0\n  Bound result 999999999999999999999998\n  Bound result 4322731\n  Bound result 1903\n  Bound result 4\n  Bound result 105934556605004389041004\n  Bound result 4576\n  Bound result 239\n  Bound result 3\n  Bound result 14421060\n  Bound result 2\n  Bound result 17095\n  Bound result 7001\n  Bound result 5224\n  Bound result 3\n  Bound result 796\n  Bound result 2\n  Bound result 4\n  Bound result 2\n  Bound result 1\n  Bound result 760406886145281280232872\n  Bound result 737261249270243758087498\n  Bound result 3\n  Bound result 5\n  Bound result 545103483646286463408455\n  Bound result 72438447266503668350338\n  Bound result 12930045852677376161131\n  Bound result 7111077830955444100686\n  Bound result 181436939673882730482571\n  Bound result 236172802719181098879220\n  Bound result 9310\n  Bound result 0\n  Bound result 4\n  Bound result 17476\n  Bound result 3\n  Bound result 1\n  Bound result 146464205210273133793369\n  Bound result 17721568895624806019054\n  Bound result 3\n  Bound result 6000000000000000000\n  Bound result 143917959085393392\n  Bound result 569750049132660808\n  Bound result 430022091022976353\n  Bound result 60000000000000000000\n  Bound result 0\n  Bound result 0\n  Bound result 361414176\n  Bound result 4\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 823089650342941853215\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 55027\n  Bound result 4752150\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 3107\n  Bound result 1\n  Bound result 100000000000000000001\n  Bound result 75383512607025124787\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.41s (3.41s CPU time)\n\nRan 7 test suites in 3.41s (4.10s CPU time): 100 tests passed, 0 failed, 0 skipped (100 total tests)\n","passed":true},{"durationMs":43,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubCreatorPool.acceptOwnership()\",\"OGClubCreatorPool.cancelMonth(uint256)\",\"OGClubCreatorPool.changePayout(bytes32,address)\",\"OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[])\",\"OGClubCreatorPool.delistGame(bytes32)\",\"OGClubCreatorPool.fund(uint256)\",\"OGClubCreatorPool.listGame(bytes32,address)\",\"OGClubCreatorPool.proposeMonth(uint256,bytes32,uint256)\",\"OGClubCreatorPool.relistGame(bytes32)\",\"OGClubCreatorPool.renounceOwnership()\",\"OGClubCreatorPool.sweep(uint256)\",\"OGClubCreatorPool.transferOwnership(address)\"],\"files\":{\".gitignore\":5,\"README.md\":198,\"foundry.toml\":28,\"remappings.txt\":2,\"script/DeployCreatorPool.s.sol\":38,\"script/DeployCreatorPoolSepolia.s.sol\":77,\"script/config/sepolia-games.example.json\":5,\"src/OGClubCreatorPool.sol\":318,\"test/DeployScripts.t.sol\":97,\"test/OGClubCreatorPool.actors.invariant.t.sol\":440,\"test/OGClubCreatorPool.adversarial.t.sol\":801,\"test/OGClubCreatorPool.fuzz.t.sol\":126,\"test/OGClubCreatorPool.integration.t.sol\":121,\"test/OGClubCreatorPool.invariant.t.sol\":193,\"test/OGClubCreatorPool.t.sol\":861,\"test/support/FeeOnTransferToken.sol\":30,\"test/support/Merkle.sol\":48,\"test/support/MockOG.sol\":13,\"test/support/OGClubFarmVault.sol\":79},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"2cabbc38cb531124d3642119132afd41152bbededbe5fd1c4702517b09b607ee","verifiedTreeHash":"8defa53246f7841f6164efc3dd00e92570ebc4e6","verifierVersion":"0.1.0+fa479356"},{"checks":[{"durationMs":2651,"exitCode":0,"name":"build","output":"Compiling 47 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.57s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/OGClubCreatorPool.fuzz.t.sol:95:14:\n   |\n95 |         for (uint256 i; i < 3; ++i) {\n   |              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/OGClubCreatorPool.fuzz.t.sol:104:9:\n    |\n104 |         uint256 i = bound(which, 0, 2);\n    |         ^^^^^^^^^\n\n","passed":true},{"durationMs":715,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/OGClubCreatorPool.fuzz.t.sol:OGClubCreatorPoolFuzzTest\n[PASS] testFuzz_forgedLeafRejected(uint256,uint256,uint8) (runs: 256, μ: 354837, ~: 354980)\nLogs:\n  Bound result 2\n  Bound result 340282366920938463463374607431768211455\n\n[PASS] testFuzz_monthIdValidation(uint256) (runs: 256, μ: 116699, ~: 114957)\n[PASS] testFuzz_paidPerMonthNeverExceedsTotal(uint256,uint8,uint256,uint256) (runs: 256, μ: 994630, ~: 844320)\nLogs:\n  Bound result 1\n  Bound result 1000000000000000000000000\n  Bound result 994100093111533958961165\n  Bound result 239569045160042287309888\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 33.27ms (49.42ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.integration.t.sol:OGClubCreatorPoolIntegrationTest\n[PASS] test_monthCannotBeProposedBeforeVaultPays() (gas: 485559)\n[PASS] test_vaultPayoutsAcrossSeasonsAccumulateAsFree() (gas: 720303)\n[PASS] test_vaultSeasonFundsPoolThenPoolPaysGames() (gas: 1114201)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 33.28ms (852.20µs CPU time)\n\nRan 7 tests for test/DeployScripts.t.sol:DeployScriptsTest\n[PASS] test_mainnetScript_deploysWithTokenAndOwnerAndNoGames() (gas: 4466543)\nLogs:\n  OGClubCreatorPool: 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac\n    token: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    owner: 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266\n    constructor args (abi-encoded, for forge verify-contract --constructor-args):\n  0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000007c8999dc9a822c1f0df42023113edb4fdd543266\n\n[PASS] test_mainnetScript_rejectsZeroToken() (gas: 2336013)\n[PASS] test_sepoliaScript_deploysMockListsGamesAndHandsOver() (gas: 5689859)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_emptyListIsFine() (gas: 5493644)\nLogs:\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_parsesGames() (gas: 3313269)\n[PASS] test_sepoliaScript_rejectsBadPayout() (gas: 5475400)\n[PASS] test_sepoliaScript_sameOwnerSkipsHandover() (gas: 5591218)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 33.31ms (3.75ms CPU time)\n\nRan 65 tests for test/OGClubCreatorPool.t.sol:OGClubCreatorPoolTest\n[PASS] test_anyoneCanPushClaim_payoutWalletReceives() (gas: 811361)\n[PASS] test_cancelMonth_lastMonthNeverDropsBelowOpenMonth() (gas: 579806)\n[PASS] test_cancelMonth_onlyLastMonthMovesLastMonth() (gas: 533881)\n[PASS] test_cancelMonth_onlyOwnerAndMustExist() (gas: 402141)\n[PASS] test_cancelMonth_releasesAndAllowsRepropose() (gas: 808180)\n[PASS] test_cancelMonth_restoresLastMonthAfterTypo() (gas: 1026226)\n[PASS] test_cancelMonth_tooLate() (gas: 423080)\n[PASS] test_cancelMonth_walksBackOverCancelledMonths() (gas: 819071)\n[PASS] test_changePayout_byPayoutWallet() (gas: 133147)\n[PASS] test_changePayout_ownerCannot() (gas: 38396)\n[PASS] test_changePayout_rejectsZeroSelfAndPool() (gas: 95103)\n[PASS] test_changePayout_strangerCannot() (gas: 38419)\n[PASS] test_changePayout_unknownGame() (gas: 43563)\n[PASS] test_changePayout_worksWhenDelisted() (gas: 88068)\n[PASS] test_claim_cannotPayFromOtherMonthsReserve() (gas: 1130357)\n[PASS] test_claim_gameListedInProposalBlockCanClaim() (gas: 485190)\n[PASS] test_claim_lateListedGameIsPaidByTheNextMonth() (gas: 848066)\n[PASS] test_claim_reproposedMonthAcceptsGamesListedBeforeTheReproposal() (gas: 638265)\n[PASS] test_claim_revertsEarly() (gas: 520629)\n[PASS] test_claim_revertsForGameListedAfterProposal() (gas: 944360)\n[PASS] test_claim_revertsLate() (gas: 535026)\n[PASS] test_claim_revertsOverBudget() (gas: 618663)\n[PASS] test_claim_revertsTwice() (gas: 506094)\n[PASS] test_claim_revertsUnknownGame() (gas: 381037)\n[PASS] test_claim_revertsUnknownOrCancelledMonth() (gas: 460484)\n[PASS] test_claim_revertsWhenPayoutBecameOwner() (gas: 760953)\n[PASS] test_claim_revertsWrongLeaf() (gas: 854027)\n[PASS] test_constructor() (gas: 48317)\n[PASS] test_constructor_revertsOnZeroOwner() (gas: 6368)\n[PASS] test_constructor_revertsOnZeroToken() (gas: 6113)\n[PASS] test_delistRelist() (gas: 161026)\n[PASS] test_delistRelist_onlyOwner() (gas: 63163)\n[PASS] test_delistRelist_unknownGame() (gas: 70968)\n[PASS] test_delistedGameCanStillClaim() (gas: 503105)\n[PASS] test_feeOnTransfer_claimReverts() (gas: 1062627)\n[PASS] test_feeOnTransfer_claimReverts_recipientCharged() (gas: 1063646)\n[PASS] test_feeOnTransfer_fundReverts() (gas: 792635)\n[PASS] test_fullMonth_evenLeaves() (gas: 905916)\n[PASS] test_fullMonth_fiveLeavesAndSurplusFree() (gas: 985183)\n[PASS] test_fullMonth_oddLeaves() (gas: 865892)\n[PASS] test_fund_pullsExactAmount() (gas: 149051)\n[PASS] test_fund_revertsOnZero() (gas: 37271)\n[PASS] test_fund_revertsWithoutAllowance() (gas: 46123)\n[PASS] test_gameId() (gas: 14076)\n[PASS] test_isValidMonth() (gas: 46219)\n[PASS] test_listGame_emits() (gas: 93539)\n[PASS] test_listGame_onlyOnceEver() (gas: 102113)\n[PASS] test_listGame_onlyOwner() (gas: 43605)\n[PASS] test_listGame_revertsOnPoolAsPayout() (gas: 43857)\n[PASS] test_listGame_revertsOnZeroPayout() (gas: 43054)\n[PASS] test_listGame_setsPayoutAndListed() (gas: 33439)\n[PASS] test_noEthAccepted() (gas: 38775)\n[PASS] test_ownerCannotBeAPayoutWallet() (gas: 190616)\n[PASS] test_ownerHasNoWayToTakeTokens() (gas: 432610)\n[PASS] test_ownershipIsTwoStep() (gas: 116355)\n[PASS] test_payoutChangedBeforeClaim_paysNewWallet() (gas: 517769)\n[PASS] test_plainTransferCountsAsFree() (gas: 74977)\n[PASS] test_proposeMonth_onlyOwner() (gas: 151536)\n[PASS] test_proposeMonth_reservesAndSchedules() (gas: 382401)\n[PASS] test_proposeMonth_reverts() (gas: 710291)\n[PASS] test_renounceOwnershipDisabled() (gas: 31307)\n[PASS] test_singleLeafMonth() (gas: 407641)\n[PASS] test_sweep_fullyClaimedMonthIsNoop() (gas: 751863)\n[PASS] test_sweep_returnsUnclaimedToFreeAndReuse() (gas: 1144212)\n[PASS] test_sweep_unknownMonth() (gas: 32293)\nSuite result: ok. 65 passed; 0 failed; 0 skipped; finished in 33.32ms (25.89ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.invariant.t.sol:OGClubCreatorPoolInvariantTest\n[PASS]\nOGClubCreatorPoolInvariantTest invariants:\n[PASS] invariant_balanceCoversReserved\n[PASS] invariant_conservation\n[PASS] invariant_lastMonthIsHighestLiveMonth\n[PASS] invariant_ownerIsNeverAPayout\n[PASS] invariant_ownerNeverGainsOG\n[PASS] invariant_reservedIsSumOfRemaining\n OGClubCreatorPoolInvariantTest invariants (runs: 64, calls: 4096, reverts: 415)\n\n╭-------------+------------------+-------+---------+----------╮\n| Contract    | Selector         | Calls | Reverts | Discards |\n+=============================================================+\n| PoolHandler | cancel           | 409   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | changePayout     | 408   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | claim            | 408   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | fund             | 439   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | propose          | 380   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | sweep            | 421   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | toggleListing    | 422   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | transferIn       | 403   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | tryOwnerAsPayout | 415   | 415     | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | warp             | 391   | 0       | 0        |\n╰-------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 193663991531814835972249\n  Bound result 2187\n  Bound result 1\n  Bound result 286625000185825177896\n  Bound result 279191468174879865467\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 128000\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 123000000000000000000\n  Bound result 129647750131783143061199\n  Bound result 0\n  Bound result 0\n  Bound result 240\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1827\n  Bound result 0\n  Bound result 0\n  Bound result 2636\n  Bound result 0\n  Bound result 6\n  Bound result 202601\n  Bound result 29369\n  Bound result 5184\n  Bound result 17455\n  Bound result 30786\n  Bound result 4632\n  Bound result 32242\n  Bound result 42000000000000000000\n  Bound result 1\n  Bound result 203175\n  Bound result 0\n  Bound result 1\n  Bound result 30786\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 5\n  Bound result 2672\n  Bound result 2\n  Bound result 3963891460\n  Bound result 1856479216\n  Bound result 174525624\n  Bound result 1\n  Bound result 259199\n  Bound result 231589\n  Bound result 1\n  Bound result 0\n  Bound result 3\n  Bound result 999999999999999999999998\n  Bound result 1600000\n  Bound result 20\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 6\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 620.98ms (617.69ms CPU time)\n\nRan 5 test suites in 623.27ms (754.16ms CPU time): 79 tests passed, 0 failed, 0 skipped (79 total tests)\n","passed":true},{"durationMs":40,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubCreatorPool.acceptOwnership()\",\"OGClubCreatorPool.cancelMonth(uint256)\",\"OGClubCreatorPool.changePayout(bytes32,address)\",\"OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[])\",\"OGClubCreatorPool.delistGame(bytes32)\",\"OGClubCreatorPool.fund(uint256)\",\"OGClubCreatorPool.listGame(bytes32,address)\",\"OGClubCreatorPool.proposeMonth(uint256,bytes32,uint256)\",\"OGClubCreatorPool.relistGame(bytes32)\",\"OGClubCreatorPool.sweep(uint256)\",\"OGClubCreatorPool.transferOwnership(address)\"],\"files\":{\".gitignore\":5,\"README.md\":227,\"foundry.toml\":28,\"remappings.txt\":2,\"script/DeployCreatorPool.s.sol\":38,\"script/DeployCreatorPoolSepolia.s.sol\":77,\"script/config/sepolia-games.example.json\":5,\"src/OGClubCreatorPool.sol\":363,\"test/DeployScripts.t.sol\":97,\"test/OGClubCreatorPool.fuzz.t.sol\":126,\"test/OGClubCreatorPool.integration.t.sol\":121,\"test/OGClubCreatorPool.invariant.t.sol\":225,\"test/OGClubCreatorPool.t.sol\":1099,\"test/support/FeeOnTransferToken.sol\":32,\"test/support/Merkle.sol\":48,\"test/support/MockOG.sol\":13,\"test/support/OGClubFarmVault.sol\":79},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":763,"exitCode":0,"name":"slither","output":"[low/medium] timestamp at src/OGClubCreatorPool.sol:269: OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[]) (src/OGClubCreatorPool.sol#269-299) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:344: OGClubCreatorPool.isOpen(uint256) (src/OGClubCreatorPool.sol#344-348) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:303: OGClubCreatorPool.sweep(uint256) (src/OGClubCreatorPool.sol#303-316) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:244: OGClubCreatorPool.cancelMonth(uint256) (src/OGClubCreatorPool.sol#244-263) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:333: OGClubCreatorPool.status(uint256) (src/OGClubCreatorPool.sol#333-341) uses timestamp for comparisons","passed":true},{"durationMs":202,"exitCode":0,"name":"aderyn","output":"[low] centralization-risk at src/OGClubCreatorPool.sol:30: Centralization Risk (6 places)\n[low] literal-instead-of-constant at src/OGClubCreatorPool.sol:327: Literal Instead of Constant (2 places)\n[low] push-zero-opcode at src/OGClubCreatorPool.sol:2: PUSH0 Opcode\n[low] unspecific-solidity-pragma at src/OGClubCreatorPool.sol:2: Unspecific Solidity Pragma\n[low] unused-public-function at src/OGClubCreatorPool.sol:155: Public Function Not Used Internally","passed":true},{"durationMs":1390,"exitCode":0,"name":"proof e517ca509f11","output":"Compiling 40 files with Solc 0.8.26\nSolc 0.8.26 finished in 873.59ms\nCompiler run successful!\n\nRan 1 test for test/imd-proof-e3d583e7/Proof_e517ca509f11.t.sol:UnlistedLeafTest\n[PASS] test_ownerCannotRedirectOpenMonthByLateListing() (gas: 260536)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 809.08µs (178.92µs CPU time)\n\nRan 1 test suite in 2.25ms (809.08µs CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true},{"durationMs":1073,"exitCode":0,"name":"proof 5eff71f79ceb","output":"2026-10-25T11:09:39.081485Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-dnX4p9/repo/test/imd-proof-e3d583e7/Proof_e517ca509f11.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 579.91ms\nCompiler run successful!\n\nRan 1 test for test/imd-proof-ec6b41ec/Proof_5eff71f79ceb.t.sol:LastMonthCancelTest\n[PASS] test_cancelledTypoMonthDoesNotBlockEarlierMonths() (gas: 992979)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 592.81µs (455.65µs CPU time)\n\nRan 1 test suite in 2.42ms (592.81µs 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":"5251303ace131c2df84cabddaf80753333a3187138353849d8421ad13ef71def","verifiedTreeHash":"a76de8df317849079bc4705b5a0c300b69ed7d4f","verifierVersion":"0.1.0+fa479356"},{"checks":[{"durationMs":4239,"exitCode":0,"name":"build","output":"Compiling 47 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.10s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/OGClubCreatorPool.fuzz.t.sol:95:14:\n   |\n95 |         for (uint256 i; i < 3; ++i) {\n   |              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/OGClubCreatorPool.fuzz.t.sol:104:9:\n    |\n104 |         uint256 i = bound(which, 0, 2);\n    |         ^^^^^^^^^\n\n","passed":true},{"durationMs":857,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 54 tests for test/OGClubCreatorPool.t.sol:OGClubCreatorPoolTest\n[PASS] test_anyoneCanPushClaim_payoutWalletReceives() (gas: 788762)\n[PASS] test_cancelMonth_onlyOwnerAndMustExist() (gas: 399252)\n[PASS] test_cancelMonth_releasesAndAllowsRepropose() (gas: 770295)\n[PASS] test_cancelMonth_tooLate() (gas: 420115)\n[PASS] test_cancelledMonthIsNotLastMonthBarrierForOlderMonths() (gas: 510047)\n[PASS] test_changePayout_byPayoutWallet() (gas: 124457)\n[PASS] test_changePayout_ownerCannot() (gas: 38331)\n[PASS] test_changePayout_rejectsZeroSelfAndPool() (gas: 90687)\n[PASS] test_changePayout_strangerCannot() (gas: 38353)\n[PASS] test_changePayout_unknownGame() (gas: 43496)\n[PASS] test_changePayout_worksWhenDelisted() (gas: 83692)\n[PASS] test_claim_cannotPayFromOtherMonthsReserve() (gas: 1078345)\n[PASS] test_claim_revertsEarly() (gas: 511093)\n[PASS] test_claim_revertsLate() (gas: 525514)\n[PASS] test_claim_revertsOverBudget() (gas: 597971)\n[PASS] test_claim_revertsTwice() (gas: 496593)\n[PASS] test_claim_revertsUnknownGame() (gas: 378038)\n[PASS] test_claim_revertsUnknownOrCancelledMonth() (gas: 451797)\n[PASS] test_claim_revertsWrongLeaf() (gas: 810023)\n[PASS] test_constructor() (gas: 48273)\n[PASS] test_constructor_revertsOnZeroOwner() (gas: 6345)\n[PASS] test_constructor_revertsOnZeroToken() (gas: 6090)\n[PASS] test_delistRelist() (gas: 161048)\n[PASS] test_delistRelist_onlyOwner() (gas: 63118)\n[PASS] test_delistRelist_unknownGame() (gas: 70835)\n[PASS] test_delistedGameCanStillClaim() (gas: 493623)\n[PASS] test_feeOnTransfer_claimReverts() (gas: 1022134)\n[PASS] test_feeOnTransfer_fundReverts() (gas: 792524)\n[PASS] test_fullMonth_evenLeaves() (gas: 876715)\n[PASS] test_fullMonth_fiveLeavesAndSurplusFree() (gas: 949466)\n[PASS] test_fullMonth_oddLeaves() (gas: 843304)\n[PASS] test_fund_pullsExactAmount() (gas: 148942)\n[PASS] test_fund_revertsOnZero() (gas: 37270)\n[PASS] test_fund_revertsWithoutAllowance() (gas: 46056)\n[PASS] test_gameId() (gas: 14032)\n[PASS] test_isValidMonth() (gas: 46154)\n[PASS] test_listGame_emits() (gas: 68986)\n[PASS] test_listGame_onlyOnceEver() (gas: 102113)\n[PASS] test_listGame_onlyOwner() (gas: 43560)\n[PASS] test_listGame_revertsOnPoolAsPayout() (gas: 43798)\n[PASS] test_listGame_revertsOnZeroPayout() (gas: 43076)\n[PASS] test_listGame_setsPayoutAndListed() (gas: 12378)\n[PASS] test_noEthAccepted() (gas: 38732)\n[PASS] test_ownerHasNoWayToTakeTokens() (gas: 429659)\n[PASS] test_ownershipIsTwoStep() (gas: 116355)\n[PASS] test_payoutChangedBeforeClaim_paysNewWallet() (gas: 503975)\n[PASS] test_plainTransferCountsAsFree() (gas: 74999)\n[PASS] test_proposeMonth_onlyOwner() (gas: 151491)\n[PASS] test_proposeMonth_reservesAndSchedules() (gas: 379502)\n[PASS] test_proposeMonth_reverts() (gas: 684986)\n[PASS] test_singleLeafMonth() (gas: 398115)\n[PASS] test_sweep_fullyClaimedMonthIsNoop() (gas: 729181)\n[PASS] test_sweep_returnsUnclaimedToFreeAndReuse() (gas: 1098808)\n[PASS] test_sweep_unknownMonth() (gas: 32270)\nSuite result: ok. 54 passed; 0 failed; 0 skipped; finished in 4.50ms (25.30ms CPU time)\n\nRan 7 tests for test/DeployScripts.t.sol:DeployScriptsTest\n[PASS] test_mainnetScript_deploysWithTokenAndOwnerAndNoGames() (gas: 4096491)\nLogs:\n  OGClubCreatorPool: 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac\n    token: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    owner: 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266\n    constructor args (abi-encoded, for forge verify-contract --constructor-args):\n  0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000007c8999dc9a822c1f0df42023113edb4fdd543266\n\n[PASS] test_mainnetScript_rejectsZeroToken() (gas: 2142600)\n[PASS] test_sepoliaScript_deploysMockListsGamesAndHandsOver() (gas: 5274686)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_emptyListIsFine() (gas: 5123579)\nLogs:\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_parsesGames() (gas: 3120074)\n[PASS] test_sepoliaScript_rejectsBadPayout() (gas: 5105311)\n[PASS] test_sepoliaScript_sameOwnerSkipsHandover() (gas: 5176067)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 17.93ms (20.63ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.integration.t.sol:OGClubCreatorPoolIntegrationTest\n[PASS] test_monthCannotBeProposedBeforeVaultPays() (gas: 482715)\n[PASS] test_vaultPayoutsAcrossSeasonsAccumulateAsFree() (gas: 720303)\n[PASS] test_vaultSeasonFundsPoolThenPoolPaysGames() (gas: 1091603)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 48.36ms (1.49ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.fuzz.t.sol:OGClubCreatorPoolFuzzTest\n[PASS] testFuzz_forgedLeafRejected(uint256,uint256,uint8) (runs: 256, μ: 347423, ~: 347545)\nLogs:\n  Bound result 2\n  Bound result 340282366920938463463374607431768211455\n\n[PASS] testFuzz_monthIdValidation(uint256) (runs: 256, μ: 117214, ~: 114957)\n[PASS] testFuzz_paidPerMonthNeverExceedsTotal(uint256,uint8,uint256,uint256) (runs: 256, μ: 961592, ~: 823126)\nLogs:\n  Bound result 1\n  Bound result 35000000000000000000\n  Bound result 6595\n  Bound result 24668597419326467371\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 48.44ms (64.24ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.invariant.t.sol:OGClubCreatorPoolInvariantTest\n[PASS]\nOGClubCreatorPoolInvariantTest invariants:\n[PASS] invariant_balanceCoversReserved\n[PASS] invariant_conservation\n[PASS] invariant_ownerNeverGainsOG\n[PASS] invariant_reservedIsSumOfRemaining\n OGClubCreatorPoolInvariantTest invariants (runs: 64, calls: 4096, reverts: 0)\n\n╭-------------+---------------+-------+---------+----------╮\n| Contract    | Selector      | Calls | Reverts | Discards |\n+==========================================================+\n| PoolHandler | cancel        | 448   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | changePayout  | 447   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | claim         | 432   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | fund          | 450   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | propose       | 495   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | sweep         | 457   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | toggleListing | 426   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | transferIn    | 468   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | warp          | 473   | 0       | 0        |\n╰-------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 2\n  Bound result 0\n  Bound result 12\n  Bound result 190\n  Bound result 2\n  Bound result 5\n  Bound result 3856056066\n  Bound result 0\n  Bound result 3\n  Bound result 1226\n  Bound result 324\n  Bound result 225\n  Bound result 158\n  Bound result 0\n  Bound result 0\n  Bound result 467\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 3\n  Bound result 2058\n  Bound result 223\n  Bound result 887217811883949069578915\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1022\n  Bound result 5\n  Bound result 0\n  Bound result 10000000000000000000000\n  Bound result 5\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 12031\n  Bound result 3\n  Bound result 1800000000\n  Bound result 581552120\n  Bound result 3489127\n  Bound result 196759900\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 8640000\n  Bound result 0\n  Bound result 0\n  Bound result 259200\n  Bound result 4\n  Bound result 7472\n  Bound result 2\n  Bound result 0\n  Bound result 417864309969283415311566\n  Bound result 1568000\n  Bound result 3\n  Bound result 322\n  Bound result 0\n  Bound result 1\n  Bound result 6\n  Bound result 5339\n  Bound result 441\n  Bound result 162\n  Bound result 539\n  Bound result 798\n  Bound result 300\n  Bound result 181\n  Bound result 0\n  Bound result 808\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 5156\n  Bound result 2218\n  Bound result 999999999999999999999997\n  Bound result 1\n  Bound result 2185686\n  Bound result 0\n  Bound result 1868\n  Bound result 259199\n  Bound result 4\n  Bound result 4000000000000000000\n  Bound result 118110353552653699\n  Bound result 546598017023130577\n  Bound result 870906631516358117\n  Bound result 463921500111041988\n  Bound result 1\n  Bound result 1404526068550957476229204\n  Bound result 1150149194848789308390721\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 686.50ms (680.49ms CPU time)\n\nRan 5 test suites in 689.94ms (805.71ms CPU time): 68 tests passed, 0 failed, 0 skipped (68 total tests)\n","passed":true},{"durationMs":62,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubCreatorPool.acceptOwnership()\",\"OGClubCreatorPool.cancelMonth(uint256)\",\"OGClubCreatorPool.changePayout(bytes32,address)\",\"OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[])\",\"OGClubCreatorPool.delistGame(bytes32)\",\"OGClubCreatorPool.fund(uint256)\",\"OGClubCreatorPool.listGame(bytes32,address)\",\"OGClubCreatorPool.proposeMonth(uint256,bytes32,uint256)\",\"OGClubCreatorPool.relistGame(bytes32)\",\"OGClubCreatorPool.renounceOwnership()\",\"OGClubCreatorPool.sweep(uint256)\",\"OGClubCreatorPool.transferOwnership(address)\"],\"files\":{\".gitignore\":5,\"README.md\":198,\"foundry.toml\":28,\"remappings.txt\":2,\"script/DeployCreatorPool.s.sol\":38,\"script/DeployCreatorPoolSepolia.s.sol\":77,\"script/config/sepolia-games.example.json\":5,\"src/OGClubCreatorPool.sol\":318,\"test/DeployScripts.t.sol\":97,\"test/OGClubCreatorPool.fuzz.t.sol\":126,\"test/OGClubCreatorPool.integration.t.sol\":121,\"test/OGClubCreatorPool.invariant.t.sol\":193,\"test/OGClubCreatorPool.t.sol\":861,\"test/support/FeeOnTransferToken.sol\":30,\"test/support/Merkle.sol\":48,\"test/support/MockOG.sol\":13,\"test/support/OGClubFarmVault.sol\":79},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1581,"exitCode":0,"name":"slither","output":"[low/medium] timestamp at src/OGClubCreatorPool.sol:301: OGClubCreatorPool.isOpen(uint256) (src/OGClubCreatorPool.sol#301-305) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:290: OGClubCreatorPool.status(uint256) (src/OGClubCreatorPool.sol#290-298) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:233: OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[]) (src/OGClubCreatorPool.sol#233-256) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:218: OGClubCreatorPool.cancelMonth(uint256) (src/OGClubCreatorPool.sol#218-229) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubCreatorPool.sol:260: OGClubCreatorPool.sweep(uint256) (src/OGClubCreatorPool.sol#260-273) uses timestamp for comparisons","passed":true},{"durationMs":574,"exitCode":0,"name":"aderyn","output":"[low] centralization-risk at src/OGClubCreatorPool.sol:24: Centralization Risk (6 places)\n[low] literal-instead-of-constant at src/OGClubCreatorPool.sol:284: Literal Instead of Constant (2 places)\n[low] push-zero-opcode at src/OGClubCreatorPool.sol:2: PUSH0 Opcode\n[low] unspecific-solidity-pragma at src/OGClubCreatorPool.sol:2: Unspecific Solidity Pragma\n[low] unused-public-function at src/OGClubCreatorPool.sol:136: Public Function Not Used Internally","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a38815fec0099542751dd16a14dc41db13319f714638dbe28f55e13304be9336","verifiedTreeHash":"3569224db25eeb2fc38bd5542aafef760574570a","verifierVersion":"0.1.0+fa479356"},{"checks":[{"durationMs":3847,"exitCode":0,"name":"build","output":"Compiling 49 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.75s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/OGClubCreatorPool.fuzz.t.sol:95:14:\n   |\n95 |         for (uint256 i; i < 3; ++i) {\n   |              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/OGClubCreatorPool.fuzz.t.sol:104:9:\n    |\n104 |         uint256 i = bound(which, 0, 2);\n    |         ^^^^^^^^^\n\n","passed":true},{"durationMs":3415,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OGClubCreatorPool.integration.t.sol:OGClubCreatorPoolIntegrationTest\n[PASS] test_monthCannotBeProposedBeforeVaultPays() (gas: 523281)\n[PASS] test_vaultBytecodeIsTheLiveContract() (gas: 1091592)\n[PASS] test_vaultPayoutsAcrossSeasonsAccumulateAsFree() (gas: 787567)\n[PASS] test_vaultSeasonFundsPoolThenPoolPaysGames() (gas: 1194520)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.39ms (1.51ms CPU time)\n\nRan 65 tests for test/OGClubCreatorPool.t.sol:OGClubCreatorPoolTest\n[PASS] test_anyoneCanPushClaim_payoutWalletReceives() (gas: 811361)\n[PASS] test_cancelMonth_lastMonthNeverDropsBelowOpenMonth() (gas: 579806)\n[PASS] test_cancelMonth_onlyLastMonthMovesLastMonth() (gas: 533881)\n[PASS] test_cancelMonth_onlyOwnerAndMustExist() (gas: 402141)\n[PASS] test_cancelMonth_releasesAndAllowsRepropose() (gas: 808180)\n[PASS] test_cancelMonth_restoresLastMonthAfterTypo() (gas: 1026226)\n[PASS] test_cancelMonth_tooLate() (gas: 423080)\n[PASS] test_cancelMonth_walksBackOverCancelledMonths() (gas: 819071)\n[PASS] test_changePayout_byPayoutWallet() (gas: 133147)\n[PASS] test_changePayout_ownerCannot() (gas: 38396)\n[PASS] test_changePayout_rejectsZeroSelfAndPool() (gas: 95103)\n[PASS] test_changePayout_strangerCannot() (gas: 38419)\n[PASS] test_changePayout_unknownGame() (gas: 43563)\n[PASS] test_changePayout_worksWhenDelisted() (gas: 88068)\n[PASS] test_claim_cannotPayFromOtherMonthsReserve() (gas: 1130357)\n[PASS] test_claim_gameListedInProposalBlockCanClaim() (gas: 485190)\n[PASS] test_claim_lateListedGameIsPaidByTheNextMonth() (gas: 848066)\n[PASS] test_claim_reproposedMonthAcceptsGamesListedBeforeTheReproposal() (gas: 638265)\n[PASS] test_claim_revertsEarly() (gas: 520629)\n[PASS] test_claim_revertsForGameListedAfterProposal() (gas: 944360)\n[PASS] test_claim_revertsLate() (gas: 535026)\n[PASS] test_claim_revertsOverBudget() (gas: 618663)\n[PASS] test_claim_revertsTwice() (gas: 506094)\n[PASS] test_claim_revertsUnknownGame() (gas: 381037)\n[PASS] test_claim_revertsUnknownOrCancelledMonth() (gas: 460484)\n[PASS] test_claim_revertsWhenPayoutBecameOwner() (gas: 760953)\n[PASS] test_claim_revertsWrongLeaf() (gas: 854027)\n[PASS] test_constructor() (gas: 48317)\n[PASS] test_constructor_revertsOnZeroOwner() (gas: 6368)\n[PASS] test_constructor_revertsOnZeroToken() (gas: 6113)\n[PASS] test_delistRelist() (gas: 161026)\n[PASS] test_delistRelist_onlyOwner() (gas: 63163)\n[PASS] test_delistRelist_unknownGame() (gas: 70968)\n[PASS] test_delistedGameCanStillClaim() (gas: 503105)\n[PASS] test_feeOnTransfer_claimReverts() (gas: 1062627)\n[PASS] test_feeOnTransfer_claimReverts_recipientCharged() (gas: 1063646)\n[PASS] test_feeOnTransfer_fundReverts() (gas: 792635)\n[PASS] test_fullMonth_evenLeaves() (gas: 905916)\n[PASS] test_fullMonth_fiveLeavesAndSurplusFree() (gas: 985183)\n[PASS] test_fullMonth_oddLeaves() (gas: 865892)\n[PASS] test_fund_pullsExactAmount() (gas: 149051)\n[PASS] test_fund_revertsOnZero() (gas: 37271)\n[PASS] test_fund_revertsWithoutAllowance() (gas: 46123)\n[PASS] test_gameId() (gas: 14076)\n[PASS] test_isValidMonth() (gas: 46219)\n[PASS] test_listGame_emits() (gas: 93539)\n[PASS] test_listGame_onlyOnceEver() (gas: 102113)\n[PASS] test_listGame_onlyOwner() (gas: 43605)\n[PASS] test_listGame_revertsOnPoolAsPayout() (gas: 43857)\n[PASS] test_listGame_revertsOnZeroPayout() (gas: 43054)\n[PASS] test_listGame_setsPayoutAndListed() (gas: 33439)\n[PASS] test_noEthAccepted() (gas: 38775)\n[PASS] test_ownerCannotBeAPayoutWallet() (gas: 190616)\n[PASS] test_ownerHasNoWayToTakeTokens() (gas: 432610)\n[PASS] test_ownershipIsTwoStep() (gas: 116355)\n[PASS] test_payoutChangedBeforeClaim_paysNewWallet() (gas: 517769)\n[PASS] test_plainTransferCountsAsFree() (gas: 74977)\n[PASS] test_proposeMonth_onlyOwner() (gas: 151536)\n[PASS] test_proposeMonth_reservesAndSchedules() (gas: 382401)\n[PASS] test_proposeMonth_reverts() (gas: 710291)\n[PASS] test_renounceOwnershipDisabled() (gas: 31307)\n[PASS] test_singleLeafMonth() (gas: 407641)\n[PASS] test_sweep_fullyClaimedMonthIsNoop() (gas: 751863)\n[PASS] test_sweep_returnsUnclaimedToFreeAndReuse() (gas: 1144212)\n[PASS] test_sweep_unknownMonth() (gas: 32293)\nSuite result: ok. 65 passed; 0 failed; 0 skipped; finished in 3.24ms (20.65ms CPU time)\n\nRan 31 tests for test/OGClubCreatorPool.adversarial.t.sol:OGClubCreatorPoolAdversarialTest\n[PASS] test_cancel_exactBoundary() (gas: 443302)\n[PASS] test_cancelledMonth_cannotBeCancelledAgainOrSwept() (gas: 446520)\n[PASS] test_cancelledOlderMonthCannotComeBackOnceANewerOneExists() (gas: 763262)\n[PASS] test_claimByAnotherGamesWalletPaysTheClaimedGame() (gas: 481505)\n[PASS] test_claimWindow_exactBoundaries() (gas: 775068)\n[PASS] test_concurrentMonths_areIsolated() (gas: 1472435)\n[PASS] test_firstValidMonthIsJanuary2026() (gas: 314869)\n[PASS] test_fund_exactAllowanceAndOneWei() (gas: 178683)\n[PASS] test_leafForNeverListedGameIsUnclaimableUntilListed() (gas: 359071)\n[PASS] test_manyLeaves_allPaidExactly() (gas: 43761266)\n[PASS] test_overwrite_canReserveMoreThanTheCancelledVersion() (gas: 623694)\n[PASS] test_overwrite_oldRootDeadNewRootLive() (gas: 909939)\n[PASS] test_ownerHasNoOtherTokenExit_allPublicSelectorsAccountedFor() (gas: 543804)\n[PASS] test_ownershipHandover_pendingOwnerPowerlessUntilAccept_oldOwnerPowerlessAfter() (gas: 511290)\n[PASS] test_payoutChangeAfterClaimDoesNotAllowSecondClaim() (gas: 542763)\n[PASS] test_payoutMovedTwice_onlyLatestWalletIsPaid_andOldWalletLosesControl() (gas: 587520)\n[PASS] test_proofCannotBeRedirectedToAnotherGameOrAmount() (gas: 589996)\n[PASS] test_proofForOneMonthDoesNotWorkInAnother_evenWithTheSameRoot() (gas: 769306)\n[PASS] test_proposeExactlyFree_thenOneMoreWeiFails() (gas: 570164)\n[PASS] test_proposeSameMonthTwiceWithoutCancelReverts() (gas: 578323)\n[PASS] test_reentrancy_claimFromPayoutHookIsBlocked() (gas: 1885573)\n[PASS] test_reentrancy_fundFromPayoutHookIsBlocked() (gas: 1773159)\n[PASS] test_reentrancy_swallowedReentryLeavesAccountingSound() (gas: 2076627)\n[PASS] test_reentrancy_sweepFromPayoutHookFindsWindowOpen() (gas: 1776247)\n[PASS] test_relistKeepsCurrentPayoutWallet() (gas: 145208)\n[PASS] test_renounceIsRefused_andMonthsStillPayAfterAHandover() (gas: 626384)\n[PASS] test_sweep_exactBoundaryOnceAndNotWhilePendingOrOpen() (gas: 707882)\n[PASS] test_tokenReturningFalse_claimAndFundRevertAndRollBack() (gas: 1174470)\n[PASS] test_tokenWithoutReturnValue_worksForFundAndClaim() (gas: 786773)\n[PASS] test_yearRollover() (gas: 868221)\n[PASS] test_zeroAmountLeafIsRefusedEvenIfInTheTree() (gas: 355409)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 47.73ms (51.79ms CPU time)\n\nRan 7 tests for test/DeployScripts.t.sol:DeployScriptsTest\n[PASS] test_mainnetScript_deploysWithTokenAndOwnerAndNoGames() (gas: 4466543)\nLogs:\n  OGClubCreatorPool: 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac\n    token: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    owner: 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266\n    constructor args (abi-encoded, for forge verify-contract --constructor-args):\n  0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000007c8999dc9a822c1f0df42023113edb4fdd543266\n\n[PASS] test_mainnetScript_rejectsZeroToken() (gas: 2336013)\n[PASS] test_sepoliaScript_deploysMockListsGamesAndHandsOver() (gas: 5689859)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_emptyListIsFine() (gas: 5493644)\nLogs:\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_parsesGames() (gas: 3313269)\n[PASS] test_sepoliaScript_rejectsBadPayout() (gas: 5475400)\n[PASS] test_sepoliaScript_sameOwnerSkipsHandover() (gas: 5591218)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 47.73ms (5.61ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.fuzz.t.sol:OGClubCreatorPoolFuzzTest\n[PASS] testFuzz_forgedLeafRejected(uint256,uint256,uint8) (runs: 256, μ: 354854, ~: 355045)\nLogs:\n  Bound result 1\n  Bound result 1224042257895598176423898\n\n[PASS] testFuzz_monthIdValidation(uint256) (runs: 256, μ: 115581, ~: 114975)\n[PASS] testFuzz_paidPerMonthNeverExceedsTotal(uint256,uint8,uint256,uint256) (runs: 256, μ: 991666, ~: 844148)\nLogs:\n  Bound result 1\n  Bound result 1000000000000000000000000\n  Bound result 994100093111533958961165\n  Bound result 239569045160042287309888\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 47.73ms (50.04ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.invariant.t.sol:OGClubCreatorPoolInvariantTest\n[PASS]\nOGClubCreatorPoolInvariantTest invariants:\n[PASS] invariant_balanceCoversReserved\n[PASS] invariant_conservation\n[PASS] invariant_lastMonthIsHighestLiveMonth\n[PASS] invariant_ownerIsNeverAPayout\n[PASS] invariant_ownerNeverGainsOG\n[PASS] invariant_reservedIsSumOfRemaining\n OGClubCreatorPoolInvariantTest invariants (runs: 64, calls: 4096, reverts: 415)\n\n╭-------------+------------------+-------+---------+----------╮\n| Contract    | Selector         | Calls | Reverts | Discards |\n+=============================================================+\n| PoolHandler | cancel           | 409   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | changePayout     | 408   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | claim            | 408   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | fund             | 439   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | propose          | 380   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | sweep            | 421   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | toggleListing    | 422   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | transferIn       | 403   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | tryOwnerAsPayout | 415   | 415     | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | warp             | 391   | 0       | 0        |\n╰-------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 193663991531814835972249\n  Bound result 2187\n  Bound result 1\n  Bound result 286625000185825177896\n  Bound result 279191468174879865467\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 345600\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 65\n  Bound result 129647750131783143061199\n  Bound result 0\n  Bound result 0\n  Bound result 1787171\n  Bound result 2\n  Bound result 500000000000000000000\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 12776\n  Bound result 0\n  Bound result 0\n  Bound result 398\n  Bound result 5\n  Bound result 2\n  Bound result 202512\n  Bound result 18689\n  Bound result 96861\n  Bound result 1000001\n  Bound result 2\n  Bound result 293196\n  Bound result 0\n  Bound result 3\n  Bound result 2289\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 2681\n  Bound result 3\n  Bound result 946\n  Bound result 8\n  Bound result 213\n  Bound result 263\n  Bound result 2\n  Bound result 7000000000000000000\n  Bound result 2227868663056876047\n  Bound result 1088607478404842166\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 999999999999999999999998\n  Bound result 1824000\n  Bound result 2514000704\n  Bound result 0\n  Bound result 2\n  Bound result 3\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 202700\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 670.34ms (667.26ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.actors.invariant.t.sol:OGClubCreatorPoolActorsInvariantTest\n[PASS]\nOGClubCreatorPoolActorsInvariantTest invariants:\n[PASS] invariant_balanceCoversReservedAndConserves\n[PASS] invariant_onlyPayoutWalletsEverReceive\n[PASS] invariant_ownerAndTokenFixed\n[PASS] invariant_poolAgreesWithModelOnEveryAttempt\n[PASS] invariant_reservedIsSumOfOpenMonthsRemaining_andMonthsNeverOverpay\n OGClubCreatorPoolActorsInvariantTest invariants (runs: 128, calls: 15360, reverts: 16)\n\n╭---------------+--------------------+-------+---------+----------╮\n| Contract      | Selector           | Calls | Reverts | Discards |\n+=================================================================+\n| ActorsHandler | cancel             | 1024  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | changePayout       | 1017  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | claim              | 1007  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | claimOpen          | 1021  | 9       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | forgedClaim        | 1064  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | fund               | 1044  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | ownerChangesPayout | 1013  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | propose            | 1015  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | proposeBad         | 1006  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | strangerOwnerCall  | 999   | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | sweep              | 1048  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | sweepClosed        | 991   | 7       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | toggleListing      | 1023  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | transferIn         | 1054  | 0       | 0        |\n|---------------+--------------------+-------+---------+----------|\n| ActorsHandler | warp               | 1034  | 0       | 0        |\n╰---------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 2\n  Bound result 15183\n  Bound result 10000\n  Bound result 1\n  Bound result 6832\n  Bound result 5017\n  Bound result 1\n  Bound result 3\n  Bound result 1790000007\n  Bound result 15065\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 202611\n  Bound result 51831\n  Bound result 185191\n  Bound result 125058\n  Bound result 182437\n  Bound result 2\n  Bound result 0\n  Bound result 6\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 101000000000000000000\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 1\n  Bound result 1\n  Bound result 13544\n  Bound result 2\n  Bound result 2\n  Bound result 99000000000000000000\n  Bound result 48887145120094799525\n  Bound result 30447422872990656044\n  Bound result 4\n  Bound result 6988\n  Bound result 261\n  Bound result 4842\n  Bound result 6128\n  Bound result 3471\n  Bound result 4\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 25000000000000000000\n  Bound result 2000000000000000000\n  Bound result 116293\n  Bound result 1\n  Bound result 1\n  Bound result 65\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 2026\n  Bound result 3327641369\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 2898\n  Bound result 419\n  Bound result 13\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 18342\n  Bound result 1\n  Bound result 0\n  Bound result 7586\n  Bound result 1\n  Bound result 5616001\n  Bound result 1\n  Bound result 1\n  Bound result 5647\n  Bound result 3\n  Bound result 0\n  Bound result 7105\n  Bound result 2\n  Bound result 3\n  Bound result 2\n  Bound result 3\n  Bound result 1\n  Bound result 1\n  Bound result 400000000000000000000\n  Bound result 4\n  Bound result 1294\n  Bound result 3\n  Bound result 1244\n  Bound result 806\n  Bound result 677\n  Bound result 1155\n  Bound result 4754510\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 115651\n  Bound result 3\n  Bound result 3\n  Bound result 3\n  Bound result 2\n  Bound result 576\n  Bound result 0\n  Bound result 999999999999999999999998\n  Bound result 4322731\n  Bound result 355\n  Bound result 4\n  Bound result 6664\n  Bound result 3750\n  Bound result 597\n  Bound result 4\n  Bound result 4278\n  Bound result 2\n  Bound result 598463682\n  Bound result 260677583\n  Bound result 34772758\n  Bound result 3\n  Bound result 3390906526\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 837822097695203611295080\n  Bound result 792279475046209090136210\n  Bound result 0\n  Bound result 5\n  Bound result 24417586171199670049787\n  Bound result 20569361277686640776474\n  Bound result 13319054778810688532676\n  Bound result 8381946859160732334721\n  Bound result 21156429009758162663848\n  Bound result 18524023980961425400208\n  Bound result 11572\n  Bound result 0\n  Bound result 6\n  Bound result 1634624358\n  Bound result 6\n  Bound result 1\n  Bound result 110314483380673382345441\n  Bound result 31525234137736683334558\n  Bound result 3\n  Bound result 35000000000000000000\n  Bound result 11196526370736623705\n  Bound result 7681546696764971246\n  Bound result 5174222311542362323\n  Bound result 202702\n  Bound result 6\n  Bound result 0\n  Bound result 361414176\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 823089650342941853215\n  Bound result 5\n  Bound result 1\n  Bound result 3\n  Bound result 55027\n  Bound result 1990\n  Bound result 1\n  Bound result 3\n  Bound result 7\n  Bound result 6146\n  Bound result 1\n  Bound result 99999999999999999999\n  Bound result 14982835971759019819\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.30s (3.30s CPU time)\n\nRan 7 test suites in 3.30s (4.12s CPU time): 112 tests passed, 0 failed, 0 skipped (112 total tests)\n","passed":true},{"durationMs":43,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubCreatorPool.acceptOwnership()\",\"OGClubCreatorPool.cancelMonth(uint256)\",\"OGClubCreatorPool.changePayout(bytes32,address)\",\"OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[])\",\"OGClubCreatorPool.delistGame(bytes32)\",\"OGClubCreatorPool.fund(uint256)\",\"OGClubCreatorPool.listGame(bytes32,address)\",\"OGClubCreatorPool.proposeMonth(uint256,bytes32,uint256)\",\"OGClubCreatorPool.relistGame(bytes32)\",\"OGClubCreatorPool.sweep(uint256)\",\"OGClubCreatorPool.transferOwnership(address)\"],\"files\":{\".gitignore\":5,\"README.md\":227,\"foundry.toml\":28,\"remappings.txt\":2,\"script/DeployCreatorPool.s.sol\":38,\"script/DeployCreatorPoolSepolia.s.sol\":77,\"script/config/sepolia-games.example.json\":5,\"src/OGClubCreatorPool.sol\":363,\"test/DeployScripts.t.sol\":97,\"test/OGClubCreatorPool.actors.invariant.t.sol\":445,\"test/OGClubCreatorPool.adversarial.t.sol\":809,\"test/OGClubCreatorPool.fuzz.t.sol\":126,\"test/OGClubCreatorPool.integration.t.sol\":162,\"test/OGClubCreatorPool.invariant.t.sol\":225,\"test/OGClubCreatorPool.t.sol\":1099,\"test/support/FeeOnTransferToken.sol\":32,\"test/support/Merkle.sol\":48,\"test/support/MockOG.sol\":13,\"test/support/OGClubFarmVaultBytecode.sol\":45},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a696be4aef72b4746c1f3bb780953fa11ed1afb1c80411913d031f998dd25e2a","verifiedTreeHash":"bb8244ce37e613128b68d100d2b0040325783e0f","verifierVersion":"0.1.0+fa479356"},{"checks":[{"durationMs":2200,"exitCode":0,"name":"build","output":"Compiling 47 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.12s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/OGClubCreatorPool.fuzz.t.sol:95:14:\n   |\n95 |         for (uint256 i; i < 3; ++i) {\n   |              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/OGClubCreatorPool.fuzz.t.sol:104:9:\n    |\n104 |         uint256 i = bound(which, 0, 2);\n    |         ^^^^^^^^^\n\n","passed":true},{"durationMs":521,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 54 tests for test/OGClubCreatorPool.t.sol:OGClubCreatorPoolTest\n[PASS] test_anyoneCanPushClaim_payoutWalletReceives() (gas: 788762)\n[PASS] test_cancelMonth_onlyOwnerAndMustExist() (gas: 399252)\n[PASS] test_cancelMonth_releasesAndAllowsRepropose() (gas: 770295)\n[PASS] test_cancelMonth_tooLate() (gas: 420115)\n[PASS] test_cancelledMonthIsNotLastMonthBarrierForOlderMonths() (gas: 510047)\n[PASS] test_changePayout_byPayoutWallet() (gas: 124457)\n[PASS] test_changePayout_ownerCannot() (gas: 38331)\n[PASS] test_changePayout_rejectsZeroSelfAndPool() (gas: 90687)\n[PASS] test_changePayout_strangerCannot() (gas: 38353)\n[PASS] test_changePayout_unknownGame() (gas: 43496)\n[PASS] test_changePayout_worksWhenDelisted() (gas: 83692)\n[PASS] test_claim_cannotPayFromOtherMonthsReserve() (gas: 1078345)\n[PASS] test_claim_revertsEarly() (gas: 511093)\n[PASS] test_claim_revertsLate() (gas: 525514)\n[PASS] test_claim_revertsOverBudget() (gas: 597971)\n[PASS] test_claim_revertsTwice() (gas: 496593)\n[PASS] test_claim_revertsUnknownGame() (gas: 378038)\n[PASS] test_claim_revertsUnknownOrCancelledMonth() (gas: 451797)\n[PASS] test_claim_revertsWrongLeaf() (gas: 810023)\n[PASS] test_constructor() (gas: 48273)\n[PASS] test_constructor_revertsOnZeroOwner() (gas: 6345)\n[PASS] test_constructor_revertsOnZeroToken() (gas: 6090)\n[PASS] test_delistRelist() (gas: 161048)\n[PASS] test_delistRelist_onlyOwner() (gas: 63118)\n[PASS] test_delistRelist_unknownGame() (gas: 70835)\n[PASS] test_delistedGameCanStillClaim() (gas: 493623)\n[PASS] test_feeOnTransfer_claimReverts() (gas: 1022134)\n[PASS] test_feeOnTransfer_fundReverts() (gas: 792524)\n[PASS] test_fullMonth_evenLeaves() (gas: 876715)\n[PASS] test_fullMonth_fiveLeavesAndSurplusFree() (gas: 949466)\n[PASS] test_fullMonth_oddLeaves() (gas: 843304)\n[PASS] test_fund_pullsExactAmount() (gas: 148942)\n[PASS] test_fund_revertsOnZero() (gas: 37270)\n[PASS] test_fund_revertsWithoutAllowance() (gas: 46056)\n[PASS] test_gameId() (gas: 14032)\n[PASS] test_isValidMonth() (gas: 46154)\n[PASS] test_listGame_emits() (gas: 68986)\n[PASS] test_listGame_onlyOnceEver() (gas: 102113)\n[PASS] test_listGame_onlyOwner() (gas: 43560)\n[PASS] test_listGame_revertsOnPoolAsPayout() (gas: 43798)\n[PASS] test_listGame_revertsOnZeroPayout() (gas: 43076)\n[PASS] test_listGame_setsPayoutAndListed() (gas: 12378)\n[PASS] test_noEthAccepted() (gas: 38732)\n[PASS] test_ownerHasNoWayToTakeTokens() (gas: 429659)\n[PASS] test_ownershipIsTwoStep() (gas: 116355)\n[PASS] test_payoutChangedBeforeClaim_paysNewWallet() (gas: 503975)\n[PASS] test_plainTransferCountsAsFree() (gas: 74999)\n[PASS] test_proposeMonth_onlyOwner() (gas: 151491)\n[PASS] test_proposeMonth_reservesAndSchedules() (gas: 379502)\n[PASS] test_proposeMonth_reverts() (gas: 684986)\n[PASS] test_singleLeafMonth() (gas: 398115)\n[PASS] test_sweep_fullyClaimedMonthIsNoop() (gas: 729181)\n[PASS] test_sweep_returnsUnclaimedToFreeAndReuse() (gas: 1098808)\n[PASS] test_sweep_unknownMonth() (gas: 32270)\nSuite result: ok. 54 passed; 0 failed; 0 skipped; finished in 2.33ms (18.58ms CPU time)\n\nRan 7 tests for test/DeployScripts.t.sol:DeployScriptsTest\n[PASS] test_mainnetScript_deploysWithTokenAndOwnerAndNoGames() (gas: 4096491)\nLogs:\n  OGClubCreatorPool: 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac\n    token: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    owner: 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266\n    constructor args (abi-encoded, for forge verify-contract --constructor-args):\n  0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000007c8999dc9a822c1f0df42023113edb4fdd543266\n\n[PASS] test_mainnetScript_rejectsZeroToken() (gas: 2142600)\n[PASS] test_sepoliaScript_deploysMockListsGamesAndHandsOver() (gas: 5274686)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_emptyListIsFine() (gas: 5123579)\nLogs:\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_parsesGames() (gas: 3120074)\n[PASS] test_sepoliaScript_rejectsBadPayout() (gas: 5105311)\n[PASS] test_sepoliaScript_sameOwnerSkipsHandover() (gas: 5176067)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 2.47ms (10.55ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.integration.t.sol:OGClubCreatorPoolIntegrationTest\n[PASS] test_monthCannotBeProposedBeforeVaultPays() (gas: 482715)\n[PASS] test_vaultPayoutsAcrossSeasonsAccumulateAsFree() (gas: 720303)\n[PASS] test_vaultSeasonFundsPoolThenPoolPaysGames() (gas: 1091603)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 38.67ms (1.45ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.fuzz.t.sol:OGClubCreatorPoolFuzzTest\n[PASS] testFuzz_forgedLeafRejected(uint256,uint256,uint8) (runs: 256, μ: 347423, ~: 347545)\nLogs:\n  Bound result 2\n  Bound result 340282366920938463463374607431768211455\n\n[PASS] testFuzz_monthIdValidation(uint256) (runs: 256, μ: 117214, ~: 114957)\n[PASS] testFuzz_paidPerMonthNeverExceedsTotal(uint256,uint8,uint256,uint256) (runs: 256, μ: 961592, ~: 823126)\nLogs:\n  Bound result 5\n  Bound result 7662858\n  Bound result 286843278264645116942630\n  Bound result 5012366\n  Bound result 7039180\n  Bound result 4174248\n  Bound result 1389963\n  Bound result 3368376\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 38.71ms (51.85ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.invariant.t.sol:OGClubCreatorPoolInvariantTest\n[PASS]\nOGClubCreatorPoolInvariantTest invariants:\n[PASS] invariant_balanceCoversReserved\n[PASS] invariant_conservation\n[PASS] invariant_ownerNeverGainsOG\n[PASS] invariant_reservedIsSumOfRemaining\n OGClubCreatorPoolInvariantTest invariants (runs: 64, calls: 4096, reverts: 0)\n\n╭-------------+---------------+-------+---------+----------╮\n| Contract    | Selector      | Calls | Reverts | Discards |\n+==========================================================+\n| PoolHandler | cancel        | 448   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | changePayout  | 447   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | claim         | 432   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | fund          | 450   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | propose       | 495   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | sweep         | 457   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | toggleListing | 426   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | transferIn    | 468   | 0       | 0        |\n|-------------+---------------+-------+---------+----------|\n| PoolHandler | warp          | 473   | 0       | 0        |\n╰-------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 2\n  Bound result 0\n  Bound result 12\n  Bound result 190\n  Bound result 2\n  Bound result 5\n  Bound result 3856056066\n  Bound result 0\n  Bound result 3\n  Bound result 1226\n  Bound result 324\n  Bound result 225\n  Bound result 158\n  Bound result 0\n  Bound result 0\n  Bound result 467\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 3\n  Bound result 2058\n  Bound result 223\n  Bound result 887217811883949069578915\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1022\n  Bound result 5\n  Bound result 0\n  Bound result 10000000000000000000000\n  Bound result 5\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 12031\n  Bound result 3\n  Bound result 1800000000\n  Bound result 581552120\n  Bound result 3489127\n  Bound result 196759900\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 8640000\n  Bound result 0\n  Bound result 0\n  Bound result 259200\n  Bound result 4\n  Bound result 7472\n  Bound result 2\n  Bound result 0\n  Bound result 417864309969283415311566\n  Bound result 1568000\n  Bound result 3\n  Bound result 322\n  Bound result 0\n  Bound result 1\n  Bound result 6\n  Bound result 5339\n  Bound result 441\n  Bound result 162\n  Bound result 539\n  Bound result 798\n  Bound result 300\n  Bound result 181\n  Bound result 0\n  Bound result 808\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 5156\n  Bound result 2218\n  Bound result 999999999999999999999997\n  Bound result 1\n  Bound result 2185686\n  Bound result 0\n  Bound result 1868\n  Bound result 259199\n  Bound result 4\n  Bound result 4000000000000000000\n  Bound result 118110353552653699\n  Bound result 546598017023130577\n  Bound result 870906631516358117\n  Bound result 463921500111041988\n  Bound result 1\n  Bound result 1404526068550957476229204\n  Bound result 1150149194848789308390721\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 425.85ms (422.63ms CPU time)\n\nRan 5 test suites in 428.60ms (508.03ms CPU time): 68 tests passed, 0 failed, 0 skipped (68 total tests)\n","passed":true},{"durationMs":37,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubCreatorPool.acceptOwnership()\",\"OGClubCreatorPool.cancelMonth(uint256)\",\"OGClubCreatorPool.changePayout(bytes32,address)\",\"OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[])\",\"OGClubCreatorPool.delistGame(bytes32)\",\"OGClubCreatorPool.fund(uint256)\",\"OGClubCreatorPool.listGame(bytes32,address)\",\"OGClubCreatorPool.proposeMonth(uint256,bytes32,uint256)\",\"OGClubCreatorPool.relistGame(bytes32)\",\"OGClubCreatorPool.renounceOwnership()\",\"OGClubCreatorPool.sweep(uint256)\",\"OGClubCreatorPool.transferOwnership(address)\"],\"files\":{\".gitignore\":5,\"README.md\":198,\"foundry.toml\":28,\"launch.json\":13,\"remappings.txt\":2,\"script/DeployCreatorPool.s.sol\":38,\"script/DeployCreatorPoolSepolia.s.sol\":77,\"script/config/sepolia-games.example.json\":5,\"src/OGClubCreatorPool.sol\":318,\"test/DeployScripts.t.sol\":97,\"test/OGClubCreatorPool.fuzz.t.sol\":126,\"test/OGClubCreatorPool.integration.t.sol\":121,\"test/OGClubCreatorPool.invariant.t.sol\":193,\"test/OGClubCreatorPool.t.sol\":861,\"test/support/FeeOnTransferToken.sol\":30,\"test/support/Merkle.sol\":48,\"test/support/MockOG.sol\":13,\"test/support/OGClubFarmVault.sol\":79},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"af8938cc384abeada4f5d2d45f48cb7dd5cca5d0660901d158fe06c3b1a3c933","verifiedTreeHash":"e9c11729dbc38f461b44cfe80ce70238979efb4f","verifierVersion":"0.1.0+fa479356"},{"checks":[{"durationMs":2594,"exitCode":0,"name":"build","output":"Compiling 47 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.51s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/OGClubCreatorPool.fuzz.t.sol:95:14:\n   |\n95 |         for (uint256 i; i < 3; ++i) {\n   |              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/OGClubCreatorPool.fuzz.t.sol:104:9:\n    |\n104 |         uint256 i = bound(which, 0, 2);\n    |         ^^^^^^^^^\n\n","passed":true},{"durationMs":732,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 7 tests for test/DeployScripts.t.sol:DeployScriptsTest\n[PASS] test_mainnetScript_deploysWithTokenAndOwnerAndNoGames() (gas: 4466543)\nLogs:\n  OGClubCreatorPool: 0xffD4505B3452Dc22f8473616d50503bA9E1710Ac\n    token: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    owner: 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266\n    constructor args (abi-encoded, for forge verify-contract --constructor-args):\n  0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000007c8999dc9a822c1f0df42023113edb4fdd543266\n\n[PASS] test_mainnetScript_rejectsZeroToken() (gas: 2336013)\n[PASS] test_sepoliaScript_deploysMockListsGamesAndHandsOver() (gas: 5689859)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_emptyListIsFine() (gas: 5493644)\nLogs:\n    ownership offered to 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 (must call acceptOwnership)\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\n[PASS] test_sepoliaScript_parsesGames() (gas: 3313269)\n[PASS] test_sepoliaScript_rejectsBadPayout() (gas: 5475400)\n[PASS] test_sepoliaScript_sameOwnerSkipsHandover() (gas: 5591218)\nLogs:\n    listed coin-dash -> 0xe502cDeB29B3BB515138A7F4d39D05CFB9E33557\n  0xce651833fd553539407c1130ef7f245e81b7fa924a0759323979b6a4f771c4b5\n    listed rocket-run -> 0x74b4Ac123147157a4e3517335BdcED13A74e3043\n  0xcd32e29dd74adc10b5bfc1a714e711c414b6b41a9ef43b759257ff05ecfdbd60\n  MockOG: 0x104fBc016F4bb334D775a19E8A6510109AC63E00\n  OGClubCreatorPool: 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3\n    constructor args (abi-encoded):\n  0x000000000000000000000000104fbc016f4bb334d775a19e8a6510109ac63e000000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 35.26ms (4.71ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.fuzz.t.sol:OGClubCreatorPoolFuzzTest\n[PASS] testFuzz_forgedLeafRejected(uint256,uint256,uint8) (runs: 256, μ: 354837, ~: 354980)\nLogs:\n  Bound result 2\n  Bound result 340282366920938463463374607431768211455\n\n[PASS] testFuzz_monthIdValidation(uint256) (runs: 256, μ: 116699, ~: 114957)\n[PASS] testFuzz_paidPerMonthNeverExceedsTotal(uint256,uint8,uint256,uint256) (runs: 256, μ: 994630, ~: 844320)\nLogs:\n  Bound result 1\n  Bound result 1000000000000000000000000\n  Bound result 994100093111533958961165\n  Bound result 239569045160042287309888\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 37.36ms (51.07ms CPU time)\n\nRan 3 tests for test/OGClubCreatorPool.integration.t.sol:OGClubCreatorPoolIntegrationTest\n[PASS] test_monthCannotBeProposedBeforeVaultPays() (gas: 485559)\n[PASS] test_vaultPayoutsAcrossSeasonsAccumulateAsFree() (gas: 720303)\n[PASS] test_vaultSeasonFundsPoolThenPoolPaysGames() (gas: 1114201)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 37.38ms (1.13ms CPU time)\n\nRan 65 tests for test/OGClubCreatorPool.t.sol:OGClubCreatorPoolTest\n[PASS] test_anyoneCanPushClaim_payoutWalletReceives() (gas: 811361)\n[PASS] test_cancelMonth_lastMonthNeverDropsBelowOpenMonth() (gas: 579806)\n[PASS] test_cancelMonth_onlyLastMonthMovesLastMonth() (gas: 533881)\n[PASS] test_cancelMonth_onlyOwnerAndMustExist() (gas: 402141)\n[PASS] test_cancelMonth_releasesAndAllowsRepropose() (gas: 808180)\n[PASS] test_cancelMonth_restoresLastMonthAfterTypo() (gas: 1026226)\n[PASS] test_cancelMonth_tooLate() (gas: 423080)\n[PASS] test_cancelMonth_walksBackOverCancelledMonths() (gas: 819071)\n[PASS] test_changePayout_byPayoutWallet() (gas: 133147)\n[PASS] test_changePayout_ownerCannot() (gas: 38396)\n[PASS] test_changePayout_rejectsZeroSelfAndPool() (gas: 95103)\n[PASS] test_changePayout_strangerCannot() (gas: 38419)\n[PASS] test_changePayout_unknownGame() (gas: 43563)\n[PASS] test_changePayout_worksWhenDelisted() (gas: 88068)\n[PASS] test_claim_cannotPayFromOtherMonthsReserve() (gas: 1130357)\n[PASS] test_claim_gameListedInProposalBlockCanClaim() (gas: 485190)\n[PASS] test_claim_lateListedGameIsPaidByTheNextMonth() (gas: 848066)\n[PASS] test_claim_reproposedMonthAcceptsGamesListedBeforeTheReproposal() (gas: 638265)\n[PASS] test_claim_revertsEarly() (gas: 520629)\n[PASS] test_claim_revertsForGameListedAfterProposal() (gas: 944360)\n[PASS] test_claim_revertsLate() (gas: 535026)\n[PASS] test_claim_revertsOverBudget() (gas: 618663)\n[PASS] test_claim_revertsTwice() (gas: 506094)\n[PASS] test_claim_revertsUnknownGame() (gas: 381037)\n[PASS] test_claim_revertsUnknownOrCancelledMonth() (gas: 460484)\n[PASS] test_claim_revertsWhenPayoutBecameOwner() (gas: 760953)\n[PASS] test_claim_revertsWrongLeaf() (gas: 854027)\n[PASS] test_constructor() (gas: 48317)\n[PASS] test_constructor_revertsOnZeroOwner() (gas: 6368)\n[PASS] test_constructor_revertsOnZeroToken() (gas: 6113)\n[PASS] test_delistRelist() (gas: 161026)\n[PASS] test_delistRelist_onlyOwner() (gas: 63163)\n[PASS] test_delistRelist_unknownGame() (gas: 70968)\n[PASS] test_delistedGameCanStillClaim() (gas: 503105)\n[PASS] test_feeOnTransfer_claimReverts() (gas: 1062627)\n[PASS] test_feeOnTransfer_claimReverts_recipientCharged() (gas: 1063646)\n[PASS] test_feeOnTransfer_fundReverts() (gas: 792635)\n[PASS] test_fullMonth_evenLeaves() (gas: 905916)\n[PASS] test_fullMonth_fiveLeavesAndSurplusFree() (gas: 985183)\n[PASS] test_fullMonth_oddLeaves() (gas: 865892)\n[PASS] test_fund_pullsExactAmount() (gas: 149051)\n[PASS] test_fund_revertsOnZero() (gas: 37271)\n[PASS] test_fund_revertsWithoutAllowance() (gas: 46123)\n[PASS] test_gameId() (gas: 14076)\n[PASS] test_isValidMonth() (gas: 46219)\n[PASS] test_listGame_emits() (gas: 93539)\n[PASS] test_listGame_onlyOnceEver() (gas: 102113)\n[PASS] test_listGame_onlyOwner() (gas: 43605)\n[PASS] test_listGame_revertsOnPoolAsPayout() (gas: 43857)\n[PASS] test_listGame_revertsOnZeroPayout() (gas: 43054)\n[PASS] test_listGame_setsPayoutAndListed() (gas: 33439)\n[PASS] test_noEthAccepted() (gas: 38775)\n[PASS] test_ownerCannotBeAPayoutWallet() (gas: 190616)\n[PASS] test_ownerHasNoWayToTakeTokens() (gas: 432610)\n[PASS] test_ownershipIsTwoStep() (gas: 116355)\n[PASS] test_payoutChangedBeforeClaim_paysNewWallet() (gas: 517769)\n[PASS] test_plainTransferCountsAsFree() (gas: 74977)\n[PASS] test_proposeMonth_onlyOwner() (gas: 151536)\n[PASS] test_proposeMonth_reservesAndSchedules() (gas: 382401)\n[PASS] test_proposeMonth_reverts() (gas: 710291)\n[PASS] test_renounceOwnershipDisabled() (gas: 31307)\n[PASS] test_singleLeafMonth() (gas: 407641)\n[PASS] test_sweep_fullyClaimedMonthIsNoop() (gas: 751863)\n[PASS] test_sweep_returnsUnclaimedToFreeAndReuse() (gas: 1144212)\n[PASS] test_sweep_unknownMonth() (gas: 32293)\nSuite result: ok. 65 passed; 0 failed; 0 skipped; finished in 37.42ms (27.85ms CPU time)\n\nRan 1 test for test/OGClubCreatorPool.invariant.t.sol:OGClubCreatorPoolInvariantTest\n[PASS]\nOGClubCreatorPoolInvariantTest invariants:\n[PASS] invariant_balanceCoversReserved\n[PASS] invariant_conservation\n[PASS] invariant_lastMonthIsHighestLiveMonth\n[PASS] invariant_ownerIsNeverAPayout\n[PASS] invariant_ownerNeverGainsOG\n[PASS] invariant_reservedIsSumOfRemaining\n OGClubCreatorPoolInvariantTest invariants (runs: 64, calls: 4096, reverts: 415)\n\n╭-------------+------------------+-------+---------+----------╮\n| Contract    | Selector         | Calls | Reverts | Discards |\n+=============================================================+\n| PoolHandler | cancel           | 409   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | changePayout     | 408   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | claim            | 408   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | fund             | 439   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | propose          | 380   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | sweep            | 421   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | toggleListing    | 422   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | transferIn       | 403   | 0       | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | tryOwnerAsPayout | 415   | 415     | 0        |\n|-------------+------------------+-------+---------+----------|\n| PoolHandler | warp             | 391   | 0       | 0        |\n╰-------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 193663991531814835972249\n  Bound result 2187\n  Bound result 1\n  Bound result 286625000185825177896\n  Bound result 279191468174879865467\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 128000\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 123000000000000000000\n  Bound result 129647750131783143061199\n  Bound result 0\n  Bound result 0\n  Bound result 240\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1827\n  Bound result 0\n  Bound result 0\n  Bound result 2636\n  Bound result 0\n  Bound result 6\n  Bound result 202601\n  Bound result 29369\n  Bound result 5184\n  Bound result 17455\n  Bound result 30786\n  Bound result 4632\n  Bound result 32242\n  Bound result 42000000000000000000\n  Bound result 1\n  Bound result 203175\n  Bound result 0\n  Bound result 1\n  Bound result 29369\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 5\n  Bound result 2672\n  Bound result 2\n  Bound result 3963891460\n  Bound result 1856479216\n  Bound result 174525624\n  Bound result 1\n  Bound result 259199\n  Bound result 231589\n  Bound result 1\n  Bound result 0\n  Bound result 3\n  Bound result 999999999999999999999998\n  Bound result 1600000\n  Bound result 20\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 6\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 629.24ms (626.93ms CPU time)\n\nRan 5 test suites in 631.75ms (776.66ms CPU time): 79 tests passed, 0 failed, 0 skipped (79 total tests)\n","passed":true},{"durationMs":41,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubCreatorPool.acceptOwnership()\",\"OGClubCreatorPool.cancelMonth(uint256)\",\"OGClubCreatorPool.changePayout(bytes32,address)\",\"OGClubCreatorPool.claim(uint256,bytes32,uint256,bytes32[])\",\"OGClubCreatorPool.delistGame(bytes32)\",\"OGClubCreatorPool.fund(uint256)\",\"OGClubCreatorPool.listGame(bytes32,address)\",\"OGClubCreatorPool.proposeMonth(uint256,bytes32,uint256)\",\"OGClubCreatorPool.relistGame(bytes32)\",\"OGClubCreatorPool.sweep(uint256)\",\"OGClubCreatorPool.transferOwnership(address)\"],\"files\":{\".gitignore\":5,\"README.md\":227,\"foundry.toml\":28,\"launch.json\":13,\"remappings.txt\":2,\"script/DeployCreatorPool.s.sol\":38,\"script/DeployCreatorPoolSepolia.s.sol\":77,\"script/config/sepolia-games.example.json\":5,\"src/OGClubCreatorPool.sol\":363,\"test/DeployScripts.t.sol\":97,\"test/OGClubCreatorPool.fuzz.t.sol\":126,\"test/OGClubCreatorPool.integration.t.sol\":121,\"test/OGClubCreatorPool.invariant.t.sol\":225,\"test/OGClubCreatorPool.t.sol\":1099,\"test/support/FeeOnTransferToken.sol\":32,\"test/support/Merkle.sol\":48,\"test/support/MockOG.sol\":13,\"test/support/OGClubFarmVault.sol\":79},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b5161fe0f8fbb6c0844b0ff547f34cc65c8adec3f0a283b7cb25f85f62ea8a24","verifiedTreeHash":"5e9ab5b2c265f64852ae05fb7cc5e616fd326c3f","verifierVersion":"0.1.0+fa479356"}]}