{"assessments":[],"deployments":[{"attestationHash":"3b89a47a29b702af5e0cdbd8ce87ca6c583b09994317c320c27a3db2db99ae28","chainId":11155111,"contracts":[{"address":"0x178481ac37e68a5c6ef95336db4616ba0169a17a","blockNumber":11885684,"name":"Seasons","role":"other","txHash":"0x9de8d4a7b24b04f2ee52fea389572341844d1a27d5a131f50194af83db833be8"},{"address":"0xabaecde2b71f0e3fa5d1b70f9a2bb9c24d6f3a7f","blockNumber":11885684,"name":"PleaDistributor","role":"other","txHash":"0x9de8d4a7b24b04f2ee52fea389572341844d1a27d5a131f50194af83db833be8"},{"address":"0x29aa568f93d7d4d8255ba54b6201bbe1abd01ab4","blockNumber":11885684,"name":"PleaLaunch","role":"other","txHash":"0x9de8d4a7b24b04f2ee52fea389572341844d1a27d5a131f50194af83db833be8"},{"address":"0x9b8d9aae44e81b1205e227911db279bde6edead9","blockNumber":11885684,"name":"PLEA","role":"other","txHash":"0x9de8d4a7b24b04f2ee52fea389572341844d1a27d5a131f50194af83db833be8"},{"address":"0x758b8300c62563591950f32717be44a5140a20f9","blockNumber":11885684,"name":"CabalGate","role":"other","txHash":"0x9de8d4a7b24b04f2ee52fea389572341844d1a27d5a131f50194af83db833be8"},{"address":"0xd2311b6d4c42a6dc3900a0a74a364b2775dd61c1","blockNumber":11885684,"name":"Laureates","role":"other","txHash":"0x9de8d4a7b24b04f2ee52fea389572341844d1a27d5a131f50194af83db833be8"}],"id":"9dac26b9-ae28-48e0-9348-015c0c182a6e","manifestHash":"9426a6e6151370075c2fc047865a5eefd30bc6e6e0847a5f62311ded8fdcc8da","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":"3593725e-d086-4a90-881e-41e3f41ab02b","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"ddc531b55b1d42fd987fd1e972a1075b3bac705aaf1efa0ac1f8aa08897f4628","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"81b7052da6cdca6819abb4b1fb4924e31086633863b272c8ed89d9b24523ab82","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"81b7052da6cdca6819abb4b1fb4924e31086633863b272c8ed89d9b24523ab82","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"f5846c9c0a7ee982259b38d59b1be074f3c044abcc26fd25758ecab6db86a539","dependsOn":["adapt_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":"52836f18bbf9286e79ed769823aa8cba894e87cf6e638983b0f86e89c01f1143","dependsOn":["adapt_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":"94c51be37c22c86f11f1eaa462c5a8a96a6148450202fe6549f9119096e4d50a","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"a8a813e83c38511f6d0d7a196ebb0a2ad2ade9be9e6816b6a2847beed8cdfde7","dependsOn":["adapt_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":"9be53a4b5a7fabe53951a34872a275ddb2080b804dd8bcb19bb248a77427829a","dependsOn":["adapt_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":"b454820987e9aca89de305abfcb5690a224ba597e35f8cc66635dff8589b39eb","dependsOn":["adapt_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":"58bb63e9881916c8f40209620cc2cb479bdfee76badb89b6ab0515befcd7b241","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"4e6150a46d570a37c23f6353c45cf6d80889d97bcfef26a4894b1683e9e19a68","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Launch PLEA on Sepolia from this Foundry repository exactly as launch.json lists it: six contracts (PLEA, CabalGate, Seasons, Laureates, PleaDistributor, PleaLaunch), deployed in order in one transaction with the constructor arguments in launch.json. Audit the imported code and deploy it unchanged; fix only what the audit proves is a real bug, and keep every number as it is (fees, timings, panel 30, quorum 17, START 1791817200, credit gas 1300000). PleaHook is not a launch.json entry: PleaLaunch.deployHook deploys it after launch with a salt mined off chain. Keep PLEA.setLauncher accepting either the deploy-transaction flag or PLEA’s deployment block (the launch rehearsal deploys each constructor in its own call). Keep foundry.toml as it is, including [lint] lint_on_build = false (forge’s linter runs out of memory on PleaHook).","parentJobId":null,"planHash":"e5577e4fb3ade60b7d5eda9117f44d07926f373293e56ac7166defb047161272","previousHash":"fd1718a68ae54a4478c578fa0879a089932d8badee8d8666d03cc0a0f01656c4","projectId":"3593725e-d086-4a90-881e-41e3f41ab02b","publication":{"commit":"7d247e8a45bbdbf04e727cb91e7b100ccfe9c7df","deliveredAt":"2026-10-10T16:15:01.712Z","repoUrl":"https://github.com/identity-md-launches/launch-1242-launch-plea-sepolia-foundry"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"ee114c98aa8a290e1529837e755fc8aa508b7b2a7262d57dc4ff68a40f0e52f5","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"f0e8a729543d3e36afd88e90c776c20e53c1f19e6c578282281e84be9cb25523","device":"20a3efdc039f2089","findings":[{"description":"The cap rate limiter stores sub-second budget consumption in capDecayRemainder, but its next allowance calculation uses only block.timestamp - lastCapDecayAt. A swap that consumes less than a full second leaves lastCapDecayAt unchanged; a second swap can consume the full integer-second allowance again. Consequently the cumulative inventory-cap decrease exceeds CAP_DECAY_PER_DAY times elapsed seconds / 86400. The excess is bounded by less than one second of decay (about 3.47223 PLEA), so this is a low-severity policy/accounting error rather than a material reserve theft. Account for capDecayRemainder when calculating remaining allowance, preserving the agreed 300000e18/day constant.","line":633,"path":"src/PleaHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PLEA} from \"src/PLEA.sol\";\nimport {PleaHook} from \"src/PleaHook.sol\";\nimport {IStacker} from \"src/interfaces/IStacker.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/interfaces/IPoolManager.sol\";\nimport {PoolKey} from \"v4-core/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/types/Currency.sol\";\nimport {SwapParams} from \"v4-core/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"v4-core/types/BalanceDelta.sol\";\nimport {TickMath} from \"v4-core/libraries/TickMath.sol\";\n\ncontract CapProofQuote is ERC20 {\n    constructor() ERC20(\"Quote\", \"Q\") {}\n    function mint(address who, uint256 amount) external { _mint(who, amount); }\n}\n\ncontract CapProofGate {\n    function restricted() external pure returns (bool) { return true; }\n}\n\ncontract CapProofStacker {\n    function credit(address, uint256) external pure { revert(\"plain cashback\"); }\n}\n\ncontract CapDecayProof is Test {\n    PLEA token;\n    CapProofQuote quote;\n    PoolManager manager;\n    PleaHook hook;\n    uint256 initialCap;\n    uint256 constant FLAGS = (1 << 13) | (1 << 11) | (1 << 7) | (1 << 6) | (1 << 3) | (1 << 2);\n\n    function setUp() public {\n        vm.chainId(11155111);\n        vm.warp(1791817200);\n        manager = new PoolManager(address(this));\n        quote = new CapProofQuote();\n        token = new PLEA(address(this));\n        CapProofGate gate = new CapProofGate();\n        CapProofStacker stacker = new CapProofStacker();\n        token.setLauncher(address(gate), address(this), address(this), makeAddr(\"distributor\"));\n        bytes memory code = abi.encodePacked(type(PleaHook).creationCode,\n            abi.encode(address(manager), address(token), address(quote), address(stacker), address(this), address(this), uint256(1300000)));\n        bytes32 hash = keccak256(code);\n        uint256 salt;\n        while (uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(salt), hash)))) & 0x3fff != FLAGS) ++salt;\n        hook = new PleaHook{salt: bytes32(salt)}(IPoolManager(address(manager)), address(token), IERC20(address(quote)), IStacker(address(stacker)), address(this), address(this), 1300000);\n        token.init(address(hook), address(manager));\n        hook.seed();\n        initialCap = hook.inventoryCap();\n        quote.mint(address(this), 1000e18);\n        vm.warp(block.timestamp + 91 minutes);\n    }\n\n    function buy(uint256 amount) internal { manager.unlock(abi.encode(amount)); }\n\n    function unlockCallback(bytes calldata raw) external returns (bytes memory) {\n        require(msg.sender == address(manager));\n        bool zeroForOne = !hook.pleaIsZero();\n        BalanceDelta delta = manager.swap(hook.poolKey(), SwapParams({zeroForOne: zeroForOne,\n            amountSpecified: -int256(abi.decode(raw, (uint256))),\n            sqrtPriceLimitX96: zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1}), abi.encode(address(this)));\n        (int128 q, int128 p) = hook.pleaIsZero() ? (delta.amount1(), delta.amount0()) : (delta.amount0(), delta.amount1());\n        manager.sync(Currency.wrap(address(quote)));\n        quote.transfer(address(manager), uint256(uint128(-q)));\n        manager.settle();\n        manager.take(Currency.wrap(address(token)), address(this), uint256(uint128(p)));\n        return \"\";\n    }\n\n    function test_capDecayCannotReuseFractionalTimeInTheSameBlock() public {\n        buy(1e12); // consumes a fraction of one second's decay budget\n        assertGt(hook.capDecayRemainder(), 0);\n        buy(100e18); // consumes the integer-second budget again, at the identical timestamp\n        uint256 maximum = hook.CAP_DECAY_PER_DAY() * (block.timestamp - hook.launchedAt()) / 1 days;\n        uint256 actual = initialCap - hook.inventoryCap();\n        emit log_named_uint(\"maximum elapsed-time decay\", maximum);\n        emit log_named_uint(\"actual decay\", actual);\n        assertLe(actual, maximum, \"cap fell faster than the agreed decay rate\");\n    }\n}","reproduction":"Run the proof as test/scratch/CapDecayProof.t.sol with forge test --match-path test/scratch/CapDecayProof.t.sol -vv. It deploys the real PLEA, PleaHook and v4 PoolManager, seeds at timestamp 1791817200, advances 91 minutes, and buys with 1e12 quote wei followed by 100e18 quote wei without advancing time. Expected initialCap - inventoryCap <= 18958333333333333333333. Actual decrease is 18958505549857848571824. The final assertion fails on the current implementation. This exact failing test was run locally.","severity":"low","title":"Consecutive swaps reuse the fractional inventory-cap decay budget"}],"hash":"01fef3b34e70100eb72226deec92dc0078030033c065e130eba34374692d2af6","nodeId":"a661b59f-638f-491e-8b95-adac45c09382","outcome":"completed","summary":"Added failure-path tests, fuzz tests, and four invariant campaigns.\n\nClean offline build succeeds; **184 tests pass**, including 32,768 invariant calls. Production code, manifest, and configuration remain unchanged.\n\nReported one low-severity cap-decay defect with a failing reproducer in [.imd-findings.json](/home/seat/.identitymd/work/3593725e-d086-4a90-881e-41e3f41ab02b/a661b59f-638f-491e-8b95-adac45c09382/.imd-findings.json). Coverage and limitations are documented in [test/AUDIT.md](/home/seat/.identitymd/work/3593725e-d086-4a90-881e-41e3f41ab02b/a661b59f-638f-491e-8b95-adac45c09382/test/AUDIT.md).","treeHash":"a35de1eef23c71a3adbdf09c10ccecb013021bc0","usage":{"cachedInputTokens":5252480,"inputTokens":192032,"model":"gpt-6-astra","outputTokens":61508,"runtime":"codex","turns":12,"wallClockMs":1770451}},{"artifacts":[],"attempt":1,"bundleHash":"a6bd493e26d41729b56ee397ffefa88f317b48be08d61bee24692d2d123b40c3","device":"26997d33f12beaa6","findings":[],"hash":"4e6150a46d570a37c23f6353c45cf6d80889d97bcfef26a4894b1683e9e19a68","nodeId":"a661b59f-638f-491e-8b95-adac45c09382","outcome":"completed","summary":"Updated existing tests for cooldowns, season accounting, claim payouts/redemptions, and cap decay. Only `test/` changed.\n\nValidation passed: 219 tests, zero failures, and 32,768 invariant handler calls. `forge build --offline` and scope checks also passed.","treeHash":"fe06100538fe65d51ba271e9e2238d051719f132","usage":{"cachedInputTokens":2975744,"inputTokens":130144,"model":"gpt-6-astra","outputTokens":20135,"runtime":"codex","turns":8,"wallClockMs":677615}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"d63ea36a2b809080","findings":[{"citation":"resolved","description":"appeal() sets o.appealed = true (line 275) and only then pays the 0.5 oracle IMD + 0.35 pool IMD and asks the Intake. If the request completes without a verdict (panel refused or disagreed: requests(id).completed becomes true with no callback, or the callback reverts, or 20 minutes pass), the appeal plea is Expired by _clearStale/expire, but o.appealed is never reset. Line 267 (`if (o.appealed || o.isAppeal) revert AlreadyAppealed();`) then refuses a second appeal although the Cabal never judged the first, while the seller is still inside the 4-hour denial cooldown, so they can neither appeal nor plead again. A first-round plea that gets no verdict is cleared and can be re-submitted at once (no cooldown), so the two paths are asymmetric: the oracle failure costs an appellant 0.85 IMD plus their appeal right, but a first-round pleader only 0.5 IMD. Scratch test test/scratch/Review.t.sol::test_appealWithoutVerdictBurnsTheAppealRight reproduces it on this tree. Minimal fix: clear pleas[o].appealed (via originalId) in _expire when the expired plea isAppeal, so an unjudged appeal can be re-filed within the original window.","line":275,"path":"src/CabalGate.sol","reproduction":"Fixture (5h seasons, 33h dead-man). alice buys 50 IMD of PLEA; plead(amount=10% balance) -> denied with score 0 (lastDeniedAt = t). alice.appeal(id, amount/2, text): pays 0.5 oIMD + 0.35 IMD, returns appeal id a, pleas[id].appealed == true. intake.complete(intakeIdOf(a), status=1, \"\") (completed, no verdict). gate.expire(a) -> status Expired, pendingOf[alice]==0. Still within verdictAt+4h: alice.appeal(id, amount/2, text) reverts AlreadyAppealed; alice.submitSell(amount/2, text) reverts Cooldown. Expected: an appeal the Cabal never scored should not consume the single appeal (or should at least not lock the seller out for the remaining cooldown). Contrast: bob's first-round plea with the same no-verdict completion is expired and bob pleads again immediately.","severity":"low","snippet":"        o.appealed = true;","title":"CabalGate.appeal marks the original plea `appealed` before the oracle answers, so an appeal the Intake completes without a verdict burns the seller's only appeal and 0.85 IMD"},{"citation":"resolved","description":"The pot is Seasons' entire IMD balance (pot() = imd.balanceOf(this)), fed continuously by the hook's 0.25% prize fee on every trade. closeSeason(nextToClose) can be called any time after end + 1 hour but nothing forces it then, and the fee keeps flowing in from trades that belong to later seasons. Whatever has accumulated when someone finally closes season N is shared by season N's top 10, including every prize fee earned during seasons N+1, N+2, ... that are still running. The README's promise is that each season's top 10 share 'the prize pot' with unpaid shares rolling forward; here paid shares roll backward: participants of the running season lose their fees to a leaderboard they were not competing on. No privileged actor is needed; a season-N winner simply benefits from nobody calling closeSeason, and because closing is permissionless the running season's participants have to race to protect their own pot. Reproduced by test/scratch/Review.t.sol::test_lateCloseSeasonPaysNextSeasonsFeesToPreviousWinners. Minimal fix: snapshot the pot when a season ends (e.g. record imd.balanceOf at the first fee or close after `end` through a per-season accrual: track `accruedUpTo[season]` by having closeSeason of season N use the balance recorded at the time season N ended plus rollover, or have the hook route the prize fee with the current season id so Seasons can bucket it).","line":222,"path":"src/Seasons.sol","reproduction":"Fixture with SEASON = 5h. Season 0: alice gets three approvals (score 45, each lapsing after 7 minutes so no cooldown) and records them: 135 points, rank 1. skip(10h) and one keep-alive plea: currentSeason() == 2, nextToClose() == 0, season 0 ended at t0+5h. potAtSeason0End = seasons.pot(). bob now buys 10 x 1000 IMD of PLEA in season 2; seasons.pot() more than doubles (potNow). Anyone calls seasons.closeSeason([]): alice receives exactly potNow * 2500 / 10000, i.e. 25% of season 2's prize fees as well. Expected: season 0's payout is computed from IMD that accrued up to season 0's end (plus rollover), not from fees paid by season 2's trades.","severity":"low","snippet":"        uint256 amountIn = pot();","title":"Seasons.closeSeason pays season N's winners from the whole pot at close time, so a late close hands later seasons' prize fees to the previous season's leaderboard"},{"citation":"resolved","description":"seed() approves the Stacker (Sepolia 0x293C7134Ab8f6Bf1D8fF44Ed806575f8F1bAF477, verified to have code and the credit(address,uint256) selector) for type(uint256).max of IMD. The hook's IMD balance is not only the cashback in flight (at most 0.5% of one fill): it is also retainedImd, the buy wall's whole reserve between rebalances (appeal fees from fundWall, redeemed claims, closed-wall proceeds, Seasons.flushToWall leftovers). The allowance is set once and can never be reduced (no owner function, no re-seed), so the external Stacker (its operator, an upgrade or a compromise) can transferFrom the entire wall reserve at any time. This is a documented external dependency, not a code defect: the design wants cashback paid as sIMD. Reported as the trust assumption the adapter asks for, with the concrete exposure. A tighter variant would be safeIncreaseAllowance(stacker, amount) immediately before each credit and reset after, within the existing creditGas budget.","line":374,"path":"src/PleaHook.sol","reproduction":"After seed(): imd.allowance(hook, stacker) == type(uint256).max. Fund the wall (gate.appeal routes 0.35 IMD; Seasons.flushToWall; buys then rebalance close a wall into retainedImd): hook.retainedImd() == R > 0 and imd.balanceOf(hook) >= R. A call imd.transferFrom(hook, X, R) made by the Stacker contract succeeds, and the next rebalance's _settleImd reverts (hook balance < retainedImd) until retainedImd is reduced. Expected: the hook only exposes the cashback amount being credited.","severity":"info","snippet":"        if (address(stacker).code.length != 0) imd.approve(address(stacker), type(uint256).max);","title":"Trust assumption: the imd/acc Stacker gets an unlimited IMD allowance over the hook, which also holds the buy wall's retained reserve"}],"hash":"52836f18bbf9286e79ed769823aa8cba894e87cf6e638983b0f86e89c01f1143","nodeId":"8a6b9031-f939-42df-b6b5-e27af1c6b0e8","outcome":"completed","summary":"Review complete. The findings file is in place and the working tree has no changes to tracked files.\n\n**Outcome**\n\nI found no defect that loses funds, pays the wrong party, or breaks the launch. The manifest matches the six constructors in dependency order with the agreed numbers, and all five Sepolia dependencies hold code with the selectors the gate and hook call. The oracle signer address is an externally owned account, as intended. The existing 119 tests pass.\n\n**Findings written to `.imd-findings.json`**\n\n- **Low, CabalGate.appeal.** The original plea is marked `appealed` before the oracle answers. If the Intake completes the appeal request without a verdict, the appeal is expired but the flag stays, so the seller loses the single appeal and 0.85 IMD and is still locked by the denial cooldown. A first-round plea in the same situation can be re-filed at once. Reproduced by a scratch test.\n- **Low, Seasons.closeSeason.** The payout base is the live IMD balance at close time, so a season closed late pays its leaderboard with prize fees earned by trades in later seasons. Reproduced by a scratch test with 5-hour seasons.\n- **Info, PleaHook.seed.** The imd/acc Stacker receives an unlimited IMD allowance that also covers the buy wall's retained reserve, and it can never be reduced. Reported as a trust assumption, not a defect.\n\n**Coverage**\n\nAll 39 listed entry points have a row, plus two invariant rows. Two are marked `finding`, the rest `holds` with a one-line trace reason. Items I could not verify from here and noted as assumptions: the real Intake's callback calldata layout and whether it completes and calls back in one transaction, and the Stacker's internal behaviour beyond selector presence.\n\nScratch tests live in `test/scratch/Review.t.sol` and both pass on this tree, documenting the two low findings. No proof files were attached since nothing reached high severity.","treeHash":null,"usage":{"cachedInputTokens":2384560,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":61277,"runtime":"claude","turns":32,"wallClockMs":1037637}},{"artifacts":[],"attempt":1,"bundleHash":"4cc7a479a5642fe3621e4ed9cd44e5703dd006ea383fc7b7923f3fafcc3ec196","device":"3da9a8665ac1dd17","findings":[],"hash":"58bb63e9881916c8f40209620cc2cb479bdfee76badb89b6ab0515befcd7b241","nodeId":"6fe7f9da-87bc-4c37-8eba-02cdf3dace63","outcome":"completed","summary":"Updated only [launch.json](/home/imd1/.identitymd/work/3593725e-d086-4a90-881e-41e3f41ab02b/6fe7f9da-87bc-4c37-8eba-02cdf3dace63/launch.json), refining notes for the accepted implementation. All six entries, constructor arguments, addresses, and numbers remain unchanged.\n\nManifest structure and compiled ABIs verified. `forge build` succeeded; `forge test` passed all 151 tests.","treeHash":"5215e34ec6dded4801a7a87574447557763de1ec","usage":{"cachedInputTokens":737408,"inputTokens":65850,"model":"gpt-6-astra","outputTokens":5942,"runtime":"codex","turns":5,"wallClockMs":196363}},{"artifacts":[],"attempt":1,"bundleHash":"c510cb5d1a77d6cea55a265131496c4ffa2a9a5a7cab867ed2d5255ef53899eb","device":"5babf7922a7c2b14","findings":[],"hash":"67b5db6a210707812dcda6f962b17a9e6cb0e6b2dbb4a04bdb17dcb599280f95","nodeId":"f534a9bf-19c8-4451-a905-3ad6d92f773b","outcome":"completed","summary":"Implemented oracle replay protection and deterministic season tie-breaking, with regression tests and an exact six-contract factory rehearsal. Launch values, constructors, configuration and dependencies remain unchanged.\n\n`forge build` succeeds. `forge test`: **119 passed, 0 failed**.\n\n[ADAPTATION.md](/home/imd2/.identitymd/work/3593725e-d086-4a90-881e-41e3f41ab02b/f534a9bf-19c8-4451-a905-3ad6d92f773b/ADAPTATION.md) documents every change and remaining assumptions. The Intake still must associate each first-use attestation with the correct plea; replay protection prevents reuse.","treeHash":"5e8a03445f76c84e13cb4f1ff43de51ce80b3910","usage":{"cachedInputTokens":2138880,"inputTokens":121255,"model":"gpt-6-astra","outputTokens":22091,"runtime":"codex","turns":7,"wallClockMs":628698}},{"artifacts":[],"attempt":1,"bundleHash":"3b23e132f7f095ff6fab9fd15b8b9abd39124a97d8c3d2c21640e356ad708a03","device":"d6be3c85730d2da2","findings":[],"hash":"8d59928dd78fa668d078de68d978737033289032fabd04e3f4b43c03ecfa98ec","nodeId":"6fe7f9da-87bc-4c37-8eba-02cdf3dace63","outcome":"completed","summary":"Updated `launch.json` notes to clarify atomic deployment, the rehearsal fallback, ownership, and later hook deployment. Preserved all six contracts and constructor arguments.\n\nValidation passed: manifest/ABI checks, `forge build`, and all 120 tests, including the pinned protected check. Only `launch.json` changed outside permitted scratch files.","treeHash":"24b4823a2fd08977a37417c85910a44de70ce673","usage":{"cachedInputTokens":1190528,"inputTokens":82169,"model":"gpt-6-astra","outputTokens":8741,"runtime":"codex","turns":6,"wallClockMs":289310}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"56e50117311155be","findings":[{"citation":"resolved","description":"The verdict is looked up by the `intakeId` the Intake passes, but nothing ties the signed attestation to that request: `a.requestId` and `a.questionHash` are never compared with the plea, and `_consume(a.requestId)` (offered by OracleAttestationConsumer for exactly this) is not called. Only the signature, the window, the panel sizes and the score range are checked. So a single attestation legitimately signed for plea A (score 45, valid for 3600 s) is accepted for plea B when presented under B's intakeId, and can then still be delivered for A. The oracle signer's separation from the Intake's writer is therefore not enforced by the gate: whoever can make the Intake call the callback (the Intake writer, or anyone if the live Intake relays completions permissionlessly) can approve every pending plea for an hour with one real signature, opening sell windows the Cabal never granted and feeding Seasons points/Laureates. OracleAttestation.sol's own doc says a consumer that neither consumes nor keys on the request 'accepts the same signed answer as many times as it is presented'. The precondition (a misbehaving or permissionless Intake completion path) could not be verified: the Sepolia Intake at 0x1397434cd35e8a9c8ac312a61d3a285eb31dea56 exposes `request` and `requests` (selectors 0x380c2cda, 0x9d866985 present in its bytecode) but its source was not available. Minimal fix that preserves the design: call `_consume(a.requestId)` after `_verifyAttestation` and before any effect, and, if the protocol's request id or canonical question hash is derivable for the plea, require `a.requestId`/`a.questionHash` to match it. Verified: with `_consume(a.requestId);` inserted right after `_verifyAttestation(a, signature);` the attached proof passes and the existing test_callbackFitsTheStipend still passes (the extra SSTORE fits the 200k callback stipend).","line":389,"path":"src/CabalGate.sol","reproduction":"State: trading open, alice and bob hold PLEA. 1) alice: submitSell(bal/10, text) -> plea 1 (intakeId I1). 2) bob: submitSell(bal/10, text) -> plea 2 (intakeId I2). 3) Oracle signs attestation attA for plea 1: requestId=keccak('oracle',1), chainId=1, answerType=uint256, answer=abi.encode(45), panelSize=30, quorum=17, agreed=20, issuedAt=now, expiresAt=now+3600. 4) Intake calls gate.onOracleResult(I2, attA, sigA). Expected: revert (attestation is for plea 1). Actual: accepted, plea 2 becomes Approved with score 45 (bob may executeSell for 7 minutes). 5) Intake calls gate.onOracleResult(I1, attA, sigA): also accepted. Confirmed with the repository's MockIntake: test test_attestationForAnotherPleaIsAccepted in test/scratch/Audit.t.sol passes against the current code. Self-contained proof: test/scratch/AttestationReuse.t.sol (forge test --match-path test/scratch/AttestationReuse.t.sol) fails on the current code with 'one signed attestation settled two pleas: 2 > 1'.","severity":"medium","snippet":"        _verifyAttestation(a, signature);\n        if (a.chainId != QUESTION_CHAIN || a.panelSize < PANEL_SIZE || a.quorum < QUORUM || a.agreed < QUORUM) {\n            revert WrongPanel();\n        }","title":"CabalGate.onOracleResult does not bind the attestation to the plea: one signed answer is accepted for any pending plea, repeatedly"},{"citation":"resolved","description":"`_insertPlea` implements 'older plea wins ties' by assuming pleas are inserted in id order, but `record(pleaId)` and `closeSeason(pleaIds)` are permissionless and accept any order. Whoever records first wins an equal-score tie: a later plea takes rank 1 (and, with five tied entries, the fifth Laureate slot) from an earlier one. The same mechanism affects `_insertWallet`: `Entry.pleaId` is 'the plea that last raised the total', which is the last *recorded* plea, so a wallet can lower its tie-break key by recording its pleas in reverse id order, and `_better` then ranks it above a wallet with equal points whose key is larger. Impact is limited to rank/eligibility among tied scores (Laureate NFT rank and the 25/18/14/... prize split between tied wallets). Fix: compare `pleaId` on equal scores in `_insertPlea` (lower id wins, as `_better` already does), and set `Entry.pleaId` to the max plea id among the wallet's counted pleas rather than the last recorded.","line":182,"path":"src/Seasons.sol","reproduction":"State: alice and bob each hold PLEA; season 0 running. 1) alice submitSell -> plea 1, approved with score 45. 2) bob submitSell -> plea 2, approved with score 45. 3) anyone calls seasons.record(2) then seasons.record(1). Expected: topPleasOf(0)[0].pleaId == 1 (earlier plea wins the tie). Actual: topPleasOf(0)[0].pleaId == 2, [1].pleaId == 1. Recording 1 then 2 gives the opposite order. Confirmed by test_recordOrderDecidesLaureateTies in test/scratch/Audit.t.sol (logs rank1 pleaId: 2, rank2 pleaId: 1).","severity":"low","snippet":"        // A newer plea needs a strictly higher score to pass an older one.\n        if (m[n - 1].pleaId != 0 && score <= m[n - 1].score) return;","title":"Seasons: Laureate ranking and wallet tie-break keys depend on the order record() is called, not on plea id"},{"citation":"resolved","description":"The deployment-block fallback the task asks to keep means that, if PLEA and PleaLaunch were ever deployed in separate transactions of the same block, any account could call setLauncher first and become `launcher`, gaining `init` (mint 90%/10% to addresses of its choosing) and `begin`/`seed` authority, with no way to reset (AlreadySet). In the real launch all six constructors run in one transaction, so PleaLaunch's constructor consumes the slot atomically and there is no window; the fallback only matters for the rehearsal. Recorded so the adapter and deployer keep the single-transaction property; no code change requested.","line":56,"path":"src/PLEA.sol","reproduction":"State: PLEA deployed at block N in transaction T1; PleaLaunch not yet deployed. Input: attacker EOA in block N (after T1) calls plea.setLauncher(anyGate, anySeasons, anyLaureates, attackerDistributor). Expected (intended design): revert NotDeployTx. Actual: succeeds (block.number == deployBlock), launcher = attacker; PleaLaunch's later constructor reverts AlreadySet. Not reachable when the launch is a single transaction.","severity":"info","snippet":"        if (flag != 1 && block.number != deployBlock) revert NotDeployTx();","title":"PLEA.setLauncher is callable by anyone during PLEA's deployment block (accepted by the task; documented as a launch assumption)"},{"citation":"resolved","description":"The task accepts PleaLaunch.deployHook running after launch, but the launch policy lists 'minting after launch' and 'anything configured after deployment rather than in a constructor' as things to flag. Concretely: (1) PLEA's whole 1e9 supply is minted in `init`, called from `deployHook` in a later transaction (one-shot, launcher-only, fixed split 90% hook / 10% distributor; no further mint path exists). (2) PleaDistributor.setMerkleRoot (owner, once) decides who receives the 10% share; if never set, 100M PLEA is stuck. (3) PLEA.allow (owner, add-only) exempts senders from the transfer restriction while the Cabal watches; allowed senders still cannot send to the PoolManager or the gate, so they cannot sell, but can move PLEA to other wallets or venues. (4) PleaHook.owner receives 0.5% of every trade's IMD. There is no pause, freeze, blacklist, seizure, proxy, DELEGATECALL, CALLCODE or SELFDESTRUCT: the protected scanner over the six runtimes passes (test_noForbiddenOpcodes in test/scratch/Audit.t.sol). These are trust assumptions of the accepted design, not defects; listed for the adapter and the policy review.","line":80,"path":"src/PLEA.sol","reproduction":"State: launch transaction mined; hook not deployed. plea.totalSupply() == 0 until anyone calls launch.deployHook(salt, initCode), after which totalSupply == 1e27 (900e24 to the hook, 100e24 to the distributor). distributor.claim(...) reverts RootNotSet until the owner calls setMerkleRoot once. plea.allow(x) by the owner lets x transfer to any non-PoolManager, non-gate address while gate.restricted() is true.","severity":"info","snippet":"        _mint(hook_, TOTAL_SUPPLY * 90 / 100);\n        _mint(distributor, TOTAL_SUPPLY * 10 / 100);","title":"Post-deployment configuration and owner powers to record for the launch policy: supply minted in init after the launch transaction; setMerkleRoot and allow set after deployment"},{"citation":"resolved","description":"Read in full: src/PLEA.sol, src/CabalGate.sol, src/Seasons.sol, src/Laureates.sol, src/PleaDistributor.sol, src/PleaLaunch.sol, src/PleaHook.sol, src/OracleAttestation.sol, src/interfaces/*.sol, launch.json, script/*.s.sol, test/utils/* and the test suite (105 tests pass on forge 1.8.3). launch.json matches the constructors (names unique, one argument per parameter in order, address arguments as $owner/$contract refs or static words, chain-agnostic timings 18000/118800 accepted off chain id 1). Sizes: every runtime is under 24,576 bytes (PleaLaunch runtime 1,962, init code 25,800; PleaHook runtime 21,712 deployed later by create2). lib/ contains 305 plain tracked files, no submodules. Could not be read (no source available): the IdentityMD Intake (0x1397...), imd/acc Stacker (0x293C...), TestIMD (0x2B69...), test IMD oracle asset (0x44a1...) and the Sepolia Uniswap v4 PoolManager (0xE03A...); their Sepolia bytecode was fetched and holds code (24009/2767/1904/6568/1821 bytes) and the Stacker bytecode contains credit(address,uint256) 0xef6506db while the Intake contains request(...) 0x380c2cda and requests(bytes32) 0x9d866985; the oracle signer 0x5598... is an EOA. Reviewed and found sound: PLEA transfer rule paths (PoolManager/gate/hook/distributor/allowlist), hook fee and delta accounting for exact-in/exact-out buys and sells, gate sell routing (PartialFill, slippage, callbackExpected), appeal and cooldown windows, dead-man monotonicity, season bounds at death, closeSeason payouts and Laureate minting, hook permission flags vs PleaLaunch.FLAGS, CREATE2 commitment, oracle EIP-712 digest. Not exercised: live Intake/Stacker behaviour, mainnet-length seasons with real clocks, fuzzing of hook liquidity math beyond the existing suite.","line":23,"path":"src/PleaLaunch.sol","reproduction":"Not a defect; coverage statement required by the acceptance criteria. Build: forge build --sizes; tests: forge test (105 passed, 0 failed); scratch checks: forge test --match-path test/scratch/Audit.t.sol.","severity":"info","snippet":"contract PleaLaunch {","title":"Audit coverage: all eight source files read; external Sepolia dependencies verified by bytecode only"}],"hash":"94c51be37c22c86f11f1eaa462c5a8a96a6148450202fe6549f9119096e4d50a","nodeId":"9dec9715-fb8f-497b-8cb3-53c941c1253d","outcome":"completed","summary":"Review complete. The findings are in `.imd-findings.json` at the repository root, and no tracked file was changed.\n\n**What I read**\n- All eight source files in full: PLEA, CabalGate, Seasons, Laureates, PleaDistributor, PleaLaunch, PleaHook, OracleAttestation, plus the interfaces, launch.json, both scripts, the test fixture and mocks, and the existing suite. All 105 existing tests pass on forge 1.8.3.\n- Could not be read as source: the Sepolia Intake, Stacker, TestIMD, the test IMD oracle asset and the Uniswap v4 PoolManager. I fetched their Sepolia bytecode instead. All five hold code, the Stacker exposes `credit(address,uint256)`, the Intake exposes `request` and `requests`, and the oracle signer is an EOA. The constructor arguments in launch.json line up with the constructors in declaration order.\n\n**Findings**\n- **Medium.** CabalGate.onOracleResult never binds the attestation to the plea. It ignores `a.requestId` and `a.questionHash` and does not call `_consume`. One attestation legitimately signed for plea A is accepted for plea B under B's intake id, and then again for A. Whoever drives the Intake's completion path can approve every pending plea for an hour with one real signature. The attached self-contained proof fails on the current code and passes with `_consume(a.requestId)` added after verification, which still fits the 200k callback stipend. The real-world precondition depends on the live Intake's completion access, which I could not inspect.\n- **Low.** Seasons tie-breaks follow the order `record()` is called, not plea id. Recording a later equal-score plea first gives it rank 1 and can take the fifth Laureate slot. The wallet tie key has the same dependence. Confirmed by a scratch test.\n- **Info.** Three notes for the adapter: the deployment-block fallback in PLEA.setLauncher is only safe because the launch is one transaction; the supply is minted in `init` after the launch transaction and the Merkle root and allowlist are set after deployment, which the launch policy lists as things to flag even though the task accepts the deployHook design; and the coverage statement above. The protected opcode scanner passes over all six runtimes and every runtime is under the EIP-170 limit.\n\n**Checked and found sound**\nPLEA containment across every transfer path to the PoolManager and gate, hook fee and delta accounting for exact-in and exact-out buys and sells, the gate's sell routing and partial-fill guard, appeal and cooldown windows, dead-man monotonicity, season bounds at death, closeSeason payouts and Laureate minting, hook permission flags against PleaLaunch.FLAGS, and the CREATE2 commitment.\n\n**Not exercised**\nLive Intake and Stacker behaviour, mainnet-length seasons, and fuzzing of the hook's liquidity math beyond the existing suite.","treeHash":null,"usage":{"cachedInputTokens":3073927,"inputTokens":674,"model":"claude-fable-5-1","outputTokens":79815,"runtime":"claude","turns":35,"wallClockMs":1495527}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"74a99f640688d37b","findings":[{"citation":"resolved","description":"Merged from audit_permissions (c10c9214) and audit_economics (dfad9bb3); same root cause. _requireCanPlead (lines 327-330) enforces COOLDOWN only from lastExecutedAt (set in executeSell, line 422) and lastDeniedAt (set in onOracleResult, line 406). The third exit from a wallet's slot, an approval whose 7-minute window passes, is handled here by _clearStale: it only sets Status.Lapsed and clears pendingOf, recording no timestamp. CabalGate.result (line 208) still reports a Lapsed plea as approved, so Seasons.record credits its 0-45 points and it competes for the five Laureate slots. A wallet that never intends to sell therefore gets one scored plea per (oracle latency + 7 minutes) for 0.5 oracle IMD each, while honest sellers get one per 4 hours; on the Sepolia 5-hour season an honest seller enters at most two pleas per season, a grinder around twenty, so the 25/18/14 % prize shares and Laureate NFTs go to wallets with no exposure. The economics specialist's dust variant (plead to sell 1 wei after a 1e12-wei buy) is the same root cause with _checkAmount only refusing amount == 0. Minimal fix keeping every number: in this branch record the lapse (e.g. lastDeniedAt[seller] = p.verdictAt, or a dedicated lastLapsedAt checked in _requireCanPlead) so any verdict starts the 4-hour clock.","line":341,"path":"src/CabalGate.sol","reproduction":"Fixture with launch.json clock (SEASON 18000, DEADMAN 118800), seeded, launch window over; alice and bob each buy 50 IMD of PLEA. (1) alice: submitSell(bal/10) -> signed score 45 -> Approved -> executeSell(0). alice.submitSell(1e18,...) reverts Cooldown (expected). (2) bob: submitSell(bal/10) -> score 45 -> Approved; bob does nothing; skip(7 min + 1 s); bob.submitSell(bal/10) SUCCEEDS (actual; expected Cooldown like alice). getPlea(first).status == Lapsed and gate.result(first) returns approved == true, score 45. Repeat twice more 7 minutes apart; seasons.record on all three: bestOf(0,bob) sums to 135 points 842 seconds after bob's first plea, while alice is still locked out for 4 hours. Reproduced in test/scratch/Judge.t.sol::test_A_lapsedApprovalNoCooldown and the attached self-contained proof.","severity":"medium","snippet":"        } else if (p.status == Status.Approved && block.timestamp > uint256(p.verdictAt) + EXECUTE_WINDOW) {","title":"Approved plea that lapses carries no cooldown: a wallet that never sells pleads every ~10 minutes while executed and denied sellers wait 4 hours, farming season points and Laureates"},{"citation":"resolved","description":"Merged from audit_flow (f6f6f4a6, low) and audit_economics (1438c1aa, medium); same root cause, kept at medium because prize IMD is paid to a party that did not earn it. The hook pays 0.25% of every trade to Seasons continuously (PleaHook._payFees, poolManager.take(c, seasons, toPrize)), but Seasons never attributes IMD to a season: pot() is imd.balanceOf(this), and closeSeason snapshots it at the moment it is called. closeSeason is permissionless and only possible from end + 1 hour, nothing forces it then and there is no keeper, so every prize fee earned between the end of season N and the actual close (season N+1's and later trades) is paid to season N's top ten, and the running season's contenders inherit only what is left. The README promises unpaid shares roll forward, not that later seasons' fees flow backwards. Season N's leader also has an incentive to wait for a whale buy before closing. Fix that keeps the design: snapshot the pot at the season boundary (record potAt[season] on the first call after end, or bucket the hook's prize fee by currentSeason()), paying season N from fees earned up to its end plus rollover only.","line":222,"path":"src/Seasons.sol","reproduction":"Fixture, SEASON 18000. Season 0: alice buys 1000 IMD, enters three pleas of 1000 PLEA scored 45 (7 min apart, each lapsing), all recorded: 135 points, rank 1. warp(T0 + SEASON + 1 h): seasons.pot() == 2.463 IMD (potAtEnd); currentSeason() == 1. carol buys 10 x 2000 IMD in season 1: seasons.pot() == 51.724 IMD. Anyone calls closeSeason([]): alice receives 12.931 IMD == 25% of 51.724 (actual), i.e. more than the entire 2.463 IMD pot that existed when her season ended; expected 25% of 2.463 = 0.616 IMD. Reproduced in test/scratch/Judge.t.sol::test_B_lateClosePaysLaterFees.","severity":"medium","snippet":"        uint256 amountIn = pot();","title":"closeSeason pays season N's winners from the whole pot at call time, so prize fees earned during later seasons flow backwards to the previous leaderboard whenever a close is late"},{"citation":"resolved","description":"From audit_math (dde042c4), reproduced with its proof. The comment (lines 512-513) says the fallback is 'only possible on the first buy after seeding', but the condition compares out = 1.25% of the realised fill with the PoolManager's whole IMD balance before the swapper has settled its input, so it fires on any single buy whose net fill exceeds about 80x the IMD the pool currently holds, an ordinary early-market buy at a 5,700 IMD market cap. When it fires the owner's 0.5%, Seasons' 0.25% and the trader's 0.5% cashback are all converted to ERC-6909 claims retained for the wall (retainClaims), so the owner and the season pot never receive the IMD the fee schedule promises and the trader pays a fee advertised as cashback. The hook already has a non-reverting path that preserves the payee (_refund mints ERC-6909 IMD claims to the trader when the PoolManager is short, lines 562-564); _payFees could mint claims to owner/seasons/hook the same way, or defer the payouts, instead of giving them to liquidity.","line":531,"path":"src/PleaHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/interfaces/IPoolManager.sol\";\nimport {TickMath} from \"v4-core/libraries/TickMath.sol\";\nimport {BalanceDelta} from \"v4-core/types/BalanceDelta.sol\";\nimport {Currency} from \"v4-core/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/types/PoolKey.sol\";\nimport {SwapParams} from \"v4-core/types/PoolOperation.sol\";\nimport {PLEA} from \"src/PLEA.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\nimport {Seasons} from \"src/Seasons.sol\";\nimport {Laureates} from \"src/Laureates.sol\";\nimport {PleaDistributor} from \"src/PleaDistributor.sol\";\nimport {PleaLaunch} from \"src/PleaLaunch.sol\";\nimport {PleaHook} from \"src/PleaHook.sol\";\n\ncontract ProofIMD is ERC20 {\n    constructor() ERC20(\"TestIMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @dev imd/acc Stacker shape: pulls IMD from the caller and records the credit.\ncontract ProofStacker {\n    IERC20 public imd;\n    mapping(address => uint256) public credited;\n\n    constructor(IERC20 imd_) {\n        imd = imd_;\n    }\n\n    function credit(address to, uint256 amount) external {\n        imd.transferFrom(msg.sender, address(this), amount);\n        credited[to] += amount;\n    }\n}\n\n/// @dev Intake shape: never called in this proof (no plea is submitted), present so constructors wire.\ncontract ProofIntake {\n    struct Req {\n        address payer;\n        address target;\n        bytes4 selector;\n        bool completed;\n    }\n\n    mapping(bytes32 => Req) public requests;\n}\n\n/// @dev A plain v4 router for exact-input buys against the hook's pool.\ncontract ProofRouter {\n    IPoolManager public pm;\n    PleaHook public hook;\n    IERC20 public imd;\n    IERC20 public plea;\n\n    constructor(IPoolManager pm_, PleaHook hook_, IERC20 imd_, IERC20 plea_) {\n        pm = pm_;\n        hook = hook_;\n        imd = imd_;\n        plea = plea_;\n    }\n\n    function buyExactIn(uint256 imdIn, bytes memory hookData) external {\n        pm.unlock(abi.encode(msg.sender, -int256(imdIn), hookData));\n    }\n\n    function unlockCallback(bytes calldata raw) external returns (bytes memory) {\n        require(msg.sender == address(pm), \"pm\");\n        (address payer, int256 amountSpecified, bytes memory hookData) = abi.decode(raw, (address, int256, bytes));\n        PoolKey memory key = hook.poolKey();\n        bool pleaIsZero = hook.pleaIsZero();\n        bool zeroForOne = !pleaIsZero;\n        uint160 limit = zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1;\n        BalanceDelta d = pm.swap(\n            key, SwapParams({zeroForOne: zeroForOne, amountSpecified: amountSpecified, sqrtPriceLimitX96: limit}), hookData\n        );\n        int128 imdDelta = pleaIsZero ? d.amount1() : d.amount0();\n        uint256 amountIn = uint256(uint128(-imdDelta));\n        pm.sync(Currency.wrap(address(imd)));\n        imd.transferFrom(payer, address(pm), amountIn);\n        pm.settle();\n        return \"\";\n    }\n}\n\n/// @notice PleaHook._payFees: on a buy whose 1.25% payout exceeds the PoolManager's current IMD\n/// balance, the owner's 0.5%, the prize 0.25% and the trader's 0.5% cashback are all redirected to\n/// pool liquidity. The code comment says this can only happen on the first buy after seeding; this\n/// test shows it on the second buy (50 IMD in the pool, then a 5,000 IMD buy) and expects the fee\n/// schedule to be honoured.\ncontract PayoutsToPoolOnSecondBuyTest is Test {\n    address constant OWNER = 0x4b91078b2374c956A65F7Af0999CaE0a935E6821;\n    address constant SIGNER = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n    uint256 constant CREDIT_GAS = 300_000;\n    uint256 constant T0 = 1_800_000_000;\n\n    PoolManager pm;\n    ProofIMD imd;\n    ProofIMD oimd;\n    ProofStacker stacker;\n    ProofIntake intake;\n    PLEA plea;\n    CabalGate gate;\n    Seasons seasons;\n    Laureates laureates;\n    PleaDistributor distributor;\n    PleaLaunch launch;\n    PleaHook hook;\n    ProofRouter router;\n\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.chainId(11155111);\n        vm.warp(T0);\n        vm.roll(1000);\n        pm = new PoolManager(address(this));\n        imd = new ProofIMD();\n        oimd = new ProofIMD();\n        stacker = new ProofStacker(imd);\n        intake = new ProofIntake();\n        plea = new PLEA(OWNER);\n        gate = new CabalGate(address(plea), address(intake), address(oimd), address(imd), SIGNER, 18_000, 118_800);\n        seasons = new Seasons(address(plea), address(gate), address(imd));\n        laureates = new Laureates(address(plea));\n        distributor = new PleaDistributor(address(plea), OWNER);\n        launch = new PleaLaunch(\n            address(plea),\n            address(gate),\n            address(seasons),\n            address(laureates),\n            address(distributor),\n            address(pm),\n            address(imd),\n            address(stacker),\n            CREDIT_GAS,\n            T0 + 1 days\n        );\n        bytes memory code = abi.encodePacked(\n            type(PleaHook).creationCode,\n            abi.encode(address(pm), address(plea), address(imd), address(stacker), OWNER, address(seasons), CREDIT_GAS)\n        );\n        hook = PleaHook(launch.deployHook(mineSalt(keccak256(code)), code));\n        vm.prank(OWNER);\n        launch.seed();\n        skip(91 minutes); // past the launch window: no extra fee, no per-buy cap\n        router = new ProofRouter(IPoolManager(address(pm)), hook, imd, plea);\n        for (uint256 i; i < 2; ++i) {\n            address who = i == 0 ? alice : bob;\n            imd.mint(who, 100_000e18);\n            vm.prank(who);\n            imd.approve(address(router), type(uint256).max);\n        }\n    }\n\n    function mineSalt(bytes32 initHash) internal view returns (bytes32) {\n        uint160 flags = launch.FLAGS();\n        for (uint256 s;; ++s) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), bytes32(s), initHash))))\n            );\n            if (uint160(a) & 0x3fff == flags) return bytes32(s);\n        }\n    }\n\n    function buy(address who, uint256 imdIn) internal {\n        vm.prank(who);\n        router.buyExactIn(imdIn, abi.encode(who));\n    }\n\n    function test_secondBuyStillPaysOwnerPrizeAndCashback() public {\n        buy(bob, 50e18); // IMD now sits in the pool: the documented first-buy exception is over\n        assertEq(imd.balanceOf(address(pm)), 50e18);\n\n        uint256 ownerBefore = paid(OWNER);\n        uint256 prizeBefore = paid(address(seasons));\n        uint256 cashbackBefore = stacker.credited(alice) + paid(alice);\n\n        uint256 amt = 5_000e18;\n        uint256 net = amt - amt * 150 / 10_150; // the IMD that reaches the pool\n        buy(alice, amt); // the router pulls exactly `amt` IMD from alice\n\n        // The fee schedule: 0.5% of the fill to the owner, 0.25% to the season's prize pot,\n        // 0.5% back to the trader as sIMD. On this code all three are 0 and the whole 1.5%\n        // becomes pool claims (PayoutsToPool is emitted).\n        assertEq(paid(OWNER) - ownerBefore, net * 50 / 10_000, \"owner fee not paid\");\n        assertEq(paid(address(seasons)) - prizeBefore, net * 25 / 10_000, \"prize not paid\");\n        // cashback counts however it is delivered: sIMD credit, ERC-6909 claim or plain IMD.\n        assertEq(stacker.credited(alice) + paid(alice) + amt - cashbackBefore, net * 50 / 10_000, \"cashback not paid\");\n    }\n\n    /// @dev IMD a payee can dispose of: ERC-20 held plus ERC-6909 IMD claims on the PoolManager.\n    function paid(address who) internal view returns (uint256) {\n        return imd.balanceOf(who) + pm.balanceOf(who, uint256(uint160(address(imd))));\n    }\n}","reproduction":"Launch and seed (either orientation), launch window over. bob buys 50 IMD exact-in with hookData = abi.encode(bob): PoolManager IMD balance = 50e18. alice buys 5,000 IMD exact-in with hookData = abi.encode(alice): net fill 4,926.1 IMD, out = 61.58 IMD > 50 IMD. Expected: owner +24.63 IMD, Seasons +12.32 IMD, alice credited 24.63 sIMD. Actual: PayoutsToPool(61.58e18) emitted, owner/Seasons/alice receive 0, retainClaims grows by 73.89e18. A 4,000 IMD buy (out 49.26 <= 50) pays all three. The attached proof fails on this code with 'owner fee not paid: 0 != 24630541871921182266'.","severity":"medium","snippet":"            if (imd.balanceOf(address(poolManager)) < out) {","title":"_payFees redirects the owner fee, prize share and trader cashback to pool liquidity on any buy whose 1.25% payout exceeds the PoolManager's IMD balance, not only the first buy"},{"citation":"resolved","description":"From audit_economics (e769c32f). The plea's amount is fixed at submission; unlockCallback swaps exact-in to the extreme price limit and requires the realised fill to equal it. The pool is seeded with PLEA only and the only IMD in range is what buyers paid in, so whenever the band holds less IMD than the sell needs (right after seeding, after a run of sells) the swap fills partially and the gate reverts for the whole window. The seller cannot reduce the amount, cannot retry after WindowLapsed, and has paid 0.5 oracle IMD for an approval it cannot use (which still earns season points, see finding 1). Low: the loss is the oracle fee and time, not principal. A fix would let executeSell take an amount <= p.amount, or fill what the pool can take and return the rest.","line":451,"path":"src/CabalGate.sol","reproduction":"Fixture. distributor transfers 1,000,000 PLEA to alice; alice buys 1e12 wei of IMD so her basis exists. alice: submitSell(1000e18) -> score 45 -> Approved. alice: executeSell(0) reverts PartialFill(~2.67e18, 1000e18) (actual; expected a sale of what the pool can absorb or a reducible amount). After 7 min + 1 s executeSell reverts WindowLapsed; the 0.5 IMD oracle fee is spent. Reproduced in test/scratch/Judge.t.sol::test_G_partialFill.","severity":"low","snippet":"        if (pleaIn != amount) revert PartialFill(pleaIn, amount);","title":"An approved sell can only execute as an all-or-nothing fill: when the market band holds less IMD than the plea's amount every call in the 7-minute window reverts PartialFill and the 0.5 IMD oracle fee"},{"citation":"resolved","description":"From audit_math (9a7209f9). The hook records imdSpent as imdBasis + imdFee (PleaHook.sol:500), the gross IMD paid including the 1.5% fee, and pleaHeld net of the 0.25% PLEA burn; factScore compares pleaHeld * latest / Q96 with that gross figure. Unless the checkpoint price has risen more than ~1.75% plus the buyer's own impact, value < spent for every buyer, so the component meant for holders who are losing money pays its maximum 14 points to anyone who just bought, lowering need by 14 of the 45 judge points. Fix keeping the numbers: compare against the net basis (exclude imdFee) or value pleaHeld + burned, or grant the points only when the shortfall exceeds the round-trip fee.","line":235,"path":"src/CabalGate.sol","reproduction":"Fixture, launch window over. bob buys 10 IMD (fixing the hour's checkpoint), alice buys 50 IMD in the same hour. hook.basisOf(alice).imdSpent == 50e18; pleaHeld * hook.latestPrice() / 2^96 == 48.673e18 < 50e18. gate.factScore(alice, balance/10) == 37 (actual) = 18 share + 0 time + 14 'loss' + 5 no-24h-history; expected 23 for a buyer whose price has not moved. Reproduced in test/scratch/Judge.t.sol::test_F_factScoreLossForFreshBuyer.","severity":"low","snippet":"            uint256 value = FullMath.mulDiv(heldPlea, latest, FixedPoint96.Q96);","title":"factScore's 14-point 'underwater' bonus goes to every fresh buyer because the cost basis is gross of the 1.5% IMD fee while value is net of it"},{"citation":"resolved","description":"From audit_permissions (920cefc9). closeSeason is permissionless and the only input the caller controls is which plea ids get recorded before the season is sealed. Once closed[season] is set, record() reverts SeasonClosed (line 125) and _tryRecord silently skips, so an approval nobody recorded within CLOSE_GRACE (1 hour) after the season end loses its points and Laureate eligibility forever. A plea approved in the final minutes has as little as one hour, and the actor with the strongest incentive to call closeSeason([]) at end+1h is a rival in the top ten. Documented in README (record within an hour), so recorded as a broken-guarantee edge; lengthening CLOSE_GRACE or letting record() display-only after close are the author's call.","line":218,"path":"src/Seasons.sol","reproduction":"Fixture, SEASON 18000. alice buys 50 IMD. warp(T0 + SEASON - 10 min): alice submitSell, score 45 -> Approved (plea X, verdictAt in season 0). warp(T0 + SEASON + 1 h): any address calls closeSeason([]) -> succeeds, closed[0] == true. seasons.record(X) reverts SeasonClosed(0) (actual) instead of crediting 45 points (expected). Reproduced in test/scratch/Judge.t.sol::test_E_closeEmptyDropsLate.","severity":"low","snippet":"        if (!exists || !ended || block.timestamp < uint256(end) + CLOSE_GRACE) revert NotReady(season);","title":"closeSeason with an empty list exactly one hour after a season ends permanently drops any approval nobody recorded; the caller chooses which late pleas score"},{"citation":"resolved","description":"From audit_flow (ae431723). o.appealed is set here before the 0.5 oracle IMD + 0.35 pool IMD are paid and the Intake asked. If the request completes without a verdict (panel refused/disagreed, callback reverted, or 20 minutes passed) the appeal plea is Expired by expire/_clearStale but o.appealed is never reset, so line 267 refuses a second appeal although the Cabal never judged the first, and the seller is still inside the 4-hour denial cooldown: they can neither appeal nor plead. A first-round plea with the same no-verdict completion is re-submittable at once, so the paths are asymmetric. Minimal fix: in _expire, when the expired plea isAppeal, clear pleas[originalId].appealed.","line":275,"path":"src/CabalGate.sol","reproduction":"Fixture. alice buys 50 IMD; plead(bal/10) -> signed score 0 -> Denied. alice.appeal(id, amount/2, text) -> appeal id a; getPlea(id).appealed == true. intake.complete(intakeIdOf(a), status 1, '') (completed, no callback). gate.expire(a) -> Expired. Still within verdictAt + 4 h: alice.appeal(id, amount/2, text) reverts AlreadyAppealed and alice.submitSell(amount/2, text) reverts Cooldown (actual). Expected: an appeal the Cabal never scored does not consume the single appeal. Contrast: bob's first-round plea completed with status 1 is expired by _clearStale and bob pleads again immediately. Reproduced in test/scratch/Judge.t.sol::test_D_appealNoVerdict.","severity":"low","snippet":"        o.appealed = true;","title":"appeal marks the original plea appealed before the oracle answers, so an appeal the Intake completes without a verdict burns the seller's only appeal and 0.85 IMD while the denial cooldown still locks"},{"citation":"resolved","description":"From audit_permissions (9634d841). While the Cabal lives an exact-input buy must name its recipient in hookData, so cashback, PLEA delivery and basisOf go to the real buyer. Once dead, the same buy with empty hookData is accepted and trader falls back to sender, which for every generic Uniswap v4 router is the router contract. afterSwap then calls stacker.credit(router, cashback) and records basisOf[router]: the 0.5% cashback of every such trade is minted as sIMD to a stateless router and lost to the buyer (or swept by whoever can call the router's sweep). Minimal fix without changing any fee: keep RecipientRequired for buys regardless of alive.","line":419,"path":"src/PleaHook.sol","reproduction":"Fixture. bob buys 50 IMD so the PoolManager holds IMD. skip(DEADMAN + 1): plea.restricted() == false. alice calls router.buyExactIn(10e18, '') (hookData empty). Actual: alice receives PLEA, simd.balanceOf(alice) unchanged, simd.balanceOf(router) increased by the cashback; hook.basisOf(router).pleaHeld > 0 and alice's basis is 0. Expected: cashback and basis belong to alice as for the identical call while the Cabal is alive. Reproduced in test/scratch/Judge.t.sol::test_C_cashbackToRouterAfterDeath.","severity":"low","snippet":"            if (buy && alive) revert RecipientRequired();","title":"After the Cabal dies, a buy with empty hookData credits the 0.5% cashback and the cost basis to the swap sender (the router), not to the payer"},{"citation":"resolved","description":"From write_foundry_tests (46c91083), reproduced with its proof. _applyCap stores sub-second budget consumption in capDecayRemainder (line 641) but computes the next allowance from block.timestamp - lastCapDecayAt alone, so a ratchet that consumed less than one full second leaves lastCapDecayAt unchanged and the next swap in the same second can consume the whole integer-second allowance again. The cumulative cap decrease exceeds CAP_DECAY_PER_DAY * elapsed / 1 day by less than one second of decay (about 3.47 PLEA per occurrence): a policy/accounting error, not a reserve loss. Fix: subtract capDecayRemainder from the allowance numerator, preserving the 300,000e18/day constant.","line":633,"path":"src/PleaHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PLEA} from \"src/PLEA.sol\";\nimport {PleaHook} from \"src/PleaHook.sol\";\nimport {IStacker} from \"src/interfaces/IStacker.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/interfaces/IPoolManager.sol\";\nimport {PoolKey} from \"v4-core/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/types/Currency.sol\";\nimport {SwapParams} from \"v4-core/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"v4-core/types/BalanceDelta.sol\";\nimport {TickMath} from \"v4-core/libraries/TickMath.sol\";\n\ncontract CapProofQuote is ERC20 {\n    constructor() ERC20(\"Quote\", \"Q\") {}\n    function mint(address who, uint256 amount) external { _mint(who, amount); }\n}\n\ncontract CapProofGate {\n    function restricted() external pure returns (bool) { return true; }\n}\n\ncontract CapProofStacker {\n    function credit(address, uint256) external pure { revert(\"plain cashback\"); }\n}\n\ncontract CapDecayProof is Test {\n    PLEA token;\n    CapProofQuote quote;\n    PoolManager manager;\n    PleaHook hook;\n    uint256 initialCap;\n    uint256 constant FLAGS = (1 << 13) | (1 << 11) | (1 << 7) | (1 << 6) | (1 << 3) | (1 << 2);\n\n    function setUp() public {\n        vm.chainId(11155111);\n        vm.warp(1791817200);\n        manager = new PoolManager(address(this));\n        quote = new CapProofQuote();\n        token = new PLEA(address(this));\n        CapProofGate gate = new CapProofGate();\n        CapProofStacker stacker = new CapProofStacker();\n        token.setLauncher(address(gate), address(this), address(this), makeAddr(\"distributor\"));\n        bytes memory code = abi.encodePacked(type(PleaHook).creationCode,\n            abi.encode(address(manager), address(token), address(quote), address(stacker), address(this), address(this), uint256(1300000)));\n        bytes32 hash = keccak256(code);\n        uint256 salt;\n        while (uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(salt), hash)))) & 0x3fff != FLAGS) ++salt;\n        hook = new PleaHook{salt: bytes32(salt)}(IPoolManager(address(manager)), address(token), IERC20(address(quote)), IStacker(address(stacker)), address(this), address(this), 1300000);\n        token.init(address(hook), address(manager));\n        hook.seed();\n        initialCap = hook.inventoryCap();\n        quote.mint(address(this), 1000e18);\n        vm.warp(block.timestamp + 91 minutes);\n    }\n\n    function buy(uint256 amount) internal { manager.unlock(abi.encode(amount)); }\n\n    function unlockCallback(bytes calldata raw) external returns (bytes memory) {\n        require(msg.sender == address(manager));\n        bool zeroForOne = !hook.pleaIsZero();\n        BalanceDelta delta = manager.swap(hook.poolKey(), SwapParams({zeroForOne: zeroForOne,\n            amountSpecified: -int256(abi.decode(raw, (uint256))),\n            sqrtPriceLimitX96: zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1}), abi.encode(address(this)));\n        (int128 q, int128 p) = hook.pleaIsZero() ? (delta.amount1(), delta.amount0()) : (delta.amount0(), delta.amount1());\n        manager.sync(Currency.wrap(address(quote)));\n        quote.transfer(address(manager), uint256(uint128(-q)));\n        manager.settle();\n        manager.take(Currency.wrap(address(token)), address(this), uint256(uint128(p)));\n        return \"\";\n    }\n\n    function test_capDecayCannotReuseFractionalTimeInTheSameBlock() public {\n        buy(1e12); // consumes a fraction of one second's decay budget\n        assertGt(hook.capDecayRemainder(), 0);\n        buy(100e18); // consumes the integer-second budget again, at the identical timestamp\n        uint256 maximum = hook.CAP_DECAY_PER_DAY() * (block.timestamp - hook.launchedAt()) / 1 days;\n        uint256 actual = initialCap - hook.inventoryCap();\n        emit log_named_uint(\"maximum elapsed-time decay\", maximum);\n        emit log_named_uint(\"actual decay\", actual);\n        assertLe(actual, maximum, \"cap fell faster than the agreed decay rate\");\n    }\n}","reproduction":"Real PLEA, PleaHook and v4 PoolManager; seed at timestamp 1791817200, advance 91 minutes, buy with 1e12 quote wei then 100e18 quote wei without advancing time. Expected initialCap - inventoryCap <= 18958333333333333333333; actual 18958505549857848571824. The attached proof fails on this code with 'cap fell faster than the agreed decay rate'.","severity":"low","snippet":"            uint256 allowance = CAP_DECAY_PER_DAY * elapsed / 1 days;","title":"Consecutive swaps in one second reuse the fractional inventory-cap decay budget: the cap falls faster than CAP_DECAY_PER_DAY"},{"citation":"resolved","description":"From audit_economics (47e36feb). Holding time and profit/loss are read from PleaHook.basisOf, written only by _updateBasis in afterSwap for PLEA that went through the pool. PLEA received from PleaDistributor.claim (100,000,000 PLEA) has no basis, so a pure distributor recipient scores 18 + 5 = 23, need 47 > 45, and _open reverts CannotPass: the distributor share is unsellable through the gate until the holder trades in the pool. Conversely the smallest hook buy sets imdSpent and avgBuyTime, so the same wallet immediately gets +14 'loss' (finding 5) on a position worth 1 wei and +14 holding time after 7 days while holding 1,000,000 free PLEA: the fact score describes 1 wei, not the seller's position. Fix options keeping the numbers: weight the basis by the whole balance, or exclude the profit/holding components when pleaHeld < amount.","line":226,"path":"src/CabalGate.sol","reproduction":"Fixture. distributor transfers 1,000,000 PLEA to alice. gate.factScore(alice, 1000e18) == 23; alice.submitSell(1000e18, text) reverts CannotPass(47). alice buys 1e12 wei of IMD through the router: gate.factScore(alice, 1000e18) == 37 and submitSell(1000e18) succeeds (need 33). Reproduced in test/scratch/Judge.t.sol::test_G_partialFill.","severity":"low","snippet":"        (uint256 spent, uint256 heldPlea, uint256 avgBuyTime) = h.basisOf(seller);","title":"factScore only sees hook-bought PLEA: distributor recipients cannot plead (need 47), while a 1-wei buy grants them the full loss and holding-time credits"},{"citation":"resolved","description":"Merged from audit_flow (14cbf740) and audit_economics (a6647601). The hook's IMD balance is not only the cashback in flight: retainedImd (appeal fees via fundWall, redeemed claims, closed-wall proceeds, Seasons.flushToWall leftovers) sits in the same balance, the allowance is set once and can never be reduced, so whoever controls the Sepolia Stacker (0x293C...) can transferFrom the entire wall reserve, after which the next rebalance's _settleImd reverts until retainedImd is reduced. Documented external dependency, not a code defect; a per-credit forceApprove(stacker, amount) inside _payCashback would bound exposure to one cashback.","line":374,"path":"src/PleaHook.sol","reproduction":"After seed(): imd.allowance(hook, stacker) == type(uint256).max. After gate.appeal routes 0.35 IMD via fundWall, hook.retainedImd() == R > 0 and imd.balanceOf(hook) >= R; a call imd.transferFrom(hook, X, R) made by the Stacker contract succeeds. Not reproducible against the mock Stacker (it pulls only amount); a property of the live dependency.","severity":"info","snippet":"        if (address(stacker).code.length != 0) imd.approve(address(stacker), type(uint256).max);","title":"Trust assumption: the hook grants the imd/acc Stacker an unlimited IMD allowance over its whole balance, which includes the buy wall's retained reserve"},{"citation":"resolved","description":"From audit_permissions (47b8cd47), checked against the code. (1) PLEA owner ($owner, single-step OZ Ownable): add-only allowlist of senders exempt from the Cabal rule; an allowed wallet can transfer peer-to-peer but still cannot send to the PoolManager or the gate. (2) PleaDistributor owner ($owner): sets the Merkle root once; 100,000,000 PLEA are unreachable until then and a wrong root strands them. (3) PleaHook.owner and PleaLaunch.owner are PLEA.owner() captured inside the launch transaction and immutable: the 0.5% owner fee keeps flowing to the original owner after any transferOwnership, and only that address may seed before START = 1791817200. (4) Oracle signer 0x5598... is a single key with no rotation path (_setOracleSigner is never exposed); a rotation makes the Cabal die after 33 hours and PLEA trade freely forever (fail-open). (5) The Intake is trusted to deliver each signed answer to the request that paid for it (next entry). (6) Anyone may call deployHook and, after START, seed. (7) PLEA.setLauncher's deployment-block fallback (kept per the brief) means the six constructors must run atomically; a separate-transaction deployment would let any caller register in PLEA's deployment block.","line":86,"path":"src/PLEA.sol","reproduction":"Not a failing input. Example of (1): OWNER calls plea.allow(alice); alice.transfer(bob, 1e18) succeeds while the Cabal lives (test/Token.t.sol::test_distributorAndAllowlistMaySend); alice.transfer(address(pm), 1) still reverts CabalIsWatching.","severity":"info","snippet":"    function allow(address account) external onlyOwner {","title":"Privilege map after the launch transaction (trust assumptions, not defects)"},{"citation":"resolved","description":"From audit_permissions (47d1f75d), already recorded in ADAPTATION.md. The attestation is verified against the gate's EIP-712 domain and its requestId consumed, so a signed answer settles at most one plea, but the gate never checks a.questionHash against its own question(id)/body(id) and the oracle requestId is not tied to the Intake id the callback names; only the Intake's bookkeeping routes a 45 to plea #7 rather than #8. msg.sender must be the Intake (line 382), so no unprivileged actor can trigger it. If the protocol's canonical question document is defined, pinning questionHash would close the gap without changing the ABI.","line":389,"path":"src/CabalGate.sol","reproduction":"Requires the trusted Intake to misroute: two pending pleas A (text scores 45) and B (text scores 0) from different wallets; the Intake calls onOracleResult(intakeIdOf(B), attestationFor(A), sigFor(A)). Actual: B is Approved with score 45. Expected: revert. Not reproducible by a third party.","severity":"info","snippet":"        _verifyAttestation(a, signature);","title":"onOracleResult binds a verdict to the gate's domain and consumes requestId but not to the plea: questionHash and intakeId are never compared, so a misrouting Intake could apply one unused signed answe"},{"citation":"resolved","description":"From audit_math (b0a2b30d); numbers only, recorded because the brief keeps every number. inventoryCap starts at the 899,999,100 PLEA deposit and falls at most 300,000 PLEA per day (floor 900,000). A trim fires only when the pool's PLEA exceeds the cap, and the pool never holds more than the deposit minus burns, so trims can only occur while cumulative net buying has removed less than 300,000 x days PLEA from the pool (110M after a year); reaching the floor takes 2,996 days. The trim path itself is correct. A decision for the author, not a defect.","line":84,"path":"src/PleaHook.sol","reproduction":"Fixture: buy 2,000 IMD twice (pool PLEA 899.8M -> 509.8M), skip 365 days, buy 1 wei. hook.inventoryCap() == 790,480,138 PLEA vs pleaInMarket() == 509.7M: no trim possible until sells return more than 280M PLEA. (cap0 - CAP_FLOOR) / CAP_DECAY_PER_DAY = 2,996 days.","severity":"info","snippet":"    uint256 public constant CAP_DECAY_PER_DAY = 300_000e18;","title":"Cap decay of 300,000 PLEA/day against a 900M PLEA deposit means the trim/burn path is dormant for years under realistic trading"}],"hash":"955cdf3f23ebe521d51e57a422a1d7e62f6b253e2a50d0d66f73100f869ca26a","nodeId":"f2e07a08-1c23-4ae8-851b-aeae454f2578","outcome":"completed","summary":"The review is complete. The findings file is written, every snippet matches the tree, and no tracked file was changed (only `.imd-findings.json` and my scratch tests under `test/scratch/`, which are not kept).\n\n**What I did.** I rebuilt the project offline, read all eight application sources, launch.json and the earlier contributors' notes, then reproduced every specialist finding against the code. The seven reproductions I wrote (`test/scratch/Judge.t.sol`) all pass as demonstrations, and the three proofs fail on the current code for the reasons the findings state.\n\n**Findings kept, after merging duplicates (14 total, 10 defects):**\n\n- **Medium, lapsed approval has no cooldown** (CabalGate._clearStale). Merged from the permissions and economics specialists. Bob pleads again 7 minutes after an approval he never executes while Alice is locked out 4 hours after selling; three lapsed approvals gave 135 points in 842 seconds. Carries a self-contained proof.\n- **Medium, late closeSeason pays later seasons' fees backwards** (Seasons.closeSeason). Merged from the flow and economics specialists. Alice received 12.93 IMD, five times the entire pot that existed when her season ended.\n- **Medium, _payFees redirects owner, prize and cashback to pool liquidity** on any buy over ~80x the PoolManager's IMD, not just the first. The specialist's proof fails as stated and is attached.\n- **Low:** all-or-nothing PartialFill on approved sells; 14-point \"loss\" bonus for every fresh buyer; closeSeason with an empty list drops unrecorded approvals; an unanswered appeal burns the appeal right; empty hookData after death credits the router; fractional cap-decay reuse (tester's proof attached); distributor recipients cannot plead without a 1-wei buy.\n- **Info:** Stacker unlimited allowance over the wall reserve (merged from two specialists), the privilege map, the Intake request-binding gap, and cap-decay dormancy.\n\nNothing was dropped as non-reproducing. I found no additional defect beyond the specialists' in my own pass, and no deployment-model blocker: all six manifest runtimes are under the size limits, constructor argument counts match in order, and PleaHook is deployed later by deployHook as the task states.\n\n**Coverage.** All 38 entry points are answered (33 holds, 5 pointing at findings), plus three invariant rows.","treeHash":null,"usage":{"cachedInputTokens":2275120,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":41418,"runtime":"claude","turns":27,"wallClockMs":749837}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"63458a1bd2b2d376","findings":[{"citation":"resolved","description":"Boundary: `out` (1.25% of the realised IMD fill: 0.5% cashback + 0.5% owner + 0.25% prize) is compared with the PoolManager's whole IMD balance *before* the swapper has settled its input. The comment (lines 512-513) says this is 'only possible on the first buy after seeding, before any IMD sits in the pool', but the condition is simply `net * 125 / 10000 > PM balance`, i.e. any single buy whose net fill exceeds about 80 times the IMD the pool currently holds. Early in the market's life (Sepolia market cap 5,700 IMD, pool seeded with zero IMD) that is an ordinary buy. When it triggers, the owner's 0.5%, the season prize pot's 0.25% and the trader's 0.5% cashback are all silently converted to ERC-6909 pool claims (`retainClaims`) instead: the owner and Seasons never receive the IMD the fee schedule promises them, and the trader pays a fee that was advertised as cashback. The hook already has a non-reverting path that preserves the payee (`_refund` mints ERC-6909 IMD claims to the trader when the PoolManager is short, lines 562-564); `_payFees` could mint claims to owner/seasons/hook the same way, or defer the payouts, instead of giving them to liquidity. Numbers from the reproduction (test/scratch/Payout.t.sol, both currency orientations behave the same): PM holds 50 IMD after bob's 50 IMD buy; alice buys 5,000 IMD: net = 4,926.1 IMD, out = 61.58 IMD > 50 IMD, so owner gained 0, seasons gained 0, alice's sIMD gained 0, and retainClaims grew by 73.89 IMD (the full 1.5%). A 4,000 IMD buy (out = 49.26 < 50) pays everybody normally, so the cliff is exact.","line":531,"path":"src/PleaHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/interfaces/IPoolManager.sol\";\nimport {TickMath} from \"v4-core/libraries/TickMath.sol\";\nimport {BalanceDelta} from \"v4-core/types/BalanceDelta.sol\";\nimport {Currency} from \"v4-core/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/types/PoolKey.sol\";\nimport {SwapParams} from \"v4-core/types/PoolOperation.sol\";\nimport {PLEA} from \"src/PLEA.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\nimport {Seasons} from \"src/Seasons.sol\";\nimport {Laureates} from \"src/Laureates.sol\";\nimport {PleaDistributor} from \"src/PleaDistributor.sol\";\nimport {PleaLaunch} from \"src/PleaLaunch.sol\";\nimport {PleaHook} from \"src/PleaHook.sol\";\n\ncontract ProofIMD is ERC20 {\n    constructor() ERC20(\"TestIMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @dev imd/acc Stacker shape: pulls IMD from the caller and records the credit.\ncontract ProofStacker {\n    IERC20 public imd;\n    mapping(address => uint256) public credited;\n\n    constructor(IERC20 imd_) {\n        imd = imd_;\n    }\n\n    function credit(address to, uint256 amount) external {\n        imd.transferFrom(msg.sender, address(this), amount);\n        credited[to] += amount;\n    }\n}\n\n/// @dev Intake shape: never called in this proof (no plea is submitted), present so constructors wire.\ncontract ProofIntake {\n    struct Req {\n        address payer;\n        address target;\n        bytes4 selector;\n        bool completed;\n    }\n\n    mapping(bytes32 => Req) public requests;\n}\n\n/// @dev A plain v4 router for exact-input buys against the hook's pool.\ncontract ProofRouter {\n    IPoolManager public pm;\n    PleaHook public hook;\n    IERC20 public imd;\n    IERC20 public plea;\n\n    constructor(IPoolManager pm_, PleaHook hook_, IERC20 imd_, IERC20 plea_) {\n        pm = pm_;\n        hook = hook_;\n        imd = imd_;\n        plea = plea_;\n    }\n\n    function buyExactIn(uint256 imdIn, bytes memory hookData) external {\n        pm.unlock(abi.encode(msg.sender, -int256(imdIn), hookData));\n    }\n\n    function unlockCallback(bytes calldata raw) external returns (bytes memory) {\n        require(msg.sender == address(pm), \"pm\");\n        (address payer, int256 amountSpecified, bytes memory hookData) = abi.decode(raw, (address, int256, bytes));\n        PoolKey memory key = hook.poolKey();\n        bool pleaIsZero = hook.pleaIsZero();\n        bool zeroForOne = !pleaIsZero;\n        uint160 limit = zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1;\n        BalanceDelta d = pm.swap(\n            key, SwapParams({zeroForOne: zeroForOne, amountSpecified: amountSpecified, sqrtPriceLimitX96: limit}), hookData\n        );\n        int128 imdDelta = pleaIsZero ? d.amount1() : d.amount0();\n        uint256 amountIn = uint256(uint128(-imdDelta));\n        pm.sync(Currency.wrap(address(imd)));\n        imd.transferFrom(payer, address(pm), amountIn);\n        pm.settle();\n        return \"\";\n    }\n}\n\n/// @notice PleaHook._payFees: on a buy whose 1.25% payout exceeds the PoolManager's current IMD\n/// balance, the owner's 0.5%, the prize 0.25% and the trader's 0.5% cashback are all redirected to\n/// pool liquidity. The code comment says this can only happen on the first buy after seeding; this\n/// test shows it on the second buy (50 IMD in the pool, then a 5,000 IMD buy) and expects the fee\n/// schedule to be honoured.\ncontract PayoutsToPoolOnSecondBuyTest is Test {\n    address constant OWNER = 0x4b91078b2374c956A65F7Af0999CaE0a935E6821;\n    address constant SIGNER = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n    uint256 constant CREDIT_GAS = 300_000;\n    uint256 constant T0 = 1_800_000_000;\n\n    PoolManager pm;\n    ProofIMD imd;\n    ProofIMD oimd;\n    ProofStacker stacker;\n    ProofIntake intake;\n    PLEA plea;\n    CabalGate gate;\n    Seasons seasons;\n    Laureates laureates;\n    PleaDistributor distributor;\n    PleaLaunch launch;\n    PleaHook hook;\n    ProofRouter router;\n\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.chainId(11155111);\n        vm.warp(T0);\n        vm.roll(1000);\n        pm = new PoolManager(address(this));\n        imd = new ProofIMD();\n        oimd = new ProofIMD();\n        stacker = new ProofStacker(imd);\n        intake = new ProofIntake();\n        plea = new PLEA(OWNER);\n        gate = new CabalGate(address(plea), address(intake), address(oimd), address(imd), SIGNER, 18_000, 118_800);\n        seasons = new Seasons(address(plea), address(gate), address(imd));\n        laureates = new Laureates(address(plea));\n        distributor = new PleaDistributor(address(plea), OWNER);\n        launch = new PleaLaunch(\n            address(plea),\n            address(gate),\n            address(seasons),\n            address(laureates),\n            address(distributor),\n            address(pm),\n            address(imd),\n            address(stacker),\n            CREDIT_GAS,\n            T0 + 1 days\n        );\n        bytes memory code = abi.encodePacked(\n            type(PleaHook).creationCode,\n            abi.encode(address(pm), address(plea), address(imd), address(stacker), OWNER, address(seasons), CREDIT_GAS)\n        );\n        hook = PleaHook(launch.deployHook(mineSalt(keccak256(code)), code));\n        vm.prank(OWNER);\n        launch.seed();\n        skip(91 minutes); // past the launch window: no extra fee, no per-buy cap\n        router = new ProofRouter(IPoolManager(address(pm)), hook, imd, plea);\n        for (uint256 i; i < 2; ++i) {\n            address who = i == 0 ? alice : bob;\n            imd.mint(who, 100_000e18);\n            vm.prank(who);\n            imd.approve(address(router), type(uint256).max);\n        }\n    }\n\n    function mineSalt(bytes32 initHash) internal view returns (bytes32) {\n        uint160 flags = launch.FLAGS();\n        for (uint256 s;; ++s) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), bytes32(s), initHash))))\n            );\n            if (uint160(a) & 0x3fff == flags) return bytes32(s);\n        }\n    }\n\n    function buy(address who, uint256 imdIn) internal {\n        vm.prank(who);\n        router.buyExactIn(imdIn, abi.encode(who));\n    }\n\n    function test_secondBuyStillPaysOwnerPrizeAndCashback() public {\n        buy(bob, 50e18); // IMD now sits in the pool: the documented first-buy exception is over\n        assertEq(imd.balanceOf(address(pm)), 50e18);\n\n        uint256 ownerBefore = paid(OWNER);\n        uint256 prizeBefore = paid(address(seasons));\n        uint256 cashbackBefore = stacker.credited(alice) + paid(alice);\n\n        uint256 amt = 5_000e18;\n        uint256 net = amt - amt * 150 / 10_150; // the IMD that reaches the pool\n        buy(alice, amt); // the router pulls exactly `amt` IMD from alice\n\n        // The fee schedule: 0.5% of the fill to the owner, 0.25% to the season's prize pot,\n        // 0.5% back to the trader as sIMD. On this code all three are 0 and the whole 1.5%\n        // becomes pool claims (PayoutsToPool is emitted).\n        assertEq(paid(OWNER) - ownerBefore, net * 50 / 10_000, \"owner fee not paid\");\n        assertEq(paid(address(seasons)) - prizeBefore, net * 25 / 10_000, \"prize not paid\");\n        // cashback counts however it is delivered: sIMD credit, ERC-6909 claim or plain IMD.\n        assertEq(stacker.credited(alice) + paid(alice) + amt - cashbackBefore, net * 50 / 10_000, \"cashback not paid\");\n    }\n\n    /// @dev IMD a payee can dispose of: ERC-20 held plus ERC-6909 IMD claims on the PoolManager.\n    function paid(address who) internal view returns (uint256) {\n        return imd.balanceOf(who) + pm.balanceOf(who, uint256(uint160(address(imd))));\n    }\n}","reproduction":"1. Launch and seed (any orientation). 2. bob buys 50 IMD exact-in through any v4 router with hookData=abi.encode(bob): PoolManager IMD balance = 50e18. 3. alice buys 5,000 IMD exact-in with hookData=abi.encode(alice). Expected: owner receives 0.5% of the 4,926.1 IMD fill (24.63 IMD), Seasons receives 0.25% (12.32 IMD), alice is credited 24.63 sIMD. Actual: PayoutsToPool(61.58e18) is emitted, owner/Seasons/alice receive nothing, hook.retainClaims grows by 73.89e18. The same buy of 4,000 IMD (out = 49.26e18 <= 50e18) pays all three.","severity":"medium","snippet":"            if (imd.balanceOf(address(poolManager)) < out) {\n                emit PayoutsToPool(out);\n                (cashback, toOwner, toPrize, out) = (0, 0, 0, 0);\n            }","title":"PleaHook._payFees redirects owner fee, prize and cashback to pool liquidity on any buy larger than ~80x the PoolManager's IMD balance, not only the first buy"},{"citation":"resolved","description":"Precision x invariant seam. The hook records `imdSpent` as `imdBasis + imdFee` (src/PleaHook.sol:500), i.e. the gross IMD paid including the 1.5% IMD fee, and `pleaHeld` net of the 0.25% PLEA burn. factScore then compares `pleaHeld * latest / Q96` with that gross figure. Unless the checkpoint price has risen by more than about 1.75% plus the buyer's own price impact since the buy, `value < spent` holds for every buyer, so the component meant to reward holders who are actually losing money ('P/L') pays its maximum 14 points to anyone who just bought. Measured in test/scratch/Fact.t.sol on the project's fixture: bob buys 10 IMD (fixing the hour's checkpoint), alice buys 50 IMD; alice's basis is spent = 50.000 IMD, value at the checkpoint = 48.673 IMD (2.65% short), factScore(alice, 10% of her balance) = 37 = 18 (share) + 0 (held < 1 day) + 14 ('loss') + 5 (no 24h history). When alice's own buy is the first trade of the hour (checkpoint = post-buy price) value = 49.608 IMD and the score is still 37. The invariant the scorer assumes, 'a buyer at the current price is at break-even', is broken by the fee and burn truncation, which lowers `need` by 14 of the 45 judge points for every fresh buyer. Fix options that keep the agreed numbers: compare against the net basis (`imdBasis`, excluding `imdFee`) and/or value `pleaHeld + burned`; or give the 14 points only when the shortfall exceeds the round-trip fee.","line":235,"path":"src/CabalGate.sol","reproduction":"Fixture (either orientation), launch window over. 1. bob buys 10 IMD exact-in (hookData = abi.encode(bob)). 2. alice buys 50 IMD exact-in in the same hour. 3. gate.factScore(alice, plea.balanceOf(alice)/10). Expected (scorer's intent): no 'loss' points for a buyer whose price has not moved, i.e. 23. Actual: 37; hook.basisOf(alice) = (50e18 gross, held), held * hook.latestPrice() / 2^96 = 48.673e18 < 50e18 so 14 points are added. Same result (37) if alice's buy is the first trade of its hour.","severity":"low","snippet":"            uint256 value = FullMath.mulDiv(heldPlea, latest, FixedPoint96.Q96);\n            if (value < spent) {\n                score += 14;","title":"factScore's 14-point 'underwater' bonus is granted to every fresh buyer because the cost basis is gross of fees while value is net"},{"citation":"resolved","description":"Numbers only (the brief says to keep every number as it is; this is recorded so the author knows what the agreed constants do on this supply). `inventoryCap` starts at the seeded deposit, 899,999,100 PLEA, and may fall by at most CAP_DECAY_PER_DAY = 300,000 PLEA per elapsed day (unused allowance banks without bound), with CAP_FLOOR = 900,000 PLEA. A trim (burn of pool PLEA above the cap) only fires when the pool's PLEA exceeds the cap, and the pool can never hold more than the deposit minus burns. Measured in test/scratch/Fact.t.sol: after 4,000 IMD of buys the pool holds 509.8M PLEA; after 365 further days the cap is still 790.5M PLEA; reaching the floor takes 2,996 days. So trims can only occur while cumulative net buying has removed less than 300,000 x days PLEA from the pool (110M after a year, 11% of supply); otherwise the 'trims burn 100%' path is dormant and only the 0.25% per-trade burn and the wall's settle burns reduce supply. The trim path itself is correct (test/scratch/Trim.t.sol: a 171,753 PLEA sell-back after a 2-day ratchet burns 171,753 PLEA and returns the pool to the cap within 215 wei). Decision for the author, not a code defect.","line":633,"path":"src/PleaHook.sol","reproduction":"Fixture: buy 2,000 IMD twice (pool PLEA 899.8M -> 509.8M), skip 365 days, buy 1 wei. hook.inventoryCap() = 790,480,138 PLEA vs pleaInMarket() = 509.7M: no trim is possible until sells return more than 280M PLEA to the pool. (cap0 - CAP_FLOOR) / CAP_DECAY_PER_DAY = 2,996 days.","severity":"info","snippet":"            uint256 allowance = CAP_DECAY_PER_DAY * elapsed / 1 days;\n            uint256 rateFloor = inventoryCap > allowance ? inventoryCap - allowance : 0;\n            if (next < rateFloor) next = rateFloor;","title":"Cap decay of 300,000 PLEA/day against a 900M PLEA deposit means the trim/burn mechanism cannot fire for years under any realistic trading"}],"hash":"9be53a4b5a7fabe53951a34872a275ddb2080b804dd8bcb19bb248a77427829a","nodeId":"a9396acd-e92d-4e6a-9070-87ad372689c8","outcome":"completed","summary":"The review is complete. Findings are in `.imd-findings.json` with a coverage row for all 38 entry points plus three checked invariants. No tracked file was changed; the 119 existing tests still pass offline.\n\n**What I found**\n\n1. **Medium, PleaHook._payFees (src/PleaHook.sol:531).** The fallback that sends the owner fee, prize share and trader cashback to pool liquidity triggers on any buy whose 1.25% payout exceeds the PoolManager's current IMD balance, not only on the first buy as the comment claims. With 50 IMD in the pool, a 5,000 IMD buy pays the owner nothing, the season pot nothing and the trader no cashback. All 73.89 IMD of fees become pool claims. A 4,000 IMD buy pays everyone, so the cliff is exact. A self-contained proof test is embedded. It fails on the current code and passes under a claims-based fix I tried locally and reverted.\n\n2. **Low, CabalGate.factScore (src/CabalGate.sol:235).** The 14-point \"underwater\" bonus compares a gross cost basis, fees included, against a net value. Every fresh buyer qualifies. A 50 IMD buy shows a 2.65% shortfall at the checkpoint and scores 37 instead of 23.\n\n3. **Info, cap decay constants (src/PleaHook.sol:633).** At 300,000 PLEA per day against a 900M deposit, the cap takes 2,996 days to reach the floor. The trim path is correct when reached, but it stays dormant unless net buying has removed under roughly 11% of supply after a year. The brief says to keep the numbers, so this is recorded as a design note only.\n\n**What held under probing**\n\nFee formulas never underflow or revert for amounts from 1 wei upward. Seed pricing, tick alignment and single-sided liquidity are correct in both currency orientations. The trim path burned a 171,753 PLEA sell-back to within 215 wei of the cap. The wall deployed, filled, settled and redeployed with correct burns and keeper tips. Season share percentages sum exactly to 100%, and timing boundaries in the gate and Seasons are consistent at every edge.\n\n**Not reached**\n\nLive Sepolia behaviour of the Intake, Stacker and PoolManager was not exercised, and no long fuzz campaign was run on the liquidity math beyond the targeted sweeps.","treeHash":null,"usage":{"cachedInputTokens":4526698,"inputTokens":802,"model":"claude-fable-5-1","outputTokens":91834,"runtime":"claude","turns":48,"wallClockMs":1888112}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7d454e6cee88c390","findings":[{"citation":"resolved","description":"Second-round settlement of finding c4417c7f (cashback to the router after death). The fix makes every buy require an encoded recipient, which I confirmed: after DEADMAN a router buy with empty hookData reverts and a buy with abi.encode(alice) credits alice (test_C_buyEmptyDataRevertsAfterDeath). The same fallback is still taken for sells. _payFees computes cashback = imdBasis * CASHBACK_BPS / BPS for every swap with an IMD fee, sells included (src/PleaHook.sol:530), and afterSwap then calls _payCashback(trader, cashback) and _updateBasis(trader, false, ...) (lines 501-508). While the Cabal lives sells only reach the pool through the gate, which always encodes the seller, so the fallback is unreachable; once the Cabal is dead any wallet can sell through a generic Uniswap v4 router, and a router that does not forward hookData (the Universal Router and the project's own BuyRouter shape pass whatever the caller supplies; most front ends pass nothing) is the swap sender. The 0.5% IMD cashback of every such sale is then minted as sIMD to the router and lost to the seller, and the seller's basisOf is never reduced while the router's goes to zero. Severity stays low: the loss is the cashback of a post-death sale, not principal, and the seller can avoid it by encoding their address. Minimal fix that keeps every number: apply the same RecipientRequired rule to sells once the gate is no longer the only seller (i.e. revert whenever trader == address(0)), or document that post-death sells must encode the recipient. The brief's 'free selling after death' is preserved either way: only the hookData word is required.","line":420,"path":"src/PleaHook.sol","reproduction":"Fixture (test/utils/Fixture.sol, SEASON 18000, DEADMAN 118800, launch window over). 1) buy(alice, 50e18) and buy(bob, 50e18) with hookData = abi.encode(who). 2) skip(DEADMAN + 1): plea.restricted() == false. 3) alice approves PLEA to the router and calls router.sellExactIn(plea.balanceOf(alice) / 2, \"\") (hookData empty). Actual: the sale fills (out > 0), simd.balanceOf(alice) is unchanged (gained 0), simd.balanceOf(router) grows by 125463927414719079 (0.1255 IMD = 0.5% of the 25.09 IMD fill), and hook.basisOf(alice).pleaHeld is still 8507899035819885849323161 (unchanged by the sale). Expected: the cashback is stacked for alice and alice's basis is reduced, exactly as the identical sale through the gate (hookData = seller) does while the Cabal lives. Reproduced in test/scratch/Judge2.t.sol::test_C2_sellEmptyDataAfterDeathCreditsRouter against the revised tree; the companion test_C_buyEmptyDataRevertsAfterDeath shows the buy half of the original finding is fixed.","severity":"low","snippet":"        if (trader == address(0)) {\n            if (buy) revert RecipientRequired();\n            trader = sender;\n        }","title":"Residual of c4417c7f: after the Cabal dies a sell with empty hookData still credits the 0.5% cashback and the basis update to the swap sender (the router), not to the seller"},{"citation":"resolved","description":"Settlement of the four earlier advisory findings the author disputed as policy. I re-read each against the revised code and accept the author's position; they are recorded here so the record is complete and none of them reopens the work. (a) ee3aab4e, PartialFill: executeSell still swaps the whole approved amount exact-in to the price extreme and reverts unless pleaIn == amount (this line). The author states the all-or-nothing contract is intentional and the oracle fee buys a judgment, not liquidity; the dust-funded variant that produced my reproduction is now closed by the basis-coverage rule in factScore (heldPlea >= amount), which I confirmed (test_F_factScoreCovered: a 1,000,000 PLEA distributor recipient with a 1e12-wei buy scores 23 before and after the buy and after 7 days). An approved seller whose amount exceeds the IMD in the market band still cannot execute within the window; that is the documented behaviour. (b) bfc69ac0, 14 loss points for a fresh buyer: imdSpent is gross of the 1.5% fee and pleaHeld net of the burn, so value < spent for any buyer whose checkpoint price has not risen about 1.75% (src/CabalGate.sol:237-240). The author keeps the cost/value definition; I note only that it is a scoring choice, not an arithmetic defect. (c) 75b7c738, closeSeason([]) at end + CLOSE_GRACE seals unrecorded approvals (src/Seasons.sol:50, :153, :321): documented settlement rule, timings fixed by the brief. (d) 831feb67, cap decay of 300,000 PLEA/day against a 900M deposit reaches the floor after 2,996 days: a parameter the brief preserves. The fractional-budget correction (4db127f5) is confirmed fixed: test_E_capSameSecond (three same-second buys) keeps initialCap - inventoryCap <= CAP_DECAY_PER_DAY * elapsed / 1 day and lastCapDecayAt <= block.timestamp.","line":460,"path":"src/CabalGate.sol","reproduction":"Not a failing input this round. Each item's original reproduction still holds on the revised code where the state is reachable: (a) an approved sell of more PLEA than the band holds in IMD reverts PartialFill(filled, amount) for the whole 7-minute window; (b) bob buys 10 IMD then alice 50 IMD in the same hour: gate.factScore(alice, balance/10) == 37 with 14 loss points (test_F_factScoreCovered asserts 37 for a fresh hook buyer); (c) warp to season end + 1 hour, closeSeason([]) succeeds and a later record(X) of an approval from that season reverts SeasonClosed; (d) (inventoryCap0 - CAP_FLOOR) / CAP_DECAY_PER_DAY == 2996 days.","severity":"info","snippet":"        if (pleaIn != amount) revert PartialFill(pleaIn, amount);","title":"Design limits the author confirmed and kept (settled, no change requested): all-or-nothing executeSell, gross-of-fee loss points, one-hour close grace, 300,000 PLEA/day cap decay"},{"citation":"resolved","description":"Settlement of b1646eff, d970e4be and 6af90e91, which the author confirmed as accepted assumptions and documents in ADAPTATION.md and the manifest notes. Re-checked against the revised code: (1) PLEA owner ($owner, single-step Ownable) holds an add-only sender allowlist (src/PLEA.sol:86); allowed wallets can transfer peer-to-peer but not to the PoolManager or the gate. (2) PleaDistributor owner sets the Merkle root once; 100,000,000 PLEA are unreachable until then. (3) PleaHook.owner and PleaLaunch.owner are PLEA.owner() captured in the launch transaction and immutable: the 0.5% owner fee follows the original owner after any transferOwnership, and only that address may seed before START = 1791817200. (4) The oracle signer is a single key with no rotation path; a rotation makes the Cabal die after 33 hours and PLEA trade freely (fail-open). (5) onOracleResult (src/CabalGate.sol:388-418) binds a verdict to the gate's domain and consumes requestId once but never compares questionHash or intakeId with the plea, so delivery to the right plea rests on the Intake (NotIntake blocks third parties). (6) seed() grants the Stacker an unlimited IMD allowance over the hook's whole ERC-20 balance, which includes retainedImd (appeal fees, closed-wall proceeds, Seasons.flushToWall leftovers); whoever controls the live Stacker can pull that reserve, after which the next rebalance's _settleImd reverts until retainedImd is reduced. (7) deployHook and post-START seed are permissionless; PLEA.setLauncher's deployment-block fallback (kept per the brief) requires the six constructors to run atomically in production. New this round and benign: Seasons.checkpoint() is public, so anyone may attribute a direct IMD donation to the running season; it only adds to the pot.","line":376,"path":"src/PleaHook.sol","reproduction":"Not a failing input. Examples: OWNER calls plea.allow(alice); alice.transfer(bob, 1e18) succeeds while the Cabal lives and alice.transfer(address(pm), 1) reverts CabalIsWatching (test/Token.t.sol). After seed(), imd.allowance(hook, stacker) == type(uint256).max; after an appeal routes 0.35 IMD through fundWall, hook.retainedImd() > 0 and a transferFrom(hook, x, retainedImd) made by the Stacker contract succeeds. Two pending pleas A (text scores 45) and B (text scores 0): the Intake calling onOracleResult(intakeIdOf(B), attestationFor(A), sigFor(A)) approves B with 45.","severity":"info","snippet":"        if (address(stacker).code.length != 0) imd.approve(address(stacker), type(uint256).max);","title":"Trust assumptions after the launch transaction (unchanged, not defects): privilege map, unlimited Stacker allowance over the wall reserve, Intake routing of verdicts"}],"hash":"a8a813e83c38511f6d0d7a196ebb0a2ad2ade9be9e6816b6a2847beed8cdfde7","nodeId":"f2e07a08-1c23-4ae8-851b-aeae454f2578","outcome":"completed","summary":"The review is complete. The findings file is valid, its three snippets match the tree, the scratch directory is removed, and the working tree holds no stray files.\n\n**Outcome: every fix from the last round holds. One residual remains, at low severity.**\n\nSettled findings, each re-run against the revised code with my own scratch tests and the attached proof:\n\n- **Lapsed approval cooldown (medium)**: fixed. The gate records the verdict time on lapse and refuses a new plea until four hours after it. A plea at seven minutes and at 4h minus one second reverts Cooldown, one at 4h succeeds, and the lapsed plea still scores.\n- **Late close paying later seasons' fees (medium)**: fixed. The hook checkpoints every prize fee into the running season, and a close pays only that season's fees plus rollover. Three seasons closed late each paid 25 percent of their own fees, rollover carried forward correctly, and the pot equals rollover plus open season fees after death and flush.\n- **Unfunded payouts to liquidity on later buys (medium)**: fixed. The attached proof passes on the revised tree. Only the first buy redirects; later shortages mint IMD claims to owner, Seasons and trader.\n- **Unjudged appeal burned the appeal right (low)**: fixed. Expiring an unanswered appeal clears the flag, a retry succeeds, and a judged appeal stays final.\n- **Same-second cap decay (low)**: fixed. Three same-second buys stay within the agreed rate.\n- **Dust buy lending history to untracked PLEA (low)**: fixed. The distributor whale scores 23 before and after the dust buy and after seven days.\n\n**The residual (finding 1, low)**: the recipient rule was applied to buys only. After the Cabal dies, a sell through a router with empty hookData still falls back to the swap sender, so the 0.5 percent cashback is stacked for the router and the seller's basis is never reduced. Reproduced at `src/PleaHook.sol:420`: alice's post-death sale of half her PLEA gained her no sIMD while the router gained 0.1255 IMD. Requiring the hookData word for sells too keeps free selling and every number.\n\n**Disputed items**: I accept the author's position on the all-or-nothing executeSell, the gross-of-fee loss points, the one-hour close grace and the cap-decay numbers. They are recorded as one info entry so nothing reopens. The trust assumptions (privilege map, unlimited Stacker allowance, Intake routing) are kept as a second info entry.\n\nThe project suite passes with 219 tests and no failures. The coverage record answers all 41 entry points, 40 holding and one pointing at finding 1, plus rows for each settled finding.","treeHash":null,"usage":{"cachedInputTokens":2187688,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":41863,"runtime":"claude","turns":33,"wallClockMs":902665}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"87804e27e9c9f85a","findings":[{"citation":"resolved","description":"Asymmetry between the three ways a plea leaves a wallet's slot. A denial writes lastDeniedAt (onOracleResult, src/CabalGate.sol:404-406) and an executed sell writes lastExecutedAt (executeSell, src/CabalGate.sol:422); _requireCanPlead (src/CabalGate.sol:327-330) refuses a new plea for COOLDOWN = 4 hours after either. The third exit, an approval whose 7-minute window the seller simply lets pass, only flips the status to Lapsed and clears pendingOf (this snippet). Nothing records a timestamp, so _requireCanPlead lets the same wallet submit again in the next block. Seasons counts a Lapsed plea as approved (CabalGate.result, src/CabalGate.sol:208; Seasons.record, src/Seasons.sol:121-126), so every such approval scores its 0-45 points and competes for the five Laureate slots. An unprivileged wallet that never intends to sell therefore gets one judged plea per (oracle latency + 7 minutes) for the 0.5 oracle-IMD fee, while honest participants who execute or are denied get one per 4 hours. With the Sepolia clock (5-hour seasons) an honest seller can enter at most two pleas per season; a grinder can enter around twenty, filling its best-three with the three highest scores it draws, taking the 25/18/14 % prize shares of the IMD pot and several Laureate NFTs away from sellers who used the gate as intended. Each approval also resets the dead-man, which the grinder benefits from. Minimal fix that keeps every number: treat a lapsed approval like a verdict for cooldown purposes, e.g. in this branch set lastDeniedAt[seller] = p.verdictAt (or a new lastVerdictOf[seller] checked in _requireCanPlead), so any verdict starts the 4-hour clock.","line":341,"path":"src/CabalGate.sol","reproduction":"Sepolia launch.json clock (SEASON 18000, DEADMAN 118800), trading seeded, alice and bob each bought PLEA. (1) alice: submitSell(10% of balance) -> Intake delivers score 45 -> executeSell(0). alice.submitSell(1e18, \"again\") now reverts Cooldown(until) for 4 hours (expected). (2) bob: submitSell(10% of balance) -> score 45 -> Approved; bob does nothing; skip(7 minutes + 1 s); bob.submitSell(10% of balance) SUCCEEDS (actual) where the same call for alice reverts (expected: a verdict should start the 4-hour cooldown regardless of execution). getPlea(first).status == Lapsed; Seasons.record(first) credits 45 points to bob. Repeating the cycle twice more (score 45 each, 7 min apart) gives bob bestOf(0) = 45+45+45 = 135 points about 25 minutes after his first plea, while alice is still locked out. Verified in test/scratch/Perm.t.sol::test_lapsedApprovalHasNoCooldown.","severity":"medium","snippet":"        } else if (p.status == Status.Approved && block.timestamp > uint256(p.verdictAt) + EXECUTE_WINDOW) {\n            p.status = Status.Lapsed;\n            pendingOf[seller] = 0;\n            emit PleaLapsed(id);\n        }","title":"Approved-then-lapsed pleas carry no cooldown: a wallet can plead every ~10 minutes while executed and denied sellers wait 4 hours, grinding season points and Laureate slots"},{"citation":"resolved","description":"Access x asymmetry seam. closeSeason is permissionless and the only input the caller controls is which plea ids get recorded before the season is sealed. Once closed[season] is set, record() reverts SeasonClosed (src/Seasons.sol:125) and _tryRecord silently skips (src/Seasons.sol:262), so an approved plea that nobody recorded within CLOSE_GRACE (1 hour) after the season end loses its points and its Laureate eligibility forever. A plea approved in the final minutes of a season has a window of as little as one hour, and the actor with the strongest incentive to call closeSeason at end+1h with an empty list is a rival in the top ten or top five. The points are not recoverable: the next closeSeason ignores ids whose season is closed. The behaviour is documented in README (record within an hour), so this is recorded as a broken-guarantee edge rather than a design change request; a minimal mitigation is to let record() accept pleas for a closed season only for ranking display, or to lengthen CLOSE_GRACE to cover PENDING_EXPIRY plus one season of margin, both of which are the author's call.","line":212,"path":"src/Seasons.sol","reproduction":"Sepolia clock (SEASON 18000). t0 = gate.startedAt(). warp(t0 + SEASON - 10 min): alice submitSell, score 45 -> Approved (plea id X, verdictAt inside season 0). warp(t0 + SEASON + 1 hour): any address calls closeSeason([]) -> succeeds, closed[0] = true. Then seasons.record(X) reverts SeasonClosed(0) (actual) instead of crediting 45 points (expected). warp(t0 + 2*SEASON + 1 hour): closeSeason([X]) succeeds but recorded(X) stays false. Verified in test/scratch/Perm.t.sol::test_closeWithEmptyListDropsLateApprovals.","severity":"low","snippet":"    function closeSeason(uint256[] calldata pleaIds) external {\n        for (uint256 i; i < pleaIds.length; ++i) {\n            _tryRecord(pleaIds[i]);\n        }\n        uint256 season = nextToClose;\n        (bool exists,, uint64 end, bool ended) = seasonBounds(season);\n        if (!exists || !ended || block.timestamp < uint256(end) + CLOSE_GRACE) revert NotReady(season);","title":"closeSeason with an empty list exactly one hour after a season ends permanently drops any approval nobody recorded; the caller chooses which late pleas score"},{"citation":"resolved","description":"Branch asymmetry in beforeSwap. While the Cabal lives an exact-input buy must name its recipient in hookData (RecipientRequired), so cashback, PLEA delivery and basisOf always go to the real buyer. Once the Cabal is dead the same buy with empty hookData is accepted and trader falls back to sender, which for every generic Uniswap v4 router (Universal Router, PositionManager-style routers, the project's own BuyRouter shape) is the router contract, not the payer. afterSwap then calls stacker.credit(router, cashback) (src/PleaHook.sol:606) or transfers plain IMD to the router, and records basisOf[router]. The 0.5% cashback of every such trade is paid to the wrong party: it is minted as sIMD to a stateless router and is lost to the buyer (or sweepable by whoever can call the router's sweep). Minimal fix without changing any fee: keep RecipientRequired for buys regardless of alive (or require hookData for every swap), so a buyer never silently forfeits cashback.","line":418,"path":"src/PleaHook.sol","reproduction":"Seeded pool, one priming buy so the PoolManager holds IMD. skip(DEADMAN) so plea.restricted() == false. alice calls router.buyExactIn(10e18, \"\") (hookData empty). Actual: alice receives PLEA but simd.balanceOf(alice) is unchanged and simd.balanceOf(router) increases by the cashback; hook.basisOf(router).pleaHeld > 0 while alice's basis is untouched. Expected: the cashback and basis belong to alice as they do for the identical call while the Cabal is alive (where the empty hookData reverts RecipientRequired instead). Verified in test/scratch/Perm.t.sol::test_cashbackGoesToRouterWhenHookDataEmptyAfterDeath.","severity":"low","snippet":"        if (trader == address(0)) {\n            if (buy && alive) revert RecipientRequired();\n            trader = sender;\n        }","title":"After the Cabal dies, a buy with empty hookData credits the 0.5% cashback and the cost basis to the swap sender (the router), not to the payer"},{"citation":"resolved","description":"Not defects; recorded so the judge has the privilege map. (1) PLEA owner ($owner, single-step OZ Ownable): add-only allowlist of senders exempt from the Cabal rule; an allowed wallet can transfer PLEA peer-to-peer (an OTC exit) but still cannot send to the PoolManager or the gate, and renounceOwnership only disables allow. (2) PleaDistributor owner ($owner): sets the Merkle root once; 100,000,000 PLEA (10%) are minted to the distributor at deployHook and are unreachable until a root is set; a wrong root strands them. (3) PleaHook.owner and PleaLaunch.owner are captured as PLEA.owner() inside the launch transaction and are immutable: the 0.5% owner fee keeps flowing to the original owner after any transferOwnership, and only that address may seed before START = 1791817200 (2026-10-12 15:00 UTC). (4) Oracle signer 0x5598... (an EOA on Sepolia, code length 0): every verdict rests on its key; there is no rotation path (OracleAttestationConsumer._setOracleSigner is never exposed), so a key rotation at IdentityMD makes the Cabal die after 33 hours and PLEA trade freely forever (fail-open). (5) The Intake 0x1397... is trusted to deliver each signed answer to the request that paid for it; see the next entry. (6) Anyone may call deployHook and, after START, seed; neither needs the owner. All six Sepolia dependency addresses in launch.json have code and the Intake and Stacker expose the selectors the interfaces use (checked with cast on a public Sepolia RPC); the PoolManager at 0xE03A... is a 48 kB runtime owned by 0x5b73...","line":86,"path":"src/PLEA.sol","reproduction":"Not a failing input. Example of (1): OWNER calls plea.allow(alice); alice.transfer(bob, 1e18) succeeds while the Cabal lives (test/Token.t.sol::test_distributorAndAllowlistMaySend); alice.transfer(address(pm), 1) still reverts CabalIsWatching.","severity":"info","snippet":"    function allow(address account) external onlyOwner {","title":"Trust assumptions of the launch: privileged powers and their holders after the launch transaction"},{"citation":"resolved","description":"Trust-gap note, already recorded by the previous contributor in ADAPTATION.md and retained here because it is the one place where the permission model relies on an external party's correctness rather than on a check. The attestation is verified against the gate's EIP-712 domain and its requestId is consumed, so a signed answer can settle at most one plea. But the gate never checks a.questionHash against keccak of its own question(id)/body(id), and the oracle requestId is not tied to the Intake id the callback names, so the only thing routing a 45 to plea #7 rather than plea #8 is the Intake's own bookkeeping. No unprivileged actor can trigger it: msg.sender must be the Intake (src/CabalGate.sol:382). Severity is therefore informational; if the protocol's canonical question document is defined, pinning questionHash = keccak256(bytes(body(id))) or the documented canonicalisation would close the gap without changing the ABI.","line":389,"path":"src/CabalGate.sol","reproduction":"Requires the trusted Intake to misroute: two pending pleas A (text scores 45) and B (text scores 0) from different wallets; the Intake calls onOracleResult(intakeIdOf(B), attestationFor(A), sigFor(A)). Actual: B is Approved with score 45 because nothing in the callback ties the attestation to B's question. Expected: revert. Not reproducible by a third party, so no test is supplied.","severity":"info","snippet":"        _verifyAttestation(a, signature);\n        _consume(a.requestId);\n        if (a.chainId != QUESTION_CHAIN || a.panelSize < PANEL_SIZE || a.quorum < QUORUM || a.agreed < QUORUM) {\n            revert WrongPanel();\n        }\n        uint256 score = decodeUint256(a);\n        if (score > MAX_PLEA_SCORE) revert ScoreOutOfRange(score);","title":"onOracleResult binds a verdict to the gate's domain and consumes requestId, but not to the plea: questionHash and intakeId are never compared, so a misrouting Intake could apply one unused signed answ"}],"hash":"b454820987e9aca89de305abfcb5690a224ba597e35f8cc66635dff8589b39eb","nodeId":"cf11ebdc-3341-4bac-a6b4-1740195bf10a","outcome":"completed","summary":"All five snippets match the tree at the cited lines, and the working tree shows no changes outside the findings file and the ignored scratch directory. The review is complete.\n\n## Recap\n\n**Scope covered.** Access Control, Trust Gap and Asymmetry passes over all six launch contracts plus PleaHook and OracleAttestation, against the Pashov guides. I mapped every role, every guard, and every storage variable with more than one writer, then traced the paired surfaces (submit/appeal, approve/deny/execute/lapse, alive/dead branches, record/closeSeason, beforeSwap/afterSwap). The full suite passes (119 tests), and I confirmed each claim below with scratch tests under `test/scratch/Perm.t.sol`. All six Sepolia dependency addresses in launch.json have code, the Intake and Stacker expose the selectors the interfaces call, and the oracle signer is an EOA.\n\n**Findings written to `.imd-findings.json`** (5 findings, 40 coverage rows, every listed entry point answered):\n\n1. **Medium, CabalGate.** An approval whose 7-minute window lapses writes no cooldown timestamp, unlike a denial or an executed sell. One wallet can plead every ~10 minutes, each lapsed approval still scores season points, and in the test it reaches 135 points in about 25 minutes while an executing seller is locked for 4 hours. This diverts prize shares and Laureate slots from sellers who use the gate as intended.\n2. **Low, Seasons.** `closeSeason` is permissionless and the caller picks which late approvals get recorded. A plea approved near the season end that nobody records within the one-hour grace loses its points permanently.\n3. **Low, PleaHook.** After the Cabal dies, a buy with empty hookData falls back to the swap sender, so the 0.5% cashback and cost basis go to the router contract instead of the payer. While alive the same call is refused.\n4. **Info.** The privilege map and trust assumptions: owner allowlist, distributor root, immutable hook and launch owner, no oracle signer rotation (fail-open to free trading), permissionless deployHook and post-START seed.\n5. **Info.** The oracle callback binds to the gate's domain and consumes the request id but never compares questionHash or the intake id, so routing rests on the trusted Intake. No unprivileged trigger exists.\n\n**What holds.** The PLEA transfer rule closes every path to the PoolManager and the gate for non-privileged senders, including the ERC-6909 claim route. Launch wiring, one-shot initialisation, constructor argument order, and the Sepolia numbers all check out. No critical or high defect was found, so no proof files were attached.","treeHash":null,"usage":{"cachedInputTokens":2673428,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":73541,"runtime":"claude","turns":35,"wallClockMs":1411357}},{"artifacts":[],"attempt":1,"bundleHash":"88f10a6b5a0c67b74d4b36265a17819a720b7932ae963ace74b44497aaaa62db","device":"1aabf616dd57561c","findings":[],"hash":"ddc531b55b1d42fd987fd1e972a1075b3bac705aaf1efa0ac1f8aa08897f4628","nodeId":"f534a9bf-19c8-4451-a905-3ad6d92f773b","outcome":"completed","summary":"Implemented seven reproduced fixes and answered all 19 findings.\n\n`forge build` succeeds; all 158 local tests pass, including the unchanged reviewer proof. Launch parameters and protected files remain unchanged.\n\nDetails are recorded in `ADAPTATION.md` and `.imd-responses.json`, including disputed findings and remaining trust assumptions.","treeHash":"4ff2d6856b6e11bd09c9d428459f092c5e8be648","usage":{"cachedInputTokens":4840704,"inputTokens":166398,"model":"gpt-6-astra","outputTokens":41552,"runtime":"codex","turns":9,"wallClockMs":1632506}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"63c29c49a249ab7e","findings":[{"citation":"resolved","description":"Economic / flow-gap (execution x first principles). A plea is, by the protocol's own description, a request to sell; the season pot (25/18/14/11/9/7/6/4/3/3 % of 0.25% of all volume) and the Laureate NFTs reward the best such pleas. Two gaps let the pot be captured by wallets that never sell. (1) `_requireCanPlead` enforces the 4-hour COOLDOWN only after an executed sell (`lastExecutedAt`, set in `executeSell`) or a denial (`lastDeniedAt`, set in `onOracleResult`). An approval whose 7-minute window passes is turned into `Status.Lapsed` by `_clearStale` (src/CabalGate.sol:341-344) without recording any timestamp, so the same wallet pleads again immediately, and `result()` (src/CabalGate.sol:208) still counts a Lapsed plea as approved for `Seasons.record`. Executed -> 4 h, Denied -> 4 h, Lapsed -> 0 h: the asymmetry defeats the purpose of the denial cooldown (no immediate re-roll of the oracle) for exactly the wallets that score. (2) `_checkAmount` (src/CabalGate.sol:372) refuses only `amount == 0`, `amount > MAX_SELL` and `amount > 35% of balance`, so a wallet holding a fraction of one PLEA may plead to sell 1 wei; a buy with `hookData = abi.encode(wallet)` for 1e-6 IMD both funds it and sets its `basisOf`, which gives the fact score +18 (share 0 bps) +14 ('loss', fees make value < spent) +5 (no 24h checkpoint) = 37, need 33. Each approved plea costs 0.5 oracle IMD and earns the judges' score as points, best three per wallet count, so one wallet reaches the maximum 135 points for 1.5 IMD and 3 wei of 'intent to sell' and keeps everything it holds. Ten such wallets reusing one high-scoring text take all ten prize slots and the five Laureates; genuine sellers, who wait 4 hours after every real sale, are out-competed by wallets with no exposure. Economics: with 20,000 IMD of volume in a season the pot is ~50 IMD against ~15 IMD of oracle fees and dust. Minimal fix that keeps the design: record a cooldown when an approval lapses (e.g. set `lastExecutedAt[seller]` or a dedicated `lastLapsedAt` in `_clearStale`) so Lapsed costs the same 4 hours as Executed/Denied; whether to add a minimum plea amount or balance is a product decision.","line":327,"path":"src/CabalGate.sol","reproduction":"Setup: PLEA, CabalGate(..., SEASON 18000, DEADMAN 118800), Seasons, Laureates, PleaDistributor, PleaLaunch; deployHook; owner seed(); skip 91 min. Steps: 1) alice buys 50 IMD of PLEA through a v4 router (hookData = alice). 2) alice: gate.submitSell(bal/10, text) -> id1; Intake delivers a signed score 45 -> status Approved. 3) skip(7 minutes + 1). 4) alice: gate.submitSell(bal/10, text) -> EXPECTED Cooldown(until) like after an executed sell or a denial; ACTUAL succeeds (id2), id1 is now Lapsed and `gate.result(id1)` still reports approved=true with score 45. Dust variant (test/scratch/LapseNoCooldown.t.sol, fails on current code): alice buys with imdIn = 1e12 and hookData = abi.encode(dust) -> dust holds ~1e17 wei PLEA; dust: submitSell(1, text) succeeds (need 33); score 45 -> Approved; skip 7 min + 1; repeat twice; seasons.record each: seasons.topOf(0)[0] == dust with 135 points while plea.balanceOf(dust) is unchanged; closeSeason after the season pays dust 25% of the pot and mints it Laureate #1. The proof test (test/scratch/LapseProof.t.sol) fails on the current code with 'next call did not revert as expected'.","severity":"medium","snippet":"        uint256 until = lastExecutedAt[seller] + COOLDOWN;\n        if (lastExecutedAt[seller] != 0 && block.timestamp < until) revert Cooldown(until);\n        until = lastDeniedAt[seller] + COOLDOWN;\n        if (lastDeniedAt[seller] != 0 && block.timestamp < until) revert Cooldown(until);","title":"Lapsed approval carries no cooldown and dust balances may plead: season prizes and Laureates are farmable by wallets that never sell"},{"citation":"resolved","description":"Flow gap (execution x first principles) / broken coupling between the prize accrual clock and the season clock. The hook pays 0.25% of every trade to Seasons continuously (`PleaHook._payFees`, `poolManager.take(c, seasons, toPrize)`), but the pot is not attributed to seasons: `closeSeason` snapshots `pot()` = the whole IMD balance at the moment it is called and pays season N's top ten from it. `closeSeason` is permissionless and only possible from `end + CLOSE_GRACE` (1 hour) onwards; nothing forces it to happen then. Every fee earned between the end of season N and the actual close, i.e. season N+1's (and later) fees, is paid to season N's winners, and season N+1's contenders inherit only what is left. The README says 'unpaid shares roll over' (forwards), not that later seasons' fees flow backwards; on Sepolia with 5-hour seasons and no keeper, closes will routinely be late by many hours or days. The leader of season N also has an incentive to delay or front-run: they can wait for a large buy (or make one: 2,000 IMD of buys add 5 IMD to the pot at a 1.5% fee cost of 30 IMD, but a whale buying anyway adds it for free) and then call closeSeason. Fix that keeps the design: snapshot the pot at the season boundary (e.g. record `potAt[season]` on the first call after `end`, or have the hook/Seasons bucket prize fees by `currentSeason()`), paying season N from fees earned up to its end plus rollover only.","line":222,"path":"src/Seasons.sol","reproduction":"Fixture (Seasons 5 h, DEADMAN 33 h), test/scratch/PotTiming.t.sol test_lateCloseHandsNextSeasonFeesToPreviousWinners (passes = demonstrates). 1) alice and bob buy 1,000 IMD each; alice records three approved pleas scored 45 in season 0 (135 points). 2) Keep the Cabal alive with denied verdicts and warp to the end of season 0: seasons.pot() = 2.463 IMD. 3) Nobody closes. In season 1 bob records three 45s (135 points) and carol buys 10 x 2,000 IMD: pot() = 51.724 IMD (49.26 IMD earned in season 1). 4) seasons.closeSeason([]) for season 0: alice receives 12.931 IMD = 25% of 51.724, instead of 0.616 IMD = 25% of the 2.463 IMD that existed when her season ended; season 1's pot for bob starts 12.3 IMD short. Expected: a season's prizes are a share of the fees earned during that season (plus rollover); actual: a share of everything earned until someone calls closeSeason.","severity":"medium","snippet":"        uint256 amountIn = pot();\n        uint256 paid;\n        Entry[10] memory t = _top[season];","title":"closeSeason pays the entire pot at call time, so prize fees earned in later seasons go to the previous season's winners whenever a close is late"},{"citation":"resolved","description":"Economic / invariant (view-vs-intent divergence). The fact score is meant to reflect the seller's real position: holding time (0/5/9/14) and profit or loss (14/9/5/0) of what they hold. Both are read from `PleaHook.basisOf(seller)`, which is only written by `_updateBasis` in `afterSwap`, i.e. only for PLEA that went through the pool with `hookData = abi.encode(seller)`. PLEA received from `PleaDistributor.claim` (the 10% share, 100,000,000 PLEA) has no basis. Two consequences: (a) a pure distributor recipient scores at most 18 (share) + 5 or 9 (24h trend) = 23-27 -> need 43-47, and `_open` reverts `CannotPass(47)` in the common case, so the swarm share is effectively unsellable while the Cabal lives unless the holder first trades in the pool; (b) the holding-time and loss components are fully determined by the smallest hook buy: buying 1 wei of IMD sets `imdSpent = 1`, `pleaHeld ~ 1.7e5 wei`, `avgBuyTime = now`; fees make value < spent, so the same wallet immediately gets +14 'loss' on a position worth 1 wei while holding 1,000,000 free PLEA, and +14 holding time after 7 days: need drops from 47 to 19, the easiest possible plea. The fact score is thus not a fact about the seller's 1,000,000 PLEA but about 1 wei of it. A whale who bought early at a low price can likewise reset `avgBuyTime` weighting only by buying a comparable amount, but can never be penalised for the free tokens. Fix options preserving the numbers: weight the basis by the seller's whole balance (treat PLEA without basis as spent 0 / held since the distributor claim), or exclude the profit/holding components when `pleaHeld < amount`.","line":226,"path":"src/CabalGate.sol","reproduction":"Fixture, test/scratch/FactScore.t.sol test_oneWeiBuyGrantsFullLossAndHoldingCreditToADistributorWhale (passes = demonstrates). 1) distributor transfers 1,000,000 PLEA to alice (same path as claim). gate.factScore(alice, 1000e18) == 23; alice: submitSell(1000e18, text) reverts CannotPass(47). 2) alice buys 1 wei of IMD through the router: basisOf(alice) = (1, ~1.7e5, now); gate.factScore(alice, 1000e18) == 37. 3) 7 days later (Cabal kept alive by bob's denied pleas): gate.factScore(alice, 1000e18) == 51; submitSell(1000e18) succeeds with need == 19.","severity":"low","snippet":"        (uint256 spent, uint256 heldPlea, uint256 avgBuyTime) = h.basisOf(seller);\n        if (avgBuyTime != 0 && avgBuyTime <= block.timestamp) {\n            uint256 held = block.timestamp - avgBuyTime;\n            if (held >= 7 days) score += 14;\n            else if (held >= 3 days) score += 9;\n            else if (held >= 1 days) score += 5;\n        }","title":"factScore only sees hook-bought PLEA: distributor recipients cannot plead (need 47), while a 1-wei buy grants them the full loss and holding-time credits (need 19)"},{"citation":"resolved","description":"Flow gap (execution x periphery x first principles). The gate promises 'a seven-minute window to sell through this gate' once approved, and the plea's amount is fixed at submission (p.amount). `unlockCallback` swaps exact-in with the extreme price limit and then requires the realised fill to equal the amount. The pool is seeded with PLEA only, the hook is the only LP, and the only IMD in range is what buyers have paid in (plus the wall below the price), so whenever the market band holds less IMD than the sell needs (right after seeding, after a run of sells, or after a trim moved IMD to claims) the swap fills partially and the gate reverts for every call in the window. The seller cannot reduce the amount (it is stored), cannot retry later (WindowLapsed), paid 0.5 oracle IMD for an approval it cannot use, and has to plead again (and the approval still earns season points, see finding 1). Expected: either fill what the pool can take and return the rest, or let `executeSell` take an `amount <= p.amount`. Low because the seller's loss is the oracle fee and time, not principal, and the condition depends on pool state.","line":451,"path":"src/CabalGate.sol","reproduction":"Fixture, test/scratch/FactScore.t.sol test_approvedSellerCannotExecuteIntoAnImdLessPool (passes = demonstrates). 1) distributor transfers 1,000,000 PLEA to alice; alice buys 1e12 wei of IMD so her basis exists (pool now holds ~1e-6 IMD plus the fee dust). 2) alice: submitSell(1000e18) -> Approved with score 45. 3) alice: executeSell(0) reverts PartialFill(2665982110550151208, 1000000000000000000000): the pool filled 2.67 PLEA of the 1,000 requested. 4) After 7 minutes + 1 s executeSell reverts WindowLapsed; the 0.5 IMD oracle fee is spent and the plea is Lapsed.","severity":"low","snippet":"        if (pleaIn != amount) revert PartialFill(pleaIn, amount);","title":"An approved sell can only execute as an all-or-nothing fill: when the pool holds less IMD than the plea's amount the whole 7-minute window reverts PartialFill and the 0.5 IMD oracle fee is lost"},{"citation":"resolved","description":"Documented as a trust assumption, not a bypass. `seed()` approves the imd/acc Stacker (launch.json: 0x293C7134Ab8f6Bf1D8fF44Ed806575f8F1bAF477, verified on Sepolia to have code, `IMD() == 0x2B69...` the pool's TestIMD, and the `credit(address,uint256)` selector) for type(uint256).max of IMD, while the hook holds `retainedImd` (appeal fees, wall reserve between rebalances, unpaid cashback) as ERC-20 IMD. `credit` only needs `amount` per swap; a Stacker upgrade, bug or compromised owner could `transferFrom` the entire reserve. A per-credit `forceApprove(stacker, amount)` inside `_payCashback` would bound exposure to one cashback at a time at ~5k gas per swap. No change required by the brief; recorded so the owner knows the Stacker is a custodian of the wall reserve.","line":374,"path":"src/PleaHook.sol","reproduction":"State after seed: imd.allowance(hook, stacker) == type(uint256).max. Any later hook balance (e.g. appeal fees via fundWall: 0.35 IMD each, closed-wall IMD between rebalances) is pullable by whoever controls the Stacker contract with imd.transferFrom(hook, x, balance). Not reproducible against the mock Stacker (it only pulls `amount`); it is a property of the live dependency.","severity":"info","snippet":"        if (address(stacker).code.length != 0) imd.approve(address(stacker), type(uint256).max);","title":"Trust assumption: the hook grants the Stacker an unlimited IMD allowance over the whole wall reserve"}],"hash":"f5846c9c0a7ee982259b38d59b1be074f3c044abcc26fd25758ecab6db86a539","nodeId":"fbedc6d1-058e-4aec-bada-9afc70f27da5","outcome":"completed","summary":"Review complete. The findings file at the repository root holds 5 findings and a 43-row coverage record, every snippet verified against the tree, and the one proof test confirmed to fail on the current code.\n\n**What I found (Economic Security, Invariant, Flow Gap area)**\n\n1. **Medium, src/CabalGate.sol:327.** An approved plea that is never executed starts no cooldown. Executed and Denied cost 4 hours, Lapsed costs nothing, and `_checkAmount` lets a wallet holding a fraction of one PLEA plead to sell 1 wei. Three lapsed approvals from a wallet funded with 1e-6 IMD reach 135 points and the top prize slot without selling anything. Proof test fails on the current code and passes once a lapsed approval starts the same cooldown.\n2. **Medium, src/Seasons.sol:222.** The pot is snapshotted when `closeSeason` is called, not when the season ends. In the reproduction the season-0 winner received 12.93 IMD, which is 25% of 51.72 IMD, although only 2.46 IMD had been earned when season 0 ended. The rest belonged to season 1.\n3. **Low, src/CabalGate.sol:226.** The fact score only sees hook-bought PLEA. A distributor recipient holding 1,000,000 PLEA gets need 47 and cannot plead; after buying 1 wei of IMD the same wallet gets the full loss credit at once and the holding-time credit after 7 days, need 19.\n4. **Low, src/CabalGate.sol:451.** An approved sell is all-or-nothing. With little IMD in the pool `executeSell` reverts `PartialFill` for the whole window and the 0.5 IMD oracle fee is lost.\n5. **Info, src/PleaHook.sol:374.** The unlimited IMD allowance makes the Stacker a custodian of the wall reserve. Recorded as a trust assumption.\n\n**What held.** Hook delta conservation for every swap shape, the fee split, cap and trim accounting, wall deployment and keeper tip bounds, the dead-man clock, replay consumption, the PLEA transfer matrix, the launch wiring and the manifest. I also checked the live Sepolia dependencies over RPC: the Intake exposes both selectors and the 4-word `requests` tuple the gate decodes, the Stacker's token is the pool's TestIMD and it has the `credit` selector, TestIMD has no pause or blacklist, the PoolManager already holds tIMD, and the oracle signer is an EOA.\n\n**Not reached.** No long fuzz campaign over the hook's liquidity math, and the live Intake's binding of an attestation to the paid request remains the documented trust assumption from the earlier adaptation.","treeHash":null,"usage":{"cachedInputTokens":2849977,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":91748,"runtime":"claude","turns":42,"wallClockMs":1877148}}],"verification":[{"checks":[{"durationMs":137835,"exitCode":0,"name":"build","output":"Compiling 134 files with Solc 0.8.26\nSolc 0.8.26 finished in 137.71s\nCompiler run successful!\n","passed":true},{"durationMs":9358,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_callbackSelectorHasTheProtocolStruct() (gas: 748)\n[PASS] test_digestMatchesTheProtocol() (gas: 10505)\n[PASS] test_liveAttestationRecoversToOracleSigner() (gas: 130878)\n[PASS] test_protocolSignatureRecoversToVectorSigner() (gas: 13921)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.69ms (1.97ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:PostLaunchHookTest\n[PASS] test_committedHookDeploysLaterAndMintsOnlyTheFixedSplit() (gas: 9062751)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.00ms (5.05ms CPU time)\n\nRan 3 tests for test/LaunchManifest.t.sol:RehearsalManifestTest\n[PASS] test_laterBlockCannotRegisterLauncher() (gas: 14025019)\n[PASS] test_separateConstructorCallsInDeploymentBlockStillWork() (gas: 14713798)\n[PASS] test_separateTransactionsLeaveTheAcceptedDeploymentBlockWindow() (gas: 14184022)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 12.69ms (5.84ms CPU time)\n\nRan 3 tests for test/HookAdversarial.t.sol:LaunchFeeBoundaryTest\n[PASS] testFuzz_launchFeeOnlyFallsWithTime(uint256,uint256) (runs: 256, μ: 23851, ~: 23972)\n[PASS] test_largeLaunchBuyRollsBackAndSucceedsAtWindowEnd() (gas: 686783)\n[PASS] test_launchFeeHasExactStartMidpointAndEndValues() (gas: 42727)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 26.71ms (6.14ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:AtomicManifestTest\n[PASS] test_factoryDeploysExactManifestOnAnEmptySepoliaChain() (gas: 30165537)\nLogs:\n  six-contract factory deployment gas: 15868055\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 29.47ms (23.27ms CPU time)\n\nRan 10 tests for test/Orientation.t.sol:HookPleaIsZeroTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1158821)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1060766)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1207396)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1723225)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 550472)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1058432)\n[PASS] test_orientationIsPleaZero() (gas: 15725)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1109208)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4110336)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 725412)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 34.86ms (12.62ms CPU time)\n\nRan 9 tests for test/Hook.t.sol:HookTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1158821)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1060766)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1207374)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1723225)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 550450)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1058410)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1109208)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4110336)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 725412)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 36.95ms (8.30ms CPU time)\n\nRan 6 tests for test/DistributorAdversarial.t.sol:DistributorAdversarialTest\n[PASS] testFuzz_modifiedLeafOrProofCannotRedirectFunds(uint8,uint8,uint256) (runs: 256, μ: 259249, ~: 259212)\n[PASS] test_claimsCrossBitmapWordsAndCannotBeClaimedTwice() (gas: 1716099)\n[PASS] test_failedTokenTransferRollsBackBitmapAndCanBeRetried() (gas: 316968)\n[PASS] test_fullAllocationAndZeroAmountLeavesDoNotCorruptAdjacentBits() (gas: 260336)\n[PASS] test_rootCannotChangeAfterCommitmentEvenBeforeFirstClaim() (gas: 115955)\n[PASS] test_unsetRootAndUnauthorizedRootDoNotConsumeClaims() (gas: 275919)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 40.16ms (44.99ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_distributorAndAllowlistMaySend() (gas: 208891)\n[PASS] test_freeForeverOnceTheCabalDies() (gas: 183694)\n[PASS] test_launcherAndInitAreOneShot() (gas: 127042)\n[PASS] test_walletsCannotSendWhileTheCabalWatches() (gas: 313213)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 46.63ms (564.03µs CPU time)\n\nRan 20 tests for test/Gate.t.sol:GateTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8005967)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6440526)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3920871)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3257902)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3796268)\n[PASS] test_callbackFitsTheStipend() (gas: 5467043)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3643081)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 353449)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5780321)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5370757)\n[PASS] test_onePendingPleaPerWallet() (gas: 3098819)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5366141)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3185476)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5398579)\n[PASS] test_scoreBelowNeedDenies() (gas: 3422872)\n[PASS] test_sellWindowLapses() (gas: 5408466)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3271062)\n[PASS] test_textFilter() (gas: 3369179)\n[PASS] test_wrongSignerIsRefused() (gas: 3235655)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 89.15ms (24.28ms CPU time)\n\nRan 10 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3247287)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230739)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17412651)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 44243105)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8603614)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3358998)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32062767)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29690317)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81458293)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 97.76ms (94.86ms CPU time)\n\nRan 3 tests for test/OracleReplay.t.sol:OracleReplayTest\n[PASS] testFuzz_oneSignedRequestCannotSettleTwoPleas(bool,bool) (runs: 32, μ: 5576185, ~: 5586751)\n[PASS] test_deniedRequestCannotBeResignedToApproveItsAppeal() (gas: 5833031)\n[PASS] test_invalidCallbackDoesNotConsumeTheRequest() (gas: 5425209)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 113.72ms (69.73ms CPU time)\n\nRan 11 tests for test/Orientation.t.sol:SeasonsPleaIsZeroTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3247309)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230850)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17412673)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 44243127)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8603614)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3359020)\n[PASS] test_orientationIsPleaZero() (gas: 15664)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32062767)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29690339)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81458315)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 116.33ms (88.00ms CPU time)\n\nRan 11 tests for test/HookAdversarial.t.sol:HookAdversarialTest\n[PASS] testFuzz_immediateRoundTripCannotProfitIncludingCashback(uint256) (runs: 256, μ: 1040370, ~: 1033055)\n[PASS] test_exactOutputBuyWorksAfterDeathAndKeepsAllAccountingSettled() (gas: 1147839)\n[PASS] test_firstPartialFillRefundIsBackedByRedeemableQuoteClaims() (gas: 632131)\n[PASS] test_hookCallbacksRejectCallersAndForeignPools() (gas: 134434)\n[PASS] test_keeperTipsRequireWorkAndRespectTheOneHourCooldown() (gas: 1188630)\n[PASS] test_onlyHookMayInitializeOrAddLiquidity() (gas: 64005)\n[PASS] test_partialFillRefundChargesOnlyRealizedImdAndKeepsCostBasisCorrect() (gas: 1221155)\n[PASS] test_realCreditBudgetMustBeAffordableAndExhaustedCreditFallsBack() (gas: 2461353)\n[PASS] test_seedAndUnlockAreOneShotAndOnlyAuthorizedContextsWork() (gas: 137974)\n[PASS] test_wallFundingCannotCreateUnbackedReserveWhenTransferFails() (gas: 290063)\n[PASS] test_zeroBuyRevertsAndOneWeiBuyConservesSupply() (gas: 573405)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 117.21ms (105.56ms CPU time)\n\nRan 11 tests for test/HookAdversarial.t.sol:HookAdversarialPleaZeroTest\n[PASS] testFuzz_immediateRoundTripCannotProfitIncludingCashback(uint256) (runs: 256, μ: 1040601, ~: 1033573)\n[PASS] test_exactOutputBuyWorksAfterDeathAndKeepsAllAccountingSettled() (gas: 1148563)\n[PASS] test_firstPartialFillRefundIsBackedByRedeemableQuoteClaims() (gas: 632071)\n[PASS] test_hookCallbacksRejectCallersAndForeignPools() (gas: 135262)\n[PASS] test_keeperTipsRequireWorkAndRespectTheOneHourCooldown() (gas: 1204566)\n[PASS] test_onlyHookMayInitializeOrAddLiquidity() (gas: 63945)\n[PASS] test_partialFillRefundChargesOnlyRealizedImdAndKeepsCostBasisCorrect() (gas: 1221141)\n[PASS] test_realCreditBudgetMustBeAffordableAndExhaustedCreditFallsBack() (gas: 2460873)\n[PASS] test_seedAndUnlockAreOneShotAndOnlyAuthorizedContextsWork() (gas: 137974)\n[PASS] test_wallFundingCannotCreateUnbackedReserveWhenTransferFails() (gas: 290039)\n[PASS] test_zeroBuyRevertsAndOneWeiBuyConservesSupply() (gas: 572929)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 139.98ms (124.87ms CPU time)\n\nRan 6 tests for test/SeasonRanking.t.sol:SeasonRankingTest\n[PASS] testFuzz_rankingsMatchSortedResultsInAnyRecordOrder(uint256) (runs: 32, μ: 11228556, ~: 11206461)\n[PASS] test_closeSeasonUsesTheSameTiesForPrizesAndNfts() (gas: 1233690)\n[PASS] test_earlierEqualScoreCanReplaceACountedPleaWithoutChangingPoints() (gas: 879686)\n[PASS] test_earlierTiedPleaTakesFirstAndFifthLaureateSlots() (gas: 1191499)\n[PASS] test_replacingALowerScoreRemovesItsIdFromTheTieKey() (gas: 879654)\n[PASS] test_walletTieUsesNewestCountedPleaNotLastRecordedPlea() (gas: 910672)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 173.82ms (178.19ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_deployHookChecksTheInitCodeAndFlags() (gas: 364251178)\n[PASS] test_eachStepFitsAMainnetTransaction() (gas: 363307703)\nLogs:\n  launch (6 contracts + intake mock): 826923\n  deployHook: 5217579\n  seed: 534221\n\n[PASS] test_launchWiresEverythingWithoutCallingOutside() (gas: 861024)\n[PASS] test_ownerMaySeedEarly() (gas: 363322636)\n[PASS] test_seedByOwnerAnyTimeByAnyoneAfterStart() (gas: 363418802)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 193.61ms (720.29ms CPU time)\n\nRan 21 tests for test/Orientation.t.sol:GatePleaIsZeroTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8006079)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6440698)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3920991)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3257954)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3796710)\n[PASS] test_callbackFitsTheStipend() (gas: 5467125)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3643141)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 353449)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5780373)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5370817)\n[PASS] test_onePendingPleaPerWallet() (gas: 3098819)\n[PASS] test_orientationIsPleaZero() (gas: 15796)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5366253)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3185528)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5398661)\n[PASS] test_scoreBelowNeedDenies() (gas: 3422962)\n[PASS] test_sellWindowLapses() (gas: 5408526)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3271114)\n[PASS] test_textFilter() (gas: 3369179)\n[PASS] test_wrongSignerIsRefused() (gas: 3235685)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 259.61ms (31.40ms CPU time)\n\nRan 11 tests for test/SeasonAdversarial.t.sol:SeasonAdversarialTest\n[PASS] testFuzz_failedPrizeDoesNotBlockOthersAndUnpaidShareReachesWall(bool) (runs: 256, μ: 1846440, ~: 1845568)\n[PASS] testFuzz_namesAreUniqueIdempotentAndReleasedOnClear(uint256,uint8) (runs: 256, μ: 298493, ~: 296527)\n[PASS] testFuzz_prizeRoundingConservesAnOddSizedPot(uint256) (runs: 256, μ: 4943460, ~: 4958065)\n[PASS] test_batchIgnoresUnknownDeniedAndRepeatedIdsButCannotReopenASeason() (gas: 1076540)\n[PASS] test_closeBeforeGraceRollsBackItsBatchRecording() (gas: 749447)\n[PASS] test_flushBeforeFinalCloseCannotMoveAnyFunds() (gas: 419227)\n[PASS] test_invalidNamesAndFailedRenamesPreserveTheOldReservation() (gas: 872503)\n[PASS] test_metadataDecodesToValidJsonAndEscapesUntrustedTextInSvg() (gas: 3039654)\n[PASS] test_onlySeasonsMintsAndFailedMintCannotIncrementSupply() (gas: 307118)\n[PASS] test_prizesRequireSixtyPointsButLaureatesDoNot() (gas: 1442647)\n[PASS] test_recordRejectsDenialsDuplicatesAndLateApprovals() (gas: 892099)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 288.33ms (578.21ms CPU time)\n\nRan 16 tests for test/GateAdversarial.t.sol:GateAdversarialTest\n[PASS] testFuzz_panelAndAnswerValidationCannotConsumeRequests(uint8) (runs: 256, μ: 3353277, ~: 3356873)\n[PASS] testFuzz_printablePleaRoundTripsThroughQuestionJson(uint256,uint16) (runs: 256, μ: 4674533, ~: 4848314)\n[PASS] test_amountLimitsFailBeforeChargingAndOneWeiCanBeSubmitted() (gas: 3366112)\n[PASS] test_appealIsAcceptedAtItsLastSecondAndCannotBeStolen() (gas: 5722237)\n[PASS] test_appealOracleFeeFailureRollsBackWallFundingAndOriginalFlag() (gas: 6204319)\n[PASS] test_approvedWindowOnlyClearsAfterTheLastSecond() (gas: 5275523)\n[PASS] test_changingSignedAnswerOrConsumerChainInvalidatesSignature() (gas: 3377645)\n[PASS] test_deadManExpiresAtTheExactSecondAndNeverAcceptsANewVerdict() (gas: 3273375)\n[PASS] test_denialCooldownEndsExactlyAtFourHours() (gas: 5253922)\n[PASS] test_futureIssuanceAndExpiredAttestationsRejectAtExactBoundaries() (gas: 5444914)\n[PASS] test_gateUnlockCallbackCannotBeInvokedOutsideItsOwnSale() (gas: 86519)\n[PASS] test_latePendingCannotConsumeSignatureOrExtendHeartbeat() (gas: 3263395)\n[PASS] test_malformedUtf8AndHiddenControlsFailWithoutCharging() (gas: 808621)\n[PASS] test_missingSellAllowanceDoesNotConsumeTheApprovedPlea() (gas: 3350990)\n[PASS] test_pendingAndExecutionDeadlinesAreInclusive() (gas: 3798494)\n[PASS] test_slippageRevertRestoresApprovalSupplyAndAllFeeState() (gas: 4395638)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 289.15ms (351.79ms CPU time)\n\nRan 11 tests for test/Seasons.t.sol:FastClockTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3246625)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230761)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17411418)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 39892510)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8622981)\n[PASS] test_fastFullCycle() (gas: 58520110)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13499)\n[PASS] test_onlyApprovedPleasScore() (gas: 3356039)\n[PASS] test_secondSeasonScoresSeparately() (gas: 36375760)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29688119)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 85759678)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 288.39ms (106.10ms CPU time)\n\nRan 1 test for test/DistributorAdversarial.t.sol:DistributionInvariantTest\n[PASS]\nDistributionInvariantTest invariants:\n[PASS] invariant_deathAndSystemWiringArePermanent\n[PASS] invariant_distributorPaysEachCommittedLeafAtMostOnce\n[PASS] invariant_supplyEqualsAllBalancesAndOnlyBurnsReduceIt\n DistributionInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------------+----------------------------+-------+---------+----------╮\n| Contract            | Selector                   | Calls | Reverts | Discards |\n+===============================================================================+\n| DistributionHandler | advance                    | 1010  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | allowSender                | 1012  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | approveAndSpend            | 1041  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | burnTokens                 | 1027  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | claimAllocation            | 1006  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | donate                     | 1085  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | transferTokens             | 1003  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | unauthorizedAdministration | 1008  | 0       | 0        |\n╰---------------------+----------------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.51s (1.50s CPU time)\n\nRan 2 tests for test/TradingInvariant.t.sol:TradingInvariantTest\n[PASS]\nTradingInvariantTest invariants:\n[PASS] invariant_allPleaIsAccountedForAndSupplyOnlyFallsByActualBurns\n[PASS] invariant_quoteConservationAndFeePaymentsMatchTheirCounters\n[PASS] invariant_wallReservesClaimsAndGateStateRemainBacked\n TradingInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+---------------+-------+---------+----------╮\n| Contract       | Selector      | Calls | Reverts | Discards |\n+=============================================================+\n| TradingHandler | advance       | 859   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | buy           | 813   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | donateQuote   | 748   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | execute       | 828   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | freeSell      | 849   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | fundWall      | 781   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | pauseCashback | 823   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | rebalance     | 831   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | submit        | 838   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | verdict       | 822   | 0       | 0        |\n╰----------------+---------------+-------+---------+----------╯\n\n[PASS] test_handlerExercisesTradingVerdictsRebalancesAndDeath() (gas: 7123295)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.28s (2.24s CPU time)\n\nRan 2 tests for test/TradingInvariant.t.sol:TradingPleaZeroInvariantTest\n[PASS]\nTradingPleaZeroInvariantTest invariants:\n[PASS] invariant_allPleaIsAccountedForAndSupplyOnlyFallsByActualBurns\n[PASS] invariant_quoteConservationAndFeePaymentsMatchTheirCounters\n[PASS] invariant_wallReservesClaimsAndGateStateRemainBacked\n TradingPleaZeroInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+---------------+-------+---------+----------╮\n| Contract       | Selector      | Calls | Reverts | Discards |\n+=============================================================+\n| TradingHandler | advance       | 859   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | buy           | 813   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | donateQuote   | 748   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | execute       | 828   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | freeSell      | 849   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | fundWall      | 781   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | pauseCashback | 823   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | rebalance     | 831   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | submit        | 838   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | verdict       | 822   | 0       | 0        |\n╰----------------+---------------+-------+---------+----------╯\n\n[PASS] test_handlerExercisesTradingVerdictsRebalancesAndDeath() (gas: 7128992)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.34s (2.33s CPU time)\n\nRan 2 tests for test/SeasonInvariant.t.sol:SeasonInvariantTest\n[PASS]\nSeasonInvariantTest invariants:\n[PASS] invariant_nftsRemainUniqueAndOwnedAfterRandomTransfers\n[PASS] invariant_prizeMoneyIsPaidOnceOrRemainsInThePotOrWall\n[PASS] invariant_rankingsMatchAllRecordedApprovalsAndClosedSeasonsNeverChange\n SeasonInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| SeasonHandler | advance          | 1007  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| SeasonHandler | approvePlea      | 1050  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| SeasonHandler | closeOldest      | 1035  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| SeasonHandler | donate           | 1022  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| SeasonHandler | endCabal         | 1054  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| SeasonHandler | flush            | 996   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| SeasonHandler | record           | 1023  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| SeasonHandler | transferLaureate | 1005  | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\n[PASS] test_modelCoversPayableClosesRolloverAndFinalFlush() (gas: 4540160)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 9.22s (9.22s CPU time)\n\nRan 25 test suites in 9.23s (17.76s CPU time): 184 tests passed, 0 failed, 0 skipped (184 total tests)\n","passed":true},{"durationMs":76,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalGate.appeal(uint256,uint256,string)\",\"CabalGate.begin()\",\"CabalGate.executeSell(uint256)\",\"CabalGate.expire(uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.submitSell(uint256,string)\",\"CabalGate.unlockCallback(bytes)\",\"Laureates.approve(address,uint256)\",\"Laureates.mint(address,uint256,uint8,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256,bytes)\",\"Laureates.setApprovalForAll(address,bool)\",\"Laureates.setName(string)\",\"Laureates.transferFrom(address,address,uint256)\",\"PLEA.allow(address)\",\"PLEA.approve(address,uint256)\",\"PLEA.burn(uint256)\",\"PLEA.init(address,address)\",\"PLEA.renounceOwnership()\",\"PLEA.setLauncher(address,address,address,address)\",\"PLEA.transfer(address,uint256)\",\"PLEA.transferFrom(address,address,uint256)\",\"PLEA.transferOwnership(address)\",\"PleaDistributor.claim(uint256,address,uint256,bytes32[])\",\"PleaDistributor.renounceOwnership()\",\"PleaDistributor.setMerkleRoot(bytes32)\",\"PleaDistributor.transferOwnership(address)\",\"PleaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PleaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PleaHook.fundWall(uint256)\",\"PleaHook.rebalance()\",\"PleaHook.seed()\",\"PleaHook.unlockCallback(bytes)\",\"PleaLaunch.deployHook(bytes32,bytes)\",\"PleaLaunch.seed()\",\"Seasons.closeSeason(uint256[])\",\"Seasons.flushToWall()\",\"Seasons.record(uint256)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":59,\"README.md\":52,\"foundry.toml\":24,\"launch.json\":60,\"remappings.txt\":4,\"script/Deploy.s.sol\":52,\"script/MineSalt.s.sol\":44,\"src/CabalGate.sol\":596,\"src/Laureates.sol\":227,\"src/OracleAttestation.sol\":227,\"src/PLEA.sol\":116,\"src/PleaDistributor.sol\":49,\"src/PleaHook.sol\":908,\"src/PleaLaunch.sol\":107,\"src/Seasons.sol\":283,\"src/interfaces/IPleaParts.sol\":63,\"src/interfaces/IStacker.sol\":9,\"test/AUDIT.md\":68,\"test/DistributorAdversarial.t.sol\":329,\"test/Gate.t.sol\":287,\"test/GateAdversarial.t.sol\":329,\"test/Hook.t.sol\":125,\"test/HookAdversarial.t.sol\":271,\"test/Launch.t.sol\":144,\"test/LaunchManifest.t.sol\":242,\"test/OracleConformance.t.sol\":114,\"test/OracleReplay.t.sol\":59,\"test/Orientation.t.sol\":58,\"test/SeasonAdversarial.t.sol\":326,\"test/SeasonInvariant.t.sol\":282,\"test/SeasonRanking.t.sol\":190,\"test/Seasons.t.sol\":263,\"test/Token.t.sol\":78,\"test/TradingInvariant.t.sol\":374,\"test/utils/ClaimTree.sol\":41,\"test/utils/Fixture.sol\":219,\"test/utils/Mocks.sol\":204,\"test/utils/SeasonModel.sol\":112,\"test/utils/SepoliaFixture.sol\":34},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"01fef3b34e70100eb72226deec92dc0078030033c065e130eba34374692d2af6","verifiedTreeHash":"a35de1eef23c71a3adbdf09c10ccecb013021bc0","verifierVersion":"0.1.0+fdeb4d4a"},{"checks":[{"durationMs":195088,"exitCode":0,"name":"build","output":"Compiling 136 files with Solc 0.8.26\nSolc 0.8.26 finished in 194.93s\nCompiler run successful!\n","passed":true},{"durationMs":10917,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/LaunchManifest.t.sol:PostLaunchHookTest\n[PASS] test_committedHookDeploysLaterAndMintsOnlyTheFixedSplit() (gas: 7244440)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 10.34ms (4.87ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_distributorAndAllowlistMaySend() (gas: 208891)\n[PASS] test_freeForeverOnceTheCabalDies() (gas: 183694)\n[PASS] test_launcherAndInitAreOneShot() (gas: 127039)\n[PASS] test_walletsCannotSendWhileTheCabalWatches() (gas: 313213)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 19.02ms (1.24ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:AtomicManifestTest\n[PASS] test_factoryDeploysExactManifestOnAnEmptySepoliaChain() (gas: 31878840)\nLogs:\n  six-contract factory deployment gas: 16622688\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 29.59ms (26.08ms CPU time)\n\nRan 3 tests for test/HookAdversarial.t.sol:LaunchFeeBoundaryTest\n[PASS] testFuzz_launchFeeOnlyFallsWithTime(uint256,uint256) (runs: 256, μ: 23837, ~: 23957)\n[PASS] test_largeLaunchBuyRollsBackAndSucceedsAtWindowEnd() (gas: 709488)\n[PASS] test_launchFeeHasExactStartMidpointAndEndValues() (gas: 42715)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 30.79ms (10.42ms CPU time)\n\nRan 8 tests for test/SeasonFunds.t.sol:SeasonFundsTest\n[PASS] testFuzz_lateCloseConservesAssets(uint96,uint96,bool) (runs: 32, μ: 1174092, ~: 1192218)\n[PASS] test_claimRedemptionCallbackCannotBeInvokedOutsideUnlock() (gas: 74978)\n[PASS] test_deathAtBoundaryFlushesClaimsAndLateDonationsOnce() (gas: 1507105)\n[PASS] test_deathMidSeasonPreservesEarlierSeasonFees() (gas: 1487044)\n[PASS] test_failedPayoutRollsForwardWithoutBlockingOtherWinners() (gas: 1612166)\n[PASS] test_feeAtBoundaryBelongsToNextSeason() (gas: 1135047)\n[PASS] test_lateClosesOnlyRollUnpaidSharesForward() (gas: 2334155)\n[PASS] test_unobservedDonationCannotFlowBackwards() (gas: 1045375)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 53.20ms (50.61ms CPU time)\n\nRan 3 tests for test/LaunchManifest.t.sol:RehearsalManifestTest\n[PASS] test_laterBlockCannotRegisterLauncher() (gas: 14777809)\n[PASS] test_separateConstructorCallsInDeploymentBlockStillWork() (gas: 15467590)\n[PASS] test_separateTransactionsLeaveTheAcceptedDeploymentBlockWindow() (gas: 14936813)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 58.93ms (18.09ms CPU time)\n\nRan 10 tests for test/Orientation.t.sol:HookPleaIsZeroTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1234745)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1083521)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1283320)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1838054)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 573173)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1078825)\n[PASS] test_orientationIsPleaZero() (gas: 15719)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1185140)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4437504)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 748072)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 64.12ms (17.61ms CPU time)\n\nRan 21 tests for test/Orientation.t.sol:GatePleaIsZeroTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8017780)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6472285)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3952542)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3260437)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3799193)\n[PASS] test_callbackFitsTheStipend() (gas: 5472091)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3645624)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 356016)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5814323)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5375903)\n[PASS] test_onePendingPleaPerWallet() (gas: 3101302)\n[PASS] test_orientationIsPleaZero() (gas: 15790)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5371339)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3188011)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5403627)\n[PASS] test_scoreBelowNeedDenies() (gas: 3425467)\n[PASS] test_sellWindowLapses() (gas: 5433782)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3273597)\n[PASS] test_textFilter() (gas: 3395652)\n[PASS] test_wrongSignerIsRefused() (gas: 3238168)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 85.57ms (44.87ms CPU time)\n\nRan 6 tests for test/DistributorAdversarial.t.sol:DistributorAdversarialTest\n[PASS] testFuzz_modifiedLeafOrProofCannotRedirectFunds(uint8,uint8,uint256) (runs: 256, μ: 259283, ~: 259255)\n[PASS] test_claimsCrossBitmapWordsAndCannotBeClaimedTwice() (gas: 1716099)\n[PASS] test_failedTokenTransferRollsBackBitmapAndCanBeRetried() (gas: 316968)\n[PASS] test_fullAllocationAndZeroAmountLeavesDoNotCorruptAdjacentBits() (gas: 260336)\n[PASS] test_rootCannotChangeAfterCommitmentEvenBeforeFirstClaim() (gas: 115955)\n[PASS] test_unsetRootAndUnauthorizedRootDoNotConsumeClaims() (gas: 275919)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 94.68ms (94.35ms CPU time)\n\nRan 3 tests for test/OracleReplay.t.sol:OracleReplayTest\n[PASS] testFuzz_oneSignedRequestCannotSettleTwoPleas(bool,bool) (runs: 32, μ: 5581977, ~: 5591837)\n[PASS] test_deniedRequestCannotBeResignedToApproveItsAppeal() (gas: 5835566)\n[PASS] test_invalidCallbackDoesNotConsumeTheRequest() (gas: 5430175)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 142.98ms (116.65ms CPU time)\n\nRan 20 tests for test/Gate.t.sol:GateTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8017668)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6472113)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3952422)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3260385)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3798751)\n[PASS] test_callbackFitsTheStipend() (gas: 5472009)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3645564)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 356016)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5814271)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5375843)\n[PASS] test_onePendingPleaPerWallet() (gas: 3101302)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5371227)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3187959)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5403545)\n[PASS] test_scoreBelowNeedDenies() (gas: 3425377)\n[PASS] test_sellWindowLapses() (gas: 5433722)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3273545)\n[PASS] test_textFilter() (gas: 3395652)\n[PASS] test_wrongSignerIsRefused() (gas: 3238138)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 144.14ms (33.40ms CPU time)\n\nRan 11 tests for test/HookAdversarial.t.sol:HookAdversarialPleaZeroTest\n[PASS] testFuzz_immediateRoundTripCannotProfitIncludingCashback(uint256) (runs: 256, μ: 1064829, ~: 1058729)\n[PASS] test_exactOutputBuyWorksAfterDeathAndKeepsAllAccountingSettled() (gas: 1169324)\n[PASS] test_firstPartialFillRefundIsBackedByRedeemableQuoteClaims() (gas: 654774)\n[PASS] test_hookCallbacksRejectCallersAndForeignPools() (gas: 135250)\n[PASS] test_keeperTipsRequireWorkAndRespectTheOneHourCooldown() (gas: 1204516)\n[PASS] test_onlyHookMayInitializeOrAddLiquidity() (gas: 63930)\n[PASS] test_partialFillRefundChargesOnlyRealizedImdAndKeepsCostBasisCorrect() (gas: 1297069)\n[PASS] test_realCreditBudgetMustBeAffordableAndExhaustedCreditFallsBack() (gas: 2536787)\n[PASS] test_seedAndUnlockAreOneShotAndOnlyAuthorizedContextsWork() (gas: 137962)\n[PASS] test_wallFundingCannotCreateUnbackedReserveWhenTransferFails() (gas: 290017)\n[PASS] test_zeroBuyRevertsAndOneWeiBuyConservesSupply() (gas: 595420)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 179.42ms (103.36ms CPU time)\n\nRan 11 tests for test/Seasons.t.sol:FastClockTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249130)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230805)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 1287708)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 31395767)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 1184066)\n[PASS] test_fastFullCycle() (gas: 56516800)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13499)\n[PASS] test_onlyApprovedPleasScore() (gas: 3358532)\n[PASS] test_secondSeasonScoresSeparately() (gas: 34297316)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 2586356)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 85855324)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 181.18ms (129.35ms CPU time)\n\nRan 4 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_callbackSelectorHasTheProtocolStruct() (gas: 748)\n[PASS] test_digestMatchesTheProtocol() (gas: 10505)\n[PASS] test_liveAttestationRecoversToOracleSigner() (gas: 131611)\n[PASS] test_protocolSignatureRecoversToVectorSigner() (gas: 13921)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 190.07ms (3.78ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_deployHookChecksTheInitCodeAndFlags() (gas: 162524779)\n[PASS] test_eachStepFitsAMainnetTransaction() (gas: 161712833)\nLogs:\n  launch (6 contracts + intake mock): 826923\n  deployHook: 5184037\n  seed: 534215\n\n[PASS] test_launchWiresEverythingWithoutCallingOutside() (gas: 861046)\n[PASS] test_ownerMaySeedEarly() (gas: 161727763)\n[PASS] test_seedByOwnerAnyTimeByAnyoneAfterStart() (gas: 161823951)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 190.08ms (628.54ms CPU time)\n\nRan 11 tests for test/Orientation.t.sol:SeasonsPleaIsZeroTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249814)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230894)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17478002)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 42281540)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8726369)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3361513)\n[PASS] test_orientationIsPleaZero() (gas: 15658)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32133791)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29723601)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81550282)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 213.52ms (143.70ms CPU time)\n\nRan 12 tests for test/AuditRevision.t.sol:AuditRevisionTest\n[PASS] testFuzz_cumulativeCapDecayStaysWithinElapsedBudget(uint256) (runs: 32, μ: 3998767, ~: 3996574)\n[PASS] test_appealRetryClearsTimedOutPendingAppeal() (gas: 8663875)\n[PASS] test_deadCabalBuyStillRequiresARecipient() (gas: 1599742)\n[PASS] test_dustBuyDoesNotGiveUntrackedTokensLossOrHoldingPoints() (gas: 1075644)\n[PASS] test_expiredAppealCanBeRetriedWithoutLiftingDenialCooldown() (gas: 8791698)\n[PASS] test_lapsedApprovalCannotBypassCooldown() (gas: 6328947)\n[PASS] test_largeBuyClaimsAreRedeemableAndNextBuyStacksNormally() (gas: 2149980)\n[PASS] test_lateCloseDoesNotPayFutureSeasonFees() (gas: 11143768)\n[PASS] test_sameSecondCapRatchetsCannotReuseFractionalBudget() (gas: 1042010)\n[PASS] test_seasonClaimsArePaidAsImdAtClose() (gas: 7904442)\n[PASS] test_secondLargeBuyPreservesEveryPayee() (gas: 1231332)\n[PASS] test_unansweredAppealDoesNotExtendTheOriginalWindow() (gas: 6363564)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 213.82ms (247.39ms CPU time)\n\nRan 12 tests for test/AuditRevision.t.sol:AuditRevisionPleaZeroTest\n[PASS] testFuzz_cumulativeCapDecayStaysWithinElapsedBudget(uint256) (runs: 32, μ: 3993068, ~: 3993814)\n[PASS] test_appealRetryClearsTimedOutPendingAppeal() (gas: 8663642)\n[PASS] test_deadCabalBuyStillRequiresARecipient() (gas: 1600476)\n[PASS] test_dustBuyDoesNotGiveUntrackedTokensLossOrHoldingPoints() (gas: 1075168)\n[PASS] test_expiredAppealCanBeRetriedWithoutLiftingDenialCooldown() (gas: 8791465)\n[PASS] test_lapsedApprovalCannotBypassCooldown() (gas: 6328714)\n[PASS] test_largeBuyClaimsAreRedeemableAndNextBuyStacksNormally() (gas: 2150284)\n[PASS] test_lateCloseDoesNotPayFutureSeasonFees() (gas: 11143183)\n[PASS] test_sameSecondCapRatchetsCannotReuseFractionalBudget() (gas: 1041516)\n[PASS] test_seasonClaimsArePaidAsImdAtClose() (gas: 7903827)\n[PASS] test_secondLargeBuyPreservesEveryPayee() (gas: 1231205)\n[PASS] test_unansweredAppealDoesNotExtendTheOriginalWindow() (gas: 6363331)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 236.50ms (226.73ms CPU time)\n\nRan 6 tests for test/SeasonRanking.t.sol:SeasonRankingTest\n[PASS] testFuzz_rankingsMatchSortedResultsInAnyRecordOrder(uint256) (runs: 32, μ: 11216652, ~: 11226798)\n[PASS] test_closeSeasonUsesTheSameTiesForPrizesAndNfts() (gas: 1360241)\n[PASS] test_earlierEqualScoreCanReplaceACountedPleaWithoutChangingPoints() (gas: 879842)\n[PASS] test_earlierTiedPleaTakesFirstAndFifthLaureateSlots() (gas: 1191572)\n[PASS] test_replacingALowerScoreRemovesItsIdFromTheTieKey() (gas: 879810)\n[PASS] test_walletTieUsesNewestCountedPleaNotLastRecordedPlea() (gas: 910760)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 238.08ms (238.90ms CPU time)\n\nRan 9 tests for test/Hook.t.sol:HookTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1234745)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1083521)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1283298)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1838054)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 573151)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1078803)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1185140)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4437504)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 748072)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 274.18ms (15.51ms CPU time)\n\nRan 11 tests for test/SeasonAdversarial.t.sol:SeasonAdversarialTest\n[PASS] testFuzz_failedPrizeDoesNotBlockOthersAndUnpaidShareReachesWall(bool) (runs: 256, μ: 2093558, ~: 2092664)\n[PASS] testFuzz_namesAreUniqueIdempotentAndReleasedOnClear(uint256,uint8) (runs: 256, μ: 298169, ~: 295538)\n[PASS] testFuzz_prizeRoundingConservesAnOddSizedPot(uint256) (runs: 256, μ: 5098360, ~: 5113389)\n[PASS] test_batchIgnoresUnknownDeniedAndRepeatedIdsButCannotReopenASeason() (gas: 1211312)\n[PASS] test_closeBeforeGraceRollsBackItsBatchRecording() (gas: 767644)\n[PASS] test_flushBeforeFinalCloseCannotMoveAnyFunds() (gas: 500701)\n[PASS] test_invalidNamesAndFailedRenamesPreserveTheOldReservation() (gas: 872899)\n[PASS] test_metadataDecodesToValidJsonAndEscapesUntrustedTextInSvg() (gas: 3039852)\n[PASS] test_onlySeasonsMintsAndFailedMintCannotIncrementSupply() (gas: 307118)\n[PASS] test_prizesRequireSixtyPointsButLaureatesDoNot() (gas: 1588633)\n[PASS] test_recordRejectsDenialsDuplicatesAndLateApprovals() (gas: 910290)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 274.22ms (526.84ms CPU time)\n\nRan 10 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249792)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230783)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17477980)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 42281518)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8726369)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3361491)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32133791)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29723579)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81550260)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 418.63ms (134.69ms CPU time)\n\nRan 11 tests for test/HookAdversarial.t.sol:HookAdversarialTest\n[PASS] testFuzz_immediateRoundTripCannotProfitIncludingCashback(uint256) (runs: 256, μ: 1064799, ~: 1058211)\n[PASS] test_exactOutputBuyWorksAfterDeathAndKeepsAllAccountingSettled() (gas: 1168600)\n[PASS] test_firstPartialFillRefundIsBackedByRedeemableQuoteClaims() (gas: 654834)\n[PASS] test_hookCallbacksRejectCallersAndForeignPools() (gas: 134422)\n[PASS] test_keeperTipsRequireWorkAndRespectTheOneHourCooldown() (gas: 1188580)\n[PASS] test_onlyHookMayInitializeOrAddLiquidity() (gas: 63990)\n[PASS] test_partialFillRefundChargesOnlyRealizedImdAndKeepsCostBasisCorrect() (gas: 1297083)\n[PASS] test_realCreditBudgetMustBeAffordableAndExhaustedCreditFallsBack() (gas: 2537267)\n[PASS] test_seedAndUnlockAreOneShotAndOnlyAuthorizedContextsWork() (gas: 137962)\n[PASS] test_wallFundingCannotCreateUnbackedReserveWhenTransferFails() (gas: 290041)\n[PASS] test_zeroBuyRevertsAndOneWeiBuyConservesSupply() (gas: 595896)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 423.24ms (413.74ms CPU time)\n\nRan 16 tests for test/GateAdversarial.t.sol:GateAdversarialTest\n[PASS] testFuzz_panelAndAnswerValidationCannotConsumeRequests(uint8) (runs: 256, μ: 3355856, ~: 3359356)\n[PASS] testFuzz_printablePleaRoundTripsThroughQuestionJson(uint256,uint16) (runs: 256, μ: 4633757, ~: 4765356)\n[PASS] test_amountLimitsFailBeforeChargingAndOneWeiCanBeSubmitted() (gas: 3378279)\n[PASS] test_appealIsAcceptedAtItsLastSecondAndCannotBeStolen() (gas: 5724766)\n[PASS] test_appealOracleFeeFailureRollsBackWallFundingAndOriginalFlag() (gas: 6206922)\n[PASS] test_approvedWindowOnlyClearsAfterTheLastSecond() (gas: 5470428)\n[PASS] test_changingSignedAnswerOrConsumerChainInvalidatesSignature() (gas: 3380128)\n[PASS] test_deadManExpiresAtTheExactSecondAndNeverAcceptsANewVerdict() (gas: 3275858)\n[PASS] test_denialCooldownEndsExactlyAtFourHours() (gas: 5258910)\n[PASS] test_futureIssuanceAndExpiredAttestationsRejectAtExactBoundaries() (gas: 5449880)\n[PASS] test_gateUnlockCallbackCannotBeInvokedOutsideItsOwnSale() (gas: 86519)\n[PASS] test_latePendingCannotConsumeSignatureOrExtendHeartbeat() (gas: 3265996)\n[PASS] test_malformedUtf8AndHiddenControlsFailWithoutCharging() (gas: 837673)\n[PASS] test_missingSellAllowanceDoesNotConsumeTheApprovedPlea() (gas: 3353495)\n[PASS] test_pendingAndExecutionDeadlinesAreInclusive() (gas: 3827883)\n[PASS] test_slippageRevertRestoresApprovalSupplyAndAllFeeState() (gas: 4456063)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 423.43ms (565.29ms CPU time)\n\nRan 1 test for test/DistributorAdversarial.t.sol:DistributionInvariantTest\n[PASS]\nDistributionInvariantTest invariants:\n[PASS] invariant_deathAndSystemWiringArePermanent\n[PASS] invariant_distributorPaysEachCommittedLeafAtMostOnce\n[PASS] invariant_supplyEqualsAllBalancesAndOnlyBurnsReduceIt\n DistributionInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------------+----------------------------+-------+---------+----------╮\n| Contract            | Selector                   | Calls | Reverts | Discards |\n+===============================================================================+\n| DistributionHandler | advance                    | 1050  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | allowSender                | 995   | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | approveAndSpend            | 987   | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | burnTokens                 | 1081  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | claimAllocation            | 1008  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | donate                     | 992   | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | transferTokens             | 1046  | 0       | 0        |\n|---------------------+----------------------------+-------+---------+----------|\n| DistributionHandler | unauthorizedAdministration | 1033  | 0       | 0        |\n╰---------------------+----------------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.89s (1.88s CPU time)\n\nRan 3 tests for test/TradingInvariant.t.sol:TradingInvariantTest\n[PASS]\nTradingInvariantTest invariants:\n[PASS] invariant_allPleaIsAccountedForAndSupplyOnlyFallsByActualBurns\n[PASS] invariant_quoteConservationAndFeePaymentsMatchTheirCounters\n[PASS] invariant_wallReservesClaimsAndGateStateRemainBacked\n TradingInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+---------------+-------+---------+----------╮\n| Contract       | Selector      | Calls | Reverts | Discards |\n+=============================================================+\n| TradingHandler | advance       | 764   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | buy           | 718   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | donateQuote   | 784   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | execute       | 760   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | freeSell      | 731   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | fundWall      | 769   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | pauseCashback | 713   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | rebalance     | 755   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | redeemClaims  | 716   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | submit        | 764   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | verdict       | 718   | 0       | 0        |\n╰----------------+---------------+-------+---------+----------╯\n\n[PASS] testFuzz_handlerAccountsForClaimFeesAndTheirRedemption(bool) (runs: 32, μ: 2909535, ~: 2909535)\n[PASS] test_handlerExercisesTradingVerdictsRebalancesAndDeath() (gas: 7540652)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.85s (3.90s CPU time)\n\nRan 3 tests for test/TradingInvariant.t.sol:TradingPleaZeroInvariantTest\n[PASS]\nTradingPleaZeroInvariantTest invariants:\n[PASS] invariant_allPleaIsAccountedForAndSupplyOnlyFallsByActualBurns\n[PASS] invariant_quoteConservationAndFeePaymentsMatchTheirCounters\n[PASS] invariant_wallReservesClaimsAndGateStateRemainBacked\n TradingPleaZeroInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+---------------+-------+---------+----------╮\n| Contract       | Selector      | Calls | Reverts | Discards |\n+=============================================================+\n| TradingHandler | advance       | 764   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | buy           | 718   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | donateQuote   | 784   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | execute       | 760   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | freeSell      | 731   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | fundWall      | 769   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | pauseCashback | 713   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | rebalance     | 755   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | redeemClaims  | 716   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | submit        | 764   | 0       | 0        |\n|----------------+---------------+-------+---------+----------|\n| TradingHandler | verdict       | 718   | 0       | 0        |\n╰----------------+---------------+-------+---------+----------╯\n\n[PASS] testFuzz_handlerAccountsForClaimFeesAndTheirRedemption(bool) (runs: 32, μ: 2909041, ~: 2909041)\n[PASS] test_handlerExercisesTradingVerdictsRebalancesAndDeath() (gas: 7546349)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 4.04s (4.09s CPU time)\n\nRan 3 tests for test/SeasonInvariant.t.sol:SeasonInvariantTest\n[PASS]\nSeasonInvariantTest invariants:\n[PASS] invariant_nftsRemainUniqueAndOwnedAfterRandomTransfers\n[PASS] invariant_prizeMoneyIsPaidOnceOrRemainsInThePotOrWall\n[PASS] invariant_rankingsMatchAllRecordedApprovalsAndClosedSeasonsNeverChange\n SeasonInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+-------------------------+-------+---------+----------╮\n| Contract      | Selector                | Calls | Reverts | Discards |\n+======================================================================+\n| SeasonHandler | advance                 | 732   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | approvePlea             | 729   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | checkpoint              | 740   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | closeOldest             | 775   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | donate                  | 726   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | donateClaims            | 741   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | donateWithoutCheckpoint | 766   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | endCabal                | 775   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | flush                   | 740   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | record                  | 745   | 0       | 0        |\n|---------------+-------------------------+-------+---------+----------|\n| SeasonHandler | transferLaureate        | 723   | 0       | 0        |\n╰---------------+-------------------------+-------+---------+----------╯\n\n[PASS] test_modelCoversDelayedDonationsAndPostFlushClaims() (gas: 3733681)\n[PASS] test_modelCoversPayableClosesRolloverAndFinalFlush() (gas: 5332226)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 10.75s (10.75s CPU time)\n\nRan 28 test suites in 10.76s (24.72s CPU time): 219 tests passed, 0 failed, 0 skipped (219 total tests)\n","passed":true},{"durationMs":132,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalGate.appeal(uint256,uint256,string)\",\"CabalGate.begin()\",\"CabalGate.executeSell(uint256)\",\"CabalGate.expire(uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.submitSell(uint256,string)\",\"CabalGate.unlockCallback(bytes)\",\"Laureates.approve(address,uint256)\",\"Laureates.mint(address,uint256,uint8,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256,bytes)\",\"Laureates.setApprovalForAll(address,bool)\",\"Laureates.setName(string)\",\"Laureates.transferFrom(address,address,uint256)\",\"PLEA.allow(address)\",\"PLEA.approve(address,uint256)\",\"PLEA.burn(uint256)\",\"PLEA.init(address,address)\",\"PLEA.renounceOwnership()\",\"PLEA.setLauncher(address,address,address,address)\",\"PLEA.transfer(address,uint256)\",\"PLEA.transferFrom(address,address,uint256)\",\"PLEA.transferOwnership(address)\",\"PleaDistributor.claim(uint256,address,uint256,bytes32[])\",\"PleaDistributor.renounceOwnership()\",\"PleaDistributor.setMerkleRoot(bytes32)\",\"PleaDistributor.transferOwnership(address)\",\"PleaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PleaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PleaHook.fundWall(uint256)\",\"PleaHook.rebalance()\",\"PleaHook.seed()\",\"PleaHook.unlockCallback(bytes)\",\"PleaLaunch.deployHook(bytes32,bytes)\",\"PleaLaunch.seed()\",\"Seasons.checkpoint()\",\"Seasons.closeSeason(uint256[])\",\"Seasons.flushToWall()\",\"Seasons.record(uint256)\",\"Seasons.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":111,\"README.md\":54,\"foundry.toml\":24,\"launch.json\":60,\"remappings.txt\":4,\"script/Deploy.s.sol\":52,\"script/MineSalt.s.sol\":44,\"src/CabalGate.sol\":605,\"src/Laureates.sol\":227,\"src/OracleAttestation.sol\":227,\"src/PLEA.sol\":116,\"src/PleaDistributor.sol\":49,\"src/PleaHook.sol\":927,\"src/PleaLaunch.sol\":107,\"src/Seasons.sol\":342,\"src/interfaces/IPleaParts.sol\":67,\"src/interfaces/IStacker.sol\":9,\"test/AUDIT.md\":103,\"test/AuditRevision.t.sol\":260,\"test/DistributorAdversarial.t.sol\":329,\"test/Gate.t.sol\":287,\"test/GateAdversarial.t.sol\":341,\"test/Hook.t.sol\":125,\"test/HookAdversarial.t.sol\":271,\"test/Launch.t.sol\":144,\"test/LaunchManifest.t.sol\":242,\"test/OracleConformance.t.sol\":114,\"test/OracleReplay.t.sol\":59,\"test/Orientation.t.sol\":58,\"test/SeasonAdversarial.t.sol\":331,\"test/SeasonFunds.t.sol\":237,\"test/SeasonInvariant.t.sol\":393,\"test/SeasonRanking.t.sol\":191,\"test/Seasons.t.sol\":279,\"test/Token.t.sol\":78,\"test/TradingInvariant.t.sol\":455,\"test/utils/ClaimTree.sol\":41,\"test/utils/Fixture.sol\":219,\"test/utils/Mocks.sol\":204,\"test/utils/SeasonModel.sol\":112,\"test/utils/SepoliaFixture.sol\":34},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"4e6150a46d570a37c23f6353c45cf6d80889d97bcfef26a4894b1683e9e19a68","verifiedTreeHash":"fe06100538fe65d51ba271e9e2238d051719f132","verifierVersion":"0.1.0+4ba55555"},{"checks":[{"durationMs":113060,"exitCode":0,"name":"build","output":"Compiling 127 files with Solc 0.8.26\nSolc 0.8.26 finished in 112.94s\nCompiler run successful!\n","passed":true},{"durationMs":280,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_callbackSelectorHasTheProtocolStruct() (gas: 748)\n[PASS] test_digestMatchesTheProtocol() (gas: 10505)\n[PASS] test_liveAttestationRecoversToOracleSigner() (gas: 131611)\n[PASS] test_protocolSignatureRecoversToVectorSigner() (gas: 13921)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.84ms (1.54ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:PostLaunchHookTest\n[PASS] test_committedHookDeploysLaterAndMintsOnlyTheFixedSplit() (gas: 7244440)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.89ms (2.70ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_distributorAndAllowlistMaySend() (gas: 208891)\n[PASS] test_freeForeverOnceTheCabalDies() (gas: 183694)\n[PASS] test_launcherAndInitAreOneShot() (gas: 127039)\n[PASS] test_walletsCannotSendWhileTheCabalWatches() (gas: 313213)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 8.10ms (667.22µs CPU time)\n\nRan 8 tests for test/SeasonFunds.t.sol:SeasonFundsTest\n[PASS] testFuzz_lateCloseConservesAssets(uint96,uint96,bool) (runs: 32, μ: 1168548, ~: 1156226)\n[PASS] test_claimRedemptionCallbackCannotBeInvokedOutsideUnlock() (gas: 74978)\n[PASS] test_deathAtBoundaryFlushesClaimsAndLateDonationsOnce() (gas: 1507105)\n[PASS] test_deathMidSeasonPreservesEarlierSeasonFees() (gas: 1487044)\n[PASS] test_failedPayoutRollsForwardWithoutBlockingOtherWinners() (gas: 1612166)\n[PASS] test_feeAtBoundaryBelongsToNextSeason() (gas: 1135047)\n[PASS] test_lateClosesOnlyRollUnpaidSharesForward() (gas: 2334155)\n[PASS] test_unobservedDonationCannotFlowBackwards() (gas: 1045375)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 13.00ms (18.22ms CPU time)\n\nRan 3 tests for test/LaunchManifest.t.sol:RehearsalManifestTest\n[PASS] test_laterBlockCannotRegisterLauncher() (gas: 14777809)\n[PASS] test_separateConstructorCallsInDeploymentBlockStillWork() (gas: 15467590)\n[PASS] test_separateTransactionsLeaveTheAcceptedDeploymentBlockWindow() (gas: 14936813)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 14.40ms (5.42ms CPU time)\n\nRan 10 tests for test/Orientation.t.sol:HookPleaIsZeroTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1234745)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1083521)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1283320)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1838054)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 573173)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1078825)\n[PASS] test_orientationIsPleaZero() (gas: 15719)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1185140)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4437504)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 748072)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 25.62ms (13.28ms CPU time)\n\nRan 21 tests for test/Orientation.t.sol:GatePleaIsZeroTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8017780)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6472285)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3952542)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3260437)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3799193)\n[PASS] test_callbackFitsTheStipend() (gas: 5472091)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3645624)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 356016)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5814323)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5375903)\n[PASS] test_onePendingPleaPerWallet() (gas: 3101302)\n[PASS] test_orientationIsPleaZero() (gas: 15790)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5371339)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3188011)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5403627)\n[PASS] test_scoreBelowNeedDenies() (gas: 3425467)\n[PASS] test_sellWindowLapses() (gas: 5433782)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3273597)\n[PASS] test_textFilter() (gas: 3395652)\n[PASS] test_wrongSignerIsRefused() (gas: 3238168)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 41.51ms (27.20ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:AtomicManifestTest\n[PASS] test_factoryDeploysExactManifestOnAnEmptySepoliaChain() (gas: 31878840)\nLogs:\n  six-contract factory deployment gas: 16622688\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 45.82ms (41.75ms CPU time)\n\nRan 9 tests for test/Hook.t.sol:HookTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1234745)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1083521)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1283298)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1838054)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 573151)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1078803)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1185140)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4437504)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 748072)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 57.46ms (12.86ms CPU time)\n\nRan 20 tests for test/Gate.t.sol:GateTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8017668)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6472113)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3952422)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3260385)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3798751)\n[PASS] test_callbackFitsTheStipend() (gas: 5472009)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3645564)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 356016)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5814271)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5375843)\n[PASS] test_onePendingPleaPerWallet() (gas: 3101302)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5371227)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3187959)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5403545)\n[PASS] test_scoreBelowNeedDenies() (gas: 3425377)\n[PASS] test_sellWindowLapses() (gas: 5433722)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3273545)\n[PASS] test_textFilter() (gas: 3395652)\n[PASS] test_wrongSignerIsRefused() (gas: 3238138)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 57.56ms (42.82ms CPU time)\n\nRan 11 tests for test/Seasons.t.sol:FastClockTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249130)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230805)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 1287708)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 31395767)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 1184066)\n[PASS] test_fastFullCycle() (gas: 56516800)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13499)\n[PASS] test_onlyApprovedPleasScore() (gas: 3358532)\n[PASS] test_secondSeasonScoresSeparately() (gas: 34297316)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 2586356)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 85855324)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 61.82ms (86.03ms CPU time)\n\nRan 10 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249792)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230783)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17477980)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 42281518)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8726369)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3361491)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32133791)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29723579)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81550260)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 63.65ms (111.92ms CPU time)\n\nRan 11 tests for test/Orientation.t.sol:SeasonsPleaIsZeroTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249814)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230894)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17478002)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 42281540)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8726369)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3361513)\n[PASS] test_orientationIsPleaZero() (gas: 15658)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32133791)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29723601)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81550282)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 63.69ms (88.08ms CPU time)\n\nRan 3 tests for test/OracleReplay.t.sol:OracleReplayTest\n[PASS] testFuzz_oneSignedRequestCannotSettleTwoPleas(bool,bool) (runs: 32, μ: 5579860, ~: 5569296)\n[PASS] test_deniedRequestCannotBeResignedToApproveItsAppeal() (gas: 5835566)\n[PASS] test_invalidCallbackDoesNotConsumeTheRequest() (gas: 5430175)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 66.67ms (58.26ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_deployHookChecksTheInitCodeAndFlags() (gas: 162524779)\n[PASS] test_eachStepFitsAMainnetTransaction() (gas: 161712833)\nLogs:\n  launch (6 contracts + intake mock): 826923\n  deployHook: 5184037\n  seed: 534215\n\n[PASS] test_launchWiresEverythingWithoutCallingOutside() (gas: 861046)\n[PASS] test_ownerMaySeedEarly() (gas: 161727763)\n[PASS] test_seedByOwnerAnyTimeByAnyoneAfterStart() (gas: 161823951)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 105.15ms (368.46ms CPU time)\n\nRan 12 tests for test/AuditRevision.t.sol:AuditRevisionTest\n[PASS] testFuzz_cumulativeCapDecayStaysWithinElapsedBudget(uint256) (runs: 32, μ: 3994331, ~: 3993299)\n[PASS] test_appealRetryClearsTimedOutPendingAppeal() (gas: 8663875)\n[PASS] test_deadCabalBuyStillRequiresARecipient() (gas: 1599742)\n[PASS] test_dustBuyDoesNotGiveUntrackedTokensLossOrHoldingPoints() (gas: 1075644)\n[PASS] test_expiredAppealCanBeRetriedWithoutLiftingDenialCooldown() (gas: 8791698)\n[PASS] test_lapsedApprovalCannotBypassCooldown() (gas: 6328947)\n[PASS] test_largeBuyClaimsAreRedeemableAndNextBuyStacksNormally() (gas: 2149980)\n[PASS] test_lateCloseDoesNotPayFutureSeasonFees() (gas: 11143768)\n[PASS] test_sameSecondCapRatchetsCannotReuseFractionalBudget() (gas: 1042010)\n[PASS] test_seasonClaimsArePaidAsImdAtClose() (gas: 7904442)\n[PASS] test_secondLargeBuyPreservesEveryPayee() (gas: 1231332)\n[PASS] test_unansweredAppealDoesNotExtendTheOriginalWindow() (gas: 6363564)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 105.82ms (118.06ms CPU time)\n\nRan 12 tests for test/AuditRevision.t.sol:AuditRevisionPleaZeroTest\n[PASS] testFuzz_cumulativeCapDecayStaysWithinElapsedBudget(uint256) (runs: 32, μ: 3995243, ~: 3995149)\n[PASS] test_appealRetryClearsTimedOutPendingAppeal() (gas: 8663642)\n[PASS] test_deadCabalBuyStillRequiresARecipient() (gas: 1600476)\n[PASS] test_dustBuyDoesNotGiveUntrackedTokensLossOrHoldingPoints() (gas: 1075168)\n[PASS] test_expiredAppealCanBeRetriedWithoutLiftingDenialCooldown() (gas: 8791465)\n[PASS] test_lapsedApprovalCannotBypassCooldown() (gas: 6328714)\n[PASS] test_largeBuyClaimsAreRedeemableAndNextBuyStacksNormally() (gas: 2150284)\n[PASS] test_lateCloseDoesNotPayFutureSeasonFees() (gas: 11143183)\n[PASS] test_sameSecondCapRatchetsCannotReuseFractionalBudget() (gas: 1041516)\n[PASS] test_seasonClaimsArePaidAsImdAtClose() (gas: 7903827)\n[PASS] test_secondLargeBuyPreservesEveryPayee() (gas: 1231205)\n[PASS] test_unansweredAppealDoesNotExtendTheOriginalWindow() (gas: 6363331)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 125.75ms (120.80ms CPU time)\n\nRan 6 tests for test/SeasonRanking.t.sol:SeasonRankingTest\n[PASS] testFuzz_rankingsMatchSortedResultsInAnyRecordOrder(uint256) (runs: 32, μ: 11247806, ~: 11229316)\n[PASS] test_closeSeasonUsesTheSameTiesForPrizesAndNfts() (gas: 1360241)\n[PASS] test_earlierEqualScoreCanReplaceACountedPleaWithoutChangingPoints() (gas: 879842)\n[PASS] test_earlierTiedPleaTakesFirstAndFifthLaureateSlots() (gas: 1191572)\n[PASS] test_replacingALowerScoreRemovesItsIdFromTheTieKey() (gas: 879810)\n[PASS] test_walletTieUsesNewestCountedPleaNotLastRecordedPlea() (gas: 910760)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 171.58ms (174.49ms CPU time)\n\nRan 18 test suites in 172.44ms (1.04s CPU time): 151 tests passed, 0 failed, 0 skipped (151 total tests)\n","passed":true},{"durationMs":81,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalGate.appeal(uint256,uint256,string)\",\"CabalGate.begin()\",\"CabalGate.executeSell(uint256)\",\"CabalGate.expire(uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.submitSell(uint256,string)\",\"CabalGate.unlockCallback(bytes)\",\"Laureates.approve(address,uint256)\",\"Laureates.mint(address,uint256,uint8,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256,bytes)\",\"Laureates.setApprovalForAll(address,bool)\",\"Laureates.setName(string)\",\"Laureates.transferFrom(address,address,uint256)\",\"PLEA.allow(address)\",\"PLEA.approve(address,uint256)\",\"PLEA.burn(uint256)\",\"PLEA.init(address,address)\",\"PLEA.renounceOwnership()\",\"PLEA.setLauncher(address,address,address,address)\",\"PLEA.transfer(address,uint256)\",\"PLEA.transferFrom(address,address,uint256)\",\"PLEA.transferOwnership(address)\",\"PleaDistributor.claim(uint256,address,uint256,bytes32[])\",\"PleaDistributor.renounceOwnership()\",\"PleaDistributor.setMerkleRoot(bytes32)\",\"PleaDistributor.transferOwnership(address)\",\"PleaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PleaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PleaHook.fundWall(uint256)\",\"PleaHook.rebalance()\",\"PleaHook.seed()\",\"PleaHook.unlockCallback(bytes)\",\"PleaLaunch.deployHook(bytes32,bytes)\",\"PleaLaunch.seed()\",\"Seasons.checkpoint()\",\"Seasons.closeSeason(uint256[])\",\"Seasons.flushToWall()\",\"Seasons.record(uint256)\",\"Seasons.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":111,\"README.md\":54,\"foundry.toml\":24,\"launch.json\":60,\"remappings.txt\":4,\"script/Deploy.s.sol\":52,\"script/MineSalt.s.sol\":44,\"src/CabalGate.sol\":605,\"src/Laureates.sol\":227,\"src/OracleAttestation.sol\":227,\"src/PLEA.sol\":116,\"src/PleaDistributor.sol\":49,\"src/PleaHook.sol\":927,\"src/PleaLaunch.sol\":107,\"src/Seasons.sol\":342,\"src/interfaces/IPleaParts.sol\":67,\"src/interfaces/IStacker.sol\":9,\"test/AuditRevision.t.sol\":260,\"test/Gate.t.sol\":287,\"test/Hook.t.sol\":125,\"test/Launch.t.sol\":144,\"test/LaunchManifest.t.sol\":242,\"test/OracleConformance.t.sol\":114,\"test/OracleReplay.t.sol\":59,\"test/Orientation.t.sol\":58,\"test/SeasonFunds.t.sol\":237,\"test/SeasonRanking.t.sol\":191,\"test/Seasons.t.sol\":279,\"test/Token.t.sol\":78,\"test/utils/Fixture.sol\":213,\"test/utils/Mocks.sol\":204},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"58bb63e9881916c8f40209620cc2cb479bdfee76badb89b6ab0515befcd7b241","verifiedTreeHash":"5215e34ec6dded4801a7a87574447557763de1ec","verifierVersion":"0.1.0+4ba55555"},{"checks":[{"durationMs":89943,"exitCode":0,"name":"build","output":"Compiling 125 files with Solc 0.8.26\nSolc 0.8.26 finished in 89.83s\nCompiler run successful!\n","passed":true},{"durationMs":277,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_callbackSelectorHasTheProtocolStruct() (gas: 748)\n[PASS] test_digestMatchesTheProtocol() (gas: 10505)\n[PASS] test_liveAttestationRecoversToOracleSigner() (gas: 130878)\n[PASS] test_protocolSignatureRecoversToVectorSigner() (gas: 13921)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.22ms (816.75µs CPU time)\n\nRan 3 tests for test/LaunchManifest.t.sol:RehearsalManifestTest\n[PASS] test_laterBlockCannotRegisterLauncher() (gas: 14025019)\n[PASS] test_separateConstructorCallsInDeploymentBlockStillWork() (gas: 14713798)\n[PASS] test_separateTransactionsLeaveTheAcceptedDeploymentBlockWindow() (gas: 14184022)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 6.21ms (5.10ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:PostLaunchHookTest\n[PASS] test_committedHookDeploysLaterAndMintsOnlyTheFixedSplit() (gas: 9062751)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.31ms (6.37ms CPU time)\n\nRan 21 tests for test/Orientation.t.sol:GatePleaIsZeroTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8006079)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6440698)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3920991)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3257954)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3796710)\n[PASS] test_callbackFitsTheStipend() (gas: 5467125)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3643141)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 353449)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5780373)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5370817)\n[PASS] test_onePendingPleaPerWallet() (gas: 3098819)\n[PASS] test_orientationIsPleaZero() (gas: 15796)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5366253)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3185528)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5398661)\n[PASS] test_scoreBelowNeedDenies() (gas: 3422962)\n[PASS] test_sellWindowLapses() (gas: 5408526)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3271114)\n[PASS] test_textFilter() (gas: 3369179)\n[PASS] test_wrongSignerIsRefused() (gas: 3235685)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 20.34ms (36.79ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_distributorAndAllowlistMaySend() (gas: 208891)\n[PASS] test_freeForeverOnceTheCabalDies() (gas: 183694)\n[PASS] test_launcherAndInitAreOneShot() (gas: 127042)\n[PASS] test_walletsCannotSendWhileTheCabalWatches() (gas: 313213)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 20.83ms (635.96µs CPU time)\n\nRan 9 tests for test/Hook.t.sol:HookTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1158821)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1060766)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1207374)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1723225)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 550450)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1058410)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1109208)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4110336)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 725412)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 30.02ms (10.42ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:AtomicManifestTest\n[PASS] test_factoryDeploysExactManifestOnAnEmptySepoliaChain() (gas: 30165537)\nLogs:\n  six-contract factory deployment gas: 15868055\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 41.46ms (36.39ms CPU time)\n\nRan 11 tests for test/Orientation.t.sol:SeasonsPleaIsZeroTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3247309)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230850)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17412673)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 44243127)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8603614)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3359020)\n[PASS] test_orientationIsPleaZero() (gas: 15664)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32062767)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29690339)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81458315)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 55.75ms (85.47ms CPU time)\n\nRan 10 tests for test/Orientation.t.sol:HookPleaIsZeroTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1158821)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1060766)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1207396)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1723225)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 550472)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1058432)\n[PASS] test_orientationIsPleaZero() (gas: 15725)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1109208)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4110336)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 725412)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 55.77ms (9.91ms CPU time)\n\nRan 3 tests for test/OracleReplay.t.sol:OracleReplayTest\n[PASS] testFuzz_oneSignedRequestCannotSettleTwoPleas(bool,bool) (runs: 32, μ: 5576188, ~: 5586751)\n[PASS] test_deniedRequestCannotBeResignedToApproveItsAppeal() (gas: 5833031)\n[PASS] test_invalidCallbackDoesNotConsumeTheRequest() (gas: 5425209)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 67.73ms (49.55ms CPU time)\n\nRan 11 tests for test/Seasons.t.sol:FastClockTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3246625)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230761)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17411418)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 39892510)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8622981)\n[PASS] test_fastFullCycle() (gas: 58520110)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13499)\n[PASS] test_onlyApprovedPleasScore() (gas: 3356039)\n[PASS] test_secondSeasonScoresSeparately() (gas: 36375760)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29688119)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 85759678)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 72.07ms (109.22ms CPU time)\n\nRan 20 tests for test/Gate.t.sol:GateTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8005967)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6440526)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3920871)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3257902)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3796268)\n[PASS] test_callbackFitsTheStipend() (gas: 5467043)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3643081)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 353449)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5780321)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5370757)\n[PASS] test_onePendingPleaPerWallet() (gas: 3098819)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5366141)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3185476)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5398579)\n[PASS] test_scoreBelowNeedDenies() (gas: 3422872)\n[PASS] test_sellWindowLapses() (gas: 5408466)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3271062)\n[PASS] test_textFilter() (gas: 3369179)\n[PASS] test_wrongSignerIsRefused() (gas: 3235655)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 72.25ms (31.45ms CPU time)\n\nRan 10 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3247287)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230739)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17412651)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 44243105)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8603614)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3358998)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32062767)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29690317)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81458293)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 72.20ms (83.39ms CPU time)\n\nRan 6 tests for test/SeasonRanking.t.sol:SeasonRankingTest\n[PASS] testFuzz_rankingsMatchSortedResultsInAnyRecordOrder(uint256) (runs: 32, μ: 11250074, ~: 11237571)\n[PASS] test_closeSeasonUsesTheSameTiesForPrizesAndNfts() (gas: 1233690)\n[PASS] test_earlierEqualScoreCanReplaceACountedPleaWithoutChangingPoints() (gas: 879686)\n[PASS] test_earlierTiedPleaTakesFirstAndFifthLaureateSlots() (gas: 1191499)\n[PASS] test_replacingALowerScoreRemovesItsIdFromTheTieKey() (gas: 879654)\n[PASS] test_walletTieUsesNewestCountedPleaNotLastRecordedPlea() (gas: 910672)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 144.77ms (146.29ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_deployHookChecksTheInitCodeAndFlags() (gas: 364251178)\n[PASS] test_eachStepFitsAMainnetTransaction() (gas: 363307703)\nLogs:\n  launch (6 contracts + intake mock): 826923\n  deployHook: 5217579\n  seed: 534221\n\n[PASS] test_launchWiresEverythingWithoutCallingOutside() (gas: 861024)\n[PASS] test_ownerMaySeedEarly() (gas: 363322636)\n[PASS] test_seedByOwnerAnyTimeByAnyoneAfterStart() (gas: 363418802)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 172.97ms (644.71ms CPU time)\n\nRan 15 test suites in 173.67ms (844.91ms CPU time): 119 tests passed, 0 failed, 0 skipped (119 total tests)\n","passed":true},{"durationMs":58,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalGate.appeal(uint256,uint256,string)\",\"CabalGate.begin()\",\"CabalGate.executeSell(uint256)\",\"CabalGate.expire(uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.submitSell(uint256,string)\",\"CabalGate.unlockCallback(bytes)\",\"Laureates.approve(address,uint256)\",\"Laureates.mint(address,uint256,uint8,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256,bytes)\",\"Laureates.setApprovalForAll(address,bool)\",\"Laureates.setName(string)\",\"Laureates.transferFrom(address,address,uint256)\",\"PLEA.allow(address)\",\"PLEA.approve(address,uint256)\",\"PLEA.burn(uint256)\",\"PLEA.init(address,address)\",\"PLEA.renounceOwnership()\",\"PLEA.setLauncher(address,address,address,address)\",\"PLEA.transfer(address,uint256)\",\"PLEA.transferFrom(address,address,uint256)\",\"PLEA.transferOwnership(address)\",\"PleaDistributor.claim(uint256,address,uint256,bytes32[])\",\"PleaDistributor.renounceOwnership()\",\"PleaDistributor.setMerkleRoot(bytes32)\",\"PleaDistributor.transferOwnership(address)\",\"PleaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PleaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PleaHook.fundWall(uint256)\",\"PleaHook.rebalance()\",\"PleaHook.seed()\",\"PleaHook.unlockCallback(bytes)\",\"PleaLaunch.deployHook(bytes32,bytes)\",\"PleaLaunch.seed()\",\"Seasons.closeSeason(uint256[])\",\"Seasons.flushToWall()\",\"Seasons.record(uint256)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":59,\"README.md\":52,\"foundry.toml\":24,\"launch.json\":60,\"remappings.txt\":4,\"script/Deploy.s.sol\":52,\"script/MineSalt.s.sol\":44,\"src/CabalGate.sol\":596,\"src/Laureates.sol\":227,\"src/OracleAttestation.sol\":227,\"src/PLEA.sol\":116,\"src/PleaDistributor.sol\":49,\"src/PleaHook.sol\":908,\"src/PleaLaunch.sol\":107,\"src/Seasons.sol\":283,\"src/interfaces/IPleaParts.sol\":63,\"src/interfaces/IStacker.sol\":9,\"test/Gate.t.sol\":287,\"test/Hook.t.sol\":125,\"test/Launch.t.sol\":144,\"test/LaunchManifest.t.sol\":242,\"test/OracleConformance.t.sol\":114,\"test/OracleReplay.t.sol\":59,\"test/Orientation.t.sol\":58,\"test/SeasonRanking.t.sol\":190,\"test/Seasons.t.sol\":263,\"test/Token.t.sol\":78,\"test/utils/Fixture.sol\":213,\"test/utils/Mocks.sol\":204},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":13385,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/PleaHook.sol:847: PleaHook._checkpoint(uint160) (src/PleaHook.sol#847-856) uses a weak PRNG: \"c = ring[hour % 25] (src/PleaHook.sol#849)\"\n[high/high] uninitialized-state at src/Seasons.sol:79: Seasons._best (src/Seasons.sol#55) is never initialized. It is used in:\n[high/high] uninitialized-state at src/Seasons.sol:133: Seasons._bestPleaIds (src/Seasons.sol#56) is never initialized. It is used in:\n[high/high] uninitialized-state at src/Seasons.sol:75: Seasons._topPleas (src/Seasons.sol#54) is never initialized. It is used in:\n[high/high] uninitialized-state at src/Seasons.sol:71: Seasons._top (src/Seasons.sol#53) is never initialized. It is used in:\n[medium/medium] divide-before-multiply at src/PleaHook.sol:884: PleaHook._alignDown(int24) (src/PleaHook.sol#884-888) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/PleaHook.sol:878: PleaHook._alignUp(int24) (src/PleaHook.sol#878-882) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/CabalGate.sol:513: CabalGate._escape(string) (src/CabalGate.sol#513-527) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:189: CabalGate.diedAt() (src/CabalGate.sol#189-192) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:184: CabalGate.restricted() (src/CabalGate.sol#184-186) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:625: PleaHook._applyCap() (src/PleaHook.sol#625-664) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:685: PleaHook.rebalance() (src/PleaHook.sol#685-692) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:513: CabalGate._escape(string) (src/CabalGate.sol#513-527) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:625: PleaHook._applyCap() (src/PleaHook.sol#625-664) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:697: PleaHook._rebalance() (src/PleaHook.sol#697-752) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:697: PleaHook._rebalance() (src/PleaHook.sol#697-752) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:301: PleaHook._pleaIn(PleaHook.Band,uint160) (src/PleaHook.sol#301-313) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Seasons.sol:247: Seasons.flushToWall() (src/Seasons.sol#247-255) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:271: PleaHook.launchExtraBps() (src/PleaHook.sol#271-276) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:218: CabalGate.factScore(address,uint256) (src/CabalGate.sol#218-248) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:754: PleaHook._closeWall() (src/PleaHook.sol#754-771) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:826: PleaHook._settleImd(uint256) (src/PleaHook.sol#826-831) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Seasons.sol:279: Seasons._pay(address,uint256) (src/Seasons.sol#279-282) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:779: Reentrancy in PleaHook._payTip(address,uint256) (src/PleaHook.sol#779-787):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:602: Reentrancy in PleaHook._payCashback(address,uint256) (src/PleaHook.sol#602-617):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:263: Reentrancy in CabalGate.appeal(uint256,uint256,string) (src/CabalGate.sol#263-283):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:697: Reentrancy in PleaHook._rebalance() (src/PleaHook.sol#697-752):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:307: Reentrancy in CabalGate._ask(uint256) (src/CabalGate.sol#307-321):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:685: Reentrancy in PleaHook.rebalance() (src/PleaHook.sol#685-692):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:754: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#754-771):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:625: Reentrancy in PleaHook._applyCap() (src/PleaHook.sol#625-664):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:443: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#443-508):\n[medium/medium] uninitialized-local at src/Laureates.sol:159: Laureates._svg(Laureates.Laureate,uint8,string,string,string).i (src/Laureates.sol#159) is a local variable never initialized\n[medium/medium] uninitialized-local at src/CabalGate.sol:521: CabalGate._escape(string).j (src/CabalGate.sol#521) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Laureates.sol:205: Laureates._escapeXml(bytes).out (src/Laureates.sol#205) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Laureates.sol:220: Laureates._escapeJson(string).out (src/Laureates.sol#220) is a local variable never initialized\n[medium/medium] uninitialized-local at src/CabalGate.sol:515: CabalGate._escape(string).extra (src/CabalGate.sol#515) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Seasons.sol:138: Seasons._record(uint256,uint256,address,uint8).mi (src/Seasons.sol#138) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PleaHook.sol:260: PleaHook.price24hAgo().bestHour (src/PleaHook.sol#260) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PleaHook.sol:524: PleaHook._payFees(address,bool,uint256,uint256,uint256).toPrize (src/PleaHook.sol#524) is a local variable never initialized\n[medium/medium] uninitialized-local at src/CabalGate.sol:544: CabalGate._validateText(string).len (src/CabalGate.sol#544) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Seasons.sol:223: Seasons.closeSeason(uint256[]).paid (src/Seasons.sol#223) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Seasons.sol:143: Seasons._record(uint256,uint256,address,uint8).pts (src/Seasons.sol#143) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PleaHook.sol:247: PleaHook.latestPrice().bestHour (src/PleaHook.sol#247) is a local variable never initialized\n[medium/medium] unused-return at src/PleaHook.sol:796: PleaHook.unlockCallback(bytes) (src/PleaHook.sol#796-824) ignores return value by poolManager.settle() (src/PleaHook.sol#816)\n[medium/medium] unused-return at src/CabalGate.sol:431: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#431-458) ignores return value by pm.settle() (src/CabalGate.sol#455)\n[medium/medium] unused-return at src/PleaHook.sol:224: PleaHook.currentSqrtPriceX96() (src/PleaHook.sol#224-226) ignores return value by (sqrtPriceX96,None,None,None) = poolManager.getSlot0(poolId()) (src/PleaHook.sol#225)\n[medium/medium] unused-return at src/PleaHook.sol:826: PleaHook._settleImd(uint256) (src/PleaHook.sol#826-831) ignores return value by poolManager.settle() (src/PleaHook.sol#830)\n[medium/medium] unused-return at src/OracleAttestation.sol:158: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/OracleAttestation.sol#158-171) ignores return value by (recovered,err,None) = ECDSA.tryRecover(digest,signature) (src/OracleAttestation.sol#166)\n[medium/medium] unused-return at src/PleaHook.sol:228: PleaHook.currentTick() (src/PleaHook.sol#228-230) ignores return value by (None,tick,None,None) = poolManager.getSlot0(poolId()) (src/PleaHook.sol#229)\n[medium/medium] unused-return at src/PleaHook.sol:666: PleaHook._removeLiquidity(int24,int24,uint256) (src/PleaHook.sol#666-678) ignores return value by (d,None) = poolManager.modifyLiquidity(poolKey(),ModifyLiquidityParams({tickLower:lower,tickUpper:upper,liquidityDelta:- int256(liquidity),salt:0}),) (src/PleaHook.sol#670-674)\n[medium/medium] unused-return at src/Seasons.sol:212: Seasons.closeSeason(uint256[]) (src/Seasons.sol#212-243) ignores return value by (seller,None,None,None) = gate.result(lp[i_scope_1].pleaId) (src/Seasons.sol#239)\n[medium/medium] unused-return at src/PleaHook.sol:697: PleaHook._rebalance() (src/PleaHook.sol#697-752) ignores return value by (d,None) = poolManager.modifyLiquidity(poolKey(),ModifyLiquidityParams({tickLower:lower,tickUpper:upper,liquidityDelta:int256(uint256(liquidity)),salt:0}),) (src/PleaHook.sol#732-738)\n[medium/medium] unused-return at src/PleaHook.sol:796: PleaHook.unlockCallback(bytes) (src/PleaHook.sol#796-824) ignores return value by (d,None) = poolManager.modifyLiquidity(poolKey(),ModifyLiquidityParams({tickLower:lower,tickUpper:upper,liquidityDelta:int256(uint256(liquidity)),salt:0}),) (src/PleaHook.sol#803-809)\n[medium/medium] unused-return at src/CabalGate.sol:348: CabalGate._stale(CabalGate.Plea) (src/CabalGate.sol#348-352) ignores return value by (None,None,None,completed) = intake.requests(p.intakeId) (src/CabalGate.sol#350)\n[medium/medium] unused-return at src/Laureates.sol:83: Laureates.tokenURI(uint256) (src/Laureates.sol#83-96) ignores return value by (seller,score,None,None) = g.result(l.pleaId) (src/Laureates.sol#87)\n[medium/medium] unused-return at src/PleaHook.sol:337: PleaHook.seed() (src/PleaHook.sol#337-377) ignores return value by imd.approve(address(stacker),type()(uint256).max) (src/PleaHook.sol#374)\n[low/medium] missing-zero-check at src/PleaLaunch.sol:50: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).plea_ (src/PleaLaunch.sol#50) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaLaunch.sol:55: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).poolManager_ (src/PleaLaunch.sol#55) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaLaunch.sol:65: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).owner_ (src/PleaLaunch.sol#65) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaHook.sol:174: PleaHook.constructor(IPoolManager,address,IERC20,IStacker,address,address,uint256).seasons_ (src/PleaHook.sol#174) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaLaunch.sol:51: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).gate_ (src/PleaLaunch.sol#51) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaHook.sol:173: PleaHook.constructor(IPoolManager,address,IERC20,IStacker,address,address,uint256).owner_ (src/PleaHook.sol#173) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaHook.sol:170: PleaHook.constructor(IPoolManager,address,IERC20,IStacker,address,address,uint256).plea_ (src/PleaHook.sol#170) lacks a zero-check on :\n[low/medium] calls-loop at src/Seasons.sol:212: Seasons.closeSeason(uint256[]) (src/Seasons.sol#212-243) has external calls inside a loop: (seller,None,None,None) = gate.result(lp[i_scope_1].pleaId) (src/Seasons.sol#239)\n[low/medium] calls-loop at src/Seasons.sol:129: Seasons._seasonOf(uint64) (src/Seasons.sol#129-131) has external calls inside a loop: (uint256(verdictAt) - gate.startedAt()) / SEASON (src/Seasons.sol#130)\n[low/medium] calls-loop at src/Seasons.sol:257: Seasons._tryRecord(uint256) (src/Seasons.sol#257-264) has external calls inside a loop: (seller,score,approved,verdictAt) = gate.result(pleaId) (src/Seasons.sol#259)\n[low/medium] calls-loop at src/Seasons.sol:212: Seasons.closeSeason(uint256[]) (src/Seasons.sol#212-243) has external calls inside a loop: tokenId = l.mint(seller,season,uint8(i_scope_1 + 1),lp[i_scope_1].pleaId) (src/Seasons.sol#240)\n[low/medium] calls-loop at src/Seasons.sol:279: Seasons._pay(address,uint256) (src/Seasons.sol#279-282) has external calls inside a loop: (ok,ret) = address(imd).call(abi.encodeCall(IERC20.transfer,(to,amount))) (src/Seasons.sol#280)\n[low/medium] reentrancy-benign at src/PleaHook.sol:625: Reentrancy in PleaHook._applyCap() (src/PleaHook.sol#625-664):\n[low/medium] reentrancy-benign at src/PleaHook.sol:625: Reentrancy in PleaHook._applyCap() (src/PleaHook.sol#625-664):\n[low/medium] reentrancy-benign at src/PleaHook.sol:515: Reentrancy in PleaHook._payFees(address,bool,uint256,uint256,uint256) (src/PleaHook.sol#515-549):\n[low/medium] reentrancy-benign at src/PleaHook.sol:337: Reentrancy in PleaHook.seed() (src/PleaHook.sol#337-377):\n[low/medium] reentrancy-benign at src/PleaHook.sol:515: Reentrancy in PleaHook._payFees(address,bool,uint256,uint256,uint256) (src/PleaHook.sol#515-549):\n[low/medium] reentrancy-benign at src/PleaHook.sol:337: Reentrancy in PleaHook.seed() (src/PleaHook.sol#337-377):\n[low/medium] reentrancy-benign at src/PleaHook.sol:697: Reentrancy in PleaHook._rebalance() (src/PleaHook.sol#697-752):\n[low/medium] reentrancy-benign at src/PleaHook.sol:754: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#754-771):\n[low/medium] reentrancy-benign at src/PleaHook.sol:754: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#754-771):\n[low/medium] reentrancy-benign at src/PleaHook.sol:443: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#443-508):\n[low/medium] reentrancy-benign at src/PleaHook.sol:443: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#443-508):\n[low/medium] reentrancy-benign at src/PleaHook.sol:754: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#754-771):\n[low/medium] reentrancy-benign at src/PleaHook.sol:337: Reentrancy in PleaHook.seed() (src/PleaHook.sol#337-377):\n[low/medium] reentrancy-benign at src/PleaHook.sol:602: Reentrancy in PleaHook._payCashback(address,uint256) (src/PleaHook.sol#602-617):\n[low/medium] reentrancy-benign at src/CabalGate.sol:307: Reentrancy in CabalGate._ask(uint256) (src/CabalGate.sol#307-321):\n[low/medium] reentrancy-events at src/PleaHook.sol:685: Reentrancy in PleaHook.rebalance() (src/PleaHook.sol#685-692):\n[low/medium] reentrancy-events at src/Seasons.sol:247: Reentrancy in Seasons.flushToWall() (src/Seasons.sol#247-255):\n[low/medium] reentrancy-events at src/PleaHook.sol:555: Reentrancy in PleaHook._refund(address,bool,uint256) (src/PleaHook.sol#555-566):\n[low/medium] reentrancy-events at src/PleaHook.sol:779: Reentrancy in PleaHook._payTip(address,uint256) (src/PleaHook.sol#779-787):\n[low/medium] reentrancy-events at src/PleaHook.sol:754: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#754-771):\n[low/medium] reentrancy-events at src/CabalGate.sol:307: Reentrancy in CabalGate._ask(uint256) (src/CabalGate.sol#307-321):\n[low/medium] reentrancy-events at src/PleaHook.sol:515: Reentrancy in PleaHook._payFees(address,bool,uint256,uint256,uint256) (src/PleaHook.sol#515-549):\n[low/medium] reentrancy-events at src/PleaHook.sol:337: Reentrancy in PleaHook.seed() (src/PleaHook.sol#337-377):\n[low/medium] reentrancy-events at src/PleaHook.sol:625: Reentrancy in PleaHook._applyCap() (src/PleaHook.sol#625-664):\n[low/medium] reentrancy-events at src/PleaHook.sol:555: Reentrancy in PleaHook._refund(address,bool,uint256) (src/PleaHook.sol#555-566):\n[low/medium] reentrancy-events at src/PleaLaunch.sol:78: Reentrancy in PleaLaunch.deployHook(bytes32,bytes) (src/PleaLaunch.sol#78-90):\n[low/medium] reentrancy-events at src/PleaHook.sol:443: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#443-508):\n[low/medium] reentrancy-events at src/Seasons.sol:212: Reentrancy in Seasons.closeSeason(uint256[]) (src/Seasons.sol#212-243):\n[low/medium] reentrancy-events at src/PleaHook.sol:602: Reentrancy in PleaHook._payCashback(address,uint256) (src/PleaHook.sol#602-617):\n[low/medium] reentrancy-events at src/PleaHook.sol:443: Reentrancy ","passed":true},{"durationMs":956,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/PleaLaunch.sol:68: `abi.encodePacked()` Hash Collision\n[high] reentrancy-state-change at src/CabalGate.sol:169: Reentrancy: State change after external call (7 places)\n[high] storage-array-memory-edit at src/PleaHook.sol:279: Storage Array Edited with Memory (3 places)\n[high] unsafe-casting at src/CabalGate.sol:295: Unsafe Casting of integers (4 places)\n[low] centralization-risk at src/PLEA.sol:12: Centralization Risk (4 places)\n[low] costly-loop at src/Seasons.sol:181: Costly operations inside loop (3 places)\n[low] internal-function-used-once at src/OracleAttestation.sol:206: Internal Function Used Only Once\n[low] large-numeric-literal at src/CabalGate.sol:221: Large Numeric Literal (7 places)\n[low] literal-instead-of-constant at src/CabalGate.sol:221: Literal Instead of Constant (73 places)\n[low] missing-inheritance at src/PleaHook.sol:35: Missing Inheritance\n[low] require-revert-in-loop at src/CabalGate.sol:536: Loop Contains `require`/`revert` (3 places)\n[low] state-change-without-event at src/CabalGate.sol:431: State Change Without Event (2 places)\n[low] unchecked-return at src/CabalGate.sol:455: Unchecked Return (4 places)\n[low] uninitialized-local-variable at src/CabalGate.sol:515: Uninitialized Local Variable (12 places)\n[low] unsafe-erc20-operation at src/PleaHook.sol:374: Unsafe ERC20 Operation (4 places)\n[low] unsafe-oz-erc721-mint at src/Laureates.sol:41: Unsafe `ERC721::_mint()`\n[low] unused-import at src/PleaLaunch.sol:4: Unused Import (3 places)\n[low] unused-public-function at src/CabalGate.sol:189: Public Function Not Used Internally (7 places)\n[low] unused-state-variable at src/PLEA.sol:25: Unused State Variable (4 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"67b5db6a210707812dcda6f962b17a9e6cb0e6b2dbb4a04bdb17dcb599280f95","verifiedTreeHash":"5e8a03445f76c84e13cb4f1ff43de51ce80b3910","verifierVersion":"0.1.0+fdeb4d4a"},{"checks":[{"durationMs":88318,"exitCode":0,"name":"build","output":"Compiling 125 files with Solc 0.8.26\nSolc 0.8.26 finished in 88.21s\nCompiler run successful!\n","passed":true},{"durationMs":318,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_callbackSelectorHasTheProtocolStruct() (gas: 748)\n[PASS] test_digestMatchesTheProtocol() (gas: 10505)\n[PASS] test_liveAttestationRecoversToOracleSigner() (gas: 130878)\n[PASS] test_protocolSignatureRecoversToVectorSigner() (gas: 13921)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.78ms (806.49µs CPU time)\n\nRan 3 tests for test/LaunchManifest.t.sol:RehearsalManifestTest\n[PASS] test_laterBlockCannotRegisterLauncher() (gas: 14025019)\n[PASS] test_separateConstructorCallsInDeploymentBlockStillWork() (gas: 14713798)\n[PASS] test_separateTransactionsLeaveTheAcceptedDeploymentBlockWindow() (gas: 14184022)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 6.25ms (5.06ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:PostLaunchHookTest\n[PASS] test_committedHookDeploysLaterAndMintsOnlyTheFixedSplit() (gas: 9062751)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.75ms (6.55ms CPU time)\n\nRan 21 tests for test/Orientation.t.sol:GatePleaIsZeroTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8006079)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6440698)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3920991)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3257954)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3796710)\n[PASS] test_callbackFitsTheStipend() (gas: 5467125)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3643141)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 353449)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5780373)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5370817)\n[PASS] test_onePendingPleaPerWallet() (gas: 3098819)\n[PASS] test_orientationIsPleaZero() (gas: 15796)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5366253)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3185528)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5398661)\n[PASS] test_scoreBelowNeedDenies() (gas: 3422962)\n[PASS] test_sellWindowLapses() (gas: 5408526)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3271114)\n[PASS] test_textFilter() (gas: 3369179)\n[PASS] test_wrongSignerIsRefused() (gas: 3235685)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 18.43ms (31.47ms CPU time)\n\nRan 9 tests for test/Hook.t.sol:HookTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1158821)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1060766)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1207374)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1723225)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 550450)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1058410)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1109208)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4110336)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 725412)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 23.65ms (9.76ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:AtomicManifestTest\n[PASS] test_factoryDeploysExactManifestOnAnEmptySepoliaChain() (gas: 30165537)\nLogs:\n  six-contract factory deployment gas: 15868055\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 32.56ms (30.62ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_distributorAndAllowlistMaySend() (gas: 208891)\n[PASS] test_freeForeverOnceTheCabalDies() (gas: 183694)\n[PASS] test_launcherAndInitAreOneShot() (gas: 127042)\n[PASS] test_walletsCannotSendWhileTheCabalWatches() (gas: 313213)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 35.24ms (458.27µs CPU time)\n\nRan 20 tests for test/Gate.t.sol:GateTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8005967)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6440526)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3920871)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3257902)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3796268)\n[PASS] test_callbackFitsTheStipend() (gas: 5467043)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3643081)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 353449)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5780321)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5370757)\n[PASS] test_onePendingPleaPerWallet() (gas: 3098819)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5366141)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3185476)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5398579)\n[PASS] test_scoreBelowNeedDenies() (gas: 3422872)\n[PASS] test_sellWindowLapses() (gas: 5408466)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3271062)\n[PASS] test_textFilter() (gas: 3369179)\n[PASS] test_wrongSignerIsRefused() (gas: 3235655)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 36.76ms (29.59ms CPU time)\n\nRan 10 tests for test/Orientation.t.sol:HookPleaIsZeroTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1158821)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1060766)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1207396)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1723225)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 550472)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1058432)\n[PASS] test_orientationIsPleaZero() (gas: 15725)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1109208)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4110336)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 725412)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 62.05ms (10.22ms CPU time)\n\nRan 11 tests for test/Orientation.t.sol:SeasonsPleaIsZeroTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3247309)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230850)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17412673)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 44243127)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8603614)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3359020)\n[PASS] test_orientationIsPleaZero() (gas: 15664)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32062767)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29690339)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81458315)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 69.69ms (79.00ms CPU time)\n\nRan 10 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3247287)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230739)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17412651)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 44243105)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8603614)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3358998)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32062767)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29690317)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81458293)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 69.70ms (77.14ms CPU time)\n\nRan 11 tests for test/Seasons.t.sol:FastClockTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3246625)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230761)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17411418)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 39892510)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8622981)\n[PASS] test_fastFullCycle() (gas: 58520110)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13499)\n[PASS] test_onlyApprovedPleasScore() (gas: 3356039)\n[PASS] test_secondSeasonScoresSeparately() (gas: 36375760)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29688119)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 85759678)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 69.63ms (106.55ms CPU time)\n\nRan 3 tests for test/OracleReplay.t.sol:OracleReplayTest\n[PASS] testFuzz_oneSignedRequestCannotSettleTwoPleas(bool,bool) (runs: 32, μ: 5576889, ~: 5586751)\n[PASS] test_deniedRequestCannotBeResignedToApproveItsAppeal() (gas: 5833031)\n[PASS] test_invalidCallbackDoesNotConsumeTheRequest() (gas: 5425209)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 109.31ms (66.67ms CPU time)\n\nRan 6 tests for test/SeasonRanking.t.sol:SeasonRankingTest\n[PASS] testFuzz_rankingsMatchSortedResultsInAnyRecordOrder(uint256) (runs: 32, μ: 11273572, ~: 11249770)\n[PASS] test_closeSeasonUsesTheSameTiesForPrizesAndNfts() (gas: 1233690)\n[PASS] test_earlierEqualScoreCanReplaceACountedPleaWithoutChangingPoints() (gas: 879686)\n[PASS] test_earlierTiedPleaTakesFirstAndFifthLaureateSlots() (gas: 1191499)\n[PASS] test_replacingALowerScoreRemovesItsIdFromTheTieKey() (gas: 879654)\n[PASS] test_walletTieUsesNewestCountedPleaNotLastRecordedPlea() (gas: 910672)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 169.34ms (170.79ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_deployHookChecksTheInitCodeAndFlags() (gas: 364251178)\n[PASS] test_eachStepFitsAMainnetTransaction() (gas: 363307703)\nLogs:\n  launch (6 contracts + intake mock): 826923\n  deployHook: 5217579\n  seed: 534221\n\n[PASS] test_launchWiresEverythingWithoutCallingOutside() (gas: 861024)\n[PASS] test_ownerMaySeedEarly() (gas: 363322636)\n[PASS] test_seedByOwnerAnyTimeByAnyoneAfterStart() (gas: 363418802)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 188.58ms (714.68ms CPU time)\n\nRan 15 test suites in 189.59ms (904.73ms CPU time): 119 tests passed, 0 failed, 0 skipped (119 total tests)\n","passed":true},{"durationMs":67,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalGate.appeal(uint256,uint256,string)\",\"CabalGate.begin()\",\"CabalGate.executeSell(uint256)\",\"CabalGate.expire(uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.submitSell(uint256,string)\",\"CabalGate.unlockCallback(bytes)\",\"Laureates.approve(address,uint256)\",\"Laureates.mint(address,uint256,uint8,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256,bytes)\",\"Laureates.setApprovalForAll(address,bool)\",\"Laureates.setName(string)\",\"Laureates.transferFrom(address,address,uint256)\",\"PLEA.allow(address)\",\"PLEA.approve(address,uint256)\",\"PLEA.burn(uint256)\",\"PLEA.init(address,address)\",\"PLEA.renounceOwnership()\",\"PLEA.setLauncher(address,address,address,address)\",\"PLEA.transfer(address,uint256)\",\"PLEA.transferFrom(address,address,uint256)\",\"PLEA.transferOwnership(address)\",\"PleaDistributor.claim(uint256,address,uint256,bytes32[])\",\"PleaDistributor.renounceOwnership()\",\"PleaDistributor.setMerkleRoot(bytes32)\",\"PleaDistributor.transferOwnership(address)\",\"PleaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PleaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PleaHook.fundWall(uint256)\",\"PleaHook.rebalance()\",\"PleaHook.seed()\",\"PleaHook.unlockCallback(bytes)\",\"PleaLaunch.deployHook(bytes32,bytes)\",\"PleaLaunch.seed()\",\"Seasons.closeSeason(uint256[])\",\"Seasons.flushToWall()\",\"Seasons.record(uint256)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":59,\"README.md\":52,\"foundry.toml\":24,\"launch.json\":60,\"remappings.txt\":4,\"script/Deploy.s.sol\":52,\"script/MineSalt.s.sol\":44,\"src/CabalGate.sol\":596,\"src/Laureates.sol\":227,\"src/OracleAttestation.sol\":227,\"src/PLEA.sol\":116,\"src/PleaDistributor.sol\":49,\"src/PleaHook.sol\":908,\"src/PleaLaunch.sol\":107,\"src/Seasons.sol\":283,\"src/interfaces/IPleaParts.sol\":63,\"src/interfaces/IStacker.sol\":9,\"test/Gate.t.sol\":287,\"test/Hook.t.sol\":125,\"test/Launch.t.sol\":144,\"test/LaunchManifest.t.sol\":242,\"test/OracleConformance.t.sol\":114,\"test/OracleReplay.t.sol\":59,\"test/Orientation.t.sol\":58,\"test/SeasonRanking.t.sol\":190,\"test/Seasons.t.sol\":263,\"test/Token.t.sol\":78,\"test/utils/Fixture.sol\":213,\"test/utils/Mocks.sol\":204},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8d59928dd78fa668d078de68d978737033289032fabd04e3f4b43c03ecfa98ec","verifiedTreeHash":"24b4823a2fd08977a37417c85910a44de70ce673","verifierVersion":"0.1.0+fdeb4d4a"},{"checks":[{"durationMs":114185,"exitCode":0,"name":"build","output":"Compiling 127 files with Solc 0.8.26\nSolc 0.8.26 finished in 114.05s\nCompiler run successful!\n","passed":true},{"durationMs":342,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_callbackSelectorHasTheProtocolStruct() (gas: 748)\n[PASS] test_digestMatchesTheProtocol() (gas: 10505)\n[PASS] test_liveAttestationRecoversToOracleSigner() (gas: 131611)\n[PASS] test_protocolSignatureRecoversToVectorSigner() (gas: 13921)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.50ms (1.23ms CPU time)\n\nRan 3 tests for test/LaunchManifest.t.sol:RehearsalManifestTest\n[PASS] test_laterBlockCannotRegisterLauncher() (gas: 14777809)\n[PASS] test_separateConstructorCallsInDeploymentBlockStillWork() (gas: 15467590)\n[PASS] test_separateTransactionsLeaveTheAcceptedDeploymentBlockWindow() (gas: 14936813)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 7.35ms (6.80ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:PostLaunchHookTest\n[PASS] test_committedHookDeploysLaterAndMintsOnlyTheFixedSplit() (gas: 7244440)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 10.41ms (4.52ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_distributorAndAllowlistMaySend() (gas: 208891)\n[PASS] test_freeForeverOnceTheCabalDies() (gas: 183694)\n[PASS] test_launcherAndInitAreOneShot() (gas: 127039)\n[PASS] test_walletsCannotSendWhileTheCabalWatches() (gas: 313213)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 15.10ms (804.70µs CPU time)\n\nRan 8 tests for test/SeasonFunds.t.sol:SeasonFundsTest\n[PASS] testFuzz_lateCloseConservesAssets(uint96,uint96,bool) (runs: 32, μ: 1187812, ~: 1222973)\n[PASS] test_claimRedemptionCallbackCannotBeInvokedOutsideUnlock() (gas: 74978)\n[PASS] test_deathAtBoundaryFlushesClaimsAndLateDonationsOnce() (gas: 1507105)\n[PASS] test_deathMidSeasonPreservesEarlierSeasonFees() (gas: 1487044)\n[PASS] test_failedPayoutRollsForwardWithoutBlockingOtherWinners() (gas: 1612166)\n[PASS] test_feeAtBoundaryBelongsToNextSeason() (gas: 1135047)\n[PASS] test_lateClosesOnlyRollUnpaidSharesForward() (gas: 2334155)\n[PASS] test_unobservedDonationCannotFlowBackwards() (gas: 1045375)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 24.30ms (30.13ms CPU time)\n\nRan 1 test for test/LaunchManifest.t.sol:AtomicManifestTest\n[PASS] test_factoryDeploysExactManifestOnAnEmptySepoliaChain() (gas: 31878840)\nLogs:\n  six-contract factory deployment gas: 16622688\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 35.18ms (31.42ms CPU time)\n\nRan 3 tests for test/OracleReplay.t.sol:OracleReplayTest\n[PASS] testFuzz_oneSignedRequestCannotSettleTwoPleas(bool,bool) (runs: 32, μ: 5578452, ~: 5569296)\n[PASS] test_deniedRequestCannotBeResignedToApproveItsAppeal() (gas: 5835566)\n[PASS] test_invalidCallbackDoesNotConsumeTheRequest() (gas: 5430175)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 56.37ms (51.39ms CPU time)\n\nRan 9 tests for test/Hook.t.sol:HookTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1234745)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1083521)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1283298)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1838054)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 573151)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1078803)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1185140)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4437504)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 748072)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 76.52ms (14.89ms CPU time)\n\nRan 20 tests for test/Gate.t.sol:GateTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8017668)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6472113)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3952422)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3260385)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3798751)\n[PASS] test_callbackFitsTheStipend() (gas: 5472009)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3645564)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 356016)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5814271)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5375843)\n[PASS] test_onePendingPleaPerWallet() (gas: 3101302)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5371227)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3187959)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5403545)\n[PASS] test_scoreBelowNeedDenies() (gas: 3425377)\n[PASS] test_sellWindowLapses() (gas: 5433722)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3273545)\n[PASS] test_textFilter() (gas: 3395652)\n[PASS] test_wrongSignerIsRefused() (gas: 3238138)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 76.69ms (43.59ms CPU time)\n\nRan 21 tests for test/Orientation.t.sol:GatePleaIsZeroTest\n[PASS] test_appealClosesAfterFourHoursAndOnlyOnce() (gas: 8017780)\n[PASS] test_appealWithinFourHoursForNoMore() (gas: 6472285)\n[PASS] test_approvedScoreOpensTheSellWindow() (gas: 3952542)\n[PASS] test_badAttestationsAreNotDelivered() (gas: 3260437)\n[PASS] test_bodyIsTheNumericPanelQuestion() (gas: 3799193)\n[PASS] test_callbackFitsTheStipend() (gas: 5472091)\nLogs:\n  approve callback gas: 58694\n  deny callback gas: 83293\n\n[PASS] test_callbackOnlyFromIntakeAndOnlyForAPendingPlea() (gas: 3645624)\n[PASS] test_cannotPassIsRefusedBeforePaying() (gas: 356016)\n[PASS] test_cooldownAfterExecutedSell() (gas: 5814323)\n[PASS] test_noPleasWhileTheCabalSleeps() (gas: 48140)\n[PASS] test_noVerdictIsClearedAtOnceWhenTheIntakeCompletes() (gas: 5375903)\n[PASS] test_onePendingPleaPerWallet() (gas: 3101302)\n[PASS] test_orientationIsPleaZero() (gas: 15790)\n[PASS] test_pendingExpiresAfterTwentyMinutesAndLateCallbacksFail() (gas: 5371339)\n[PASS] test_pleaPaysTheIntakeAndNamesTheCallback() (gas: 3188011)\n[PASS] test_scoreAboveRangeOrWrongTypeIsRefused() (gas: 5403627)\n[PASS] test_scoreBelowNeedDenies() (gas: 3425467)\n[PASS] test_sellWindowLapses() (gas: 5433782)\n[PASS] test_signerWithDelegationCodeStillVerifies() (gas: 3273597)\n[PASS] test_textFilter() (gas: 3395652)\n[PASS] test_wrongSignerIsRefused() (gas: 3238168)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 76.57ms (41.50ms CPU time)\n\nRan 11 tests for test/Orientation.t.sol:SeasonsPleaIsZeroTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249814)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230894)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17478002)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 42281540)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8726369)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3361513)\n[PASS] test_orientationIsPleaZero() (gas: 15658)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32133791)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29723601)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81550282)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 76.59ms (90.86ms CPU time)\n\nRan 11 tests for test/Seasons.t.sol:FastClockTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249130)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230805)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 1287708)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 31395767)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 1184066)\n[PASS] test_fastFullCycle() (gas: 56516800)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13499)\n[PASS] test_onlyApprovedPleasScore() (gas: 3358532)\n[PASS] test_secondSeasonScoresSeparately() (gas: 34297316)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 2586356)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 85855324)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 76.60ms (102.57ms CPU time)\n\nRan 10 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_aLateCallbackCannotRevive() (gas: 3249792)\n[PASS] test_aliveFromSeedDeadAfterSilenceForever() (gas: 230783)\n[PASS] test_bestThreeCountAndTopTenOrder() (gas: 17477980)\n[PASS] test_closeSeasonPaysTheTopTenAndMintsLaureates() (gas: 42281518)\n[PASS] test_deathEndsTheLastSeasonAndTheRestGoesToTheWall() (gas: 8726369)\n[PASS] test_mainnetGuardRefusesShortTimings() (gas: 13477)\n[PASS] test_onlyApprovedPleasScore() (gas: 3361491)\n[PASS] test_secondSeasonScoresSeparately() (gas: 32133791)\n[PASS] test_tenthPlaceIsEvictedByABetterWallet() (gas: 29723579)\n[PASS] test_verdictsKeepItAliveAcrossManySeasons() (gas: 81550260)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 76.51ms (112.55ms CPU time)\n\nRan 10 tests for test/Orientation.t.sol:HookPleaIsZeroTest\n[PASS] test_aBuyMustAffordTheCredit() (gas: 1234745)\n[PASS] test_avgBuyTimeIsBuyWeighted() (gas: 1083521)\n[PASS] test_everyFeeIsPaidInTheSameSwap() (gas: 1283320)\n[PASS] test_factScoreUsesCheckpointsNotSpot() (gas: 1838054)\n[PASS] test_firstBuyWithAnEmptyPoolSendsPayoutsToLiquidity() (gas: 573173)\n[PASS] test_freeTradingWhenTheCabalSleeps() (gas: 1078825)\n[PASS] test_orientationIsPleaZero() (gas: 15719)\n[PASS] test_plainImdOnlyWhenTheCreditReverts() (gas: 1185140)\n[PASS] test_rebalanceRedeemsClaimsIntoTheWall() (gas: 4437504)\n[PASS] test_sellsAndExactOutputOnlyThroughTheGateWhileAlive() (gas: 748072)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 76.67ms (10.81ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_deployHookChecksTheInitCodeAndFlags() (gas: 162524779)\n[PASS] test_eachStepFitsAMainnetTransaction() (gas: 161712833)\nLogs:\n  launch (6 contracts + intake mock): 826923\n  deployHook: 5184037\n  seed: 534215\n\n[PASS] test_launchWiresEverythingWithoutCallingOutside() (gas: 861046)\n[PASS] test_ownerMaySeedEarly() (gas: 161727763)\n[PASS] test_seedByOwnerAnyTimeByAnyoneAfterStart() (gas: 161823951)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 110.21ms (406.00ms CPU time)\n\nRan 12 tests for test/AuditRevision.t.sol:AuditRevisionTest\n[PASS] testFuzz_cumulativeCapDecayStaysWithinElapsedBudget(uint256) (runs: 32, μ: 3992871, ~: 3994072)\n[PASS] test_appealRetryClearsTimedOutPendingAppeal() (gas: 8663875)\n[PASS] test_deadCabalBuyStillRequiresARecipient() (gas: 1599742)\n[PASS] test_dustBuyDoesNotGiveUntrackedTokensLossOrHoldingPoints() (gas: 1075644)\n[PASS] test_expiredAppealCanBeRetriedWithoutLiftingDenialCooldown() (gas: 8791698)\n[PASS] test_lapsedApprovalCannotBypassCooldown() (gas: 6328947)\n[PASS] test_largeBuyClaimsAreRedeemableAndNextBuyStacksNormally() (gas: 2149980)\n[PASS] test_lateCloseDoesNotPayFutureSeasonFees() (gas: 11143768)\n[PASS] test_sameSecondCapRatchetsCannotReuseFractionalBudget() (gas: 1042010)\n[PASS] test_seasonClaimsArePaidAsImdAtClose() (gas: 7904442)\n[PASS] test_secondLargeBuyPreservesEveryPayee() (gas: 1231332)\n[PASS] test_unansweredAppealDoesNotExtendTheOriginalWindow() (gas: 6363564)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 115.32ms (131.95ms CPU time)\n\nRan 12 tests for test/AuditRevision.t.sol:AuditRevisionPleaZeroTest\n[PASS] testFuzz_cumulativeCapDecayStaysWithinElapsedBudget(uint256) (runs: 32, μ: 3992003, ~: 3990379)\n[PASS] test_appealRetryClearsTimedOutPendingAppeal() (gas: 8663642)\n[PASS] test_deadCabalBuyStillRequiresARecipient() (gas: 1600476)\n[PASS] test_dustBuyDoesNotGiveUntrackedTokensLossOrHoldingPoints() (gas: 1075168)\n[PASS] test_expiredAppealCanBeRetriedWithoutLiftingDenialCooldown() (gas: 8791465)\n[PASS] test_lapsedApprovalCannotBypassCooldown() (gas: 6328714)\n[PASS] test_largeBuyClaimsAreRedeemableAndNextBuyStacksNormally() (gas: 2150284)\n[PASS] test_lateCloseDoesNotPayFutureSeasonFees() (gas: 11143183)\n[PASS] test_sameSecondCapRatchetsCannotReuseFractionalBudget() (gas: 1041516)\n[PASS] test_seasonClaimsArePaidAsImdAtClose() (gas: 7903827)\n[PASS] test_secondLargeBuyPreservesEveryPayee() (gas: 1231205)\n[PASS] test_unansweredAppealDoesNotExtendTheOriginalWindow() (gas: 6363331)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 118.31ms (136.25ms CPU time)\n\nRan 6 tests for test/SeasonRanking.t.sol:SeasonRankingTest\n[PASS] testFuzz_rankingsMatchSortedResultsInAnyRecordOrder(uint256) (runs: 32, μ: 11233194, ~: 11223463)\n[PASS] test_closeSeasonUsesTheSameTiesForPrizesAndNfts() (gas: 1360241)\n[PASS] test_earlierEqualScoreCanReplaceACountedPleaWithoutChangingPoints() (gas: 879842)\n[PASS] test_earlierTiedPleaTakesFirstAndFifthLaureateSlots() (gas: 1191572)\n[PASS] test_replacingALowerScoreRemovesItsIdFromTheTieKey() (gas: 879810)\n[PASS] test_walletTieUsesNewestCountedPleaNotLastRecordedPlea() (gas: 910760)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 192.88ms (190.92ms CPU time)\n\nRan 18 test suites in 195.95ms (1.22s CPU time): 151 tests passed, 0 failed, 0 skipped (151 total tests)\n","passed":true},{"durationMs":79,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalGate.appeal(uint256,uint256,string)\",\"CabalGate.begin()\",\"CabalGate.executeSell(uint256)\",\"CabalGate.expire(uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.submitSell(uint256,string)\",\"CabalGate.unlockCallback(bytes)\",\"Laureates.approve(address,uint256)\",\"Laureates.mint(address,uint256,uint8,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256)\",\"Laureates.safeTransferFrom(address,address,uint256,bytes)\",\"Laureates.setApprovalForAll(address,bool)\",\"Laureates.setName(string)\",\"Laureates.transferFrom(address,address,uint256)\",\"PLEA.allow(address)\",\"PLEA.approve(address,uint256)\",\"PLEA.burn(uint256)\",\"PLEA.init(address,address)\",\"PLEA.renounceOwnership()\",\"PLEA.setLauncher(address,address,address,address)\",\"PLEA.transfer(address,uint256)\",\"PLEA.transferFrom(address,address,uint256)\",\"PLEA.transferOwnership(address)\",\"PleaDistributor.claim(uint256,address,uint256,bytes32[])\",\"PleaDistributor.renounceOwnership()\",\"PleaDistributor.setMerkleRoot(bytes32)\",\"PleaDistributor.transferOwnership(address)\",\"PleaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PleaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PleaHook.fundWall(uint256)\",\"PleaHook.rebalance()\",\"PleaHook.seed()\",\"PleaHook.unlockCallback(bytes)\",\"PleaLaunch.deployHook(bytes32,bytes)\",\"PleaLaunch.seed()\",\"Seasons.checkpoint()\",\"Seasons.closeSeason(uint256[])\",\"Seasons.flushToWall()\",\"Seasons.record(uint256)\",\"Seasons.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":111,\"README.md\":54,\"foundry.toml\":24,\"launch.json\":60,\"remappings.txt\":4,\"script/Deploy.s.sol\":52,\"script/MineSalt.s.sol\":44,\"src/CabalGate.sol\":605,\"src/Laureates.sol\":227,\"src/OracleAttestation.sol\":227,\"src/PLEA.sol\":116,\"src/PleaDistributor.sol\":49,\"src/PleaHook.sol\":927,\"src/PleaLaunch.sol\":107,\"src/Seasons.sol\":342,\"src/interfaces/IPleaParts.sol\":67,\"src/interfaces/IStacker.sol\":9,\"test/AuditRevision.t.sol\":260,\"test/Gate.t.sol\":287,\"test/Hook.t.sol\":125,\"test/Launch.t.sol\":144,\"test/LaunchManifest.t.sol\":242,\"test/OracleConformance.t.sol\":114,\"test/OracleReplay.t.sol\":59,\"test/Orientation.t.sol\":58,\"test/SeasonFunds.t.sol\":237,\"test/SeasonRanking.t.sol\":191,\"test/Seasons.t.sol\":279,\"test/Token.t.sol\":78,\"test/utils/Fixture.sol\":213,\"test/utils/Mocks.sol\":204},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":14365,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/PleaHook.sol:866: PleaHook._checkpoint(uint160) (src/PleaHook.sol#866-875) uses a weak PRNG: \"c = ring[hour % 25] (src/PleaHook.sol#868)\"\n[high/high] uninitialized-state at src/Seasons.sol:88: Seasons._best (src/Seasons.sol#59) is never initialized. It is used in:\n[high/high] uninitialized-state at src/Seasons.sol:161: Seasons._bestPleaIds (src/Seasons.sol#60) is never initialized. It is used in:\n[high/high] uninitialized-state at src/Seasons.sol:84: Seasons._topPleas (src/Seasons.sol#58) is never initialized. It is used in:\n[high/high] uninitialized-state at src/Seasons.sol:80: Seasons._top (src/Seasons.sol#57) is never initialized. It is used in:\n[medium/medium] divide-before-multiply at src/PleaHook.sol:897: PleaHook._alignUp(int24) (src/PleaHook.sol#897-901) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/PleaHook.sol:903: PleaHook._alignDown(int24) (src/PleaHook.sol#903-907) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/PleaHook.sol:643: PleaHook._applyCap() (src/PleaHook.sol#643-683) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:773: PleaHook._closeWall() (src/PleaHook.sol#773-790) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:716: PleaHook._rebalance() (src/PleaHook.sol#716-771) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:643: PleaHook._applyCap() (src/PleaHook.sol#643-683) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:303: PleaHook._pleaIn(PleaHook.Band,uint160) (src/PleaHook.sol#303-315) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:219: CabalGate.factScore(address,uint256) (src/CabalGate.sol#219-251) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Seasons.sol:124: Seasons.checkpoint() (src/Seasons.sol#124-135) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:522: CabalGate._escape(string) (src/CabalGate.sol#522-536) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:273: PleaHook.launchExtraBps() (src/PleaHook.sol#273-278) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:522: CabalGate._escape(string) (src/CabalGate.sol#522-536) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Seasons.sol:338: Seasons._pay(address,uint256) (src/Seasons.sol#338-341) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:190: CabalGate.diedAt() (src/CabalGate.sol#190-193) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:704: PleaHook.rebalance() (src/PleaHook.sol#704-711) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:845: PleaHook._settleImd(uint256) (src/PleaHook.sol#845-850) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PleaHook.sol:716: PleaHook._rebalance() (src/PleaHook.sol#716-771) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:185: CabalGate.restricted() (src/CabalGate.sol#185-187) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Seasons.sol:281: Seasons.flushToWall() (src/Seasons.sol#281-293) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:445: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#445-510):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:445: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#445-510):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:267: Reentrancy in CabalGate.appeal(uint256,uint256,string) (src/CabalGate.sol#267-288):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:312: Reentrancy in CabalGate._ask(uint256) (src/CabalGate.sol#312-326):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:798: Reentrancy in PleaHook._payTip(address,uint256) (src/PleaHook.sol#798-806):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:620: Reentrancy in PleaHook._payCashback(address,uint256) (src/PleaHook.sol#620-635):\n[medium/medium] reentrancy-no-eth at src/Seasons.sol:240: Reentrancy in Seasons.closeSeason(uint256[]) (src/Seasons.sol#240-277):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:716: Reentrancy in PleaHook._rebalance() (src/PleaHook.sol#716-771):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:643: Reentrancy in PleaHook._applyCap() (src/PleaHook.sol#643-683):\n[medium/medium] reentrancy-no-eth at src/Seasons.sol:281: Reentrancy in Seasons.flushToWall() (src/Seasons.sol#281-293):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:704: Reentrancy in PleaHook.rebalance() (src/PleaHook.sol#704-711):\n[medium/medium] reentrancy-no-eth at src/PleaHook.sol:773: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#773-790):\n[medium/medium] uninitialized-local at src/Laureates.sol:159: Laureates._svg(Laureates.Laureate,uint8,string,string,string).i (src/Laureates.sol#159) is a local variable never initialized\n[medium/medium] uninitialized-local at src/CabalGate.sol:530: CabalGate._escape(string).j (src/CabalGate.sol#530) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Laureates.sol:205: Laureates._escapeXml(bytes).out (src/Laureates.sol#205) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Laureates.sol:220: Laureates._escapeJson(string).out (src/Laureates.sol#220) is a local variable never initialized\n[medium/medium] uninitialized-local at src/CabalGate.sol:524: CabalGate._escape(string).extra (src/CabalGate.sol#524) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Seasons.sol:166: Seasons._record(uint256,uint256,address,uint8).mi (src/Seasons.sol#166) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PleaHook.sol:262: PleaHook.price24hAgo().bestHour (src/PleaHook.sol#262) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PleaHook.sol:528: PleaHook._payFees(address,bool,uint256,uint256,uint256).toPrize (src/PleaHook.sol#528) is a local variable never initialized\n[medium/medium] uninitialized-local at src/CabalGate.sol:553: CabalGate._validateText(string).len (src/CabalGate.sol#553) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Seasons.sol:255: Seasons.closeSeason(uint256[]).paid (src/Seasons.sol#255) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Seasons.sol:171: Seasons._record(uint256,uint256,address,uint8).pts (src/Seasons.sol#171) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PleaHook.sol:249: PleaHook.latestPrice().bestHour (src/PleaHook.sol#249) is a local variable never initialized\n[medium/medium] unused-return at src/PleaHook.sol:815: PleaHook.unlockCallback(bytes) (src/PleaHook.sol#815-843) ignores return value by poolManager.settle() (src/PleaHook.sol#835)\n[medium/medium] unused-return at src/PleaHook.sol:230: PleaHook.currentTick() (src/PleaHook.sol#230-232) ignores return value by (None,tick,None,None) = poolManager.getSlot0(poolId()) (src/PleaHook.sol#231)\n[medium/medium] unused-return at src/CabalGate.sol:440: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#440-467) ignores return value by pm.settle() (src/CabalGate.sol#464)\n[medium/medium] unused-return at src/PleaHook.sol:845: PleaHook._settleImd(uint256) (src/PleaHook.sol#845-850) ignores return value by poolManager.settle() (src/PleaHook.sol#849)\n[medium/medium] unused-return at src/PleaHook.sol:685: PleaHook._removeLiquidity(int24,int24,uint256) (src/PleaHook.sol#685-697) ignores return value by (d,None) = poolManager.modifyLiquidity(poolKey(),ModifyLiquidityParams({tickLower:lower,tickUpper:upper,liquidityDelta:- int256(liquidity),salt:0}),) (src/PleaHook.sol#689-693)\n[medium/medium] unused-return at src/PleaHook.sol:716: PleaHook._rebalance() (src/PleaHook.sol#716-771) ignores return value by (d,None) = poolManager.modifyLiquidity(poolKey(),ModifyLiquidityParams({tickLower:lower,tickUpper:upper,liquidityDelta:int256(uint256(liquidity)),salt:0}),) (src/PleaHook.sol#751-757)\n[medium/medium] unused-return at src/OracleAttestation.sol:158: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/OracleAttestation.sol#158-171) ignores return value by (recovered,err,None) = ECDSA.tryRecover(digest,signature) (src/OracleAttestation.sol#166)\n[medium/medium] unused-return at src/PleaHook.sol:815: PleaHook.unlockCallback(bytes) (src/PleaHook.sol#815-843) ignores return value by (d,None) = poolManager.modifyLiquidity(poolKey(),ModifyLiquidityParams({tickLower:lower,tickUpper:upper,liquidityDelta:int256(uint256(liquidity)),salt:0}),) (src/PleaHook.sol#822-828)\n[medium/medium] unused-return at src/CabalGate.sol:356: CabalGate._stale(CabalGate.Plea) (src/CabalGate.sol#356-360) ignores return value by (None,None,None,completed) = intake.requests(p.intakeId) (src/CabalGate.sol#358)\n[medium/medium] unused-return at src/Seasons.sol:240: Seasons.closeSeason(uint256[]) (src/Seasons.sol#240-277) ignores return value by (seller,None,None,None) = gate.result(lp[i_scope_1].pleaId) (src/Seasons.sol#273)\n[medium/medium] unused-return at src/Seasons.sol:297: Seasons._redeemClaims() (src/Seasons.sol#297-304) ignores return value by pm.unlock(abi.encode(amount)) (src/Seasons.sol#303)\n[medium/medium] unused-return at src/PleaHook.sol:339: PleaHook.seed() (src/PleaHook.sol#339-379) ignores return value by imd.approve(address(stacker),type()(uint256).max) (src/PleaHook.sol#376)\n[medium/medium] unused-return at src/Laureates.sol:83: Laureates.tokenURI(uint256) (src/Laureates.sol#83-96) ignores return value by (seller,score,None,None) = g.result(l.pleaId) (src/Laureates.sol#87)\n[medium/medium] unused-return at src/PleaHook.sol:226: PleaHook.currentSqrtPriceX96() (src/PleaHook.sol#226-228) ignores return value by (sqrtPriceX96,None,None,None) = poolManager.getSlot0(poolId()) (src/PleaHook.sol#227)\n[low/medium] missing-zero-check at src/PleaLaunch.sol:50: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).plea_ (src/PleaLaunch.sol#50) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaHook.sol:175: PleaHook.constructor(IPoolManager,address,IERC20,IStacker,address,address,uint256).owner_ (src/PleaHook.sol#175) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaLaunch.sol:55: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).poolManager_ (src/PleaLaunch.sol#55) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaLaunch.sol:65: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).owner_ (src/PleaLaunch.sol#65) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaLaunch.sol:51: PleaLaunch.constructor(address,address,address,address,address,address,address,address,uint256,uint256).gate_ (src/PleaLaunch.sol#51) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaHook.sol:172: PleaHook.constructor(IPoolManager,address,IERC20,IStacker,address,address,uint256).plea_ (src/PleaHook.sol#172) lacks a zero-check on :\n[low/medium] missing-zero-check at src/PleaHook.sol:176: PleaHook.constructor(IPoolManager,address,IERC20,IStacker,address,address,uint256).seasons_ (src/PleaHook.sol#176) lacks a zero-check on :\n[low/medium] calls-loop at src/Seasons.sol:316: Seasons._tryRecord(uint256) (src/Seasons.sol#316-323) has external calls inside a loop: (seller,score,approved,verdictAt) = gate.result(pleaId) (src/Seasons.sol#318)\n[low/medium] calls-loop at src/Seasons.sol:157: Seasons._seasonOf(uint64) (src/Seasons.sol#157-159) has external calls inside a loop: (uint256(verdictAt) - gate.startedAt()) / SEASON (src/Seasons.sol#158)\n[low/medium] calls-loop at src/Seasons.sol:240: Seasons.closeSeason(uint256[]) (src/Seasons.sol#240-277) has external calls inside a loop: (seller,None,None,None) = gate.result(lp[i_scope_1].pleaId) (src/Seasons.sol#273)\n[low/medium] calls-loop at src/Seasons.sol:338: Seasons._pay(address,uint256) (src/Seasons.sol#338-341) has external calls inside a loop: (ok,ret) = address(imd).call(abi.encodeCall(IERC20.transfer,(to,amount))) (src/Seasons.sol#339)\n[low/medium] calls-loop at src/Seasons.sol:240: Seasons.closeSeason(uint256[]) (src/Seasons.sol#240-277) has external calls inside a loop: tokenId = l.mint(seller,season,uint8(i_scope_1 + 1),lp[i_scope_1].pleaId) (src/Seasons.sol#274)\n[low/medium] reentrancy-benign at src/PleaHook.sol:339: Reentrancy in PleaHook.seed() (src/PleaHook.sol#339-379):\n[low/medium] reentrancy-benign at src/PleaHook.sol:517: Reentrancy in PleaHook._payFees(address,bool,uint256,uint256,uint256) (src/PleaHook.sol#517-561):\n[low/medium] reentrancy-benign at src/PleaHook.sol:517: Reentrancy in PleaHook._payFees(address,bool,uint256,uint256,uint256) (src/PleaHook.sol#517-561):\n[low/medium] reentrancy-benign at src/PleaHook.sol:445: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#445-510):\n[low/medium] reentrancy-benign at src/PleaHook.sol:773: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#773-790):\n[low/medium] reentrancy-benign at src/PleaHook.sol:773: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#773-790):\n[low/medium] reentrancy-benign at src/PleaHook.sol:339: Reentrancy in PleaHook.seed() (src/PleaHook.sol#339-379):\n[low/medium] reentrancy-benign at src/CabalGate.sol:312: Reentrancy in CabalGate._ask(uint256) (src/CabalGate.sol#312-326):\n[low/medium] reentrancy-benign at src/PleaHook.sol:643: Reentrancy in PleaHook._applyCap() (src/PleaHook.sol#643-683):\n[low/medium] reentrancy-benign at src/PleaHook.sol:773: Reentrancy in PleaHook._closeWall() (src/PleaHook.sol#773-790):\n[low/medium] reentrancy-benign at src/PleaHook.sol:339: Reentrancy in PleaHook.seed() (src/PleaHook.sol#339-379):\n[low/medium] reentrancy-benign at src/PleaHook.sol:716: Reentrancy in PleaHook._rebalance() (src/PleaHook.sol#716-771):\n[low/medium] reentrancy-benign at src/PleaHook.sol:517: Reentrancy in PleaHook._payFees(address,bool,uint256,uint256,uint256) (src/PleaHook.sol#517-561):\n[low/medium] reentrancy-benign at src/PleaHook.sol:445: Reentrancy in PleaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PleaHook.sol#445-510):\n[low/medium] reentrancy-benign at src/PleaHook.sol:643: Reentrancy in PleaHook._applyCap() (src/PleaHook.sol#643-683):\n[low/medium] reentrancy-benign at src/PleaHook.sol:620: Reentrancy in PleaHook._payCashback(address,uint256) (src/PleaHook.sol#620-635):\n[low/medium] reentrancy-events at src/PleaHook.sol:573: Reentrancy in PleaHook._refund(address,bool,uint256) (src/PleaHook.sol#573-584):\n[low/medium] reentrancy-events at src/CabalGate.sol:312: Reentrancy in CabalGate._ask(uint256) (src/CabalGate.sol#312-326):\n[low/medium] reentrancy-events at src/PleaHook.sol:339: Reentrancy in PleaHook.seed() (src/PleaHook.sol#339-379):\n[low/medium] reentrancy-events at src/PleaHook.sol:573: Reentrancy in PleaHook._refund(address,bool,uint256) (src/PleaHook.sol#573-584):\n[low/medium] reentrancy-events at src/PleaHook.sol:704: Reentrancy in PleaHook.rebalance() (src/PleaHook.sol#704-711):\n[low/medium] reentrancy-events at src/Seasons.sol:281: Reentrancy in Seasons.flushToWall() (src/Seasons.sol#281-293):\n[low/medium] reentrancy-events at src/PleaHook.sol:517: Reentrancy in PleaHook._payFees(address,bool,uint256,uint256,uint256) (src/PleaHook.sol#517-561):\n[low/medium] reentrancy-events at src/PleaHook.sol:620: Reentrancy in PleaHook._payCashback(address,uint256) (sr","passed":true},{"durationMs":984,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/PleaLaunch.sol:68: `abi.encodePacked()` Hash Collision\n[high] reentrancy-state-change at src/CabalGate.sol:170: Reentrancy: State change after external call (10 places)\n[high] storage-array-memory-edit at src/PleaHook.sol:281: Storage Array Edited with Memory (3 places)\n[high] unsafe-casting at src/CabalGate.sol:300: Unsafe Casting of integers (4 places)\n[low] centralization-risk at src/PLEA.sol:12: Centralization Risk (4 places)\n[low] costly-loop at src/Seasons.sol:209: Costly operations inside loop (3 places)\n[low] internal-function-used-once at src/OracleAttestation.sol:206: Internal Function Used Only Once\n[low] large-numeric-literal at src/CabalGate.sol:222: Large Numeric Literal (7 places)\n[low] literal-instead-of-constant at src/CabalGate.sol:222: Literal Instead of Constant (73 places)\n[low] missing-inheritance at src/PleaHook.sol:35: Missing Inheritance (2 places)\n[low] require-revert-in-loop at src/CabalGate.sol:545: Loop Contains `require`/`revert` (3 places)\n[low] state-change-without-event at src/CabalGate.sol:440: State Change Without Event (3 places)\n[low] unchecked-return at src/CabalGate.sol:464: Unchecked Return (5 places)\n[low] uninitialized-local-variable at src/CabalGate.sol:524: Uninitialized Local Variable (12 places)\n[low] unsafe-erc20-operation at src/PleaHook.sol:376: Unsafe ERC20 Operation (4 places)\n[low] unsafe-oz-erc721-mint at src/Laureates.sol:41: Unsafe `ERC721::_mint()`\n[low] unused-import at src/PleaLaunch.sol:4: Unused Import (3 places)\n[low] unused-public-function at src/CabalGate.sol:190: Public Function Not Used Internally (7 places)\n[low] unused-state-variable at src/PLEA.sol:25: Unused State Variable (4 places)","passed":true},{"durationMs":20091,"exitCode":0,"name":"proof b4aab24b9b24","output":"Compiling 113 files with Solc 0.8.26\nSolc 0.8.26 finished in 19.34s\nCompiler run successful with warnings:\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n   --> test/imd-proof-21614a0d/Proof_b4aab24b9b24.t.sol:165:64:\n    |\n165 |     function mineSalt(bytes32 initHash) internal view returns (bytes32) {\n    |                                                                ^^^^^^^\n\n\nRan 1 test for test/imd-proof-21614a0d/Proof_b4aab24b9b24.t.sol:PayoutsToPoolOnSecondBuyTest\n[PASS] test_secondBuyStillPaysOwnerPrizeAndCashback() (gas: 1187193)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 20.69ms (599.31µs CPU time)\n\nRan 1 test suite in 21.39ms (20.69ms 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":"ddc531b55b1d42fd987fd1e972a1075b3bac705aaf1efa0ac1f8aa08897f4628","verifiedTreeHash":"4ff2d6856b6e11bd09c9d428459f092c5e8be648","verifierVersion":"0.1.0+4ba55555"}]}