{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"62e6b27c-75bc-41f8-b4d0-322fb1711971","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"756343e8a47363bef7fabd55d1e6190c59f7ea9bf8dab10be77e05a2f78fa59f","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"3992e09e1fc6636d515cd011a47313f95c779b19df5ba6af0932f1622c9aaeb1","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":"128fe8be2ee811d95bfc588a8c0e40a50495924df25198f2a32a28603f5165cf","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":"c024bb5e14acd71c8e4ba2d3b4ee183b91a42fe1c29a55c7f73a291eef752d33","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":"9507b2ab8c0a03a7ad7700a0e70302a461a9f81ee8c172a70f35970aea036f83","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":"67dc22b8f1f724761791e088c23dc363221d6d65163f72d0c3b1953cb46f0884","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":"96662d9ed9f5d7c5fcdaa34526873f44bba7759adc2395c76e25064e6fadade0","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":"5ca33adaae886efa75523245b0706e457fef98116d2371d3daeadd35c255c9c3","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"648dd7a3cd2af045ebccf652bbfeb9a1f3ee6dfc326bac035ca0b01fabdf3e18","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":"Deploy IMD6900RobinhoodLaunch (src/IMD6900RobinhoodLaunch.sol) on Robinhood Chain exactly as it is in the repository: one contract, four constructor arguments in this order: 0x35da9c0303507ddf708e87f2568eddf12c47a059 (owner: the team wallet), 0x8366a39CC670B4001A1121B8F6A443A643e40951 (Uniswap v4's PoolManager on Robinhood Chain), 0x0000198C940D8cD70Cb9ACeC5E3af8216ac57d2F (Robinhood's IMDSTR, the old token that claims the new coin 1:1), 0x16D3f65B708883DF042d98E1C7a49B32A33E2A14 (the Robinhood timelock: owns the hook and recovers ETH). Its constructor creates IMD6900LockedPool and nothing else (no salt mining: about 6.9M gas from any deployer address). After the deploy, createHook(salt) (anyone, once) creates IMD6900Hook with CREATE2 from the launch at a salt mined off-chain for its address (script/launch.sh hook: its address carries exactly the hook's permission flags and doesn't start with 0x91; the hook is owned by the timelock); the team calls it, the deploy does not need to. The pool's fee is static: 4.44% (POOL_FEE 44_400), the same for every trade, so Uniswap's router routes the pool on its own (no dynamic fee, no return deltas); it accrues to the locked position, whose fees anyone can collect. A v4 pool's fee can't change, so IMD6900LockedPool.lowerFee (the timelock only, lower only) moves the whole position in one unlock to a new pool at the lower fee and the same price. It calls nothing that existed before it, so it deploys the same on a fresh chain (test_DeploysOnAFreshChain); it fits one transaction (test_FitsOneTransaction, ~6.9M gas, the same from any deployer); no contract shows CALLCODE, DELEGATECALL or SELFDESTRUCT, creation code included (test_PassesTheAdmissionScan). Later, its owner launches the coin IMD6900 at a 0x6900… address mined for this contract's address (launch(): the coin with CREATE2, the pool opened with the whole 1B supply as coin-only liquidity, locked for good, and the opening buy, in one transaction), through Programmable's custom launch, which binds every component to the exact source: do not change the source, the compiler settings (solc 0.8.26, via-IR, 200 runs, cancun, bytecode_hash none), the constructor, the hook's permissions, the 4.44% static fee and lowerFee's lower-only move (refused while the perps engine has positions open), the fee refund (IMD6900LockedPool.feeCheckpoint/feeRefund: only the hook's perps engine and the launch's sellHeld trade fee-free), the pool's lack of any liquidity removal (only lowerFee's move from one pool into the next), the coin's plain ERC20 (no owner, no mint, no tax) and launch()'s refusal of any coin address not starting with 0x6900, the fee split's defaults (90% the pot bridge, which feeds IMD6900's NFT floor pot on Ethereum; 10% $IMD bought for IMD's canonical Robinhood burn executor 0x4D6537ec564aFf82eABb1Ce5f355E817cBEA1e07, fixed in the code), the perps engine's fees (addPerpFees: all of it as ETH to the pot bridge), the split and every landing address being the timelock's alone to change (setPayees, setPerpFeeTo, setCoinFeeTo, setImdBurn, setImdPool), or the timelock's role (the hook's owner; it alone recovers ETH, releases the excess or sells the coins the launch holds back into the pool for the opening buy's ETH (sellHeld), ends the claims early (endClaims), repoints $IMD's pool and sets the split). test/RobinhoodFork.t.sol runs the whole launch on a Robinhood fork when ROBINHOOD_RPC_URL is set (claims, trades, buys through Uniswap's Universal Router, the fee split, the $IMD burn, a fee move to 3.33%) and skips otherwise. Everything builds offline (lib/ is vendored; v4-core's PoolManager is used by the tests only).","parentJobId":null,"planHash":"e59c9fcc88b48b24a9bb2d04387cadcc96002f3ba655ba3c1349b7b3f601fe6b","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"62e6b27c-75bc-41f8-b4d0-322fb1711971","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1547-imd6900robinhoodlaunch"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51073","feedbackHash":"4113523204012cb550dcdfdb2b6ada27d2661497c144f25cd0f5b84ba6b47708","nodeKey":"adapt_contract_project","submissionHash":"20b29d3009054b277698a16b362a9ee43805afbea7d6763c82e80af238ca9b73","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52599","feedbackHash":"802221b3cf0091fcc0674b49b13f6cdcef839ec669f7ab2e7e7dc8f11cb1efa2","nodeKey":"adapt_contract_project","submissionHash":"5dc87eb5665dc4e7ed1d7074157c3f16f90ecf66c80a0a32ac12a5ba8b781f95","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52189","feedbackHash":"c235e07dfe61ff8a93b47c973a228a2d10f9936a2da428e7bde2ff85c839d515","nodeKey":"adapt_contract_project","submissionHash":"756343e8a47363bef7fabd55d1e6190c59f7ea9bf8dab10be77e05a2f78fa59f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52289","feedbackHash":"d8a39ebfc9c2270d4a259d40af20bf4953c5b576f13a8abfcc68356c94b6f7c5","nodeKey":"audit_economics","submissionHash":"3992e09e1fc6636d515cd011a47313f95c779b19df5ba6af0932f1622c9aaeb1","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52626","feedbackHash":"f11c64106bae354037e96e04c974c657273970a44b18bb935a776bda41d30d33","nodeKey":"audit_flow","submissionHash":"128fe8be2ee811d95bfc588a8c0e40a50495924df25198f2a32a28603f5165cf","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51169","feedbackHash":"3ecdbc29ec0eb476003cb43944de04b66f65a88b16024986132023dfd725d6b7","nodeKey":"audit_imported_code","submissionHash":"c024bb5e14acd71c8e4ba2d3b4ee183b91a42fe1c29a55c7f73a291eef752d33","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51507","feedbackHash":"650a3a472ce7bc30b1204e2c03e573123937750f0f65ebcbde48f61ade3dcc11","nodeKey":"audit_judge","submissionHash":"24ec4bca857def40eec5d240b5d889556e6d52fd42ec8fc21e5742db334c720d","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52190","feedbackHash":"65e0a03cbe5c546bbb8b79658718d6d6cc798b3cab23769b31f9726f1a9f755a","nodeKey":"audit_judge","submissionHash":"3c29f36fdc19e8c1baa0235d4a2369fdc24a6611d47c9160fa931cd3878daf9c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52178","feedbackHash":"2a0fa03f3f0a1c83f46247cec77fe91120cbf8e8bf1cb961f8b791dae49c69f7","nodeKey":"audit_judge","submissionHash":"9507b2ab8c0a03a7ad7700a0e70302a461a9f81ee8c172a70f35970aea036f83","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52623","feedbackHash":"33287cc4a787e3d4a4e6c9294c6b9c2be8740f3251b720bfccc0a17e36375704","nodeKey":"audit_math","submissionHash":"67dc22b8f1f724761791e088c23dc363221d6d65163f72d0c3b1953cb46f0884","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51515","feedbackHash":"08e590f7498d126382c57284aa2efefed030fd72f90b315f367ebd71ab5afc21","nodeKey":"audit_permissions","submissionHash":"96662d9ed9f5d7c5fcdaa34526873f44bba7759adc2395c76e25064e6fadade0","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52583","feedbackHash":"99d3081efa0c69b8933c831ee2f749a19e5fcbb13712a1ec2f85ab030b0868f0","nodeKey":"manifest","submissionHash":"e4b58e68e4f6b60e13a391033667465857dd78f7a7b55adacea19730f074bbc2","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52624","feedbackHash":"f9afdb97e634e2e3c4d098c88ec1ac3f1114e0b92b7829b152b4bef0a4ab8c5c","nodeKey":"manifest","submissionHash":"e8f06b0ee8095d32f229d304dfa9b1e656f0312e6e96f41c6dca150da8cf6101","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51450","feedbackHash":"e0d22c233bf680eec1e36fc8eb210a3f338159a8b768c6319047f9912a5dce6c","nodeKey":"manifest","submissionHash":"5ca33adaae886efa75523245b0706e457fef98116d2371d3daeadd35c255c9c3","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"53910","feedbackHash":"0e5c2b4e43f73a17086fd939151c76f38efb7f1c682e28479f47c305b301ad4c","nodeKey":"write_foundry_tests","submissionHash":"a0d79eea857dc23a82a9f9aecab06101cf298727f6247b0b2acc8284cf65509f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52164","feedbackHash":"cc66850b6ebb0a8e44e4980951c2162577f3225cf836df4ee51dd0773b32123e","nodeKey":"write_foundry_tests","submissionHash":"648dd7a3cd2af045ebccf652bbfeb9a1f3ee6dfc326bac035ca0b01fabdf3e18","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52615","feedbackHash":"639dffe89445e6d00f7c865ba53a07e527facafcc748df2f2b4fb4ce8c51fc5d","nodeKey":"write_foundry_tests","submissionHash":"64bd8b26944cb8e80707512d06ab75fc968ebdfb8a6484b67037f772565f5e48","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"b7a7e59b25ce4772019a11ca759f873f57e8c61bfae11204886ba6daf3f17dd8","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"790f4e545968ee92","findings":[{"citation":"resolved","description":"split() computes `amount = balance - imdBucket` and pays every payee `amount * bps / 10_000`. A payee whose call fails only gets a PayFailed event: its part stays in the contract balance with no record of whom it belongs to. The next split() (public, no cooldown; harvest() calls it too) treats that part as fresh fees and splits it again across all payees. With the documented default split (90% pot bridge, 10% $IMD burn) a pot bridge that refuses ETH (its deposit path paused, Across halted, or any later payee contract without a payable receive) loses 10% of its share to the burn bucket on every call, compounding: after k calls the pot keeps only 0.9^k of what it was owed, and the $IMD burn bucket gets the rest. Anyone can call split() in a loop in one block for gas only. The NatSpec says a refusing payee's share \"leaves it here for the next split\", i.e. waits for that payee; the code instead hands it to the others. The same precondition also makes addPerpFees() revert outright (safeTransferETH to perpFeeTo), which bubbles up into the perps engine's fee flush until the timelock repoints perpFeeTo. Fix: book the failed part to the payee (mapping owed[payee] += part, excluded from `amount` like imdBucket, retried on the next split or claimable by that payee), or revert the whole split when a payee fails so nothing is redistributed.","line":473,"path":"src/IMD6900RobinhoodLaunch.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\n/// A stand-in for the old IMDSTR: the launch only needs an address that is not zero before the launch\ncontract Imdstr {\n    mapping(address => uint256) public balanceOf;\n}\n\n/// A payee that cannot take ETH right now (a bridge whose deposit path is paused, a contract with no receive)\ncontract RefusingPayee {\n    receive() external payable {\n        revert(\"paused\");\n    }\n}\n\n/// A payee that refuses its share must not have that share paid to the other payees by the next split.\ncontract SplitRefusedShareTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n\n    IPoolManager pm;\n    IMD6900RobinhoodLaunch launch;\n    RefusingPayee pot;\n\n    function setUp() public {\n        pm = IPoolManager(address(new PoolManager(address(this))));\n        launch = new IMD6900RobinhoodLaunch(OWNER, pm, address(new Imdstr()), TL);\n        launch.createHook(_hookSalt());\n        bytes32 salt = _coinSalt();\n        address expected = launch.tokenAddress(salt);\n        uint160 price = _sqrtPrice(19.18 ether);\n        vm.deal(OWNER, 1 ether);\n        vm.prank(OWNER);\n        launch.launch{value: 1 ether}(salt, expected, price, 0, address(0));\n        pot = new RefusingPayee();\n        // the timelock's split: 90% to a pot that is (for now) refusing ETH, 10% $IMD's burn\n        address[] memory to = new address[](2);\n        uint16[] memory bps = new uint16[](2);\n        (to[0], bps[0], to[1], bps[1]) = (address(pot), 9_000, launch.imdBurn(), 1_000);\n        vm.prank(TL);\n        launch.setPayees(to, bps);\n    }\n\n    function test_RefusedShareIsNotResplitToOtherPayees() public {\n        vm.deal(address(this), 1 ether);\n        launch.addFees{value: 1 ether}();\n        // anyone calls split repeatedly while the pot refuses; nothing else changes between the calls\n        for (uint256 i; i < 10; ++i) {\n            try launch.split() {} catch {}\n        }\n        emit log_named_decimal_uint(\"burn bucket after ten splits\", launch.imdBucket(), 18);\n        // 10% of 1 ETH is the burn's share; the pot's refused 90% is not the burn's to take\n        assertLe(launch.imdBucket(), 0.1 ether, \"the burn bucket took the pot's refused share\");\n        assertGe(address(launch).balance - launch.imdBucket(), 0.9 ether, \"the pot's share no longer waits for it\");\n    }\n\n    /*                               HELPERS                                */\n\n    function _hookSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.hookInitCodeHash();\n        uint160 flags = launch.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) >> 144 == launch.VANITY()) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched (any price), the timelock has set payees [P (a contract whose receive reverts), imdBurn] with shares [9000, 1000]; 1 ETH of fees arrives via addFees. Call split() ten times from any address. Expected: the pot's 0.9 ETH waits for P, imdBucket = 0.1 ETH. Actual: imdBucket = 0.6513 ETH (1 - 0.9^10) and only 0.3487 ETH is left for P; see test/scratch/SplitRefusedShare.t.sol (fails on this tree: `the burn bucket took the pot's refused share: 651321559900000000 > 100000000000000000`).","severity":"medium","snippet":"            (bool ok,) = to[i].call{value: part}(\"\");\n            if (!ok) emit PayFailed(to[i], part);","title":"split() re-splits a refused payee's share to the other payees on every later call, so a refusing pot bridge shifts the fees to the $IMD burn bucket"},{"citation":"resolved","description":"The refund pair assumes nothing else earns the position fees between one caller's checkpoint and its refund (\"the fees earned between the two are that swap's, to the wei\"). The hook breaks that assumption by design: IMD6900Hook._beforeSwap and _afterSwap call the perps engine's sweepLiquidations inside the very swap the launch is refunding (sender = the launch, not the engine, so the sweep runs), and a liquidation is a swap in this pool. Two outcomes, both wrong: (a) a refunding engine (perpRefunded, the PerpSwapLib pattern of checkpoint/swap/refund) calls feeCheckpoint() in the after-swap sweep; _poke(address(this)) moves every fee earned so far, including the sale's own 4.44%, to the pool contract (burned at the next collect), and the launch's feeRefund() right after finds zero: back = 0, the loop ends after one round, the sale paid the full fee. (b) a non-refunding engine's liquidation fees accrue inside the launch's window and the launch's feeRefund takes them: back exceeds the sale's own fee, sold = paid - back understates the sale (and reverts by underflow when the liquidation is larger than the sale, blocking sellHeld), and fee coins that should be burned become excessHeld. The sale is documented fee-free (sellHeld NatSpec, the README) and the perps engine's refund is the companion feature, so the two collide whenever a sale's price move sinks a position. Fix: make checkpoints nest-aware (keep the poked amount per caller in transient storage and, on a nested checkpoint, credit the outer caller's slot with the fees accrued since its own checkpoint instead of poking them to the pool), or have the hook skip the sweep for the launch's own swaps as it does for the engine's.","line":204,"path":"src/IMD6900LockedPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\ncontract Imdstr {\n    mapping(address => uint256) public balanceOf;\n}\n\n/// A perps engine that takes its fee back the way the refunding engine does (checkpoint, swap, refund), and whose\n/// post-trade sweep liquidates one position: a sale of coins into the pool, inside the hook's afterSwap\ncontract SweepingEngine {\n    IPoolManager immutable pm;\n    IMD6900LockedPool immutable lp;\n    uint256 public liquidation; // coins to sell at the next post-trade sweep\n    constructor(IPoolManager pm_, IMD6900LockedPool lp_) { (pm, lp) = (pm_, lp_); }\n    function openCount() external pure returns (uint256) { return 0; }\n    function arm(uint256 coins) external { liquidation = coins; }\n\n    function sweepLiquidations(address, int256 spec, bool, uint160) external returns (uint8) {\n        if (spec != 0 || liquidation == 0) return 0; // nothing to do before the trade; one close after it\n        uint256 coins = liquidation;\n        liquidation = 0;\n        _sell(coins);\n        return 0;\n    }\n\n    /// the engine's own buy, in its own unlock (no sweep: it is the engine)\n    function buy(uint256 eth) external {\n        pm.unlock(abi.encode(eth));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        uint256 eth = abi.decode(data, (uint256));\n        PoolKey memory k = lp.poolKey();\n        lp.feeCheckpoint();\n        BalanceDelta d = pm.swap(k, SwapParams(true, -int256(eth), TickMath.MIN_SQRT_PRICE + 1), \"\");\n        lp.feeRefund(address(this));\n        pm.settle{value: uint128(-d.amount0())}();\n        pm.take(k.currency1, address(this), uint128(d.amount1()));\n        return \"\";\n    }\n\n    function _sell(uint256 coins) internal {\n        PoolKey memory k = lp.poolKey();\n        lp.feeCheckpoint();\n        BalanceDelta d = pm.swap(k, SwapParams(false, -int256(coins), TickMath.MAX_SQRT_PRICE - 1), \"\");\n        lp.feeRefund(address(this));\n        pm.sync(k.currency1);\n        IERC20(Currency.unwrap(k.currency1)).transfer(address(pm), uint128(-d.amount1()));\n        pm.settle();\n        pm.take(k.currency0, address(this), uint128(d.amount0()));\n    }\n\n    receive() external payable {}\n}\n\n/// The timelock's sale is documented fee-free; a liquidation the hook runs inside the sale's refund window takes\n/// that guarantee away: the engine's nested checkpoint pokes the sale's fee to the pool contract, and the sale's\n/// own refund finds nothing.\ncontract NestedRefundTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    address constant R = address(0x2E7);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n\n    IPoolManager pm;\n    IMD6900RobinhoodLaunch launch;\n    IMD6900LockedPool pool;\n    IMD6900Hook hook;\n    address token;\n    SweepingEngine engine;\n\n    function setUp() public {\n        pm = IPoolManager(address(new PoolManager(address(this))));\n        launch = new IMD6900RobinhoodLaunch(OWNER, pm, address(new Imdstr()), TL);\n        hook = launch.createHook(_hookSalt());\n        pool = launch.pool();\n        bytes32 salt = _coinSalt();\n        address expected = launch.tokenAddress(salt);\n        uint160 price = _sqrtPrice(19.18 ether);\n        vm.deal(OWNER, 2.81 ether);\n        vm.prank(OWNER);\n        (token,) = launch.launch{value: 2.81 ether}(salt, expected, price, 0, address(launch)); // excess held\n        engine = new SweepingEngine(pm, pool);\n        vm.deal(address(engine), 10 ether);\n        vm.prank(TL);\n        hook.setPerpEngine(address(engine));\n        vm.prank(TL);\n        hook.setPerpRefunded(true);\n        engine.buy(1 ether); // the engine holds coins, as positions it may have to close\n    }\n\n    function test_SaleStaysFeeFreeWhenTheSweepLiquidates() public {\n        uint256 held = launch.excessHeld();\n        uint256 sale = held / 2;\n        // one position is under water after the sale's price move: the post-trade sweep closes it\n        engine.arm(IERC20(token).balanceOf(address(engine)) / 10);\n        vm.prank(TL);\n        launch.sellHeld(sale, 0, R);\n        // both the engine and the launch are refunded: nothing of either's fee may be left for the burn\n        (, uint256 coinFee) = pool.collect();\n        emit log_named_decimal_uint(\"coins of the sale's fee that were not refunded\", coinFee, 18);\n        emit log_named_decimal_uint(\"4.44% of the sale\", sale * 444 / 10_000, 18);\n        assertLt(coinFee, sale / 1_000, \"the fee-free sale paid the pool's fee: its refund went to the pool contract\");\n    }\n\n    /*                               HELPERS                                */\n\n    function _hookSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.hookInitCodeHash();\n        uint160 flags = launch.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) >> 144 == launch.VANITY()) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched with the excess held (excessTo = the launch); the timelock wired a refunding engine (setPerpEngine, setPerpRefunded(true)) that holds coins; one position is under water after the sale's price move, so the engine's post-trade sweep sells coins with its checkpoint/swap/refund pair. Timelock calls sellHeld(held/2, 0, R). Expected: the sale is fee-free, pool.collect() afterwards returns ~0 coins (both callers are refunded). Actual: pool.collect() returns 2,716,114 coins = exactly 4.44% of the sale, and R receives correspondingly less ETH; see test/scratch/NestedRefund.t.sol (fails on this tree: `2716114297381638809234320 >= 61173745436523396604376`).","severity":"medium","snippet":"    function feeCheckpoint() external {\n        if (!isRefunded(msg.sender)) revert NotRefunded();\n        _poke(address(this));","title":"feeCheckpoint/feeRefund windows nest: a liquidation the hook's sweep runs inside the timelock's sale re-checkpoints and takes the sale's fee, so sellHeld is not fee-free"}],"hash":"128fe8be2ee811d95bfc588a8c0e40a50495924df25198f2a32a28603f5165cf","nodeId":"64919a87-ae41-44b6-9547-5f7c6d51618a","outcome":"completed","summary":"Review complete. The findings file holds 2 substantiated findings, each with a failing Foundry proof, and a coverage row for all 59 entry points.\n\n**Findings (both medium, both with proofs under `test/scratch/`)**\n\n1. **A refused payee's share is re-split to the other payees.** In `split()`, a payee whose ETH call fails only gets a `PayFailed` event. The next public call treats its part as fresh fees and divides it again across everyone. With the default split, a pot bridge that refuses ETH loses 10% of its share to the $IMD burn bucket on every call, compounding. The proof launches locally, sets a reverting payee at 90%, sends 1 ETH of fees, and calls `split()` ten times: the burn bucket ends at 0.65 ETH instead of 0.1 ETH. The same precondition makes `addPerpFees` revert outright.\n\n2. **The fee-refund window nests with the hook's own sweep.** `feeCheckpoint` pokes every fee earned so far to the pool contract, whatever other refunded caller has a window open. The hook runs the perps engine's sweep inside the very swap the launch is refunding, and a liquidation is a swap in this pool. A refunding engine's nested checkpoint takes the sale's whole 4.44% fee to the pool contract, so the sale's `feeRefund` finds nothing and `sellHeld` is not fee-free. The proof shows `collect()` returning exactly 4.44% of the sale after one liquidation in the after-swap sweep. A non-refunding engine produces the mirror misattribution and can make `sellHeld` revert by underflow.\n\n**Coverage.** All 59 entry points have a row. The two findings cover `split`, `harvest`, `addPerpFees`, `sellHeld`, both unlock callbacks' sale path, `feeCheckpoint`, `feeRefund`, `beforeSwap` and `afterSwap`. Everything else holds on trace. I verified in depth: `launch` and `open` (tick flooring, all-coin position at the upper tick, dust return, allowance fully consumed), `lowerFee` and `_move` (the re-added amounts never exceed the removed principal, so no leg ever pays in), the claim Merkle path, the bucket accounting across `split`, `burnImd` and `recoverEth`, `createHook` front-running (same hook, only the address differs), and the BaseHook guards.\n\n**Not reached.** The Robinhood fork test and the real perps engine, which is outside the repo. Finding 2 therefore models the engine with the same checkpoint/swap/refund pattern the project's own `RefundingEngine` test double uses.\n\nStatic-analysis leads checked and dropped: the `abi.encodePacked` collision (fixed-size fields), the arbitrary-send in `_payOutHeld` (immutable launcher), and the strict equalities (all intended sentinels).","treeHash":null,"usage":{"cachedInputTokens":2111835,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":59127,"runtime":"claude","turns":33,"wallClockMs":873008}},{"artifacts":[],"attempt":1,"bundleHash":"1c4e226126180f4231c99c63f7c8bd9ef204784b21fdd7fc2d5fa6fd3eab4fdc","device":"43eaeedfc1287bf1","findings":[],"hash":"20b29d3009054b277698a16b362a9ee43805afbea7d6763c82e80af238ca9b73","nodeId":"05fd8dea-3d65-40d8-9cb2-9259e8b24c7a","outcome":"completed","summary":"Implemented all three reproduced audit fixes: burn rate limiting, incomplete-fill protection, and aggregate claim limits.\n\nAdded regression tests and [ADAPTATION.md](/home/imd4/.identitymd/work/62e6b27c-75bc-41f8-b4d0-322fb1711971/05fd8dea-3d65-40d8-9cb2-9259e8b24c7a/ADAPTATION.md). Configuration and dependencies remain unchanged.\n\n`forge build`, `forge test`, and supplied checks pass. All 58 local tests pass; live fork testing was skipped because `ROBINHOOD_RPC_URL` is unset.","treeHash":"0ff5e586ff181d579fe42afb17d51bac950ae106","usage":{"cachedInputTokens":3993728,"inputTokens":141097,"model":"gpt-6-astra","outputTokens":26133,"runtime":"codex","turns":9,"wallClockMs":1582459}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2dc755dfe7bd177c","findings":[{"citation":"resolved","description":"split() computes amount = balance - imdBucket and pays each payee amount*bps/10_000. A payee whose call{value} fails only gets a PayFailed event; its ETH stays in the plain balance with no record of whom it belongs to. The next split() (public, no cooldown, also run by harvest()) treats that ETH as fresh fees and splits it again: 10% of it is booked to imdBucket (the only share that is booked, not sent) and 90% is offered to the refusing payee again. After k calls the pot keeps 0.9^k of what it was owed and the rest has moved into the $IMD burn bucket, which burnImd (anyone) then spends irrevocably. The NatSpec on split ('A payee that refuses its share leaves it here for the next split') and the brief's 90/10 default are both broken. Precondition: the pot bridge (or any later payee contract) refuses ETH, e.g. its deposit path paused or Across halted; the same precondition makes addPerpFees() revert outright until the timelock repoints perpFeeTo. Merged from audit_flow and audit_economics (same root cause). Fix: book a failed part to its payee (owed[payee] += part, excluded from amount like imdBucket, retried or claimable later), or revert the whole split when a payee fails.","line":463,"path":"src/IMD6900RobinhoodLaunch.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\n/// A stand-in for the old IMDSTR: the launch only needs an address that is not zero before the launch\ncontract Imdstr {\n    mapping(address => uint256) public balanceOf;\n}\n\n/// A payee that cannot take ETH right now (a bridge whose deposit path is paused, a contract with no receive)\ncontract RefusingPayee {\n    receive() external payable {\n        revert(\"paused\");\n    }\n}\n\n/// A payee that refuses its share must not have that share paid to the other payees by the next split.\ncontract SplitRefusedShareTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n\n    IPoolManager pm;\n    IMD6900RobinhoodLaunch launch;\n    RefusingPayee pot;\n\n    function setUp() public {\n        pm = IPoolManager(address(new PoolManager(address(this))));\n        launch = new IMD6900RobinhoodLaunch(OWNER, pm, address(new Imdstr()), TL);\n        launch.createHook(_hookSalt());\n        bytes32 salt = _coinSalt();\n        address expected = launch.tokenAddress(salt);\n        uint160 price = _sqrtPrice(19.18 ether);\n        vm.deal(OWNER, 1 ether);\n        vm.prank(OWNER);\n        launch.launch{value: 1 ether}(salt, expected, price, 0, address(0));\n        pot = new RefusingPayee();\n        // the timelock's split: 90% to a pot that is (for now) refusing ETH, 10% $IMD's burn\n        address[] memory to = new address[](2);\n        uint16[] memory bps = new uint16[](2);\n        (to[0], bps[0], to[1], bps[1]) = (address(pot), 9_000, launch.imdBurn(), 1_000);\n        vm.prank(TL);\n        launch.setPayees(to, bps);\n    }\n\n    function test_RefusedShareIsNotResplitToOtherPayees() public {\n        vm.deal(address(this), 1 ether);\n        launch.addFees{value: 1 ether}();\n        // anyone calls split repeatedly while the pot refuses; nothing else changes between the calls\n        for (uint256 i; i < 10; ++i) {\n            try launch.split() {} catch {}\n        }\n        emit log_named_decimal_uint(\"burn bucket after ten splits\", launch.imdBucket(), 18);\n        // 10% of 1 ETH is the burn's share; the pot's refused 90% is not the burn's to take\n        assertLe(launch.imdBucket(), 0.1 ether, \"the burn bucket took the pot's refused share\");\n        assertGe(address(launch).balance - launch.imdBucket(), 0.9 ether, \"the pot's share no longer waits for it\");\n    }\n\n    /*                               HELPERS                                */\n\n    function _hookSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.hookInitCodeHash();\n        uint160 flags = launch.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) >> 144 == launch.VANITY()) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched; timelock setPayees([P, imdBurn],[9000,1000]) where P's receive reverts; 1 ETH arrives via addFees. Call split() ten times from any address. Expected: imdBucket = 0.1 ETH and 0.9 ETH waits for P. Actual: imdBucket = 0.651321559900000000 ETH (1 - 0.9^10), 0.3487 ETH left for P. Confirmed by running test/scratch/Proof_1b998baf1c5a.t.sol on this tree: FAIL 'the burn bucket took the pot's refused share: 651321559900000000 > 100000000000000000'. The second specialist proof (POT_BRIDGE etched to revert, 300 splits) fails the same way: imdBucket 568763999999990403 wei of a 0.0569 ETH entitlement.","severity":"medium","snippet":"        amount = address(this).balance - imdBucket;","title":"split() re-splits a refused payee's share on every later call, so a refusing pot bridge shifts its 90% into the $IMD burn bucket"},{"citation":"resolved","description":"_move removes the old position and receives its principal as integer amounts (v4 rounds both down), then _liquidityFor computes the new liquidity as min(L_from_eth, L_from_coins) - 1. When the price p is below the top tick b the ETH leg is L*(b-p)*2^96/(b*p); if its true value is in [1,2) wei the integer eth is 1 and L_from_eth = L/eth_true, so the move keeps only 1/eth_true of the position. The coins the smaller position does not need come back as net1 and _payOutHeld treats them as fees: burned, or sent to coinFeeTo. With eth == 0 the move reverts ZeroLiquidity although the position holds every coin. The state (price at the top of the range with almost no ETH in the pool) is reached whenever the circulating coins are sold back, and the launch's own sellHeld walks the pool toward it. The contract's guarantee ('moves the whole position', 'nothing is paid out but the old pool's earned fees') is broken by 33% in the reproduction. Fix: do not re-derive L from rounded amounts; start from the stored liquidity and lower it only until v4's rounded-up requirements fit the amounts that came out (or top up the at-most-one-wei ETH shortfall from the contract's balance).","line":298,"path":"src/IMD6900LockedPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {SqrtPriceMath} from \"@uniswap/v4-core/src/libraries/SqrtPriceMath.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function totalSupply() external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\n/// A trader that sells coins up to an exact sqrt price limit\ncontract LimitTrader {\n    IPoolManager immutable pm;\n    PoolKey key;\n    uint160 limit;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function sell(PoolKey calldata k, uint256 coins, uint160 limit_) external returns (BalanceDelta d) {\n        (key, limit) = (k, limit_);\n        d = abi.decode(pm.unlock(abi.encode(coins)), (BalanceDelta));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        uint256 coins = abi.decode(data, (uint256));\n        BalanceDelta d = pm.swap(key, SwapParams(false, -int256(coins), limit), \"\");\n        pm.sync(key.currency1);\n        IERC20(Currency.unwrap(key.currency1)).transfer(address(pm), uint128(-d.amount1()));\n        pm.settle();\n        if (d.amount0() > 0) pm.take(key.currency0, address(this), uint128(d.amount0()));\n        return abi.encode(d);\n    }\n    receive() external payable {}\n}\n\ncontract LowerFeeNearTopTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant BUY = 2.81 ether;\n\n    IPoolManager PM;\n    IMD6900RobinhoodLaunch L;\n    IMD6900LockedPool pool;\n    LimitTrader trader;\n    address token;\n\n    function setUp() public {\n        PM = IPoolManager(address(new PoolManager(address(this))));\n        L = new IMD6900RobinhoodLaunch(OWNER, PM, address(0xD15), TL);\n        L.createHook(_hookSalt());\n        pool = L.pool();\n        trader = new LimitTrader(PM);\n        // no claims: the whole opening buy is the excess, sent to the trader so it holds every circulating coin\n        bytes32 salt = _coinSalt();\n        address expected_ = L.tokenAddress(salt);\n        uint160 open = _sqrtPrice(19.18 ether);\n        vm.deal(OWNER, BUY);\n        vm.prank(OWNER);\n        (token,) = L.launch{value: BUY}(salt, expected_, open, 0, address(trader));\n    }\n\n    /// Sells every circulating coin into the pool up to `limit`: the fee is paid in coins and lands in the position, so\n    /// the coin fees are pointed back at the seller (as the timelock may) and the sale runs in rounds until the price\n    /// reaches the limit\n    function _sellToLimit(uint160 limit) internal {\n        vm.prank(TL);\n        pool.setCoinFeeTo(address(trader));\n        for (uint256 i; i < 80; ++i) {\n            trader.sell(pool.poolKey(), IERC20(token).balanceOf(address(trader)), limit);\n            pool.collect();\n            (uint160 p,,) = pool.state();\n            if (p == limit) return;\n        }\n    }\n\n    /// The pool left with 1.x wei of ETH principal just under the top tick: the move keeps only ~2/3 of the position\n    function test_LowerFeeBurnsAThirdOfThePositionWhenOneWeiOfEthIsLeft() public {\n        uint160 b = TickMath.getSqrtPriceAtTick(pool.upperTick());\n        uint128 l0 = pool.liquidity();\n        // sqrt-price distance below b that is worth one wei of ETH for this liquidity: d = b^2 / (L * 2^96)\n        uint256 oneWei = FullMath.mulDiv(b, b, uint256(l0) << 96);\n        uint160 limit = uint160(uint256(b) - (oneWei * 3) / 2); // ~1.5 wei of ETH stays in the position\n        _sellToLimit(limit);\n        (uint160 p,,) = pool.state();\n        assertEq(p, limit, \"the sale stopped at the limit\");\n        uint256 ethInPosition = SqrtPriceMath.getAmount0Delta(p, b, l0, false);\n        assertEq(ethInPosition, 1, \"the position's ETH principal rounds to one wei\");\n        pool.collect(); // the old pool's fees are out: what follows is principal only\n        uint256 held0 = IERC20(token).balanceOf(address(trader));\n\n        vm.prank(TL);\n        uint128 l1 = pool.lowerFee(33_300);\n\n        emit log_named_uint(\"liquidity before\", l0);\n        emit log_named_uint(\"liquidity after \", l1);\n        emit log_named_decimal_uint(\"IMD6900 paid out of the position by the move (to coinFeeTo)\", IERC20(token).balanceOf(address(trader)) - held0, 18);\n        // what the project's own test asserts for a move: all of it, to the wei of rounding\n        assertApproxEqRel(l1, l0, 1e9, \"all of the liquidity moved (to the wei of rounding)\");\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        // coins per ETH = 1e9 * 1e18 / mc ; sqrt(price) * 2^96\n        uint256 price = (1_000_000_000 ether * 1e18) / mc; // 1e18-scaled coins per ETH... scale: price*1e18\n        // sqrt(price * 1e18) * 2^96 / 1e18 = sqrt(price) * 2^96\n        return uint160((_sqrt(price * 1e18) << 96) / 1e18);\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 z) {\n        if (x == 0) return 0;\n        z = x;\n        uint256 y = (x + 1) / 2;\n        while (y < z) { z = y; y = (x / y + y) / 2; }\n    }\n\n    function _hookSalt() internal view returns (bytes32) {\n        bytes32 initHash = L.hookInitCodeHash();\n        uint160 flags = L.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt() internal view returns (bytes32) {\n        bytes32 initHash = L.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) >> 144 == 0x6900) return bytes32(i);\n        }\n    }\n}","reproduction":"Deploy launch + hook, setClaims(0,0,0), launch{value: 2.81 ether} at the 19.18 ETH market-cap price so one trader holds every circulating coin; timelock setCoinFeeTo(trader); the trader sells with zeroForOne=false and sqrtPriceLimitX96 = 570853393952424007911631977567727 (b minus 1.5 wei of ETH), repeating sell+collect until the price sits on the limit; pool.collect(). State: SqrtPriceMath.getAmount0Delta(p, b, L, false) == 1 wei. Timelock lowerFee(33_300). Expected: new liquidity 138788983920567460422827 (to the wei of rounding), only fees paid out. Actual: 92525989280381209596717 (66.67%), ~333,333,333 IMD6900 of the position paid to coinFeeTo. Confirmed by running test/scratch/Proof_52be5773efc6.t.sol on this tree: FAIL 'all of the liquidity moved (to the wei of rounding): 92525989280381209596717 !~= 138788983920567460422827 (real delta: 33.33%)'.","severity":"medium","snippet":"            uint256 fromEth = FullMath.mulDiv(eth, FullMath.mulDiv(p, b, 1 << 96), b - p);","title":"lowerFee re-derives the moved liquidity from the position's rounded-down ETH: with the price just under the top tick a third or more of the locked position leaves the pool, or the move reverts"},{"citation":"resolved","description":"The refund pair assumes nothing else earns the position fees between one caller's feeCheckpoint and its feeRefund. The hook breaks that by design: IMD6900Hook._beforeSwap/_afterSwap call perpEngine.sweepLiquidations for every swap that is not the engine's own, including the launch's sellHeld swaps (src/IMD6900RobinhoodLaunch.sol:522-524), and a liquidation is a swap on the same pool nested inside the launch's unlock. (a) A refunding engine (perpRefunded, checkpoint/swap/refund around its swap) calls feeCheckpoint in the after-swap sweep: _poke(address(this)) moves every fee earned so far, including the sale's own 4.44%, to the pool contract; the launch's feeRefund right after finds zero, back = 0, the loop ends after one round and the sale paid the full fee (burned at the next collect). (b) A non-refunding engine's liquidation fees accrue inside the launch's window and the launch's feeRefund takes them: back exceeds the sale's own fee, sold = paid - back understates the sale, the engine's coin fees join excessHeld instead of being burned and its ETH fees go to sellHeld's `to` instead of the split; if the liquidation is larger than the sale's `left`, paid - back underflows and sellHeld reverts (panic 0x11), blocking the sale while positions are under water. Merged from audit_flow (medium), audit_math (low) and audit_economics (low): one root cause. Fix: make checkpoints nest-aware (per-caller fee-growth accounting in transient storage so a nested checkpoint credits the outer caller), or have the hook skip the sweep for the launch's own swaps as it does for the engine's, and guard paid - back.","line":206,"path":"src/IMD6900LockedPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\ncontract Imdstr {\n    mapping(address => uint256) public balanceOf;\n}\n\n/// A perps engine that takes its fee back the way the refunding engine does (checkpoint, swap, refund), and whose\n/// post-trade sweep liquidates one position: a sale of coins into the pool, inside the hook's afterSwap\ncontract SweepingEngine {\n    IPoolManager immutable pm;\n    IMD6900LockedPool immutable lp;\n    uint256 public liquidation; // coins to sell at the next post-trade sweep\n    constructor(IPoolManager pm_, IMD6900LockedPool lp_) { (pm, lp) = (pm_, lp_); }\n    function openCount() external pure returns (uint256) { return 0; }\n    function arm(uint256 coins) external { liquidation = coins; }\n\n    function sweepLiquidations(address, int256 spec, bool, uint160) external returns (uint8) {\n        if (spec != 0 || liquidation == 0) return 0; // nothing to do before the trade; one close after it\n        uint256 coins = liquidation;\n        liquidation = 0;\n        _sell(coins);\n        return 0;\n    }\n\n    /// the engine's own buy, in its own unlock (no sweep: it is the engine)\n    function buy(uint256 eth) external {\n        pm.unlock(abi.encode(eth));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        uint256 eth = abi.decode(data, (uint256));\n        PoolKey memory k = lp.poolKey();\n        lp.feeCheckpoint();\n        BalanceDelta d = pm.swap(k, SwapParams(true, -int256(eth), TickMath.MIN_SQRT_PRICE + 1), \"\");\n        lp.feeRefund(address(this));\n        pm.settle{value: uint128(-d.amount0())}();\n        pm.take(k.currency1, address(this), uint128(d.amount1()));\n        return \"\";\n    }\n\n    function _sell(uint256 coins) internal {\n        PoolKey memory k = lp.poolKey();\n        lp.feeCheckpoint();\n        BalanceDelta d = pm.swap(k, SwapParams(false, -int256(coins), TickMath.MAX_SQRT_PRICE - 1), \"\");\n        lp.feeRefund(address(this));\n        pm.sync(k.currency1);\n        IERC20(Currency.unwrap(k.currency1)).transfer(address(pm), uint128(-d.amount1()));\n        pm.settle();\n        pm.take(k.currency0, address(this), uint128(d.amount0()));\n    }\n\n    receive() external payable {}\n}\n\n/// The timelock's sale is documented fee-free; a liquidation the hook runs inside the sale's refund window takes\n/// that guarantee away: the engine's nested checkpoint pokes the sale's fee to the pool contract, and the sale's\n/// own refund finds nothing.\ncontract NestedRefundTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    address constant R = address(0x2E7);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n\n    IPoolManager pm;\n    IMD6900RobinhoodLaunch launch;\n    IMD6900LockedPool pool;\n    IMD6900Hook hook;\n    address token;\n    SweepingEngine engine;\n\n    function setUp() public {\n        pm = IPoolManager(address(new PoolManager(address(this))));\n        launch = new IMD6900RobinhoodLaunch(OWNER, pm, address(new Imdstr()), TL);\n        hook = launch.createHook(_hookSalt());\n        pool = launch.pool();\n        bytes32 salt = _coinSalt();\n        address expected = launch.tokenAddress(salt);\n        uint160 price = _sqrtPrice(19.18 ether);\n        vm.deal(OWNER, 2.81 ether);\n        vm.prank(OWNER);\n        (token,) = launch.launch{value: 2.81 ether}(salt, expected, price, 0, address(launch)); // excess held\n        engine = new SweepingEngine(pm, pool);\n        vm.deal(address(engine), 10 ether);\n        vm.prank(TL);\n        hook.setPerpEngine(address(engine));\n        vm.prank(TL);\n        hook.setPerpRefunded(true);\n        engine.buy(1 ether); // the engine holds coins, as positions it may have to close\n    }\n\n    function test_SaleStaysFeeFreeWhenTheSweepLiquidates() public {\n        uint256 held = launch.excessHeld();\n        uint256 sale = held / 2;\n        // one position is under water after the sale's price move: the post-trade sweep closes it\n        engine.arm(IERC20(token).balanceOf(address(engine)) / 10);\n        vm.prank(TL);\n        launch.sellHeld(sale, 0, R);\n        // both the engine and the launch are refunded: nothing of either's fee may be left for the burn\n        (, uint256 coinFee) = pool.collect();\n        emit log_named_decimal_uint(\"coins of the sale's fee that were not refunded\", coinFee, 18);\n        emit log_named_decimal_uint(\"4.44% of the sale\", sale * 444 / 10_000, 18);\n        assertLt(coinFee, sale / 1_000, \"the fee-free sale paid the pool's fee: its refund went to the pool contract\");\n    }\n\n    /*                               HELPERS                                */\n\n    function _hookSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.hookInitCodeHash();\n        uint160 flags = launch.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt() internal view returns (bytes32) {\n        bytes32 initHash = launch.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(launch), i, initHash))))\n            );\n            if (uint160(a) >> 144 == launch.VANITY()) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched with excess held (excessTo = the launch); timelock hook.setPerpEngine(E) and setPerpRefunded(true) with E holding coins and, in sweepLiquidations, selling them with the feeCheckpoint/swap/feeRefund pair when a position is under water. Timelock sellHeld(excessHeld/2, 0, R). Expected: the sale is fee-free and pool.collect() afterwards returns ~0 coins. Actual: pool.collect() returns 2,716,114 coins = exactly 4.44% of the sale, R receives correspondingly less. Confirmed by running test/scratch/Proof_9dba11511465.t.sol on this tree: FAIL 'the fee-free sale paid the pool's fee: 2716114297381638809234320 >= 61173745436523396604376'. Case (b) by trace: E non-refunding sells 1e24 coins in the sweep (fee 4.44e22) while the launch's round sells 1e18 coins (fee 4.44e16): back = 4.44e22 + 4.44e16 > paid = 1e18, so line 530 `sold += paid - back;` reverts with panic 0x11.","severity":"medium","snippet":"        _poke(address(this));","title":"feeCheckpoint/feeRefund windows are not isolated: a perps-engine liquidation the hook's sweep runs inside the timelock's sale either takes the sale's fee (sellHeld not fee-free) or has its own fee ref"},{"citation":"resolved","description":"The brief requires lowerFee to be refused while the perps engine has positions open: after a move the hook's _beforeSwap rejects the old pool with NotOurPool and the old pool holds no liquidity, so open positions can no longer be closed. The guard only consults whatever IMD6900Hook.perpEngine currently holds, and that slot is written by setPerpEngine (src/IMD6900Hook.sol:123, onlyOwner) whose owner is the same timelock that calls lowerFee. setPerpEngine(address(0)) ('Zero turns perps off') or setPerpEngine(freshEngine) with openCount()==0 skips the check entirely. The natspec itself anticipates engine replacement, so 'wire the new engine, then move' is a plausible operational sequence, not only a malicious one. The actor is the trusted timelock, so this is a broken guarantee rather than a permission bypass. Fix: have the locked pool remember the engine last wired for the pool it would empty (recorded on setPerpEngine) and query that engine's openCount regardless of the current pointer, or refuse setPerpEngine while the current engine's openCount() != 0.","line":160,"path":"src/IMD6900LockedPool.sol","reproduction":"Reproduced in test/scratch/JudgeLeads.t.sol test_PerpsOpenBypassByUnwiring (passes on this tree, demonstrating the bypass): launched pool at 4.44%; engine E with openCount()==3; timelock hook.setPerpEngine(E). 1) timelock pool.lowerFee(33_300) reverts PerpsOpen. 2) timelock hook.setPerpEngine(address(0)) succeeds. 3) timelock pool.lowerFee(33_300) succeeds: pool.fee()==33_300 while E still reports 3 open positions, whose closes on the 4.44% key now revert NotOurPool in the hook. Expected: step 2 or 3 refused while E has positions open.","severity":"medium","snippet":"        address engine = IPerpsWiring(hook).perpEngine();","title":"lowerFee's PerpsOpen guard reads the hook's perpEngine pointer, which the same timelock can rewrite first: unwiring or replacing the engine lets the move through with positions open and strands them"},{"citation":"resolved","description":"minImd is the only slippage bound of the $IMD buy and it is chosen by whoever calls burnImd, which is anyone. The swap in unlockCallback runs to TickMath.MIN_SQRT_PRICE + 1 with no price check against anything the contract knows (no TWAP, no max impact, no keeper role). An attacker buys $IMD on the same pool, calls burnImd(0) at the inflated price, and sells back in the same block: the burn bucket's ETH pays the attacker's round trip. The per-block cap only sizes each bite at IMD_BUY_MAX; the bucket is refilled by every split. The loser is the $IMD burn (the 10% fee share's purpose); the gain goes to an unprivileged attacker.","line":490,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"State: launched; $IMD pool ETH/IMD 1% fee, tick spacing 100, no hooks, ~261 $IMD per ETH, full-range liquidity 2e19 (thin, as a new pool on Robinhood is); imdBucket > 0.1 ETH after harvest(). Honest burnImd(0) buys 23.93 $IMD. Attack bundled in one block: attacker buys with 0.3 ETH, calls burnImd(0), sells all $IMD back. Expected: the burn buys about what the honest call buys and nobody profits from it. Actual (audit_economics' test/scratch/BurnSandwich.t.sol, trace confirmed against unlockCallback what==1: exact-input 0.1 ETH, limit MIN_SQRT_PRICE+1, the only check `imd < minImd` with minImd = 0): the burn receives 15.79 $IMD (34% less) and the attacker ends 0.0297 ETH up net of both 1% fees.","severity":"medium","snippet":"        if (imd < minImd) revert Short(imd);","title":"burnImd lets any caller set minImd = 0 with no other price bound, so the 0.1 ETH $IMD buy can be sandwiched every block and the burn receives less $IMD"},{"citation":"resolved","description":"The brief fixes the first constructor argument as the static team wallet 0x35da9c0303507ddf708e87f2568eddf12c47a059 and the recipe says an owner address the brief itself states is written as that static address, not $owner ($owner is the paying wallet or the request's owner field, which the manifest cannot see). The manifest's notes say $owner 'resolves to the team wallet', but notes are explanatory text, not deployment authority. If the payer or the request's owner field is any other wallet, the launch's owner-only powers (setClaims, launch, withdrawEth, releaseUnclaimed, releaseImdstr) go to that wallet; the three other arguments are correctly static. Fix: write \"0x35da9c0303507ddf708e87f2568eddf12c47a059\" in place of \"$owner\" (the test fixture's TEAM constant is the same address).","line":7,"path":"launch.json","reproduction":"Read launch.json: contracts[0].constructorArgs[0] is \"$owner\" while the brief's argument 1 is 0x35da9c0303507ddf708e87f2568eddf12c47a059. Expected: the static address, as the recipe requires for an owner the brief states. Actual: a placeholder resolved by the service from the payer/request, so IMD6900RobinhoodLaunch.owner() equals the team wallet only if that resolution happens to match.","severity":"medium","snippet":"        \"$owner\",","title":"launch.json writes the owner as $owner although the brief states the owner address: the launch's owner role depends on what $owner resolves to"},{"citation":"resolved","description":"IMD6900Hook overrides renounceOwnership to revert NoRenounce, but IMD6900RobinhoodLaunch inherits Solady's Ownable.renounceOwnership unchanged (lib/solady/src/auth/Ownable.sol:186 sets the owner to address(0)). The launch keeps owner-only duties for life: releaseImdstr is the only function that can move the IMDSTR every claim deposits, and releaseUnclaimed is the only non-timelock release of the reserve. Once renounced no role can ever call them; the timelock has no path to the IMDSTR. The unclaimed reserve stays reachable via the timelock's endClaims. Fix: override renounceOwnership to revert, as the hook does.","line":44,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Reproduced in test/scratch/JudgeLeads.t.sol test_RenounceStrandsImdstr: after launch, a holder claims 1,000,000 coins so the launch holds 1e24 IMDSTR; the owner calls renounceOwnership(); owner()==address(0); releaseImdstr(0, to) reverts Unauthorized from the former owner and from the timelock. Expected: renounce refused (as in the hook) or the IMDSTR reachable by the timelock.","severity":"low","snippet":"contract IMD6900RobinhoodLaunch is Ownable, ReentrancyGuard {","title":"The launch's owner can renounceOwnership (the hook refuses it): afterwards releaseImdstr and releaseUnclaimed are dead and the IMDSTR the claims collected is locked forever"},{"citation":"resolved","description":"launch() treats excessTo == address(this) as 'keep for the timelock' (excessHeld = excess). releaseExcess (lines 381-383) and releaseUnclaimed (lines 330-331) only have the zero-burn branch and the transfer branch: with to == address(this) excessHeld is decremented (or the reserve zeroed) and the coins are transferred to the contract itself, remaining in its balance but counted neither as claim reserve nor as excessHeld. sellHeld and releaseExcess bound their amount by excessHeld and nothing else moves the coin, so the coins are locked without being burned (totalSupply unchanged). Timelock/owner input error, so low. Fix: treat to == address(this) as launch does (keep in excessHeld) or revert.","line":383,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Reproduced in test/scratch/JudgeLeads.t.sol test_ReleaseExcessToSelfStrands: launch with excessTo = the launch so excessHeld = H > 0; timelock releaseExcess(0, address(launch)). Actual: excessHeld == 0, the launch's coin balance unchanged, totalSupply unchanged; sellHeld(0,0,TL) then reverts ZeroAmount. Expected: the coins stay accounted (excessHeld == H) or the call is refused.","severity":"low","snippet":"        else SafeTransferLib.safeTransfer(token, to, amount);","title":"releaseExcess / releaseUnclaimed with to == address(this) self-transfer the coins and drop them out of excessHeld, so they can never be sold, released or burned"},{"citation":"resolved","description":"l = mulDiv(amount, 2^96, start - low) is a uint256; for the whole supply (1e27) it exceeds type(uint128).max whenever start - low < 2.33e17, i.e. for every opening tick from -887160 (the lowest BadPrice accepts) up to about -531000. The cast keeps the low 128 bits, so the value handed to modifyLiquidity is unrelated to the amount. In the reproduction the truncated value is above int128 max and v4 reverts SafeCastOverflow deep inside the unlock rather than the contract's own BadPrice; a truncated value below v4's per-tick cap would instead open the pool with a tiny position and hand the rest of the supply back to the launch as 'excess'. Owner-only input, so a misleading revert and a missing guard rather than a loss. Fix: revert BadPrice if l - 1 > type(uint128).max (or SafeCast).","line":144,"path":"src/IMD6900LockedPool.sol","reproduction":"Reproduced in test/scratch/JudgeLeads.t.sol test_OpenDowncastRevertsFromV4NotBadPrice: setClaims(0,0,0); launch{value: 1 ether}(salt, expected, TickMath.getSqrtPriceAtTick(-887160), 0, address(launch)). l = 6123830742008175932125694122593849901991701757965 > 2^128-1; uint128(l-1) = 189254828772555816885055183266217967628. Expected: revert IMD6900LockedPool.BadPrice. Actual: revert 0x93dafdf1 (v4 SafeCastOverflow) from PoolManager.modifyLiquidity.","severity":"low","snippet":"        liq = uint128(l - 1);","title":"open downcasts the opening liquidity to uint128 without a bounds check: a price near the bottom of the range is refused by v4's SafeCastOverflow instead of BadPrice, and a truncated value could open a"},{"citation":"resolved","description":"Documented design recorded as privileged powers, not defects. Owner (team wallet, single key): launch() sends bought - claimTotal coins to any excessTo it names (line 316) and releaseUnclaimed(to) sends the whole unclaimed reserve anywhere after claimDeadline (line 323), beside the timelock's custody the brief describes. Timelock: endClaims may run the block after launch (line 389), moving every unclaimed coin into excessHeld and so to ETH via sellHeld, while holders can only claim once the timelock has made the launch an IMDSTR distributor; setImdPool (line 433) accepts any hooks address, and anyone's burnImd then swaps 0.1 ETH per block through that pool; setPerpEngine (src/IMD6900Hook.sol:123) makes the engine a refunded caller in the locked pool and the target of _sweep's call with nearly all remaining gas on every trader's swap (fail-closed unless sweepFailOpen). All are the named roles' by design; the requester should confirm they are accepted.","line":433,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Owner launch(salt, token, price, 0, OWNER): excess coins land in OWNER's balance (the repository's test_SendsTheExcessWhereTold shows the same with the timelock). After claimDeadline, owner releaseUnclaimed(OWNER) sends claimTotal - claimedTotal coins there. Launch at T; at T+1 timelock endClaims() succeeds and claimReserve()==0. Timelock setImdPool(f, s, H) for any H; anyone's burnImd(0) swaps 0.1 ETH on that key. None of these is refused by any state on this tree.","severity":"info","snippet":"    function setImdPool(uint24 fee, int24 tickSpacing, address hooks) external {","title":"Trust assumptions (owner and timelock): launch(excessTo) and releaseUnclaimed(to) route coins anywhere; endClaims has no minimum window; setImdPool accepts any pool/hook for the public burnImd; setPer"}],"hash":"24ec4bca857def40eec5d240b5d889556e6d52fd42ec8fc21e5742db334c720d","nodeId":"8b1d046e-d304-4c1f-bbe3-5ec04bf64931","outcome":"completed","summary":"The findings file is complete and validated. Every snippet matches its line, all 59 entry points have a coverage row, and all finding references resolve.\n\n## Review outcome\n\n`.imd-findings.json` holds 10 findings and a 61-row coverage record. Nothing in the tree was changed. Scratch tests live only under `test/scratch/`.\n\n**Specialist findings kept (all reproduced):**\n\n1. **Medium, split() re-splits a refused payee's share.** Merged from audit_flow and audit_economics (same root cause). Both proofs fail on this tree; the shorter one is attached: ten splits move 0.65 ETH of the pot's 0.9 ETH into the $IMD bucket.\n2. **Medium, lowerFee loses liquidity at the top-of-range corner.** audit_math's proof fails as stated: 33% of the position is paid out as \"fees\" when the pool holds one wei of ETH. Proof attached.\n3. **Medium, checkpoint/refund windows are not isolated from the hook's nested engine sweep.** Merged from audit_flow (medium), audit_math (low) and audit_economics (low). audit_flow's proof fails as stated: the \"fee-free\" sale pays the full 4.44%. Proof attached. The non-refunding variant also makes `paid - back` underflow and block sellHeld.\n4. **Medium, PerpsOpen guard bypassed by the same timelock unwiring the engine.** Confirmed with my own scratch test: lowerFee reverts PerpsOpen, then succeeds after setPerpEngine(0) while the engine still reports 3 open positions.\n5. **Medium, burnImd sandwich with caller-chosen minImd = 0.** Confirmed by trace of the swap path; kept at the specialist's severity.\n6. **Low ×3:** renounceOwnership strands the IMDSTR, releaseExcess to the launch itself strands coins, open's unchecked uint128 downcast reverts with v4's SafeCastOverflow (0x93dafdf1) instead of BadPrice. All three confirmed in my scratch test.\n7. **Info:** owner and timelock trust assumptions, merged from audit_permissions' two info items.\n\n**My own addition:** the manifest writes the owner as `$owner` although the brief states the static team wallet, which the recipe requires be written as that address. Rated medium since the launch's owner role depends on what the placeholder resolves to.\n\n**Deployment model checked and holds:** runtime 22,677 B and initcode 34,451 B plus 128 B of arguments are under both limits; the constructor creates only the locked pool and calls nothing pre-existing; the hook salt is mined and created after deployment as the brief allows.\n\nNothing from the static-analysis output survived as an independent finding beyond what the specialists already covered. The abi.encodePacked, locks-ether and arbitrary-send lines are false positives against this code.","treeHash":null,"usage":{"cachedInputTokens":1044218,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":34057,"runtime":"claude","turns":16,"wallClockMs":576930}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ee9fbaf2480d1034","findings":[{"citation":"resolved","description":"The NatSpec promises that a payee which refuses its share leaves it here for the next split. The code does not reserve it: a failed call{value} leaves the ETH in the plain balance, and the next split() computes amount = balance - imdBucket again and gives 10% of that same ETH to the $IMD bucket (the only share that is booked, not sent). Each call therefore moves 10% of whatever the pot bridge refused into the $IMD burn bucket, and split()/harvest() are public with no rate limit, so anyone can run it until the pot's whole share is gone: after n splits the pot keeps 0.9^n of its share (300 calls leave 1e-14 of it). Flow-gap seam: execution (loop over payees) x periphery (POT_BRIDGE's receive reverting, e.g. the bridge paused or upgraded) x first principle (90% of fees are the NFT pot's). The timelock's only remedy is recoverEth, behind its delay, while burnImd (anyone, 0.1 ETH per block) is already spending the bucket on $IMD, so the pot's ETH is converted to $IMD burns that cannot be undone.","line":463,"path":"src/IMD6900RobinhoodLaunch.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\ncontract MockImdstr {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function approve(address s, uint256 a) external returns (bool) { allowance[msg.sender][s] = a; return true; }\n    function transfer(address to, uint256 a) external returns (bool) { balanceOf[msg.sender] -= a; balanceOf[to] += a; return true; }\n    function transferFrom(address f, address to, uint256 a) external returns (bool) {\n        allowance[f][msg.sender] -= a; balanceOf[f] -= a; balanceOf[to] += a; return true;\n    }\n}\n\n/// A payee that refuses ETH (a paused bridge, a contract without receive)\ncontract Refusing {\n    receive() external payable { revert(\"paused\"); }\n}\n\ncontract Trader {\n    IPoolManager immutable pm;\n    PoolKey key;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function swap(PoolKey calldata k, bool buy, int256 amountSpecified) external returns (BalanceDelta d) {\n        key = k;\n        d = abi.decode(pm.unlock(abi.encode(buy, amountSpecified)), (BalanceDelta));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (bool buy, int256 amt) = abi.decode(data, (bool, int256));\n        BalanceDelta d = pm.swap(key, SwapParams(buy, amt, buy ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1), \"\");\n        _settle(key.currency0, d.amount0());\n        _settle(key.currency1, d.amount1());\n        return abi.encode(d);\n    }\n    function _settle(Currency c, int128 v) internal {\n        if (v < 0) {\n            if (c.isAddressZero()) pm.settle{value: uint128(-v)}();\n            else { pm.sync(c); IERC20(Currency.unwrap(c)).transfer(address(pm), uint128(-v)); pm.settle(); }\n        } else if (v > 0) pm.take(c, address(this), uint128(v));\n    }\n    receive() external payable {}\n}\n\n/// Finding: split() re-splits a refused payee's share on every call, so repeated public split() calls move the\n/// whole fee pot to the other payees (here: the $IMD bucket) instead of keeping it for the refusing payee.\ncontract SplitLeakTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n\n    IPoolManager PM;\n    IMD6900RobinhoodLaunch L;\n    IMD6900LockedPool pool;\n    Trader trader;\n\n    function setUp() public {\n        PM = IPoolManager(address(new PoolManager(address(this))));\n        L = new IMD6900RobinhoodLaunch(OWNER, PM, address(new MockImdstr()), TL);\n        L.createHook(_mineHook());\n        pool = L.pool();\n        trader = new Trader(PM);\n        vm.deal(address(trader), 100 ether);\n        // launch: no claims, 2.81 ETH opening buy, excess kept for the timelock\n        bytes32 salt = _mineCoin();\n        address expected = L.tokenAddress(salt);\n        vm.deal(OWNER, 2.81 ether);\n        vm.prank(OWNER);\n        L.launch{value: 2.81 ether}(salt, expected, _sqrtPrice(19.18 ether), 0, address(L));\n    }\n\n    function test_RefusedShareLeaksToTheOtherPayee() public {\n        // the pot bridge (90%) refuses ETH for a while: its address gets a reverting receive\n        vm.etch(L.POT_BRIDGE(), address(new Refusing()).code);\n        trader.swap(pool.poolKey(), true, -10 ether); // ~0.57 ETH of fees\n        L.harvest(); // first split: 10% to the $IMD bucket, the 90% refused and left here\n        uint256 fees = address(L).balance;\n        uint256 bucket1 = L.imdBucket();\n        assertApproxEqRel(bucket1, fees / 10, 1e14, \"10% after one split\");\n\n        // anyone calls split() again and again while the pot bridge refuses\n        for (uint256 i; i < 300; ++i) L.split();\n\n        emit log_named_decimal_uint(\"fees\", fees, 18);\n        emit log_named_decimal_uint(\"$IMD bucket after 300 splits\", L.imdBucket(), 18);\n        emit log_named_decimal_uint(\"left for the pot\", address(L).balance - L.imdBucket(), 18);\n        // the pot's 90% must still be waiting here for it, not re-split away into the $IMD bucket\n        assertLe(L.imdBucket(), fees * 11 / 100, \"the refused 90% was moved to the $IMD bucket by repeated splits\");\n    }\n\n    function _mineHook() internal view returns (bytes32) {\n        bytes32 initHash = L.hookInitCodeHash();\n        uint160 flags = L.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _mineCoin() internal view returns (bytes32) {\n        bytes32 initHash = L.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) >> 144 == 0x6900) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched; POT_BRIDGE's receive reverts (vm.etch a reverting contract at 0xc39e650a24985C2bBA9FD83C81041B8f3E3f9EDd); 10 ETH of buys so ~0.569 ETH of fees are collected. Calls: harvest() once -> imdBucket = 0.0569 ETH (10%), 0.512 ETH left for the pot (expected). Then split() 300 times from any address. Expected: imdBucket stays ~0.0569 ETH and 0.512 ETH waits for the pot bridge. Actual: imdBucket = 0.568763999999990403 ETH, 9597 wei left for the pot; burnImd(0) can now spend all of it on $IMD. Proof test test/scratch/SplitLeak.t.sol fails with 'the refused 90% was moved to the $IMD bucket by repeated splits: 568763999999990403 > 62564040000000000'.","severity":"medium","snippet":"        amount = address(this).balance - imdBucket;\n        if (amount == 0) return 0;\n        (address[] memory to, uint16[] memory bps) = payees();\n        for (uint256 i; i < to.length; ++i) {\n            uint256 part = (amount * bps[i]) / 10_000;\n            if (part == 0) continue;\n            if (to[i] == imdBurn) {\n                imdBucket += part;\n                continue;\n            }\n            (bool ok,) = to[i].call{value: part}(\"\");\n            if (!ok) emit PayFailed(to[i], part);","title":"split() re-splits a refused payee's share on every call, so repeated public split() calls move the pot bridge's 90% into the $IMD bucket"},{"citation":"resolved","description":"minImd is the only slippage bound of the $IMD buy and it is chosen by whoever calls burnImd, which is anyone. The swap itself runs to TickMath.MIN_SQRT_PRICE + 1 with no price check against anything the contract knows (no TWAP, no max price impact, no keeper role). An attacker buys $IMD on the same pool, calls burnImd(0) at the inflated price, and sells back into it: the burn bucket's ETH pays the attacker's round trip. The per-block cap only sizes each bite at 0.1 ETH; every block's buy can be taken the same way, and a block builder bundles all three calls. The loser is the $IMD burn (and so the 10% fee share's purpose); the gain goes to an unprivileged attacker. Economic security: value extracted from a price-dependent operation whose protection is caller-supplied.","line":483,"path":"src/IMD6900RobinhoodLaunch.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams, ModifyLiquidityParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\ncontract MockToken {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function mint(address to, uint256 a) external { balanceOf[to] += a; }\n    function approve(address s, uint256 a) external returns (bool) { allowance[msg.sender][s] = a; return true; }\n    function transfer(address to, uint256 a) external returns (bool) { balanceOf[msg.sender] -= a; balanceOf[to] += a; return true; }\n    function transferFrom(address f, address to, uint256 a) external returns (bool) {\n        allowance[f][msg.sender] -= a; balanceOf[f] -= a; balanceOf[to] += a; return true;\n    }\n}\n\ncontract Trader {\n    IPoolManager immutable pm;\n    PoolKey key;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function swap(PoolKey calldata k, bool buy, int256 amountSpecified) external returns (BalanceDelta d) {\n        key = k;\n        d = abi.decode(pm.unlock(abi.encode(buy, amountSpecified)), (BalanceDelta));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (bool buy, int256 amt) = abi.decode(data, (bool, int256));\n        BalanceDelta d = pm.swap(key, SwapParams(buy, amt, buy ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1), \"\");\n        _settle(key.currency0, d.amount0());\n        _settle(key.currency1, d.amount1());\n        return abi.encode(d);\n    }\n    function _settle(Currency c, int128 v) internal {\n        if (v < 0) {\n            if (c.isAddressZero()) pm.settle{value: uint128(-v)}();\n            else { pm.sync(c); IERC20(Currency.unwrap(c)).transfer(address(pm), uint128(-v)); pm.settle(); }\n        } else if (v > 0) pm.take(c, address(this), uint128(v));\n    }\n    receive() external payable {}\n}\n\n/// Puts full-range liquidity in a plain pool (the stand-in for $IMD's pool on Robinhood)\ncontract LiquidityAdder {\n    IPoolManager immutable pm; PoolKey key; uint256 liq;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function add(PoolKey calldata k, uint256 l) external { (key, liq) = (k, l); pm.unlock(\"\"); }\n    function unlockCallback(bytes calldata) external returns (bytes memory) {\n        (BalanceDelta d,) = pm.modifyLiquidity(key, ModifyLiquidityParams(TickMath.minUsableTick(key.tickSpacing), TickMath.maxUsableTick(key.tickSpacing), int256(liq), 0), \"\");\n        pm.settle{value: uint128(-d.amount0())}();\n        pm.sync(key.currency1);\n        IERC20(Currency.unwrap(key.currency1)).transfer(address(pm), uint128(-d.amount1()));\n        pm.settle();\n        return \"\";\n    }\n    receive() external payable {}\n}\n\n/// Finding: burnImd(minImd) lets any caller choose the floor, so an attacker calls it with 0 between its own buy and\n/// sell on $IMD's pool and takes part of the 0.1 ETH burn buy as profit.\ncontract BurnSandwichTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n\n    IPoolManager PM;\n    IMD6900RobinhoodLaunch L;\n    IMD6900LockedPool pool;\n    Trader trader;\n    Trader attacker;\n    PoolKey ik;\n\n    function setUp() public {\n        PM = IPoolManager(address(new PoolManager(address(this))));\n        L = new IMD6900RobinhoodLaunch(OWNER, PM, address(new MockToken()), TL);\n        L.createHook(_mineHook());\n        pool = L.pool();\n        trader = new Trader(PM);\n        attacker = new Trader(PM);\n        vm.deal(address(trader), 200 ether);\n        vm.deal(address(attacker), 10 ether);\n\n        // $IMD and its pool: ETH / $IMD, 1%, tick spacing 100, no hooks; ~261 $IMD per ETH, a thin pool\n        address imd = L.IMD();\n        vm.etch(imd, address(new MockToken()).code);\n        LiquidityAdder adder = new LiquidityAdder(PM);\n        vm.deal(address(adder), 100 ether);\n        MockToken(imd).mint(address(adder), 1e30);\n        ik = L.imdPoolKey();\n        PM.initialize(ik, uint160(_sqrt(261 << 192)));\n        adder.add(ik, 2e19); // about 1.2 ETH on the pool's ETH side\n\n        bytes32 salt = _mineCoin();\n        address expected = L.tokenAddress(salt);\n        vm.deal(OWNER, 2.81 ether);\n        vm.prank(OWNER);\n        L.launch{value: 2.81 ether}(salt, expected, _sqrtPrice(19.18 ether), 0, address(0));\n        trader.swap(pool.poolKey(), true, -150 ether); // fees: >0.1 ETH set aside for the $IMD burn\n        L.harvest();\n        assertGt(L.imdBucket(), 0.1 ether);\n    }\n\n    function test_AnyoneSandwichesTheBurnBuy() public {\n        address imd = L.IMD();\n        address exec = L.IMD_BURN();\n        // what the burn buys when nobody interferes\n        uint256 snap = vm.snapshotState();\n        uint256 honest = L.burnImd(0);\n        vm.revertToState(snap);\n\n        uint256 before = address(attacker).balance;\n        // front-run: the attacker buys $IMD, pushing its price up\n        attacker.swap(ik, true, -0.3 ether);\n        uint256 got;\n        // the burn buy, at the worse price, with the floor the attacker chose: zero\n        try L.burnImd(0) returns (uint256 g) { got = g; } catch { return; } // a fix that refuses the call passes\n        // back-run: the attacker sells into the burn buy's price\n        uint256 bag = IERC20(imd).balanceOf(address(attacker));\n        attacker.swap(ik, false, -int256(bag));\n        uint256 profit = address(attacker).balance > before ? address(attacker).balance - before : 0;\n        emit log_named_decimal_uint(\"$IMD burned, honest\", honest, 18);\n        emit log_named_decimal_uint(\"$IMD burned, sandwiched\", got, 18);\n        emit log_named_decimal_uint(\"attacker profit, ETH\", profit, 18);\n        assertEq(IERC20(imd).balanceOf(exec), got);\n        assertLe(address(attacker).balance, before, \"the attacker made money off the burn buy\");\n    }\n\n    function _mineHook() internal view returns (bytes32) {\n        bytes32 initHash = L.hookInitCodeHash();\n        uint160 flags = L.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _mineCoin() internal view returns (bytes32) {\n        bytes32 initHash = L.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) >> 144 == 0x6900) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched; $IMD pool ETH/IMD 1% fee, tick spacing 100, no hooks, ~261 $IMD per ETH, full-range liquidity 2e19 (~1.2 ETH on the ETH side; thin, as a new pool on Robinhood is); imdBucket > 0.1 ETH after harvest(). Honest call burnImd(0) buys 23.93 $IMD. Attack in one block: attacker buys with 0.3 ETH, calls burnImd(0), sells all $IMD back. Expected: the burn buys about what the honest call buys and nobody profits from it. Actual: the burn receives 15.79 $IMD (34% less) and the attacker ends with 0.0297 ETH more than it started with, net of both 1% fees. Proof test test/scratch/BurnSandwich.t.sol fails with 'the attacker made money off the burn buy: 10029745030047161118 > 10000000000000000000'.","severity":"medium","snippet":"    function burnImd(uint256 minImd) external nonReentrant returns (uint256 imd) {\n        if (block.number < nextImdBurnBlock) revert BurnRateLimited();\n        uint256 spend = imdBucket < IMD_BUY_MAX ? imdBucket : IMD_BUY_MAX;\n        if (spend == 0) revert NoEth();\n        nextImdBurnBlock = block.number + 1;\n        imdBucket -= spend;\n        imd = abi.decode(poolManager.unlock(abi.encode(uint8(1), spend)), (uint256));\n        if (imd < minImd) revert Short(imd);","title":"burnImd lets any caller set minImd = 0, so the 0.1 ETH $IMD buy is sandwiched for profit and the burn receives less $IMD"},{"citation":"resolved","description":"feeRefund hands back every fee the position earned between the checkpoint and the refund, on the assumption that only the refunded caller's own swap ran in between. For the launch's sale that is not true once a perps engine is wired: the launch's swap is not the engine's, so IMD6900Hook._beforeSwap and _afterSwap call engine.sweepLiquidations, and the engine's liquidation swaps execute inside the window (the PoolManager is already unlocked by the launch, nested swaps are allowed). If the engine is not refunding its own swaps (perpRefunded false, or an engine without the checkpoint/refund pair), their LP fees are taken by the launch's feeRefund: the coin part is counted as 'back' (so sold is understated and it is re-sold or stays in excessHeld, the timelock's), the ETH part lands in the launch balance and is split as fee revenue. Those fees should have been burned (coin) or split (ETH) at the next collect. Invariant broken: the refund equals the refunded swap's own fee to the wei. Bounded by the fees of liquidations triggered during a sellHeld and only when the timelock sells while positions are under water, so low.","line":521,"path":"src/IMD6900RobinhoodLaunch.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\ncontract MockImdstr {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function approve(address s, uint256 a) external returns (bool) { allowance[msg.sender][s] = a; return true; }\n    function transfer(address to, uint256 a) external returns (bool) { balanceOf[msg.sender] -= a; balanceOf[to] += a; return true; }\n    function transferFrom(address f, address to, uint256 a) external returns (bool) {\n        allowance[f][msg.sender] -= a; balanceOf[f] -= a; balanceOf[to] += a; return true;\n    }\n}\n\n\n/// A perps engine whose sweep liquidates by selling coins into the pool, once, without any refund pair\ncontract SweepingEngine {\n    IPoolManager immutable pm; PoolKey key; bool done; address coin;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function set(PoolKey calldata k, address c) external { key = k; coin = c; }\n    function openCount() external pure returns (uint256) { return 0; }\n    function sweepLiquidations(address, int256 spec, bool, uint160) external returns (uint8) {\n        if (spec == 0 || done) return 0;\n        done = true;\n        BalanceDelta d = pm.swap(key, SwapParams(false, -int256(1_000_000 ether), TickMath.MAX_SQRT_PRICE - 1), \"\");\n        pm.sync(key.currency1);\n        IERC20(coin).transfer(address(pm), uint128(-d.amount1()));\n        pm.settle();\n        pm.take(key.currency0, address(this), uint128(d.amount0()));\n        return 0;\n    }\n    receive() external payable {}\n}\n\ncontract Trader {\n    IPoolManager immutable pm;\n    PoolKey key;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function swap(PoolKey calldata k, bool buy, int256 amountSpecified) external returns (BalanceDelta d) {\n        key = k;\n        d = abi.decode(pm.unlock(abi.encode(buy, amountSpecified)), (BalanceDelta));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (bool buy, int256 amt) = abi.decode(data, (bool, int256));\n        BalanceDelta d = pm.swap(key, SwapParams(buy, amt, buy ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1), \"\");\n        _settle(key.currency0, d.amount0());\n        _settle(key.currency1, d.amount1());\n        return abi.encode(d);\n    }\n    function _settle(Currency c, int128 v) internal {\n        if (v < 0) {\n            if (c.isAddressZero()) pm.settle{value: uint128(-v)}();\n            else { pm.sync(c); IERC20(Currency.unwrap(c)).transfer(address(pm), uint128(-v)); pm.settle(); }\n        } else if (v > 0) pm.take(c, address(this), uint128(v));\n    }\n    receive() external payable {}\n}\n\n\n/// Finding: the launch's fee refund (sellHeld) also captures fees of engine swaps nested in the hook's sweep\ncontract NestedSweepTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n    IPoolManager PM; IMD6900RobinhoodLaunch L; IMD6900LockedPool pool; Trader trader; address t;\n\n    function setUp() public {\n        PM = IPoolManager(address(new PoolManager(address(this))));\n        L = new IMD6900RobinhoodLaunch(OWNER, PM, address(new MockImdstr()), TL);\n        L.createHook(_mineHook());\n        pool = L.pool();\n        trader = new Trader(PM);\n        vm.deal(address(trader), 100 ether);\n        bytes32 salt = _mineCoin();\n        address expected = L.tokenAddress(salt);\n        vm.deal(OWNER, 2.81 ether);\n        vm.prank(OWNER);\n        (t,) = L.launch{value: 2.81 ether}(salt, expected, _sqrtPrice(19.18 ether), 0, address(L));\n    }\n\n    function test_EngineFeesInsideTheSaleGoToTheTimelocksCoins() public {\n        SweepingEngine e = new SweepingEngine(PM);\n        e.set(pool.poolKey(), t);\n        trader.swap(pool.poolKey(), true, -1 ether);\n        vm.prank(address(trader));\n        IERC20(t).transfer(address(e), 1_000_000 ether); // the position the sweep will liquidate\n        pool.collect(); // clear the fees so far\n        IMD6900Hook h = L.hook();\n        vm.prank(TL);\n        h.setPerpEngine(address(e));\n        uint256 held = L.excessHeld();\n        uint256 bal = IERC20(t).balanceOf(address(L));\n        vm.prank(TL);\n        L.sellHeld(held / 2, 0, TL);\n        uint256 parted = bal - IERC20(t).balanceOf(address(L));\n        uint256 booked = held - L.excessHeld();\n        (, uint256 burned) = pool.collect();\n        emit log_named_decimal_uint(\"coins the launch parted with\", parted, 18);\n        emit log_named_decimal_uint(\"coins booked as sold\", booked, 18);\n        emit log_named_decimal_uint(\"coin fees burned at the next collect\", burned, 18);\n        emit log_named_decimal_uint(\"engine's own fee, 4.44% of 1,000,000\", 44_400 ether, 18);\n        // the engine's 44,400-coin fee should reach the burn at collect, not the launch's held coins\n        assertGe(burned, 44_000 ether, \"the engine's liquidation fee was refunded to the launch instead of burned\");\n    }\n    function _mineHook() internal view returns (bytes32) {\n        bytes32 initHash = L.hookInitCodeHash();\n        uint160 flags = L.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _mineCoin() internal view returns (bytes32) {\n        bytes32 initHash = L.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) >> 144 == 0x6900) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched with the excess held (excessTo = the launch); a trader bought 1 ETH of coins and sent 1,000,000 of them to engine E; E's sweepLiquidations(…, spec != 0, …) sells those 1,000,000 coins into the pool (fee 4.44% = 44,400 coins) once, without calling feeCheckpoint/feeRefund; pool.collect() run so no fees are pending; timelock hook.setPerpEngine(E). Call: timelock sellHeld(excessHeld/2, 0, TL). Expected: the 44,400-coin fee of E's swap stays the position's and is burned at the next pool.collect(); the launch's refund is only its own swap's fee. Actual (test/scratch/NestedSweep.t.sol): the launch parts with 61,168,303.47 coins and books exactly that as sold, the engine's 44,400 coins come back to the launch inside feeRefund's 'back' and join its held coins, and the next pool.collect() burns 0 coins. The test fails with 'the engine's liquidation fee was refunded to the launch instead of burned: 0 < 44000000000000000000000'.","severity":"low","snippet":"            for (uint256 i; i < 3 && left != 0; ++i) {\n                pool.feeCheckpoint();\n                BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n                (, uint256 back) = pool.feeRefund(address(this));","title":"sellHeld's fee refund also captures fees of perps-engine liquidation swaps nested inside the sale, moving coin fees meant for the burn into the timelock's held coins"}],"hash":"3992e09e1fc6636d515cd011a47313f95c779b19df5ba6af0932f1622c9aaeb1","nodeId":"6adcacba-2ee6-4671-92e7-8097b6d002ca","outcome":"completed","summary":"Review complete. The findings file is written, every snippet matches the tree, and the coverage record answers all 59 entry points plus three invariants with no `unreached` rows.\n\n**What I found (economics, invariants, flow gaps):**\n\n1. **Medium: a refused payee's share is re-split on every `split()` call.** The NatSpec promises a refusing payee's ETH waits for the next split, but the loop re-derives `amount` from the whole balance each time and books 10% of it to the $IMD bucket again. Anyone can call `split()` or `harvest()` repeatedly, so if the pot bridge ever refuses ETH (paused or upgraded), the pot's 90% migrates into the $IMD burn bucket, where `burnImd` spends it irreversibly. The proof test shows 300 splits leaving 9,597 wei of a 0.512 ETH pot share.\n\n2. **Medium: `burnImd(minImd)` is sandwichable because the caller picks the floor.** There is no on-chain price bound, so an attacker buys $IMD, calls `burnImd(0)`, and sells back. In the proof test the attacker nets about 0.03 ETH from one 0.1 ETH burn buy, and the burn receives 34% less $IMD. The per-block cap only sizes each bite.\n\n3. **Low: the launch's fee-free sale captures nested perps-engine fees.** Inside `sellHeld`, the hook's sweep runs engine liquidation swaps between `feeCheckpoint` and `feeRefund`. If the engine does not refund itself, its fees are refunded to the launch instead of burned. The proof test shows the engine's 44,400-coin fee landing in the timelock's held coins and the next `collect()` burning nothing.\n\nAll three proofs under `test/scratch/` fail on the current code for the stated reason. The project's own suite passes (59 tests).\n\n**Covered and holding:** launch accounting (reserve, excess, dust), claims conservation, `lowerFee`'s principal move and rounding, `open`'s liquidity bound, `recoverEth`'s bucket cap, hook LP restrictions, and the one-pool liquidity lock. **Trust assumptions noted, not findings:** `sellHeld`'s `minEth` is public days ahead through the timelock, `setPerpEngine(0)` with positions open would let `lowerFee` strand them, and `addPerpFees` reverts if the pot bridge refuses ETH.\n\n**Not reached:** no fork run (no `ROBINHOOD_RPC_URL`), so the real pot bridge's and $IMD pool's live behaviour were not checked against the hardcoded constants.","treeHash":null,"usage":{"cachedInputTokens":2208747,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":48291,"runtime":"claude","turns":37,"wallClockMs":961103}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3beb94a990617d46","findings":[{"citation":"resolved","description":"The revised burnImd sizes each buy to poolManager.getLiquidity(id) at the moment of the call (line 536) and caps it at the pool's fee fraction of the ETH that liquidity stands for (line 541). That bounds a plain front-run through the pool's existing liquidity (the author's test), but the liquidity it reads is whatever is in range when burnImd executes, and anyone can put a position there in the same block. A sandwicher adds a narrow $IMD-only position one tick spacing wide below the current price, front-runs through the real (thin) liquidity down to the top of that range, and calls burnImd(0): inRange now includes the attacker's position, so cap >= IMD_BUY_MAX and the whole 0.1 ETH goes through, filled out of the attacker's own position at the inflated price (it also collects the buy's 1% fee as the in-range LP). The attacker then removes the position and sells the front-run's $IMD back through the real liquidity, which returns to about its old price. The round-trip costs the attacker two 1% fees on ~0.29 ETH; it gains the burn's 0.1 ETH at a 33% worse price. The sandwich bound the fix relies on ('the buy's own price impact stays under the fee a sandwich pays twice over') assumes honest depth; with just-in-time depth the ratio of impact to fee is whatever the attacker's front-run made it. Same root cause and severity as the first-round finding: the only price protection of a public, caller-sized buy is a bound the caller's counterparty controls. minImd remains caller-chosen (0). The loser is the $IMD burn (the 10% share), at most IMD_BUY_MAX per block, refilled by every split; the gain goes to an unprivileged attacker. Fix options that keep the design: bound the buy against a reference the attacker cannot move in the same block (the pool's own tick observation / a TWAP, or the last block's sqrtPrice recorded at the previous burn, refusing a buy whose execution price is more than the fee away from it), or let only a keeper the timelock names pass minImd, or require the executing price (sqrtP after the buy) to be within the fee of the price at which the pool's full-range liquidity would quote it.","line":541,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"State: launched (2.81 ETH opening buy at 19.18 ETH market cap, excess held); $IMD pool ETH/$IMD 1% fee, tick spacing 100, no hooks, ~261 $IMD/ETH, full-range liquidity 2e19 (~1.24 ETH a side); 150 ETH of buys harvested so imdBucket > 0.6 ETH. Honest burnImd(0): spends 0.01237 ETH (the cap) at 255.86 $IMD/ETH. Attack in one block, attacker starting with 10 ETH and 1000 $IMD: (1) add 2e21 liquidity in ticks [51400, 51500] ($IMD only, ~34% below the price); (2) swap ETH in, exact input 1 ETH, sqrtPriceLimit = getSqrtPriceAtTick(51500): about 0.29 ETH consumed, tick lands in [51400, 51500); (3) burnImd(0): expected the cap to limit the buy to ~0.012 ETH or the buy to execute near the honest price; actual: 0.1 ETH spent (cap = attacker's liquidity), the burn receives 17.055 $IMD = 170.55 $IMD/ETH, 33% under the honest 255.86; (4) remove the position, sell the front-run $IMD back, buy back the $IMD the burn took so the attacker holds exactly 1000 $IMD again. Actual: attacker ETH 10.026254724996830573 (+0.0263 ETH, net of all fees). Confirmed by test/scratch/Proof_JitBurnSandwich.t.sol on this tree: FAIL 'the sandwich does not pay: the attacker is not up in ETH: 10026254724996830573 > 10000000000000000000'.","severity":"medium","snippet":"            uint256 cap = FullMath.mulDiv(uint256(inRange) * imdPoolFee, 1 << 96, uint256(sqrtP) * 1_000_000);","title":"burnImd's thin-pool cap reads in-range liquidity the sandwicher supplies just in time, so the $IMD buy is still sandwiched for profit (fix for bbf57e19fc03 does not hold)"},{"citation":"resolved","description":"The booking added for finding 4891b788d800 is only settled inside split()'s loop, and split() returns at line 501 when amount = balance - imdBucket - owedTotal is zero, before reaching the loop that pays part + owed(payee). A payee whose share was booked while it refused ETH (its deposit path paused) and that later accepts cannot be paid by calling split(): every call returns 0 until some unbooked ETH reaches the contract (a collect, addFees, or a 1 wei donation). The ETH is not lost and recoverEth still works, so this is a liveness gap in the fix rather than a loss; the NatSpec ('the next split offers it again') promises the retry without that condition. Reported by the independent tester; confirmed by trace. Fix: compute the loop over max(amount, owedTotal) (run the loop whenever amount != 0 || owedTotal != 0, with part = 0 when amount == 0).","line":501,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch; timelock setPayees([P (receive reverts), imdBurn], [9000, 1000]); addFees{value: 1 ether}; split(): imdBucket = 0.1 ETH, owed(P) = 0.9 ETH, owedTotal = 0.9 ETH, balance = 1 ETH. Make P accept ETH. Call split(). Expected: P receives 0.9 ETH, owed(P) = 0. Actual: amount = 1 - 0.1 - 0.9 = 0, split() returns 0 at line 501, owed(P) stays 0.9 ETH, P's balance stays 0. Any later addFees{value: 1 wei} followed by split() pays it. The repository's own test_RefusedShareIsBookedNotResplit shows the same: assertEq(launch.split(), 0) while 0.9 ETH is booked, and the pot is only paid after another 1 ETH of fees arrives.","severity":"low","snippet":"        if (amount == 0) return 0;","title":"split() returns before the payee loop when nothing unbooked is held, so a payee that starts accepting is not paid its books until new ETH arrives"},{"citation":"resolved","description":"The owed ledger is keyed by payee and only paid inside split()'s loop over the current list. setPayees overwrites the list (line 383) without settling or cancelling the books of the payees it drops, so an address with a non-zero book that is no longer listed is never visited again: its ETH stays in the contract, kept out of every split by owedTotal, with no path to it but recoverEth, which cancels all books at once (also those of payees still listed, whose next shares then re-split, and the $IMD bucket if the recovery reaches it). The timelock has an escape, so low; but the escape is coarser than the problem. Reported by the independent tester; confirmed by trace. Fix: in setPayees, pay or cancel (owedTotal -= owed, _owed = 0, event) the books of payees not in the new list, or let recoverEth cancel one payee's book.","line":383,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch; timelock setPayees([P (refuses), A], [5000, 5000]); addFees{value: 1 ether}; split(): owed(P) = 0.5 ETH, owedTotal = 0.5 ETH, A got 0.5 ETH. Timelock setPayees([B, A], [5000, 5000]); addFees{value: 1.5 ether}; split(): amount = 2 - 0 - 0.5 = 1.5 ETH goes to B and A; owed(P) stays 0.5 ETH, balance 0.5 ETH. Expected: a way to settle or cancel P's book alone. Actual: P is never in the loop again; only recoverEth(to, x) with x > balance - imdBucket - owedTotal cancels it, and it cancels every book and bumps _owedEpoch. The repository's test_RemovedPayeesBooksAreNeitherResplitNorLostUntilRecovery (test/LaunchFailures.t.sol:462) records this behaviour.","severity":"low","snippet":"            (_payees[i], _shares[i]) = (to[i], bps[i]);","title":"A payee setPayees removes keeps its booked ETH forever; only recoverEth frees it, cancelling every other payee's book with it"},{"citation":"resolved","description":"cap = inRange * imdPoolFee * 2^96 / (sqrtP * 1e6) (line 541). The timelock's setImdPool accepts any fee (line 469-473). With imdPoolFee == 0 (a fee-free ETH/$IMD pool) the cap is 0 whenever the pool has in-range liquidity, spend becomes 0 and burnImd reverts NoEth (line 544) while the bucket is full, until the timelock repoints the pool; the revert reads as 'no ETH'. With the dynamic-fee flag 0x800000 in imdPoolFee the cap is 8.39x the ETH the in-range liquidity stands for, i.e. the sandwich bound is gone for that pool (a dynamic-fee pool's actual fee is read from slot0's lpFee, not from the key). Timelock configuration only, so low. Reported by the independent tester; confirmed by trace. Fix: use the pool's lpFee from slot0 (StateLibrary.getSlot0) instead of the key's fee for the cap, and floor the cap (or refuse a zero/dynamic fee in setImdPool).","line":544,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch; timelock setImdPool(0, 60, address(0)); initialize that ETH/$IMD pool and add 1e21 full-range liquidity; 10 ETH of buys harvested so imdBucket >= 1 ETH. burnImd(0). Expected: a buy of up to IMD_BUY_MAX (the pool charges nothing). Actual: inRange != 0, cap = 1e21 * 0 * 2^96 / (sqrtP * 1e6) = 0, spend = 0, revert NoEth; imdBucket unchanged, every block, until setImdPool. With setImdPool(0x800000, 60, H) for a dynamic-fee pool: cap = inRange * 8388608 * 2^96 / (sqrtP * 1e6), 8.39x the pool's ETH depth, so spend = IMD_BUY_MAX on any pool and the thin-pool bound does not apply.","severity":"low","snippet":"        if (spend == 0) revert NoEth();","title":"burnImd's cap is proportional to imdPoolFee: a zero-fee $IMD pool makes every burn revert NoEth, and a dynamic-fee pool flag makes the cap 8x the ETH depth"}],"hash":"3c29f36fdc19e8c1baa0235d4a2369fdc24a6611d47c9160fa931cd3878daf9c","nodeId":"8b1d046e-d304-4c1f-bbe3-5ec04bf64931","outcome":"completed","summary":"The review is complete and written to `.imd-findings.json` with 4 findings and a 60-row coverage record.\n\n**Settled from the first round**\n\n- **Fixed, confirmed by running the attached proofs on the revised tree:** the split re-splitting a refused share, lowerFee losing a third of the position near the top tick, and the nested fee-refund windows. All three proofs pass now, and the project's own 126 tests pass.\n- **Fixed, confirmed by trace and the author's regression tests:** the PerpsOpen bypass through setPerpEngine, the owner's renounceOwnership, releases to the contract itself, the uint128 downcast in open, and the manifest's static owner address.\n- **Trust assumptions:** accepted as the author answered. They are documented powers, not defects.\n\n**Not fixed: the burnImd sandwich (medium, with proof)**\n\nThe new cap reads the pool's in-range liquidity at the moment of the call. A sandwicher supplies that liquidity just in time: a narrow $IMD-only position below the price, a front-run through the real liquidity to the top of it, then burnImd(0) spends the full 0.1 ETH out of the attacker's own position at the inflated price. My self-contained test reproduces it on this tree with the author's own pool parameters.\n\n| | $IMD per ETH | attacker ETH, from 10 |\n|---|---|---|\n| honest burn | 255.86 | |\n| sandwiched burn | 170.55 | 10.0263 |\n\nThe attacker ends with exactly the $IMD it started with and 0.026 ETH more. The fix needs a reference the attacker cannot move in the same block, or a keeper the timelock names.\n\n**New, low, from the independent tester, each confirmed by trace**\n\n- split returns before its payee loop when nothing unbooked is held, so a payee that starts accepting is not paid its books until new ETH arrives.\n- A payee removed by setPayees keeps its book forever. Only recoverEth frees it, and that cancels every book at once.\n- A zero-fee $IMD pool makes every burn revert with NoEth, and a dynamic-fee flag makes the cap eight times the pool's depth.\n\nNo files outside test/scratch and the findings file were changed.","treeHash":null,"usage":{"cachedInputTokens":1886372,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":38653,"runtime":"claude","turns":25,"wallClockMs":843819}},{"artifacts":[],"attempt":1,"bundleHash":"5250ef044028942aac955ce13dd6f61626b7b5a2a7ee16fd9137e1544d5c79d3","device":"f2101c240e0b52a9","findings":[],"hash":"5ca33adaae886efa75523245b0706e457fef98116d2371d3daeadd35c255c9c3","nodeId":"be84281c-5881-41ab-a1cc-585b42e34144","outcome":"completed","summary":"The manifest is correct as it stands and needs no change for this revision.\n\n**What I checked**\n\n- The constructor in `src/IMD6900RobinhoodLaunch.sol:188` still takes four arguments in the order owner, PoolManager, IMDSTR, timelock, which matches the manifest's four static addresses after the later source revision by another contributor.\n- The owner argument is written as the static team wallet address the brief states, per the reference rule that a brief-named owner is written literally rather than as `$owner`.\n- The notes' claims match the current source: static POOL_FEE of 44400, the constructor creating only IMD6900LockedPool, createHook callable by anyone once with the 0x91 exclusion, and launch requiring a 0x6900 coin address.\n- No findings were listed in the brief, and no part of the manifest conflicts with the accepted implementation, so rewriting it would only discard verified work.\n\n**Verification**\n\n- `forge build` succeeds with lint warnings only.\n- `forge test` passes all 74 tests across 5 suites, including the fresh-chain deploy, single-transaction gas and admission-scan tests. The fork suite skips as expected without an RPC URL.\n- A schema check confirms the manifest has exactly the kind, contracts and notes keys, string arguments, a valid contract identifier, and notes under the 4000-character limit.\n- The working tree is clean, so no file other than launch.json has been touched.","treeHash":"ad9b8f4581b0c738e2af667d305c787f9e25cc02","usage":{"cachedInputTokens":155927,"inputTokens":130,"model":"claude-fable-5-1","outputTokens":2514,"runtime":"claude","turns":8,"wallClockMs":102265}},{"artifacts":[],"attempt":1,"bundleHash":"84213ef4096289d3267a4498efbbe6f3f68ffaa289eacc6751d0ce48fa0a0b85","device":"a315ee4cb81c640c","findings":[],"hash":"5dc87eb5665dc4e7ed1d7074157c3f16f90ecf66c80a0a32ac12a5ba8b781f95","nodeId":"05fd8dea-3d65-40d8-9cb2-9259e8b24c7a","outcome":"completed","summary":"All findings are answered and the tree is green. Recap:\n\n**What reproduced and what changed**\n\n- **Refused payee shares re-split** (`4891b788d800`, proof): `split()` now books a failed part to its payee (`owed`, `owedTotal`), keeps it out of every later split, and offers it again with the payee's next share. The timelock's `recoverEth` cancels the books only when it reaches into them. Proof passes: 0.1 ETH to the burn, 0.9 ETH booked to the pot.\n- **lowerFee lost a third of the position** (`959b71d4fb20`, proof): `_move` now puts the stored liquidity back and computes v4's rounded-up requirement. The one-wei shortfall per side is covered by the earned fees or by a 1,000-wei margin the locked pool now keeps back from each collect and the opening dust. Proof passes with the liquidity equal to the wei, and thirty back-to-back moves with no trades in between stay exact.\n- **Sweep nested inside the sale's refund window** (`a8a1088f7ba1`, proof): the hook skips the sweep for the launch's own swaps, as it does for the engine's. That isolates both the refunding and the non-refunding case. What the sale sinks, the next trade's sweep closes.\n- **Engine unwired with positions open** (`8d3fd3ae881f`): `setPerpEngine` refuses to unwire or replace an engine that reports open positions. One that cannot report stays replaceable, the documented way out of a broken wiring.\n- **Thin-pool sandwich on burnImd** (`bbf57e19fc03`): each buy is sized so its price impact stays under the pool's fee. On the review's pool every front-run size I tried loses money, and a deep pool still takes the full 0.1 ETH.\n- **Advisory lows** all reproduced and fixed: no `renounceOwnership`, releases to the launch itself stay accounted, and too low an opening price reverts `BadPrice`. The trust-assumptions item is recorded as design, not changed.\n\n**Verification**\n\n| Check | Result |\n| --- | --- |\n| `forge test --offline` | 72 passed |\n| The four supplied proofs, run one at a time | all pass (three failed on the starting tree) |\n| Launch runtime | 24,215 bytes, 361 under EIP-170 |\n\nOne caveat on size: the launch embeds the hook's creation code, so the two hook changes ate most of the margin. I dropped a separate pay-owed entry point to stay under the limit, and ADAPTATION.md says so. Another: this machine caps memory at 1.5 GB, which killed solc when the four proofs were compiled alongside the suite, so I ran them one at a time.\n\nFiles touched: the three contracts under `src/`, a new `test/LaunchReview.t.sol` with 13 regressions, one relaxed assertion in the existing harvest test (its exact equality encoded a rounding coincidence), README and ADAPTATION.md, and `.imd-responses.json` with a verdict for every finding. Nothing under lib/ or the build configuration changed, and no commit was made.","treeHash":"d48f55b5340f44deff93803fece5608743ed0c65","usage":{"cachedInputTokens":4319745,"inputTokens":866,"model":"claude-fable-5-1","outputTokens":83842,"runtime":"claude","turns":66,"wallClockMs":1732921}},{"artifacts":[],"attempt":1,"bundleHash":"cd49fc5de4e10513eada7235613098fa456be053f971f0e052496db195e1ebd0","device":"63458a1bd2b2d376","findings":[{"description":"split() handles the burn executor before it looks at the books: `if (to[i] == imdBurn) { imdBucket += part; continue; }` runs before `owed(to[i])` is read, so a payee that refused its share (booked in `_owed`) and is then made the executor by setImdBurn never has its books offered again, even when it accepts ETH afterwards. setPayees keeps the books because the address is still on the list, so neither the cancel-on-drop path nor the split ever frees them; they count in owedTotal (reducing every later split) until the timelock's recoverEth cancels all books at once. Only the timelock can create the state (setImdBurn to a listed payee with books), so this is a liveness nit rather than a loss: the ETH stays in the contract.","line":525,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Payees [R 50%, A 50%] with R refusing; deal 1 ETH to the launch; split() -> owed(R) = 0.5 ETH. Timelock: setImdBurn(R). R accepts from now on. Deal 1.5 ETH, split(): expected R is paid its 0.5 ETH books (or the books are cancelled into the bucket), actual imdBucket = 0.5 ETH, owed(R) = 0.5 ETH, R's balance = 0; a further split() and a setPayees with R still listed leave owed(R) = 0.5 ETH. Scratch test test/scratch/BurnExecutorBooks.t.sol (not submitted) passes on the current code asserting this behaviour.","severity":"low","title":"A listed payee's refused books are stranded once the timelock names it the burn executor"}],"hash":"648dd7a3cd2af045ebccf652bbfeb9a1f3ee6dfc326bac035ca0b01fabdf3e18","nodeId":"2f07389b-290a-4bb1-85df-c3a337e982a4","outcome":"completed","summary":"The findings file is in the repository root as required (the harness's own exclude rule keeps it out of git, which is expected), and the JSON is valid. The work is complete.\n\n**Outcome:** the suite is green again against the revised source. The run finished with 130 tests passed, 0 failed, and the fork test skipped without an RPC URL.\n\n**What changed in the source since my last round, and what I did about it.** The other contributor answered my three earlier low findings: `split` now offers refused books even with nothing new, `setPayees` cancels a dropped payee's books, the thin-pool cap is gone, and `burnImd` is now keeper-only with the keeper named by the timelock. Five of my tests encoded the old semantics and failed. I updated them rather than rewriting the files:\n\n- **test/LaunchFailures.t.sol**: the pre-launch probe now expects a stranger and the timelock to be refused as not the keeper, the owner to find no ETH, and the owner to be unable to name a keeper. The removed-payee test became a walk through a share change (books kept, offered alone, not in anyone else's split) and then a drop (cancelled, resplit among the new payees, the refuser never paid). A new test checks that list changes without a drop leave the books alone. The duplicate-payee test now ends by dropping the duplicate and checking exactly one cancellation of the full books before they are resplit.\n- **test/LaunchInvariant.t.sol**: a new `setKeeper` handler action, a keeper-aware burn action that also checks strangers are refused and that an unmeetable floor rolls the buy back whole, cancellation checks in the payee-list action, a fifth invariant that the burn stays the keeper's alone, and a new clause in the refused-shares invariant that nothing stays booked to a payee off the list. The pinned deterministic sequence drives every new path. One overflow in my own harness (a uint8 seed) was fixed along the way.\n- **test/TESTING.md**: a short section describing this revision.\n\n**One new low finding** is in `.imd-findings.json`: a listed payee with refused books that the timelock then names as the burn executor has those books stranded, because the split's executor branch runs before the books are read and the list change keeps them. Only `recoverEth` frees the ETH, and only the timelock can create the state, so it is a liveness nit, not a loss. It is reported, not asserted as correct. No proof file was attached since it is not critical or high.\n\nStill owed, as before: the fork run against live Robinhood state needs `ROBINHOOD_RPC_URL` and could not run here.","treeHash":"a228287cbc65e5b422cac369fe76bfa7c2d54398","usage":{"cachedInputTokens":3216552,"inputTokens":1154,"model":"claude-fable-5-1","outputTokens":32252,"runtime":"claude","turns":41,"wallClockMs":1023035}},{"artifacts":[],"attempt":1,"bundleHash":"b1a6bb2220d6ffe26890a910310a6baf47f67372804127b11c008c669e892c72","device":"b8fd8054ea57c5d8","findings":[{"description":"split() computes amount = balance - imdBucket - owedTotal and returns 0 when amount == 0, before the loop that pays each payee `part + owed(payee)`. A payee that refused its share (its ETH is booked in _owed) and later accepts ETH cannot collect its books by calling split(): every call returns 0 until some unbooked ETH reaches the contract (a fee collect, addFees, or a 1 wei donation). The ETH is not lost and the documented escape (recoverEth) still works; this is a liveness nit found by the invariant campaign (LaunchInvariant.t.sol, action sequence: donateEth -> configurePayees with a refusing payee -> split -> payee accepts -> split returns 0). The NatDoc says 'the next split offers it again'; a split with amount == 0 does not.","line":501,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch; setPayees([refuser 90%, imdBurn 10%]); deal 1 ETH to the launch; split() books 0.9 ETH to the refuser (owed == 0.9e18). Make the refuser accept ETH. Call split(). Expected: the refuser receives 0.9 ETH and owed() returns 0. Actual: split() returns 0, owed() stays 0.9e18, the refuser's balance stays 0. Scratch reproduction: test/scratch/ZeroFeeBurn.t.sol:test_AcceptingPayeeIsNotPaidItsBooksWithoutNewEth passes against the code as it is (asserting the actual behaviour) and was not submitted as a test.","severity":"low","title":"split() returns before the payee loop when nothing new is held, so a payee that starts accepting is not paid its books until new ETH arrives"},{"description":"The owed ledger is keyed by payee and only paid inside split()'s loop over the current list. After the timelock replaces the payees, an address with a non-zero book is never visited again: its ETH stays held (owedTotal keeps it out of every split) with no path to it other than recoverEth, which cancels all books at once (also the books of payees still on the list) and shrinks imdBucket when the recovery reaches it. setPayees could pay or cancel the books of payees it removes, or recoverEth could cancel a single payee's book. Covered as actual behaviour, with the recovery path, in test/LaunchFailures.t.sol:test_RemovedPayeesBooksAreNeitherResplitNorLostUntilRecovery.","line":376,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch; setPayees([refuser 50%, A 50%]); deal 1 ETH; split() books 0.5 ETH to the refuser. setPayees([B 50%, A 50%]). Deal 1.5 ETH and split(): 1 ETH splits to B and A, owed(refuser) stays 0.5e18 and the launch holds 0.5 ETH that nothing but recoverEth can move. Expected by the NatDoc ('the next split offers it again'): a way for the timelock to settle or cancel that one book; actual: none without cancelling all books.","severity":"low","title":"A payee taken off the list by setPayees keeps its booked ETH forever; only recoverEth frees it, and that cancels every book and may shrink the $IMD bucket"},{"description":"cap = inRange * imdPoolFee * 2^96 / (sqrtP * 1e6). With imdPoolFee == 0 (a fee-free ETH/$IMD pool set by setImdPool) the cap is 0 whenever the pool has in-range liquidity, spend becomes 0 and burnImd reverts NoEth: the whole $IMD bucket is unburnable until the timelock repoints the pool, and the revert reads as 'no ETH' while the bucket is full. With the dynamic-fee flag (0x800000) in imdPoolFee the cap is 8.4x larger than for a 100% fee, i.e. the sandwich bound is lost. A floor on the cap (or a fee floor in setImdPool) would avoid both.","line":541,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch; setImdPool(0, 60, address(0)); initialize that pool and add 1e21 full-range liquidity (any depth); deal 10 ETH and split() so imdBucket == 1 ETH. burnImd(0). Expected: a buy of up to IMD_BUY_MAX (or a positive cap). Actual: revert NoEth, imdBucket unchanged, repeatable every block. Scratch reproduction: test/scratch/ZeroFeeBurn.t.sol:test_ZeroFeeImdPoolBlocksEveryBurn (asserts the actual behaviour; not submitted).","severity":"low","title":"burnImd's thin-pool cap is proportional to imdPoolFee, so a zero-fee (or dynamic-fee) $IMD pool blocks (or unbounds) every burn"}],"hash":"64bd8b26944cb8e80707512d06ab75fc968ebdfb8a6484b67037f772565f5e48","nodeId":"2f07389b-290a-4bb1-85df-c3a337e982a4","outcome":"completed","summary":"Done. The full suite passes offline: 128 tests pass, 1 skipped (the Robinhood fork test, which needs an RPC URL), 0 failed, invariants at 256 runs of depth 80 with fail-on-revert.\n\n**What was wrong at the start.** Another contributor's accepted commit changed the source after my previous round. The locked pool now keeps a 1,000 wei margin of each currency as rounding cover for the fee move, the split books a refusing payee's share, and several new guards were added. Six of my previous tests asserted the old \"nothing stays in the locked pool\" semantics and failed.\n\n**What I changed, all under `test/`:**\n- `PoolProperties.t.sol`: payouts are checked against the margin exactly, the migration fuzz now asserts the whole position moves to the unit of liquidity when the margin is full plus coin conservation across a move, and a new unit test pins a move whose fees are below the margin.\n- `LaunchInvariant.t.sol`: the handler's collect and fee-move ghosts follow the new margin and rounding rules. It now drives a toggleable refusing payee through `setPayees`, checks every split against the owed ledger, checks the cancellation rule of `recoverEth`, closes claims by every path including a release to the launch itself, and probes the new `NoRenounce` and `BadTo` reverts. A fourth invariant keeps the owed total equal to the per-payee books and backed by held ETH beside the burn bucket.\n- `LaunchFailures.t.sol`: two edge tests for the owed ledger, a payee removed from the list and a payee listed twice.\n- `helpers/LaunchFixture.sol` and `TESTING.md`: the margin constant and the notes.\n\n**Findings reported in `.imd-findings.json`, all low, each reproduced in a scratch test:**\n- `split()` returns before the payee loop when nothing new is held, so a payee that starts accepting is not paid its books until new ETH arrives. The random campaign found this one.\n- A payee removed by `setPayees` keeps its booked ETH forever. Only `recoverEth` frees it, and that cancels every book at once.\n- The thin-pool cap in `burnImd` is proportional to the pool fee, so a zero-fee $IMD pool makes every burn revert with `NoEth`.\n\n**One environment note.** This machine's 1.5 GB memory limit kills a cold full compile. The run above succeeded from the per-file cache. The verifier's machine presumably has more memory, as previous rounds were accepted, but a cold `forge test` here would need per-file compilation first.","treeHash":"34fda8c3f9449d762015d7c1245cc965a1dde46b","usage":{"cachedInputTokens":6106940,"inputTokens":1826,"model":"claude-fable-5-1","outputTokens":46213,"runtime":"claude","turns":58,"wallClockMs":1334437}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"05f71cd1a5206480","findings":[{"citation":"resolved","description":"Seam: boundary x precision x invariant. _move removes the old position and gets its principal back as integer amounts (v4 rounds both down), then _liquidityFor derives the new liquidity as min(L_from_eth, L_from_coins) - 1. When the price is below the top tick b, the ETH leg is L*(b-p)*2^96/(b*p); if that real value is in [1, 2) wei the integer `eth` is 1 and L_from_eth = L * 1/eth_true, i.e. the move keeps only 1/eth_true of the position. The coins the smaller position does not need (net1) are then treated as 'fees' by _payOutHeld: burned, or sent to coinFeeTo. Below one wei (`eth` == 0) fromEth is 0, l is 0 and lowerFee reverts ZeroLiquidity although the position holds every coin. The state is any price just under b with the pool nearly empty of ETH: with the repository's launch parameters (open at 19.18 ETH market cap, L = 1.3879e23, b = 5.70853393952424007956e32) one wei of ETH is 2.96e13 sqrt-price units below b, so a sale that stops at sqrtPriceLimit = b - 4.44e13 leaves 1.5 wei (integer 1). Whoever holds the circulating coins can land the price there with an exact-limit swap (the launch's own sellHeld also walks the pool toward this corner: each call leaves 4.44%^3 of its coins, five calls leave under a wei). The contract's own guarantee ('moves the whole position', 'nothing is paid out but the old pool's earned fees') and the project's test bound (1e-9 relative) are broken by 33% in the reproduction; with eth_true = 1.99 wei the loss is 50%. Fix (keeps the design): do not re-derive L from the rounded amounts. Start from the old `liquidity` and lower it only until v4's rounded-up requirements (SqrtPriceMath.getAmount0Delta(p, b, L, true) and getAmount1Delta(a, p, L, true)) fit the amounts that came out, or let the contract top up the at-most-one-wei ETH shortfall from its own balance; keep the ZeroLiquidity check for a genuinely empty position only.","line":298,"path":"src/IMD6900LockedPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {SqrtPriceMath} from \"@uniswap/v4-core/src/libraries/SqrtPriceMath.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function totalSupply() external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\n/// A trader that sells coins up to an exact sqrt price limit\ncontract LimitTrader {\n    IPoolManager immutable pm;\n    PoolKey key;\n    uint160 limit;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function sell(PoolKey calldata k, uint256 coins, uint160 limit_) external returns (BalanceDelta d) {\n        (key, limit) = (k, limit_);\n        d = abi.decode(pm.unlock(abi.encode(coins)), (BalanceDelta));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        uint256 coins = abi.decode(data, (uint256));\n        BalanceDelta d = pm.swap(key, SwapParams(false, -int256(coins), limit), \"\");\n        pm.sync(key.currency1);\n        IERC20(Currency.unwrap(key.currency1)).transfer(address(pm), uint128(-d.amount1()));\n        pm.settle();\n        if (d.amount0() > 0) pm.take(key.currency0, address(this), uint128(d.amount0()));\n        return abi.encode(d);\n    }\n    receive() external payable {}\n}\n\ncontract LowerFeeNearTopTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant BUY = 2.81 ether;\n\n    IPoolManager PM;\n    IMD6900RobinhoodLaunch L;\n    IMD6900LockedPool pool;\n    LimitTrader trader;\n    address token;\n\n    function setUp() public {\n        PM = IPoolManager(address(new PoolManager(address(this))));\n        L = new IMD6900RobinhoodLaunch(OWNER, PM, address(0xD15), TL);\n        L.createHook(_hookSalt());\n        pool = L.pool();\n        trader = new LimitTrader(PM);\n        // no claims: the whole opening buy is the excess, sent to the trader so it holds every circulating coin\n        bytes32 salt = _coinSalt();\n        address expected_ = L.tokenAddress(salt);\n        uint160 open = _sqrtPrice(19.18 ether);\n        vm.deal(OWNER, BUY);\n        vm.prank(OWNER);\n        (token,) = L.launch{value: BUY}(salt, expected_, open, 0, address(trader));\n    }\n\n    /// Sells every circulating coin into the pool up to `limit`: the fee is paid in coins and lands in the position, so\n    /// the coin fees are pointed back at the seller (as the timelock may) and the sale runs in rounds until the price\n    /// reaches the limit\n    function _sellToLimit(uint160 limit) internal {\n        vm.prank(TL);\n        pool.setCoinFeeTo(address(trader));\n        for (uint256 i; i < 80; ++i) {\n            trader.sell(pool.poolKey(), IERC20(token).balanceOf(address(trader)), limit);\n            pool.collect();\n            (uint160 p,,) = pool.state();\n            if (p == limit) return;\n        }\n    }\n\n    /// The pool left with 1.x wei of ETH principal just under the top tick: the move keeps only ~2/3 of the position\n    function test_LowerFeeBurnsAThirdOfThePositionWhenOneWeiOfEthIsLeft() public {\n        uint160 b = TickMath.getSqrtPriceAtTick(pool.upperTick());\n        uint128 l0 = pool.liquidity();\n        // sqrt-price distance below b that is worth one wei of ETH for this liquidity: d = b^2 / (L * 2^96)\n        uint256 oneWei = FullMath.mulDiv(b, b, uint256(l0) << 96);\n        uint160 limit = uint160(uint256(b) - (oneWei * 3) / 2); // ~1.5 wei of ETH stays in the position\n        _sellToLimit(limit);\n        (uint160 p,,) = pool.state();\n        assertEq(p, limit, \"the sale stopped at the limit\");\n        uint256 ethInPosition = SqrtPriceMath.getAmount0Delta(p, b, l0, false);\n        assertEq(ethInPosition, 1, \"the position's ETH principal rounds to one wei\");\n        pool.collect(); // the old pool's fees are out: what follows is principal only\n        uint256 held0 = IERC20(token).balanceOf(address(trader));\n\n        vm.prank(TL);\n        uint128 l1 = pool.lowerFee(33_300);\n\n        emit log_named_uint(\"liquidity before\", l0);\n        emit log_named_uint(\"liquidity after \", l1);\n        emit log_named_decimal_uint(\"IMD6900 paid out of the position by the move (to coinFeeTo)\", IERC20(token).balanceOf(address(trader)) - held0, 18);\n        // what the project's own test asserts for a move: all of it, to the wei of rounding\n        assertApproxEqRel(l1, l0, 1e9, \"all of the liquidity moved (to the wei of rounding)\");\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        // coins per ETH = 1e9 * 1e18 / mc ; sqrt(price) * 2^96\n        uint256 price = (1_000_000_000 ether * 1e18) / mc; // 1e18-scaled coins per ETH... scale: price*1e18\n        // sqrt(price * 1e18) * 2^96 / 1e18 = sqrt(price) * 2^96\n        return uint160((_sqrt(price * 1e18) << 96) / 1e18);\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 z) {\n        if (x == 0) return 0;\n        z = x;\n        uint256 y = (x + 1) / 2;\n        while (y < z) { z = y; y = (x / y + y) / 2; }\n    }\n\n    function _hookSalt() internal view returns (bytes32) {\n        bytes32 initHash = L.hookInitCodeHash();\n        uint160 flags = L.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt() internal view returns (bytes32) {\n        bytes32 initHash = L.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) >> 144 == 0x6900) return bytes32(i);\n        }\n    }\n}","reproduction":"1. Deploy launch + hook, setClaims(0,0,0), launch{value: 2.81 ether}(salt, expected, sqrtPrice(19.18 ETH mc), 0, trader) so the trader holds every circulating coin (the excess). 2. Timelock setCoinFeeTo(trader) (only so the coin fees paid on the way back can be re-sold; any holder of all circulating coins reaches the same state). 3. Trader sells coins with zeroForOne=false and sqrtPriceLimitX96 = b - (b*b/(L<<96))*3/2 = 570853393952424007911631977567727, repeating sell+collect until the price equals the limit (about 20 rounds). 4. pool.collect() so the old pool has no fees pending. State: sqrtPriceX96 = limit < b, SqrtPriceMath.getAmount0Delta(p, b, L, false) == 1 wei. 5. Timelock calls pool.lowerFee(33_300). Expected: the new pool holds L = 138788983920567460422827 (to the wei of rounding), only fees paid out. Actual: lowerFee returns 92525989280381209596717 (66.67%), and 333,333,333.33 IMD6900 of the locked position are paid out to coinFeeTo (burned with the default). With limit = b - oneWei/2 instead (eth rounds to 0) lowerFee reverts ZeroLiquidity. Test: test/scratch/LowerFeeNearTop.t.sol, `forge test --match-path test/scratch/LowerFeeNearTop.t.sol`.","severity":"medium","snippet":"            uint256 fromEth = FullMath.mulDiv(eth, FullMath.mulDiv(p, b, 1 << 96), b - p);\n            uint256 fromCoins = FullMath.mulDiv(coins, 1 << 96, p - a);\n            l = fromEth < fromCoins ? fromEth : fromCoins;","title":"lowerFee recomputes the moved liquidity from the position's rounded-down ETH: at one wei of ETH principal a third of the locked position leaves the pool (below one wei the move reverts)"},{"citation":"resolved","description":"l = mulDiv(amount, 2^96, start - low) is a uint256; for the whole supply (1e27) it exceeds type(uint128).max whenever start - low < 2.33e17, i.e. for every opening tick from -887160 (the lowest BadPrice accepts) up to about -531000. The cast silently keeps the low 128 bits, so the value handed to modifyLiquidity is unrelated to the amount. In the reproduction the truncated value (1.89e38) is above int128 max, so v4 reverts SafeCastOverflow (0x93dafdf1) deep inside the unlock rather than the contract's own BadPrice/ZeroLiquidity; a truncated value that lands below v4's per-tick cap would instead open the pool with a tiny position and hand the rest of the supply back to the launch as 'excess'. Owner-only input, so impact is a misleading revert and a missing guard rather than a loss. Fix: `if (l - 1 > type(uint128).max) revert BadPrice();` (or SafeCast) before the cast.","line":144,"path":"src/IMD6900LockedPool.sol","reproduction":"setClaims(0,0,0); launch{value: 1 ether}(salt, expected, TickMath.getSqrtPriceAtTick(-887160), 0, address(0)). l = 6123830742008175932125694122593849901991701757965 (> 2^128-1); uint128(l-1) = 189254828772555816885055183266217967628. Expected: revert IMD6900LockedPool.BadPrice (price out of the range the opening supports). Actual: revert 0x93dafdf1 (v4 SafeCastOverflow) from PoolManager.modifyLiquidity. Test: test/scratch/OpenDowncast.t.sol.","severity":"low","snippet":"        liq = uint128(l - 1);","title":"open downcasts the opening liquidity to uint128 without a bounds check: a price near the bottom of the range is refused by v4's SafeCastOverflow (or could open a truncated position) instead of BadPric"},{"citation":"resolved","description":"Seam: boundary x invariant. The loop assumes everything the position earns between pool.feeCheckpoint() (line 522) and pool.feeRefund() (line 524) is this swap's fee, so back <= paid. But the swap on line 523 runs the hook's _beforeSwap, which calls perpEngine.sweepLiquidations inside the launch's unlock; an engine that closes positions by swapping on the same pool (what the design says it does) earns fees in that window. Unless that engine wraps each of its own swaps in its own checkpoint/refund pair, (a) its ETH fees come out in the launch's feeRefund and are sent to the timelock's `to` as sale proceeds instead of reaching the split, and (b) its coin fees inflate `back`: if the engine's sells are larger than the launch's `left` for that round, back > paid and line 530 reverts with a checked-arithmetic panic, so sellHeld cannot run while the sweep has anything to liquidate. The same window exists for every refunded caller, so this is a property of the checkpoint design rather than of the launch alone. Fix: have feeRefund bound the refund to the caller's own swap (compare the position's fee growth before and after the caller's swap only, with the hook recording swaps run by the engine) or have the engine required to call the pair around its own swaps and document it; at minimum guard `paid - back` (sold += paid > back ? paid - back : 0).","line":530,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"State: hook.setPerpEngine(E) by the timelock, where E.sweepLiquidations(...) sells 1,000,000 IMD6900 it holds into the pool (poolManager.swap zeroForOne=false, settling its own deltas) when called, and E does not call feeCheckpoint/feeRefund itself. Timelock calls L.sellHeld(1 ether of coins, 0, R). Round 1: feeCheckpoint; swap(left = 1e18 coins) -> hook beforeSwap -> E sells 1e24 coins paying 4.44e22 coin fee; the launch's swap pays 4.44e16; feeRefund returns back = 4.44e22 + 4.44e16 > paid = 1e18. Expected: sold = 1e18 - 4.44e16 and only the launch's fee refunded. Actual: `paid - back` underflows, sellHeld reverts (panic 0x11). With E selling 100 coins instead, sellHeld succeeds and the 4.44 coin fee plus E's ETH fee are credited to the sale (back and ethOut) instead of the split.","severity":"low","snippet":"                sold += paid - back;","title":"sellHeld's refund window is open to the hook's sweep: a perps engine that liquidates (swaps) inside beforeSwap between feeCheckpoint and feeRefund has its fees credited to the sale, and `paid - back` "}],"hash":"67dc22b8f1f724761791e088c23dc363221d6d65163f72d0c3b1953cb46f0884","nodeId":"09fcdb6d-173f-4c44-9144-0050a0fc81cf","outcome":"completed","summary":"The review is complete and written to `.imd-findings.json` with three findings and a coverage row for all 59 entry points. No repository file was changed; the only additions are the findings file and two scratch tests under test/scratch.\n\n**Findings**\n\n- **Medium, IMD6900LockedPool.lowerFee.** The move re-derives the new liquidity from the position's rounded-down ETH and coin amounts. When the price sits just under the top tick with one wei of ETH principal, the ETH leg gives only a fraction of the old liquidity, and the coins the smaller position does not need are paid out as if they were fees. Reproduced against a real PoolManager: the move keeps 66.67% of the position and 333,333,333 IMD6900 leave the locked pool. With less than one wei of ETH the move reverts with ZeroLiquidity although the position still holds every coin. The reproduction needs whoever holds the circulating coins to sell up to an exact price limit, and the launch's own repeated sellHeld walks toward the same corner. Proof test attached: test/scratch/LowerFeeNearTop.t.sol fails on the current code.\n\n- **Low, IMD6900LockedPool.open.** The opening liquidity is cast to uint128 without a bounds check. For any opening tick between -887160 and about -531000 the value exceeds uint128, so the cast keeps garbage bits. The concrete input reverts with v4's SafeCastOverflow instead of the contract's BadPrice. Owner-only input, so the harm is a missing guard rather than a loss.\n\n- **Low, IMD6900RobinhoodLaunch.sellHeld loop.** The refund window between feeCheckpoint and feeRefund also contains the hook's beforeSwap sweep. A perps engine that liquidates by swapping on the pool, and does not call the refund pair itself, has its fees credited to the sale, and `paid - back` underflows when its coin fees exceed the sale's, blocking sellHeld. Described with a concrete call sequence, no proof test since no engine exists in the repository.\n\n**Coverage.** Every listed entry point has a row. The opening formula, the fee move, the sell loop, the split, the claim accounting, burnImd and the hook's fee rounding were traced with concrete values. The move's sign and rounding bounds for `net0`/`net1` were checked analytically and hold outside the one-wei corner. Nothing in the assigned area was left unreached.","treeHash":null,"usage":{"cachedInputTokens":2397297,"inputTokens":642,"model":"claude-fable-5-1","outputTokens":51405,"runtime":"claude","turns":33,"wallClockMs":788468}},{"artifacts":[],"attempt":1,"bundleHash":"25fe6f82d89716c7a5687170450fcb172d8a6c6c78e0b7b5375927b4c5b74d01","device":"fe5e46fb044c6af1","findings":[],"hash":"756343e8a47363bef7fabd55d1e6190c59f7ea9bf8dab10be77e05a2f78fa59f","nodeId":"05fd8dea-3d65-40d8-9cb2-9259e8b24c7a","outcome":"completed","summary":"The responses file is in place and valid (the harness excludes it from git status by design). The work is complete.\n\n**Outcome:** the just-in-time sandwich reproduced exactly as reported, and all four findings are fixed. The suite passes with 74 tests, and the launch runtime is 24,246 bytes, 330 bytes under EIP-170.\n\n**Reproduction.** I ran the reviewer's attack unchanged in scratch space on the accepted tree. The cap read the attacker's one-spacing position as depth, the full 0.1 ETH filled at 170.55 $IMD/ETH against the honest 255.86, and the attacker finished at 10.026 ETH.\n\n**Fix for the sandwich (medium).** The root cause is the one the reviewer named: a public, caller-sized buy has no price reference the pool itself can give, because anything it reads is set by its counterparty in the same block. I took the reviewer's keeper option in `src/IMD6900RobinhoodLaunch.sol`:\n\n- **burnImd is the keeper's call.** The keeper is the owner (team wallet) until the timelock names another with `setImdKeeper`, and zero hands it back to the owner. The keeper quotes by eth_call and passes a floor, which the launch script already did from the team wallet at 97% of the quote.\n- **The liquidity cap is removed** with its reads. It bounded nothing a sandwicher could not set, and it would have made the keeper's floor fail whenever it cut the spend. The per-block limit stays.\n- **Tests:** an outsider's call reverts, the keeper's buy at its floor reverts Short under the review's exact sandwich and under plain front-runs, and the undisturbed buy spends 0.1 ETH at the quote. The timelock's naming of the keeper is tested separately.\n\n**Advisory findings, all reproduced and fixed.** split() now runs its loop when books exist with nothing new, so a payee that starts accepting is paid at once. setPayees cancels the books of payees it drops and keeps those of payees still listed. The zero-fee and dynamic-fee cap problem disappears with the cap.\n\n**Design note for the requester.** The brief describes burnImd as anyone's. It is now the keeper's, which matches how the script already operated it. Both fix options that keep it public need a reference the pool does not have, and the timelock can replace a keeper that goes dark. ADAPTATION.md records this trade-off, README and the script header are updated, and `.imd-responses.json` answers all four findings.","treeHash":"caa8dbef7ea01ea8c604f926dc12033a695f7010","usage":{"cachedInputTokens":5498518,"inputTokens":1570,"model":"claude-fable-5-1","outputTokens":51915,"runtime":"claude","turns":50,"wallClockMs":1219344}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f768e94767a9dde3","findings":[{"citation":"resolved","description":"Merged from the independent tester's finding 2a32e689789a (reproduced). split() handles the burn executor before it reads the payee's books: `if (to[i] == imdBurn) { imdBucket += part; continue; }` runs before `owed(to[i])`, so a payee that refused a share (booked in _owed, counted in owedTotal) and is then made the executor by setImdBurn never has its books offered again, even after it accepts ETH. setPayees keeps the books because the address is still listed (the cancel-on-drop path of the b63401ab3622 fix does not reach it), and no split ever pays them, so the ETH sits in the contract, kept out of every split by owedTotal, until the timelock's recoverEth cancels all books at once (also those of other payees). Only the timelock can create the state (setImdBurn to a listed payee with books), the ETH is not lost, and recoverEth frees it, so low: a liveness gap, not a loss. Fix that keeps the design: in setImdBurn, cancel (owedTotal -= due, _owed = 0, OwedCancelled) or pay the new executor's books; or in split(), read `due = owed(to[i])` before the executor branch and, for the executor, fold `due` into imdBucket with owedTotal -= due.","line":525,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch (offline fixture); timelock setPayees([R (a contract whose receive reverts until told to accept), A], [5000, 5000]); addFees{value: 1 ether}; split(): owed(R) = 0.5 ETH, owedTotal = 0.5 ETH, A got 0.5 ETH. Timelock setImdBurn(R); R starts accepting. split() with nothing new: expected R paid its 0.5 ETH books (as test_SplitPaysTheBooksAlone promises for any accepting payee); actual owed(R) stays 0.5 ETH, R's balance 0. addFees{value: 1.5 ether}; split(): imdBucket = 0.75 ETH (R's new share, as the executor), A's balance 1.25 ETH, owed(R) still 0.5 ETH, owedTotal 0.5 ETH, R's balance 0. Timelock setPayees([R, A], [5000, 5000]) again: owed(R) still 0.5 ETH (kept, since listed). Contract balance 1.25 ETH = bucket 0.75 + the stranded 0.5. Confirmed by test/scratch/Review_BurnExecutorBooks.t.sol on this tree (passes asserting the stranded state).","severity":"low","snippet":"            if (to[i] == imdBurn) {\n                imdBucket += part;\n                continue;\n            }\n            uint256 due = owed(to[i]);","title":"split() skips the books of a listed payee once the timelock names it the burn executor: its refused ETH is stranded until recoverEth cancels every book"}],"hash":"9507b2ab8c0a03a7ad7700a0e70302a461a9f81ee8c172a70f35970aea036f83","nodeId":"8b1d046e-d304-4c1f-bbe3-5ec04bf64931","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written: one low finding, 62 coverage rows (59 entry points plus two invariants), and the tree is otherwise untouched.\n\n**Earlier findings, all settled as fixed**\n\n- **burnImd sandwich (medium, 4648ff62):** burnImd is now the keeper's call only, the owner by default or whoever the timelock names, and the pool-read cap is gone. The author's test replays my exact just-in-time sandwich and the keeper's floor reverts it with Short. Fixed.\n- **split's early return (low, 92fe6a73):** the return now also requires owedTotal to be zero, so books are paid with nothing new. Fixed.\n- **setPayees strands dropped payees' books (low, b63401ab):** dropped payees' books are cancelled and re-split, kept payees' books stay. Fixed.\n- **burnImd cap with a zero or dynamic fee (low, 3a5795e7):** the cap no longer exists, so this is moot. Fixed.\n\n**Specialist findings from the first round**\n\nAll four attached proofs now pass on this tree, so the re-split, nested-refund and one-wei lowerFee defects are gone. The PerpsOpen bypass, renounce, self-release and uint128 downcast leads also show their fixes in the code. The full offline suite passes: 129 tests, 0 failures.\n\n**One new finding kept (low)**\n\nThe independent tester's lead reproduces. In split(), the burn-executor branch runs before the payee's books are read, so a listed payee that refused ETH and is then named the burn executor by setImdBurn never has its books offered again. setPayees keeps them because the address is still listed. Only recoverEth frees them, cancelling every other payee's book at the same time. Timelock-only state and no ETH is lost, so low. My scratch test confirms the stranded state on this tree.\n\nNothing in the revised code introduced a new defect that I could reproduce. Contract sizes and the constructor fit the factory's deployment model.","treeHash":null,"usage":{"cachedInputTokens":1411934,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":20815,"runtime":"claude","turns":20,"wallClockMs":464918}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ea89e16822824c6f","findings":[{"citation":"resolved","description":"Access x asymmetry (Trust Gap seam 3). The brief requires lowerFee to be 'refused while the perps engine has positions open' because an engine is bound to its pool key for good: after a move the hook's _beforeSwap (src/IMD6900Hook.sol:187) rejects the old pool with NotOurPool and the old pool holds no liquidity, so open positions can no longer be closed. The guard only consults whatever address IMD6900Hook.perpEngine currently holds. That slot is written by IMD6900Hook.setPerpEngine (src/IMD6900Hook.sol:123), guarded by onlyOwner, and the hook's owner is the same timelock that calls lowerFee. So the actor the guard constrains controls the input the guard reads: setPerpEngine(address(0)) (natspec: 'Zero turns perps off') or setPerpEngine(freshEngine) with openCount()==0 makes lowerFee skip the check entirely, and the previous engine's open positions are stranded. The natspec itself anticipates engine replacement ('Replaceable ... after a move it fails closed until a new one is wired'), so the ordering 'wire the new engine, then move' is a plausible operational sequence, not only a malicious one; either way the guarantee named in the brief does not hold. Fix without changing the design: have the locked pool remember the engine that was last wired to the pool it would empty (e.g. the hook records boundEngine per poolId when setPerpEngine is called, or the pool records every engine ever reported for the current pool) and have lowerFee query that engine's openCount regardless of the hook's current pointer; alternatively refuse setPerpEngine while the current engine's openCount()!=0 (but that removes the fail-closed escape hatch the natspec wants, so the first fix is preferable).","line":160,"path":"src/IMD6900LockedPool.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {IMD6900Hook} from \"src/IMD6900Hook.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\n/// The old IMDSTR as the launch's constructor needs it (never called here)\ncontract Imdstr {\n    mapping(address => uint256) public balanceOf;\n}\n\n/// A perps engine with positions open: it trades on the pool it was bound to (the key it saw when wired), as the real\n/// engine does, and reports its open positions truthfully\ncontract BoundEngine {\n    IPoolManager immutable pm;\n    PoolKey public key;\n    uint256 public openCount;\n    constructor(IPoolManager pm_, PoolKey memory k, uint256 open_) { pm = pm_; key = k; openCount = open_; }\n    function sweepLiquidations(address, int256, bool, uint160) external pure returns (uint8) { return 0; }\n    /// closing a position: a sell of the coin into its bound pool\n    function close(int256 amt) external returns (BalanceDelta d) {\n        d = abi.decode(pm.unlock(abi.encode(amt)), (BalanceDelta));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        int256 amt = abi.decode(data, (int256));\n        BalanceDelta d = pm.swap(key, SwapParams(false, amt, TickMath.MAX_SQRT_PRICE - 1), \"\");\n        pm.sync(key.currency1);\n        IERC20(Currency.unwrap(key.currency1)).transfer(address(pm), uint128(-d.amount1()));\n        pm.settle();\n        pm.take(key.currency0, address(this), uint128(d.amount0()));\n        return abi.encode(d);\n    }\n    receive() external payable {}\n}\n\n/// A plain buyer, to put coins in the engine's hands\ncontract Buyer {\n    IPoolManager immutable pm;\n    PoolKey key;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function buy(PoolKey calldata k, uint256 eth, address to) external {\n        key = k;\n        pm.unlock(abi.encode(eth, to));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (uint256 eth, address to) = abi.decode(data, (uint256, address));\n        BalanceDelta d = pm.swap(key, SwapParams(true, -int256(eth), TickMath.MIN_SQRT_PRICE + 1), \"\");\n        pm.settle{value: uint128(-d.amount0())}();\n        pm.take(key.currency1, to, uint128(d.amount1()));\n        return \"\";\n    }\n    receive() external payable {}\n}\n\n/// The PerpsOpen guard of IMD6900LockedPool.lowerFee reads IMD6900Hook.perpEngine(), which the same owner (the\n/// timelock) rewrites with setPerpEngine. Unwiring (or replacing) the engine first lets the move through while the\n/// engine's positions are open, and they can no longer close: the hook refuses the old pool.\ncontract PerpsOpenBypassTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n\n    IPoolManager pm;\n    IMD6900RobinhoodLaunch L;\n    IMD6900Hook hook;\n    IMD6900LockedPool pool;\n\n    function setUp() public {\n        pm = IPoolManager(address(new PoolManager(address(this))));\n        L = new IMD6900RobinhoodLaunch(OWNER, pm, address(new Imdstr()), TL);\n        hook = L.createHook(_hookSalt(L));\n        pool = L.pool();\n        bytes32 salt = _coinSalt(L);\n        address expected = L.tokenAddress(salt);\n        uint160 price = _sqrtPrice(19.18 ether);\n        vm.deal(OWNER, 2.81 ether);\n        vm.prank(OWNER);\n        L.launch{value: 2.81 ether}(salt, expected, price, 0, address(0));\n    }\n\n    function test_UnwiringTheEngineBypassesPerpsOpenAndStrandsItsPositions() public {\n        PoolKey memory old = pool.poolKey();\n        BoundEngine engine = new BoundEngine(pm, old, 3); // three positions open on the 4.44% pool\n        Buyer buyer = new Buyer(pm);\n        vm.deal(address(buyer), 1 ether);\n        buyer.buy(old, 1 ether, address(engine)); // the engine holds coins it must sell to close them\n        vm.prank(TL);\n        hook.setPerpEngine(address(engine));\n\n        // the guard holds as long as the pointer still names the engine\n        vm.prank(TL);\n        vm.expectRevert(IMD6900LockedPool.PerpsOpen.selector);\n        pool.lowerFee(33_300);\n\n        // the same owner rewrites the pointer the guard reads; a fix that refuses this while positions are open passes\n        vm.prank(TL);\n        try hook.setPerpEngine(address(0)) {} catch { return; }\n\n        // then the move must still be refused: positions are open on the pool it would empty\n        vm.prank(TL);\n        try pool.lowerFee(33_300) {} catch { return; }\n\n        // on the code as it is, the move went through and the engine can no longer close a single position\n        assertEq(pool.fee(), 33_300, \"the fee moved while positions were open\");\n        uint256 coins = IERC20(L.token()).balanceOf(address(engine));\n        assertGt(coins, 0);\n        vm.expectRevert(); // NotOurPool through the PoolManager's hook call\n        engine.close(-int256(coins));\n        assertTrue(false, \"lowerFee moved the liquidity out from under the engine's open positions\");\n    }\n\n    /*                               helpers                                 */\n\n    function _hookSalt(IMD6900RobinhoodLaunch l) internal view returns (bytes32) {\n        bytes32 initHash = l.hookInitCodeHash();\n        uint160 flags = l.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(l), i, initHash)))));\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt(IMD6900RobinhoodLaunch l) internal view returns (bytes32) {\n        bytes32 initHash = l.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(l), i, initHash)))));\n            if (uint160(a) >> 144 == 0x6900) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"State: launched pool at 4.44%; engine E bound to the 4.44% pool key, holding coins and reporting openCount()==3; timelock wires it (hook.setPerpEngine(E)). 1) timelock: pool.lowerFee(33_300) -> reverts PerpsOpen (guard holds). 2) timelock: hook.setPerpEngine(address(0)) -> succeeds. 3) timelock: pool.lowerFee(33_300) -> succeeds; pool.fee()==33_300, the 4.44% pool's liquidity is 0 and hook.poolId is the 3.33% pool. 4) E.close(): its swap on the 4.44% key reverts NotOurPool in the hook; E can never close any of its 3 positions. Expected: step 2 or step 3 refused while E has positions open. Actual: the move completes. Same result with step 2 = setPerpEngine(E2) where E2.openCount()==0. See test/scratch/PerpsOpenBypass.t.sol (fails on this tree).","severity":"medium","snippet":"        address engine = IPerpsWiring(hook).perpEngine();\n        if (engine != address(0)) {\n            // an engine that can't say how many positions it holds counts as holding some\n            (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n            if (!ok || ret.length < 32 || abi.decode(ret, (uint256)) != 0) revert PerpsOpen();\n        }","title":"lowerFee's PerpsOpen guard reads the hook's perpEngine pointer, which the same timelock rewrites first: unwiring or replacing the engine lets the move through while its positions are open, and they ca"},{"citation":"resolved","description":"Asymmetry between the two Ownable contracts: IMD6900Hook overrides renounceOwnership to revert NoRenounce (src/IMD6900Hook.sol:140) because 'the engine and the escape hatch need an owner', but IMD6900RobinhoodLaunch inherits Solady's Ownable.renounceOwnership unchanged (lib/solady/src/auth/Ownable.sol:186 sets the owner to address(0)). The launch keeps owner-only duties for the life of the contract: releaseImdstr (the only function that can move the IMDSTR every claim deposits; the natspec says it goes 'home to Ethereum') and releaseUnclaimed (the post-deadline release of the reserve, the only non-timelock close). Once renounced, no role can ever call them: the timelock has no path to the IMDSTR. The unclaimed reserve is still reachable by the timelock through endClaims, so that part is recoverable; the IMDSTR is not. Fix: override renounceOwnership in the launch to revert, as the hook does (no design change).","line":44,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"After launch, holders claim so the launch holds 1e24 IMDSTR. Owner calls L.renounceOwnership() -> owner()==address(0). Then L.releaseImdstr(0, anyone) reverts Unauthorized from every caller (owner, timelock); the 1e24 IMDSTR can never leave. Checked in test/scratch/LowLeads.t.sol test_RenounceStrandsImdstr.","severity":"low","snippet":"contract IMD6900RobinhoodLaunch is Ownable, ReentrancyGuard {","title":"The launch's owner can renounceOwnership (the hook refuses it): afterwards releaseImdstr and releaseUnclaimed are dead and the IMDSTR the claims collected is locked forever"},{"citation":"resolved","description":"Branch asymmetry on the sentinel address. launch() special-cases excessTo == address(this) (line 314: excessHeld = excess) so coins kept in the contract stay accounted and movable by the timelock. releaseExcess (lines 381-383) and releaseUnclaimed (lines 330-331) have only the zero-burn branch and the transfer branch: with to == address(this), excessHeld is decremented (or the reserve zeroed) and the coins are transferred to the contract itself, so they remain in its balance but are counted neither as claim reserve nor as excessHeld. sellHeld and releaseExcess both bound their amount by excessHeld, and nothing else moves the coin, so the coins are permanently locked without being burned (totalSupply unchanged, unlike the intended burn path). Fix: in both functions treat to == address(this) as the launch does (re-add to excessHeld, or revert).","line":382,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Launch with excessTo = address(L) so excessHeld = H > 0. Timelock calls L.releaseExcess(0, address(L)): excessHeld becomes 0, the launch's coin balance is unchanged, totalSupply unchanged. Afterwards L.sellHeld(0,0,TL) and L.releaseExcess(0,TL) both revert ZeroAmount; the H coins can never be sold, released or burned. Same with owner's L.releaseUnclaimed(address(L)) after the deadline: claimReserve() -> 0, coins stay in the contract unreachable. Checked in test/scratch/LowLeads.t.sol test_ReleaseExcessToSelfStrandsCoins.","severity":"low","snippet":"        if (to == address(0)) IMD6900(token).burn(amount);\n        else SafeTransferLib.safeTransfer(token, to, amount);","title":"releaseExcess / releaseUnclaimed treat `to == address(this)` as a plain self-transfer while launch() treats it as 'keep for the timelock': the coins drop out of excessHeld and become unreachable by an"},{"citation":"resolved","description":"Documented design, recorded as a privileged power rather than a defect. The brief describes the timelock as the actor that 'releases the excess or sells the coins the launch holds back'. Two owner-only paths sit beside that: launch() sends `bought - claimTotal` coins to any excessTo the owner names at launch time (line 316; the scripts pass the launch itself, test_SendsTheExcessWhereTold passes the timelock), and releaseUnclaimed(to) (line 323, onlyOwner, once block.timestamp >= claimDeadline) sends the entire unclaimed reserve to any address. The timelock can pre-empt the second only by calling endClaims first. Nothing is bypassed in the code's own terms; the judge should confirm the owner's single-key control over these two coin flows is accepted by the requester.","line":316,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Owner calls launch(salt, token, price, 0, OWNER): excess coins land in OWNER's balance (test_SendsTheExcessWhereTold shows the same with TL). After claimDeadline, owner calls releaseUnclaimed(OWNER): claimTotal - claimedTotal coins land in OWNER's balance. Both succeed on this tree; no state refuses them.","severity":"info","snippet":"            else SafeTransferLib.safeTransfer(t, excessTo, excess);","title":"Trust assumption (owner): launch(excessTo) and releaseUnclaimed(to) let the team wallet route the opening buy's excess and the whole unclaimed reserve to any address, bypassing the timelock's custody"},{"citation":"resolved","description":"Access x asymmetry powers held by the timelock, documented in the natspec and the brief, recorded here so the judge sees the full privilege map. (a) endClaims may run the block after launch (behind the timelock's own delay only), moving every unclaimed coin into excessHeld and then to ETH via sellHeld, while the owner's releaseUnclaimed is held to claimDeadline >= launch + 90 days; holders can only 'claim before it runs' if the timelock has already made the launch an IMDSTR distributor. (b) setImdPool(fee, tickSpacing, hooks) accepts any hooks address with no check; burnImd (anyone) then swaps up to 0.1 ETH per block through that pool, so a wrong or hostile pool drains the $IMD bucket at that rate. (c) setPerpEngine makes the engine a refunded caller in the locked pool (isRefunded) and the target of _sweep's call with nearly all remaining gas on every trader's swap (fail-closed revert if it misbehaves, unless sweepFailOpen). All three are the timelock's by design; none is a bypass.","line":389,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"(a) Launch at T; at T+1 timelock calls endClaims() -> succeeds; claimReserve()==0, excessHeld += unclaimed; sellHeld(0,0,X) sends the ETH to X. (b) Timelock calls setImdPool(f, s, H) for any H; anyone's burnImd(0) swaps 0.1 ETH on that key. (c) Timelock calls setPerpEngine(E); E.feeCheckpoint/feeRefund around its swaps returns its fee; every other swap calls E.sweepLiquidations with gasleft()-reserve.","severity":"info","snippet":"    function endClaims() external {\n        if (msg.sender != timelock) revert NotTimelock();\n        if (token == address(0)) revert NotLaunched();\n        if (unclaimedReleased) revert AlreadyReleased();","title":"Trust assumption (timelock): endClaims has no minimum window (the owner's release must wait MIN_CLAIM_WINDOW), setImdPool lets anyone's burnImd route 0.1 ETH per block through any pool/hook the timelo"}],"hash":"96662d9ed9f5d7c5fcdaa34526873f44bba7759adc2395c76e25064e6fadade0","nodeId":"0b6ec80a-2f02-445b-b802-2864af970a98","outcome":"completed","summary":"The review is complete. The findings file is written and validated, and no source files were changed.\n\n**Outcome: one substantive defect in my area, two low footguns, two documented trust assumptions.** All five snippets match the tree, every one of the 59 listed entry points has a coverage row, and the medium finding carries a Foundry proof that fails on the current code.\n\n**Findings written to .imd-findings.json**\n\n1. **Medium, `src/IMD6900LockedPool.sol:160`.** The `PerpsOpen` refusal in `lowerFee` reads the hook's `perpEngine` pointer, and the same timelock rewrites that pointer with `setPerpEngine`. Calling `setPerpEngine(0)` or wiring a fresh engine first makes `lowerFee` skip the check, the liquidity moves, and the previous engine's open positions can never close because the hook rejects the old pool. The proof test in `test/scratch/PerpsOpenBypass.t.sol` reproduces the full sequence and fails on this tree. Suggested fix keeps the design: have the pool query the engine that was bound to the pool being emptied, independent of the hook's current pointer.\n2. **Low.** The launch inherits Solady's `renounceOwnership` unchanged while the hook refuses it. After a renounce, `releaseImdstr` is dead for every caller and the IMDSTR deposited by claims is locked forever. Verified with a scratch test.\n3. **Low.** `releaseExcess` and `releaseUnclaimed` treat `to == address(this)` as a plain self-transfer, unlike `launch()`, which treats it as \"keep for the timelock\". The coins drop out of `excessHeld` and no function can ever move or burn them. Verified with a scratch test.\n4. **Info.** Owner powers recorded as trust assumptions: `launch(excessTo)` and post-deadline `releaseUnclaimed(to)` route coins anywhere without the timelock.\n5. **Info.** Timelock powers recorded as trust assumptions: `endClaims` with no minimum window, `setImdPool` accepting any hooks address that anyone's `burnImd` then trades through, and `setPerpEngine` granting fee refunds plus an all-gas call on every trade.\n\n**What held under the Access Control, Trust Gap and Asymmetry passes.** Every callback is PoolManager-only and sender-checked to the locked pool. Both `unlockCallback`s can only be reached by their own contract's `unlock` calls. The fee-refund pair is bound to the caller's own transient slot. The claims leaf encoding in claims.py matches the contract. The Slither reentrancy and arbitrary-send leads on `split` and `sellHeld` were traced and rejected: the shared guard blocks every reentrant state-changing path and the ETH destinations are constants or timelock-set.\n\n**Not reached.** The external perps engine's code, the live Robinhood addresses, and the fork test (no RPC URL in this environment).","treeHash":null,"usage":{"cachedInputTokens":2533989,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":60911,"runtime":"claude","turns":34,"wallClockMs":1054782}},{"artifacts":[],"attempt":1,"bundleHash":"045047ae4910c32a3c2ec98ff3d1154506008629f20378aac22af2ce498496ab","device":"5ebb5dcd91e9b8fc","findings":[],"hash":"a0d79eea857dc23a82a9f9aecab06101cf298727f6247b0b2acc8284cf65509f","nodeId":"2f07389b-290a-4bb1-85df-c3a337e982a4","outcome":"completed","summary":"Added failure-path tests, 1,000-case fuzz tests, and stateful invariants covering 20,480 randomized calls.\n\nVerified:\n- Offline build passed.\n- Offline suite: 110 passed, 0 failed, 1 skipped.\n- Live Robinhood fork integration passed separately.\n\nOnly `test/` changed; application source and configuration remain untouched.","treeHash":"fef50f4c2e938e2b57963d4c48de0d872b85121c","usage":{"cachedInputTokens":3422080,"inputTokens":167919,"model":"gpt-6-astra","outputTokens":37693,"runtime":"codex","turns":8,"wallClockMs":1403089}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"87804e27e9c9f85a","findings":[{"citation":"resolved","description":"burnImd is callable by anyone, takes minImd as its only slippage guard (the caller sets it, so an attacker passes 0), swaps with the pool's extreme price limit, and bounds a single call to IMD_BUY_MAX, documented as 'under what sandwiching it would be worth through two 1% fees'. Nothing bounds the number of calls per transaction or per block: nonReentrant only forbids nesting. An attacker therefore front-runs the ETH/$IMD pool, calls burnImd(0) until imdBucket is zero (each call buys 0.1 ETH of $IMD at the inflated price), and sells back in the same transaction. The per-call cap defends only against sandwiching one call; the economic defense the code relies on does not hold for the bucket as a whole, so a share of the $IMD burn's ETH (10% of all pool fees by default) is extracted by MEV instead of buying $IMD for the canonical burn executor. The deeper the bucket relative to the $IMD pool, the larger the loss.","line":464,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Local PoolManager; ETH/$IMD pool at the launch's imdPoolKey() (fee 10_000, spacing 100, no hooks) with full-range liquidity 2e20 (about 12.4 ETH a side at 261 $IMD/ETH). Launch, a 150 ETH buy on the coin's pool, harvest(): imdBucket = 0.678 ETH. (a) Sandwich a single burnImd(0) with a 10 ETH front-run: attacker ends 0.02 ETH DOWN (the cap works for one call). (b) Same front-run, then burnImd(0) seven times in the same transaction until imdBucket == 0, then sell the $IMD back: attacker ends 0.31 ETH UP, 46% of the bucket. Expected: the burn's ETH is not extractable by sandwiching, as the IMD_BUY_MAX comment claims. Actual: assertLe(attacker.balance, 100 ether) fails with 100.3099 > 100. Fix options: a per-block (or per-N-blocks) spend cap instead of per call, or a price check against an oracle/TWAP, or requiring minImd derived from a reference price; running the proof test shows the fix.","severity":"medium","snippet":"        uint256 spend = imdBucket < IMD_BUY_MAX ? imdBucket : IMD_BUY_MAX;","title":"burnImd's 0.1 ETH cap is per call, so one transaction can loop it and sandwich the whole $IMD bucket at a profit"},{"citation":"resolved","description":"burnImd debits imdBucket by `spend` before the swap, but the swap is exact-input only as far as the pool's liquidity reaches: unlockCallback settles `ethIn = -d.amount0()`, which is less than `spend` whenever the ETH/$IMD pool has too little liquidity in range (an initialized pool with none, a pool whose LPs left, or a key the timelock repointed with setImdPool to a pool that is live but thin). The difference stays in the contract's ETH balance with no record, and split() treats `balance - imdBucket` as new fees: 90% of it goes to the pot bridge and only 10% back to the bucket. Anyone can call burnImd(0) repeatedly, so with an empty $IMD pool the entire $IMD burn share is drained into the pot in a few calls, and imdBucket no longer equals the ETH reserved for $IMD. The $IMD buy is pinned to a specific pool key, so the condition is realistic over the lifetime of a pool that cannot be changed except by the timelock.","line":466,"path":"src/IMD6900RobinhoodLaunch.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {Hooks} from \"@uniswap/v4-core/src/libraries/Hooks.sol\";\nimport {PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"@uniswap/v4-core/src/libraries/FullMath.sol\";\nimport {IMD6900LockedPool} from \"src/IMD6900LockedPool.sol\";\nimport {IMD6900RobinhoodLaunch} from \"src/IMD6900RobinhoodLaunch.sol\";\n\ninterface IERC20 {\n    function balanceOf(address) external view returns (uint256);\n    function transfer(address, uint256) external returns (bool);\n}\n\ncontract MockToken {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function mint(address to, uint256 a) external { balanceOf[to] += a; totalSupply += a; }\n    function approve(address s, uint256 a) external returns (bool) { allowance[msg.sender][s] = a; return true; }\n    function transfer(address to, uint256 a) external returns (bool) { balanceOf[msg.sender] -= a; balanceOf[to] += a; return true; }\n    function transferFrom(address f, address to, uint256 a) external returns (bool) {\n        allowance[f][msg.sender] -= a; balanceOf[f] -= a; balanceOf[to] += a; return true;\n    }\n}\n\ncontract Trader {\n    IPoolManager immutable pm;\n    PoolKey key;\n    constructor(IPoolManager pm_) { pm = pm_; }\n    function swap(PoolKey calldata k, bool buy, int256 amountSpecified) external payable returns (BalanceDelta d) {\n        key = k;\n        d = abi.decode(pm.unlock(abi.encode(buy, amountSpecified)), (BalanceDelta));\n    }\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (bool buy, int256 amt) = abi.decode(data, (bool, int256));\n        BalanceDelta d = pm.swap(key, SwapParams(buy, amt, buy ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1), \"\");\n        _settle(key.currency0, d.amount0());\n        _settle(key.currency1, d.amount1());\n        return abi.encode(d);\n    }\n    function _settle(Currency c, int128 v) internal {\n        if (v < 0) {\n            if (c.isAddressZero()) pm.settle{value: uint128(-v)}();\n            else { pm.sync(c); IERC20(Currency.unwrap(c)).transfer(address(pm), uint128(-v)); pm.settle(); }\n        } else if (v > 0) pm.take(c, address(this), uint128(v));\n    }\n    receive() external payable {}\n}\n\ncontract BurnImdEmptyPoolTest is Test {\n    address constant OWNER = address(0xA11CE);\n    address constant TL = address(0x71E10C);\n    address constant POT = 0xc39e650a24985C2bBA9FD83C81041B8f3E3f9EDd;\n    uint256 constant SUPPLY = 1_000_000_000 ether;\n    uint256 constant OPEN_MC = 19.18 ether;\n    uint256 constant BUY = 2.81 ether;\n\n    IPoolManager PM;\n    IMD6900RobinhoodLaunch L;\n    IMD6900LockedPool pool;\n    Trader trader;\n\n    function setUp() public {\n        PM = IPoolManager(address(new PoolManager(address(this))));\n        L = new IMD6900RobinhoodLaunch(OWNER, PM, address(new MockToken()), TL);\n        L.createHook(_hookSalt());\n        pool = L.pool();\n        trader = new Trader(PM);\n        vm.deal(address(trader), 1000 ether);\n    }\n\n    /// $IMD's pool exists but holds no liquidity in range: burnImd(0) buys nothing yet writes the whole 0.1 ETH off\n    /// the bucket; the ETH stays in the contract as if it were new fees, and the next split pays 90% of it to the pot\n    function test_BurnImdWritesOffEthItNeverSpent() public {\n        address imd = L.IMD();\n        vm.etch(imd, address(new MockToken()).code);\n        PM.initialize(L.imdPoolKey(), uint160(_sqrt(261 << 192))); // initialized, empty\n\n        bytes32 salt = _coinSalt();\n        address expected_ = L.tokenAddress(salt);\n        vm.deal(OWNER, BUY);\n        vm.prank(OWNER);\n        L.launch{value: BUY}(salt, expected_, _sqrtPrice(OPEN_MC), 0, address(L));\n        trader.swap(pool.poolKey(), true, -10 ether);\n        L.harvest();\n\n        uint256 bucket = L.imdBucket();\n        uint256 bal = address(L).balance;\n        assertGt(bucket, 0);\n        uint256 burned = IERC20(imd).balanceOf(L.imdBurn());\n        try L.burnImd(0) {} catch {}\n        uint256 spent = bal - address(L).balance;\n        assertEq(IERC20(imd).balanceOf(L.imdBurn()) - burned, 0, \"nothing was bought\");\n        assertEq(bucket - L.imdBucket(), spent, \"the bucket may only fall by the ETH that actually bought $IMD\");\n    }\n\n    function _hookSalt() internal view returns (bytes32) {\n        bytes32 initHash = L.hookInitCodeHash();\n        uint160 flags = L.FLAGS();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) & Hooks.ALL_HOOK_MASK == flags && uint160(a) >> 152 != 0x91) return bytes32(i);\n        }\n    }\n\n    function _coinSalt() internal view returns (bytes32) {\n        bytes32 initHash = L.tokenInitCodeHash();\n        for (uint256 i;; ++i) {\n            address a = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(L), i, initHash)))));\n            if (uint160(a) >> 144 == L.VANITY()) return bytes32(i);\n        }\n    }\n\n    function _sqrtPrice(uint256 mc) internal pure returns (uint160) {\n        return uint160(_sqrt(FullMath.mulDiv(SUPPLY, 1 << 192, mc)));\n    }\n\n    function _sqrt(uint256 x) internal pure returns (uint256 y) {\n        if (x == 0) return 0;\n        y = x;\n        uint256 z = (x + 1) / 2;\n        while (z < y) (y, z) = (z, (x / z + z) / 2);\n    }\n}","reproduction":"Local PoolManager; initialize the pool at L.imdPoolKey() at 261 $IMD/ETH and add no liquidity. Launch, a 10 ETH buy, harvest(): imdBucket = 0.0569 ETH, contract balance 0.0569 ETH. Call burnImd(0): returns 0 $IMD, the burn executor receives nothing, the contract's ETH balance is unchanged, yet imdBucket is now 0. Then split(): the pot bridge receives 0.0512 ETH (90% of the burn share). Expected: imdBucket falls only by the ETH that actually bought $IMD (0 here), or the call reverts. Actual: bucket - imdBucketAfter = 56876400000000000 while ETH spent = 0. Fix: revert when ethIn < spend, or `imdBucket -= ethIn` after the swap (or credit back `spend - ethIn`).","severity":"medium","snippet":"        imdBucket -= spend;","title":"burnImd writes the whole spend off imdBucket even when the swap spends less, so unspent burn ETH is re-split 90% to the pot"},{"citation":"resolved","description":"setClaims takes the Merkle root and `total` as independent owner inputs and only checks that both are zero or both non-zero. claim() enforces each leaf's allowance but never `claimedTotal + amount <= claimTotal`. If the sum of the leaves exceeds `total` (a snapshot regenerated after the total was computed, a rounding or unit slip), claims beyond the reserve are paid out of the coins held for the timelock (excessHeld) since the contract's balance is reserve + excessHeld, and once claimedTotal > claimTotal every path that computes `claimTotal - claimedTotal` panics: endClaims, releaseUnclaimed and the claimReserve view revert with an arithmetic underflow, so the claims can never be closed and sellHeld later reverts when excessHeld exceeds the real balance. Owner input, hence low, but the guard is one line.","line":433,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"setClaims(root over leaves {A: 40M, B: 20M, C: 3.9M}, total = 50M, deadline = now + 100 days); launch with excessTo = address(L) so excessHeld > 0. A claims 40M, B claims 20M (allowed: each is within its leaf; claimedTotal = 60M > claimTotal = 50M, the extra 10M came from excessHeld's coins). Then timelock endClaims() -> panic 0x11 (claimTotal - claimedTotal underflows); owner releaseUnclaimed(to) after the deadline -> same panic; claimReserve() reverts. Expected: the second claim reverts once the reserve is exhausted (OverClaim), or the total is derived from the leaves. Fix: `if (claimedTotal + amount > claimTotal) revert OverClaim();` in claim().","severity":"low","snippet":"        claimedTotal += amount;","title":"claim does not check claimedTotal against claimTotal, so a root whose leaves sum above `total` drains the timelock's held coins and bricks endClaims/releaseUnclaimed"},{"citation":"resolved","description":"Read in full: src/IMD6900RobinhoodLaunch.sol, src/IMD6900LockedPool.sol, src/IMD6900Hook.sol, src/IMD6900.sol, plus test/IMD6900RobinhoodLaunch.t.sol, test/HookSalt.sol and the vendored BaseHook's onlyPoolManager guards. The full suite (44 local tests) passes offline; the fork test skips. Checked and found sound: access control on every state-changing function (owner: setClaims, withdrawEth pre-launch, launch, releaseUnclaimed, releaseImdstr; timelock: setPayees, recoverEth, releaseExcess, endClaims, sellHeld, setImdBurn, setPerpFeeTo, setImdPool, lowerFee, setCoinFeeTo, hook owner functions; anyone: createHook once, claim, split, burnImd, harvest, collect), the hook's sender == pool checks on initialize/add/remove, the fee refund pair (checkpoint arms a per-caller transient slot, refund is once and only for the launcher or the wired engine, and only the caller's own swap sits between the two), lowerFee's lower-only move (its -1 liquidity margin keeps net deltas non-negative; probed right after collect() with no earned fees, and with the price at the top of the range: both succeed), sellHeld's accounting (excessHeld falls by exactly paid - refunded), the Merkle leaf (double-hashed, no second-preimage with internal nodes), the coin (plain Solady ERC20, burn only), no DELEGATECALL/CALLCODE/SELFDESTRUCT in any creation or runtime code, and the constructor calling nothing external (deploys with a code-less PoolManager). Size: forge build --sizes reports IMD6900RobinhoodLaunch runtime 22,532 bytes (initcode 34,306), i.e. 2,044 bytes of EIP-170 margin, because it embeds the Hook, LockedPool and coin creation code; the adapter must not grow it by more than that or the protected runtime-size check fails. Not reachable in this review (no ROBINHOOD_RPC_URL, no network check of chain state): whether POT_BRIDGE 0xc39e650a24985C2bBA9FD83C81041B8f3E3f9EDd accepts plain ETH transfers (split() tolerates a refusal and keeps the ETH; addPerpFees() does not and would revert the perps engine's flush), whether IMD 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127, IMD_BURN 0x4D6537ec564aFf82eABb1Ce5f355E817cBEA1e07, the PoolManager 0x8366a39CC670B4001A1121B8F6A443A643e40951, IMDSTR 0x0000198C940D8cD70Cb9ACeC5E3af8216ac57d2F and the timelock 0x16D3f65B708883DF042d98E1C7a49B32A33E2A14 are the live contracts on Robinhood Chain, whether the ETH/$IMD pool exists at fee 10_000 / spacing 100 / no hooks, and the perps engine (PerpEngine, PerpSwapLib), which is not in this repository. The scripts under script/ (launch.sh, mine.sh, params.py, programmable_plan.py, claims.py) were not reviewed.","line":44,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"Not a defect. `forge build --sizes` shows IMD6900RobinhoodLaunch at 22,532 runtime bytes against the 24,576 limit the protected test asserts (assertLe(code.length, 24_576)). `forge test --offline` passes 44 tests and skips the fork test when ROBINHOOD_RPC_URL is unset.","severity":"info","snippet":"contract IMD6900RobinhoodLaunch is Ownable, ReentrancyGuard {","title":"Coverage: all four contracts read; IMD6900RobinhoodLaunch's runtime is 2,044 bytes under EIP-170; Robinhood Chain addresses could not be checked (no RPC)"}],"hash":"c024bb5e14acd71c8e4ba2d3b4ee183b91a42fe1c29a55c7f73a291eef752d33","nodeId":"c67ee0f9-223f-47bb-899e-86faa33e845f","outcome":"completed","summary":"The claim-accounting probe confirms the low finding exactly as written: claimed total 60M against a 50M reserve, the held balance now below `excessHeld`, and `endClaims`, `claimReserve` and `releaseUnclaimed` all revert with an underflow.\n\nReview complete. The findings are in `.imd-findings.json` at the repository root. No project files were changed; only `test/scratch/` holds my probe and proof tests.\n\n**What I read**\n- All four contracts in full: `IMD6900RobinhoodLaunch`, `IMD6900LockedPool`, `IMD6900Hook`, `IMD6900`, plus the existing test suite, the salt-mining helpers and the vendored BaseHook guards.\n- The full suite passes offline (44 tests). The fork test skips without an RPC.\n\n**Findings**\n- **Medium, with proof.** The `burnImd` per-call cap of 0.1 ETH is the only sandwich defense, and nothing stops looping it within one transaction. With a 12 ETH $IMD pool and a 0.68 ETH bucket, sandwiching one call loses 0.02 ETH but draining the bucket in seven calls nets the attacker 0.31 ETH. The $IMD burn's ETH becomes MEV instead of buying $IMD.\n- **Medium, with proof.** `burnImd` debits the bucket by the full spend before the swap. If the $IMD pool has no in-range liquidity, nothing is bought, the ETH stays, and the next `split` sends 90% of it to the pot bridge. Anyone can repeat this until the bucket is empty.\n- **Low.** `claim` never checks the running total against `claimTotal`. A root whose leaves sum above the total lets claims eat the timelock's held coins, after which `endClaims`, `releaseUnclaimed` and `claimReserve` revert on underflow. Owner input, one-line guard.\n- **Info.** Coverage note for the adapter. The launch's runtime is 22,532 bytes, only 2,044 under the EIP-170 limit the protected test enforces, because it embeds three contracts' creation code.\n\n**Checked and sound:** every privileged function's gate, the hook's sender checks, the fee-refund pair's transient arming, `lowerFee`'s rounding margin (probed right after `collect` and with the price at the top of the range), `sellHeld` accounting, the Merkle leaf shape, the plain coin, and the absence of forbidden opcodes in creation and runtime code.\n\n**Not reachable:** no Robinhood RPC, so the live pot bridge, $IMD, burn executor, PoolManager, IMDSTR and timelock addresses, the $IMD pool's existence at fee 10,000, and the perps engine (not in this repository) were not verified. The scripts under `script/` were not reviewed.","treeHash":null,"usage":{"cachedInputTokens":1126401,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":52771,"runtime":"claude","turns":22,"wallClockMs":902562}},{"artifacts":[],"attempt":1,"bundleHash":"92f16c55ec13f55b3019bd689facca529d377c99174ed909fe2df9c22f42a7e1","device":"6d3b3ab49d68191e","findings":[],"hash":"e4b58e68e4f6b60e13a391033667465857dd78f7a7b55adacea19730f074bbc2","nodeId":"be84281c-5881-41ab-a1cc-585b42e34144","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd-6/work/62e6b27c-75bc-41f8-b4d0-322fb1711971/be84281c-5881-41ab-a1cc-585b42e34144/launch.json) with one contract, `$owner`, and the three specified addresses in constructor order.\n\nManifest structure and compiled ABI verified. Offline `forge build` succeeded; `forge test` reported 59 passing tests. Live fork execution was skipped because `ROBINHOOD_RPC_URL` is unset.\n\nOnly `launch.json` is changed outside disposable scratch artifacts.","treeHash":"eeed0faa3920a4b8eea5dd2c083863046478168d","usage":{"cachedInputTokens":168576,"inputTokens":42789,"model":"gpt-6-astra","outputTokens":3113,"runtime":"codex","turns":3,"wallClockMs":128224}},{"artifacts":[],"attempt":1,"bundleHash":"7ca0d2b36983c5484da1e0cdbe2d9000f074f19a5a8118355df20996b68fd6d4","device":"af4be7a5238dbcbf","findings":[],"hash":"e8f06b0ee8095d32f229d304dfa9b1e656f0312e6e96f41c6dca150da8cf6101","nodeId":"be84281c-5881-41ab-a1cc-585b42e34144","outcome":"completed","summary":"The finding reproduced and is fixed. The build and all 72 tests pass. Only launch.json changed, plus the required .imd-responses.json answer file.\n\n**What was wrong**\n- The manifest's first constructor argument was the `$owner` placeholder. The brief states the owner as the team wallet, and the recipe requires a brief-stated owner to be written as its static address. The placeholder would hand the launch's owner-only powers to whatever wallet paid, if that differed from the team wallet.\n\n**What changed in launch.json**\n- The first constructor argument is now the static team wallet address from the brief. The PoolManager, IMDSTR and timelock arguments were already static and are untouched.\n- The notes no longer claim that the placeholder resolves to the team wallet. They now state the owner is written as the static address the brief gives.\n\n**Verification**\n- The manifest parses as JSON with exactly the kind, contracts and notes keys. It names one contract with four string arguments matching the constructor's parameter order, and the notes are well under the 4000 character limit.\n- `forge build` succeeds and `forge test` reports 72 passed, 0 failed. The Robinhood fork test skips as designed without an RPC URL.\n\n**Response to the reviewer**\n- .imd-responses.json marks the finding as fixed and describes the change and the checks above.","treeHash":"a86dbd576458694116eaee2da70a9172797428bd","usage":{"cachedInputTokens":107222,"inputTokens":98,"model":"claude-fable-5-1","outputTokens":2332,"runtime":"claude","turns":7,"wallClockMs":86337}}],"verification":[{"checks":[{"durationMs":44703,"exitCode":0,"name":"build","output":"Compiling 85 files with Solc 0.8.26\nSolc 0.8.26 finished in 44.47s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:101:57\n    │\n101 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:78:44\n   │\n78 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:270:9\n    │\n270 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:101:76\n    │\n101 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:123:28\n    │\n123 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:125:9\n    │\n125 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:131:9\n    │\n131 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:136:9\n    │\n136 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:174:60\n    │\n174 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:174:77\n    │\n174 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:198:9\n    │\n198 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:201:9\n    │\n201 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:222:9\n    │\n222 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:223:9\n    │\n223 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:233:27\n    │\n233 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:241:26\n    │\n241 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:271:9\n    │\n271 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:280:9\n    │\n280 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:276:73\n    │\n276 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:281:9\n    │\n281 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:118:22\n    │\n118 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:294:9\n    │\n294 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:298:32\n    │\n298 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:319:9\n    │\n319 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:323:62\n    │\n323 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:325:13\n    │\n325 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:333:9\n    │\n333 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:337:75\n    │\n337 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:342:9\n    │\n342 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:128:19\n    │\n128 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:148:9\n    │\n148 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:140:9\n    │\n140 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:144:15\n    │\n144 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:222:17\n    │\n222 │                 engine.call{gas: g - reserve}(abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit)));\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:318:9\n    │\n318 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:174:9\n    │\n174 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:163:43\n    │\n163 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:170:9\n    │\n170 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:357:13\n    │\n357 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:355:38\n    │\n355 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:360:23\n    │\n360 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:178:27\n    │\n178 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:189:9\n    │\n189 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:224:9\n    │\n224 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:372:9\n    │\n372 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:260:23\n    │\n260 │         uint256 eth = uint256(int256(out.amount0() - earned.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:261:25\n    │\n261 │         uint256 coins = uint256(int256(out.amount1() - earned.amount1()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:278:21\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:278:47\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:278:55\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:279:73\n    │\n279 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:279:81\n    │\n279 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:282:71\n    │\n282 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:282:79\n    │\n282 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:283:13\n    │\n283 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:285:60\n    │\n285 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:285:68\n    │\n285 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:304:60\n    │\n304 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:325:15\n    │\n325 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:325:23\n    │\n325 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:326:18\n    │\n326 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:384:9\n    │\n384 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:326:26\n    │\n326 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:24\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:32\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:47\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:55\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:409:34\n    │\n409 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:413:9\n    │\n413 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:455:9\n    │\n455 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:473:26\n    │\n473 │             (bool ok,) = to[i].call{value: part}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:473:26\n    │\n473 │             (bool ok,) = to[i].call{value: part}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:474:22\n    │\n474 │             if (!ok) emit PayFailed(to[i], part);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:476:9\n    │\n476 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:493:9\n    │\n493 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:503:9\n    │\n503 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:530:17\n    │\n530 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:17\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:521:29\n    │\n521 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:522:17\n    │\n522 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:523:34\n    │\n523 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:36\n    │\n524 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:527:17\n    │\n527 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:529:17\n    │\n529 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:523:73\n    │\n523 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:36\n    │\n524 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:525:32\n    │\n525 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:525:40\n    │\n525 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:27\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:35\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:529:17\n    │\n529 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:538:66\n    │\n538 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:539:25\n    │\n539 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:539:33\n    │\n539 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:540:23\n    │\n540 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:540:31\n    │\n540 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:542:9\n    │\n542 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:550:16\n    │\n550 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":413,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[PASS] test_TheWholeLaunchOnRobinhood() (gas: 2548)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.87ms (43.25µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 15466229)\nLogs:\n  factory deployment gas: 7445862\n  factory deployment gas: 7445874\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.12ms (2.97ms CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2967968)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1257069)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1458948)\n[PASS] test_ClaimsOneForOne() (gas: 1582067)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208607)\n[PASS] test_DeploysOnAFreshChain() (gas: 38177422)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 20237263)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2318005)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599550457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1298339)\n[PASS] test_FitsOneTransaction() (gas: 20215983)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1218825\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1839252)\nLogs:\n  pot bridge: 0.511887600000000000\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1428307)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1306276)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1297993)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2197805)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1949295)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288388119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2077604)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 1996640)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1967760)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1296129)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 67989)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91495)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117731)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1794782)\n[PASS] test_PassesTheAdmissionScan() (gas: 14437694)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1449133)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702296)\n[PASS] test_RefusesTheWrongAddress() (gas: 709787)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1272999)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214603)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1799606)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1231530)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1294890)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2660410)\n[PASS] test_TheFeeIsStatic() (gas: 1580762)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 68503414)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1343152)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2153166)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2310685)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2106159)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1649144)\n[PASS] test_TradesBothWays() (gas: 1553481)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 220.07ms (284.15ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1787467, ~: 1803064)\nLogs:\n  Bound result 1000000000000\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4318298)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3600546)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4425981)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1887925)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2189754)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2771837)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3790168)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4567708)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1787969)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3641651)\n[PASS] test_SingleBurnSandwichControl() (gas: 4188454)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3694297)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 219.74ms (104.25ms CPU time)\n\nRan 4 test suites in 228.54ms (444.80ms CPU time): 59 tests passed, 0 failed, 0 skipped (59 total tests)\n","passed":true},{"durationMs":117,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":101,\"README.md\":136,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":238,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":242,\"src/IMD6900LockedPool.sol\":338,\"src/IMD6900RobinhoodLaunch.sol\":562,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":928,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":412,\"test/RobinhoodFork.t.sol\":217},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":12193,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/IMD6900LockedPool.sol:309: IMD6900LockedPool._payOutHeld() (src/IMD6900LockedPool.sol#309-319) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/IMD6900RobinhoodLaunch.sol:461: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#461-477) sends eth to arbitrary user\n[high/medium] reentrancy-eth at src/IMD6900RobinhoodLaunch.sol:461: Reentrancy in IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#461-477):\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:290: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#290-320) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:366: IMD6900RobinhoodLaunch.recoverEth(address,uint256) (src/IMD6900RobinhoodLaunch.sol#366-373) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:461: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#461-477) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:461: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#461-477) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:276: IMD6900RobinhoodLaunch.withdrawEth(address,uint256) (src/IMD6900RobinhoodLaunch.sol#276-282) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/IMD6900RobinhoodLaunch.sol:188: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#188-203):\n[medium/medium] reentrancy-no-eth at src/IMD6900RobinhoodLaunch.sol:404: Reentrancy in IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address) (src/IMD6900RobinhoodLaunch.sol#404-414):\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:353: IMD6900RobinhoodLaunch.setPayees(address[],uint16[]).sum (src/IMD6900RobinhoodLaunch.sol#353) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:520: IMD6900RobinhoodLaunch.unlockCallback(bytes).sold (src/IMD6900RobinhoodLaunch.sol#520) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:519: IMD6900RobinhoodLaunch.unlockCallback(bytes).ethOut (src/IMD6900RobinhoodLaunch.sol#519) is a local variable never initialized\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) ignores return value by poolManager.settle() (src/IMD6900RobinhoodLaunch.sol#529)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:156: IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#156-175) ignores return value by (sqrtPriceX96,None,None,None) = poolManager.getSlot0(old.toId()) (src/IMD6900LockedPool.sol#167)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:128: IMD6900LockedPool.open(address,uint160,uint256) (src/IMD6900LockedPool.sol#128-149) ignores return value by poolManager.initialize(poolKey(),start) (src/IMD6900LockedPool.sol#140)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:502: IMD6900RobinhoodLaunch.harvest() (src/IMD6900RobinhoodLaunch.sol#502-505) ignores return value by pool.collect() (src/IMD6900RobinhoodLaunch.sol#503)\n[medium/medium] unused-return at src/IMD6900Hook.sol:105: IMD6900Hook.perpFeeBps() (src/IMD6900Hook.sol#105-111) ignores return value by (None,None,protocolFee,None) = StateLibrary.getSlot0(poolManager,poolId) (src/IMD6900Hook.sol#107)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) ignores return value by (None,back) = pool.feeRefund(address(this)) (src/IMD6900RobinhoodLaunch.sol#524)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:228: IMD6900LockedPool.state() (src/IMD6900LockedPool.sol#228-232) ignores return value by (sqrtPriceX96,tick,None,None) = poolManager.getSlot0(id) (src/IMD6900LockedPool.sol#230)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) ignores return value by poolManager.settle{value: ethIn}() (src/IMD6900RobinhoodLaunch.sol#542)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:156: IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#156-175) ignores return value by poolManager.initialize(poolKey(),sqrtPriceX96) (src/IMD6900LockedPool.sol#170)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:290: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#290-320) ignores return value by pool.open(t,sqrtPriceX96,SUPPLY) (src/IMD6900RobinhoodLaunch.sol#305)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:276: IMD6900LockedPool._settle(int128,int128) (src/IMD6900LockedPool.sol#276-287) ignores return value by poolManager.settle{value: uint256(uint128(- a0))}() (src/IMD6900LockedPool.sol#278)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:276: IMD6900LockedPool._settle(int128,int128) (src/IMD6900LockedPool.sol#276-287) ignores return value by poolManager.settle() (src/IMD6900LockedPool.sol#283)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:290: IMD6900LockedPool._liquidityFor(uint256,uint256) (src/IMD6900LockedPool.sol#290-305) ignores return value by (p,None,None,None) = poolManager.getSlot0(poolKey().toId()) (src/IMD6900LockedPool.sol#291)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:187: IMD6900LockedPool.collect() (src/IMD6900LockedPool.sol#187-191) ignores return value by poolManager.unlock(abi.encode(COLLECT,uint128(0))) (src/IMD6900LockedPool.sol#189)\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:128: IMD6900LockedPool.open(address,uint160,uint256).token_ (src/IMD6900LockedPool.sol#128) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:178: IMD6900LockedPool.setCoinFeeTo(address).to (src/IMD6900LockedPool.sol#178) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900Hook.sol:123: IMD6900Hook.setPerpEngine(address).engine (src/IMD6900Hook.sol#123) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:101: IMD6900LockedPool.constructor(IPoolManager,uint24,address,address).timelock_ (src/IMD6900LockedPool.sol#101) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:174: IMD6900RobinhoodLaunch.constructor(address,IPoolManager,address,address).timelock_ (src/IMD6900RobinhoodLaunch.sol#174) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:118: IMD6900LockedPool.setHook(address).hook_ (src/IMD6900LockedPool.sol#118) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:174: IMD6900RobinhoodLaunch.constructor(address,IPoolManager,address,address).imdstr_ (src/IMD6900RobinhoodLaunch.sol#174) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900Hook.sol:78: IMD6900Hook.constructor(IPoolManager,address,address).pool_ (src/IMD6900Hook.sol#78) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:433: IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address).hooks (src/IMD6900RobinhoodLaunch.sol#433) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:101: IMD6900LockedPool.constructor(IPoolManager,uint24,address,address).launcher_ (src/IMD6900LockedPool.sol#101) lacks a zero-check on :\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:461: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#461-477) has external calls inside a loop: (ok,None) = to[i].call{value: part}() (src/IMD6900RobinhoodLaunch.sol#473)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) has external calls inside a loop: s = poolManager.swap(k,SwapParams(false,- int256(left),TickMath.MAX_SQRT_PRICE - 1),) (src/IMD6900RobinhoodLaunch.sol#523)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) has external calls inside a loop: (None,back) = pool.feeRefund(address(this)) (src/IMD6900RobinhoodLaunch.sol#524)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:461: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#461-477) has external calls inside a loop: (ok,None) = to[i].call{value: part}() (src/IMD6900RobinhoodLaunch.sol#473)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) has external calls inside a loop: poolManager.sync(k.currency1) (src/IMD6900RobinhoodLaunch.sol#527)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) has external calls inside a loop: pool.feeCheckpoint() (src/IMD6900RobinhoodLaunch.sol#522)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:511: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#511-545) has external calls inside a loop: poolManager.settle() (src/IMD6900RobinhoodLaunch.sol#529)\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:188: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#188-203):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:483: Reentrancy in IMD6900RobinhoodLaunch.burnImd(uint256) (src/IMD6900RobinhoodLaunch.sol#483-494):\n[low/medium] reentrancy-benign at src/IMD6900LockedPool.sol:128: Reentrancy in IMD6900LockedPool.open(address,uint160,uint256) (src/IMD6900LockedPool.sol#128-149):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:290: Reentrancy in IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#290-320):\n[low/medium] reentrancy-benign at src/IMD6900LockedPool.sol:156: Reentrancy in IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#156-175):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:290: Reentrancy in IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#290-320):\n[low/medium] reentrancy-events at src/IMD6900LockedPool.sol:215: Reentrancy in IMD6900LockedPool.feeRefund(address) (src/IMD6900LockedPool.sol#215-225):\n[low/medium] reentrancy-events at src/IMD6900RobinhoodLaunch.sol:188: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#188-203):\n[low/medium] reentrancy-events at src/IMD6900RobinhoodLaunch.sol:502: Reentrancy in IMD6900RobinhoodLaunch.harvest() (src/IMD6900RobinhoodLaunch.sol#502-505):\n[low/medium] return-bomb at src/IMD6900Hook.sol:215: IMD6900Hook._sweep(address,int256,bool,uint160) (src/IMD6900Hook.sol#215-241) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] timestamp at src/IMD6900RobinhoodLaunch.sol:290: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#290-320) uses timestamp for comparisons\n[low/medium] timestamp at src/IMD6900RobinhoodLaunch.sol:323: IMD6900RobinhoodLaunch.releaseUnclaimed(address) (src/IMD6900RobinhoodLaunch.sol#323-334) uses timestamp for comparisons","passed":true},{"durationMs":1028,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/IMD6900RobinhoodLaunch.sol:233: `abi.encodePacked()` Hash Collision (3 places)\n[high] contract-locks-ether at src/IMD6900Hook.sol:41: Contract locks Ether without a withdraw function (2 places)\n[high] reentrancy-state-change at src/IMD6900LockedPool.sol:140: Reentrancy: State change after external call (11 places)\n[low] centralization-risk at src/IMD6900Hook.sol:41: Centralization Risk (11 places)\n[low] costly-loop at src/IMD6900RobinhoodLaunch.sol:354: Costly operations inside loop (2 places)\n[low] large-numeric-literal at src/IMD6900.sol:11: Large Numeric Literal (7 places)\n[low] literal-instead-of-constant at src/IMD6900Hook.sol:106: Literal Instead of Constant (12 places)\n[low] non-reentrant-not-first at src/IMD6900RobinhoodLaunch.sol:276: `nonReentrant` is Not the First Modifier (4 places)\n[low] push-zero-opcode at src/IMD6900.sol:2: PUSH0 Opcode (4 places)\n[low] require-revert-in-loop at src/IMD6900RobinhoodLaunch.sol:354: Loop Contains `require`/`revert`\n[low] state-no-address-check at src/IMD6900Hook.sol:124: Address State Variable Set Without Checks (5 places)\n[low] unchecked-return at src/IMD6900LockedPool.sol:140: Unchecked Return (9 places)\n[low] uninitialized-local-variable at src/IMD6900RobinhoodLaunch.sol:466: Uninitialized Local Variable (3 places)\n[low] unspecific-solidity-pragma at src/IMD6900.sol:2: Unspecific Solidity Pragma (4 places)\n[low] unused-public-function at src/IMD6900Hook.sol:105: Public Function Not Used Internally (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"20b29d3009054b277698a16b362a9ee43805afbea7d6763c82e80af238ca9b73","verifiedTreeHash":"0ff5e586ff181d579fe42afb17d51bac950ae106","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":33225,"exitCode":0,"name":"build","output":"Compiling 86 files with Solc 0.8.26\nSolc 0.8.26 finished in 33.07s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:81:44\n   │\n81 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:57\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:294:9\n    │\n294 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:76\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:128:28\n    │\n128 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:135:9\n    │\n135 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:141:9\n    │\n141 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:146:9\n    │\n146 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:188:60\n    │\n188 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:188:77\n    │\n188 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:212:9\n    │\n212 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:215:9\n    │\n215 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:236:9\n    │\n236 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:237:9\n    │\n237 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:247:27\n    │\n247 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:255:26\n    │\n255 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:295:9\n    │\n295 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:304:9\n    │\n304 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:300:73\n    │\n300 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:318:9\n    │\n318 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:322:32\n    │\n322 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:343:9\n    │\n343 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:329:9\n    │\n329 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:348:62\n    │\n348 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:350:13\n    │\n350 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:359:9\n    │\n359 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:122:22\n    │\n122 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:233:43\n    │\n233 │               (bool ok, bytes memory out) = engine.call{gas: g - reserve}(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n234 │ ┃                 abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit))\n235 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:363:75\n    │\n363 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:258:39\n    │\n258 │         (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpSweep.openCount, ()));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:368:9\n    │\n368 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:132:19\n    │\n132 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:154:9\n    │\n154 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:144:9\n    │\n144 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:149:15\n    │\n149 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:348:9\n    │\n348 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:180:9\n    │\n180 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:169:43\n    │\n169 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:176:9\n    │\n176 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:393:29\n    │\n393 │             for (uint256 j; j < n && !kept; ++j) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:393:39\n    │\n393 │             for (uint256 j; j < n && !kept; ++j) {\n    │                                       ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:385:13\n    │\n385 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:383:38\n    │\n383 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:388:23\n    │\n388 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:184:27\n    │\n184 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:195:9\n    │\n195 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:230:9\n    │\n230 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:415:17\n    │\n415 │                 emit OwedCancelled(owedTotal);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:420:9\n    │\n420 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:23\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:31\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:25\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:33\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:305:21\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:47\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:55\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:73\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:81\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:71\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:79\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:310:13\n    │\n310 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:60\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:68\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:331:60\n    │\n331 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:15\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:23\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:18\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:26\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:24\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:32\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:47\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:55\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:433:9\n    │\n433 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:458:34\n    │\n458 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:462:9\n    │\n462 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:474:27\n    │\n474 │     function setImdKeeper(address keeper) external {\n    │                           ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:511:9\n    │\n511 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-eth]: uncapped ETH transfer can be reentered before `owedTotal` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:541:17\n    │\n541 │                 emit PayFailed(to[i], pay);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:544:9\n    │\n544 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:565:9\n    │\n565 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:575:9\n    │\n575 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:602:17\n    │\n602 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:17\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:593:29\n    │\n593 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:594:17\n    │\n594 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:595:34\n    │\n595 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:36\n    │\n596 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:599:17\n    │\n599 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:601:17\n    │\n601 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:595:73\n    │\n595 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:36\n    │\n596 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:32\n    │\n597 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:40\n    │\n597 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:27\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:35\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:601:17\n    │\n601 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:610:66\n    │\n610 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:611:25\n    │\n611 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:611:33\n    │\n611 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:612:23\n    │\n612 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:612:31\n    │\n612 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:614:9\n    │\n614 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:622:16\n    │\n622 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":237,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[PASS] test_TheWholeLaunchOnRobinhood() (gas: 2548)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 309.76µs (35.93µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 16409170)\nLogs:\n  factory deployment gas: 7913684\n  factory deployment gas: 7913696\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.11ms (950.36µs CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 15 tests for test/LaunchReview.t.sol:LaunchReviewTest\n[PASS] test_AnEngineThatCantSayIsReplaceable() (gas: 1593177)\n[PASS] test_LowerFeeMovesAllOfItRightAfterCollect() (gas: 12273435)\n[PASS] test_LowerFeeMovesAllOfItWithOneWeiOfEthInThePosition() (gas: 6054159)\n[PASS] test_NoUnwiringWhilePerpsAreOpen() (gas: 2149567)\n[PASS] test_RecoverEthCancelsTheBooksOnlyWhenItReachesThem() (gas: 1931239)\n[PASS] test_RefusedShareIsBookedNotResplit() (gas: 2610193)\n[PASS] test_ReleasesToThisContractStayAccounted() (gas: 1439448)\n[PASS] test_SetPayeesCancelsTheBooksOfThoseItDrops() (gas: 1913089)\n[PASS] test_SplitPaysTheBooksAlone() (gas: 1753875)\n[PASS] test_TheBurnIsTheKeepersAtItsOwnFloor() (gas: 8436196)\n[PASS] test_TheOwnerCantRenounce() (gas: 64582)\n[PASS] test_TheSaleIsNotBrokenByANonRefundingEnginesLiquidation() (gas: 2841851)\n[PASS] test_TheSaleStaysFeeFreeWithARefundingEngineArmed() (gas: 3850866)\n[PASS] test_TheTimelockNamesTheKeeper() (gas: 3716792)\n[PASS] test_TooLowAnOpeningPriceIsBadPrice() (gas: 765401)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 103.49ms (33.28ms CPU time)\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 3000450)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1277301)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1479224)\n[PASS] test_ClaimsOneForOne() (gas: 1602431)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208739)\n[PASS] test_DeploysOnAFreshChain() (gas: 2338795)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 10970618)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2355811)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599549457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1318615)\n[PASS] test_FitsOneTransaction() (gas: 10949162)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1297482\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1866715)\nLogs:\n  pot bridge: 0.511887599999999100\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1448787)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1326684)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1318269)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2213038)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1986837)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288387119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2092674)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2016888)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 179032)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1982929)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1318619)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 68121)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91759)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117785)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1832242)\n[PASS] test_PassesTheAdmissionScan() (gas: 15409943)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1469541)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702428)\n[PASS] test_RefusesTheWrongAddress() (gas: 709963)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1293275)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214891)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1820053)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1251718)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1315078)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2684757)\n[PASS] test_TheFeeIsStatic() (gas: 1601281)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 19092505)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1363340)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21900)\n[PASS] test_TheLiquidityIsLocked() (gas: 2173553)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2335006)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2127011)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1669649)\n[PASS] test_TradesBothWays() (gas: 1573717)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 122.74ms (136.29ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1812569, ~: 1823692)\nLogs:\n  Bound result 2989\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4364978)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3692614)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4471466)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1908695)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2210714)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2809206)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3822515)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4597715)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1808705)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3673932)\n[PASS] test_SingleBurnSandwichControl() (gas: 4218131)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3735515)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 134.46ms (78.50ms CPU time)\n\nRan 5 test suites in 135.45ms (362.10ms CPU time): 74 tests passed, 0 failed, 0 skipped (74 total tests)\n","passed":true},{"durationMs":76,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdKeeper(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":228,\"README.md\":148,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"launch.json\":15,\"script/claims.py\":88,\"script/launch.sh\":239,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":262,\"src/IMD6900LockedPool.sol\":368,\"src/IMD6900RobinhoodLaunch.sol\":634,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":1034,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":418,\"test/LaunchReview.t.sol\":596,\"test/RobinhoodFork.t.sol\":238},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"5ca33adaae886efa75523245b0706e457fef98116d2371d3daeadd35c255c9c3","verifiedTreeHash":"ad9b8f4581b0c738e2af667d305c787f9e25cc02","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":36457,"exitCode":0,"name":"build","output":"Compiling 86 files with Solc 0.8.26\nSolc 0.8.26 finished in 36.29s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:81:44\n   │\n81 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:57\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:295:9\n    │\n295 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:76\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:128:28\n    │\n128 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:135:9\n    │\n135 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:141:9\n    │\n141 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:146:9\n    │\n146 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:189:77\n    │\n189 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:189:60\n    │\n189 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:213:9\n    │\n213 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:216:9\n    │\n216 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:237:9\n    │\n237 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:238:9\n    │\n238 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:248:27\n    │\n248 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:256:26\n    │\n256 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:296:9\n    │\n296 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:122:22\n    │\n122 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:301:73\n    │\n301 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:306:9\n    │\n306 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:319:9\n    │\n319 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:323:32\n    │\n323 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:344:9\n    │\n344 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:330:9\n    │\n330 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:349:62\n    │\n349 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:351:13\n    │\n351 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:360:9\n    │\n360 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:364:75\n    │\n364 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:369:9\n    │\n369 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:132:19\n    │\n132 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:154:9\n    │\n154 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:144:9\n    │\n144 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:149:15\n    │\n149 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:233:43\n    │\n233 │               (bool ok, bytes memory out) = engine.call{gas: g - reserve}(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n234 │ ┃                 abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit))\n235 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:258:39\n    │\n258 │         (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpSweep.openCount, ()));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:348:9\n    │\n348 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:180:9\n    │\n180 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:169:43\n    │\n169 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:176:9\n    │\n176 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:384:13\n    │\n384 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:382:38\n    │\n382 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:387:23\n    │\n387 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:184:27\n    │\n184 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:195:9\n    │\n195 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:230:9\n    │\n230 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:402:17\n    │\n402 │                 emit OwedCancelled(owedTotal);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:407:9\n    │\n407 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:420:9\n    │\n420 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:23\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:31\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:25\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:33\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:305:21\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:47\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:55\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:73\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:81\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:71\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:79\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:310:13\n    │\n310 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:60\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:68\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:331:60\n    │\n331 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:15\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:23\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:18\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:26\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:24\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:32\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:47\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:55\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:445:34\n    │\n445 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:449:9\n    │\n449 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:491:9\n    │\n491 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-eth]: uncapped ETH transfer can be reentered before `owedTotal` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:521:17\n    │\n521 │                 emit PayFailed(to[i], pay);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:9\n    │\n524 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:551:9\n    │\n551 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:561:9\n    │\n561 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:17\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:579:29\n    │\n579 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:588:17\n    │\n588 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:580:17\n    │\n580 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:581:34\n    │\n581 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:582:36\n    │\n582 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:585:17\n    │\n585 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:587:17\n    │\n587 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:581:73\n    │\n581 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:582:36\n    │\n582 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:583:32\n    │\n583 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:583:40\n    │\n583 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:27\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:35\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:587:17\n    │\n587 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:66\n    │\n596 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:25\n    │\n597 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:33\n    │\n597 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:23\n    │\n598 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:31\n    │\n598 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:600:9\n    │\n600 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:608:16\n    │\n608 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":273,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[PASS] test_TheWholeLaunchOnRobinhood() (gas: 2548)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 402.17µs (21.12µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 16395758)\nLogs:\n  factory deployment gas: 7907314\n  factory deployment gas: 7907326\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.42ms (1.23ms CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 13 tests for test/LaunchReview.t.sol:LaunchReviewTest\n[PASS] test_AnEngineThatCantSayIsReplaceable() (gas: 1593001)\n[PASS] test_BurnOnADeepPoolSpendsTheCap() (gas: 3448510)\n[PASS] test_BurnOnAThinPoolCantBeSandwiched() (gas: 7318465)\nLogs:\n  attacker ETH after: 9.999980484383658601\n  attacker ETH after: 9.999961676952453405\n  attacker ETH after: 9.999892159036747908\n  attacker ETH after: 9.999690438057248353\n\n[PASS] test_LowerFeeMovesAllOfItRightAfterCollect() (gas: 12273281)\n[PASS] test_LowerFeeMovesAllOfItWithOneWeiOfEthInThePosition() (gas: 6054005)\n[PASS] test_NoUnwiringWhilePerpsAreOpen() (gas: 2149413)\n[PASS] test_RecoverEthCancelsTheBooksOnlyWhenItReachesThem() (gas: 1920557)\n[PASS] test_RefusedShareIsBookedNotResplit() (gas: 2268774)\n[PASS] test_ReleasesToThisContractStayAccounted() (gas: 1438920)\n[PASS] test_TheOwnerCantRenounce() (gas: 64428)\n[PASS] test_TheSaleIsNotBrokenByANonRefundingEnginesLiquidation() (gas: 2841459)\n[PASS] test_TheSaleStaysFeeFreeWithARefundingEngineArmed() (gas: 3850496)\n[PASS] test_TooLowAnOpeningPriceIsBadPrice() (gas: 765269)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 92.35ms (28.60ms CPU time)\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2998158)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1277081)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1478960)\n[PASS] test_ClaimsOneForOne() (gas: 1602079)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208607)\n[PASS] test_DeploysOnAFreshChain() (gas: 2338377)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 10970310)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2344984)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599549457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1318351)\n[PASS] test_FitsOneTransaction() (gas: 10949030)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1297438\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1866361)\nLogs:\n  pot bridge: 0.511887599999999100\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1448391)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1326376)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1318005)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2212818)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1976274)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288387119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2092476)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2016712)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1982731)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1318355)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 67989)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91539)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117785)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1821743)\n[PASS] test_PassesTheAdmissionScan() (gas: 15443819)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1469145)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702296)\n[PASS] test_RefusesTheWrongAddress() (gas: 709787)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1293055)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214715)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1819855)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1251542)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1314902)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2684559)\n[PASS] test_TheFeeIsStatic() (gas: 1600951)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 19092109)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1363164)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2173355)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2334808)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2126315)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1669297)\n[PASS] test_TradesBothWays() (gas: 1573541)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 153.52ms (124.19ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1810879, ~: 1823120)\nLogs:\n  Bound result 19754553640120697850475709\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4379346)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3634031)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4456237)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1908035)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2209882)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2808074)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3822164)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4597983)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1808177)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3675113)\n[PASS] test_SingleBurnSandwichControl() (gas: 4218644)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3734644)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 154.31ms (73.91ms CPU time)\n\nRan 5 test suites in 155.79ms (402.01ms CPU time): 72 tests passed, 0 failed, 0 skipped (72 total tests)\n","passed":true},{"durationMs":56,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":177,\"README.md\":146,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":238,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":262,\"src/IMD6900LockedPool.sol\":368,\"src/IMD6900RobinhoodLaunch.sol\":620,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":1033,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":412,\"test/LaunchReview.t.sol\":458,\"test/RobinhoodFork.t.sol\":217},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":8638,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/IMD6900RobinhoodLaunch.sol:498: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#498-525) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/IMD6900LockedPool.sol:337: IMD6900LockedPool._payOutHeld() (src/IMD6900LockedPool.sol#337-349) sends eth to arbitrary user\n[high/medium] reentrancy-eth at src/IMD6900RobinhoodLaunch.sol:498: Reentrancy in IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#498-525):\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:498: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#498-525) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:301: IMD6900RobinhoodLaunch.withdrawEth(address,uint256) (src/IMD6900RobinhoodLaunch.sol#301-307) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:498: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#498-525) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:315: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#315-345) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:394: IMD6900RobinhoodLaunch.recoverEth(address,uint256) (src/IMD6900RobinhoodLaunch.sol#394-408) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/IMD6900RobinhoodLaunch.sol:203: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#203-218):\n[medium/medium] reentrancy-no-eth at src/IMD6900RobinhoodLaunch.sol:440: Reentrancy in IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address) (src/IMD6900RobinhoodLaunch.sol#440-450):\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:380: IMD6900RobinhoodLaunch.setPayees(address[],uint16[]).sum (src/IMD6900RobinhoodLaunch.sol#380) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:578: IMD6900RobinhoodLaunch.unlockCallback(bytes).sold (src/IMD6900RobinhoodLaunch.sol#578) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:577: IMD6900RobinhoodLaunch.unlockCallback(bytes).ethOut (src/IMD6900RobinhoodLaunch.sol#577) is a local variable never initialized\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:303: IMD6900LockedPool._settle(int128,int128) (src/IMD6900LockedPool.sol#303-314) ignores return value by poolManager.settle{value: uint256(uint128(- a0))}() (src/IMD6900LockedPool.sol#305)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:162: IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#162-181) ignores return value by poolManager.initialize(poolKey(),sqrtPriceX96) (src/IMD6900LockedPool.sol#176)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:315: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#315-345) ignores return value by pool.open(t,sqrtPriceX96,SUPPLY) (src/IMD6900RobinhoodLaunch.sol#330)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:560: IMD6900RobinhoodLaunch.harvest() (src/IMD6900RobinhoodLaunch.sol#560-563) ignores return value by pool.collect() (src/IMD6900RobinhoodLaunch.sol#561)\n[medium/medium] unused-return at src/IMD6900Hook.sol:108: IMD6900Hook.perpFeeBps() (src/IMD6900Hook.sol#108-114) ignores return value by (None,None,protocolFee,None) = StateLibrary.getSlot0(poolManager,poolId) (src/IMD6900Hook.sol#110)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:234: IMD6900LockedPool.state() (src/IMD6900LockedPool.sol#234-238) ignores return value by (sqrtPriceX96,tick,None,None) = poolManager.getSlot0(id) (src/IMD6900LockedPool.sol#236)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) ignores return value by poolManager.settle{value: ethIn}() (src/IMD6900RobinhoodLaunch.sol#600)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) ignores return value by poolManager.settle() (src/IMD6900RobinhoodLaunch.sol#587)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) ignores return value by (None,back) = pool.feeRefund(address(this)) (src/IMD6900RobinhoodLaunch.sol#582)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:303: IMD6900LockedPool._settle(int128,int128) (src/IMD6900LockedPool.sol#303-314) ignores return value by poolManager.settle() (src/IMD6900LockedPool.sol#310)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:317: IMD6900LockedPool._liquidityFor(uint256,uint256) (src/IMD6900LockedPool.sol#317-332) ignores return value by (p,None,None,None) = poolManager.getSlot0(poolKey().toId()) (src/IMD6900LockedPool.sol#318)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:193: IMD6900LockedPool.collect() (src/IMD6900LockedPool.sol#193-197) ignores return value by poolManager.unlock(abi.encode(COLLECT,uint128(0))) (src/IMD6900LockedPool.sol#195)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:162: IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#162-181) ignores return value by (sqrtPriceX96,None,None,None) = poolManager.getSlot0(old.toId()) (src/IMD6900LockedPool.sol#173)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:132: IMD6900LockedPool.open(address,uint160,uint256) (src/IMD6900LockedPool.sol#132-155) ignores return value by poolManager.initialize(poolKey(),start) (src/IMD6900LockedPool.sol#144)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:532: IMD6900RobinhoodLaunch.burnImd(uint256) (src/IMD6900RobinhoodLaunch.sol#532-552) ignores return value by (sqrtP,None,None,None) = poolManager.getSlot0(id) (src/IMD6900RobinhoodLaunch.sol#540)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:284: IMD6900LockedPool._amountsFor(uint128) (src/IMD6900LockedPool.sol#284-296) ignores return value by (p,tick,None,None) = poolManager.getSlot0(poolKey().toId()) (src/IMD6900LockedPool.sol#285)\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:189: IMD6900RobinhoodLaunch.constructor(address,IPoolManager,address,address).timelock_ (src/IMD6900RobinhoodLaunch.sol#189) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:105: IMD6900LockedPool.constructor(IPoolManager,uint24,address,address).launcher_ (src/IMD6900LockedPool.sol#105) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:105: IMD6900LockedPool.constructor(IPoolManager,uint24,address,address).timelock_ (src/IMD6900LockedPool.sol#105) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:184: IMD6900LockedPool.setCoinFeeTo(address).to (src/IMD6900LockedPool.sol#184) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:122: IMD6900LockedPool.setHook(address).hook_ (src/IMD6900LockedPool.sol#122) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:469: IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address).hooks (src/IMD6900RobinhoodLaunch.sol#469) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:132: IMD6900LockedPool.open(address,uint160,uint256).token_ (src/IMD6900LockedPool.sol#132) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900Hook.sol:81: IMD6900Hook.constructor(IPoolManager,address,address).pool_ (src/IMD6900Hook.sol#81) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:189: IMD6900RobinhoodLaunch.constructor(address,IPoolManager,address,address).imdstr_ (src/IMD6900RobinhoodLaunch.sol#189) lacks a zero-check on :\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) has external calls inside a loop: poolManager.settle() (src/IMD6900RobinhoodLaunch.sol#587)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:498: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#498-525) has external calls inside a loop: (ok,None) = to[i].call{value: pay}() (src/IMD6900RobinhoodLaunch.sol#512)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) has external calls inside a loop: s = poolManager.swap(k,SwapParams(false,- int256(left),TickMath.MAX_SQRT_PRICE - 1),) (src/IMD6900RobinhoodLaunch.sol#581)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) has external calls inside a loop: (None,back) = pool.feeRefund(address(this)) (src/IMD6900RobinhoodLaunch.sol#582)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) has external calls inside a loop: pool.feeCheckpoint() (src/IMD6900RobinhoodLaunch.sol#580)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:498: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#498-525) has external calls inside a loop: (ok,None) = to[i].call{value: pay}() (src/IMD6900RobinhoodLaunch.sol#512)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:569: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#569-603) has external calls inside a loop: poolManager.sync(k.currency1) (src/IMD6900RobinhoodLaunch.sol#585)\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:315: Reentrancy in IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#315-345):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:532: Reentrancy in IMD6900RobinhoodLaunch.burnImd(uint256) (src/IMD6900RobinhoodLaunch.sol#532-552):\n[low/medium] reentrancy-benign at src/IMD6900LockedPool.sol:162: Reentrancy in IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#162-181):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:315: Reentrancy in IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#315-345):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:203: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#203-218):\n[low/medium] reentrancy-benign at src/IMD6900LockedPool.sol:132: Reentrancy in IMD6900LockedPool.open(address,uint160,uint256) (src/IMD6900LockedPool.sol#132-155):\n[low/medium] reentrancy-events at src/IMD6900RobinhoodLaunch.sol:203: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#203-218):\n[low/medium] reentrancy-events at src/IMD6900LockedPool.sol:221: Reentrancy in IMD6900LockedPool.feeRefund(address) (src/IMD6900LockedPool.sol#221-231):\n[low/medium] reentrancy-events at src/IMD6900RobinhoodLaunch.sol:560: Reentrancy in IMD6900RobinhoodLaunch.harvest() (src/IMD6900RobinhoodLaunch.sol#560-563):\n[low/medium] return-bomb at src/IMD6900Hook.sol:227: IMD6900Hook._sweep(address,int256,bool,uint160) (src/IMD6900Hook.sol#227-254) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] return-bomb at src/IMD6900Hook.sol:257: IMD6900Hook._openPositions(address) (src/IMD6900Hook.sol#257-261) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] timestamp at src/IMD6900RobinhoodLaunch.sol:349: IMD6900RobinhoodLaunch.releaseUnclaimed(address) (src/IMD6900RobinhoodLaunch.sol#349-361) uses timestamp for comparisons\n[low/medium] timestamp at src/IMD6900RobinhoodLaunch.sol:315: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#315-345) uses timestamp for comparisons","passed":true},{"durationMs":676,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/IMD6900RobinhoodLaunch.sol:248: `abi.encodePacked()` Hash Collision (3 places)\n[high] contract-locks-ether at src/IMD6900Hook.sol:42: Contract locks Ether without a withdraw function (2 places)\n[high] reentrancy-state-change at src/IMD6900LockedPool.sol:144: Reentrancy: State change after external call (11 places)\n[low] centralization-risk at src/IMD6900Hook.sol:42: Centralization Risk (12 places)\n[low] costly-loop at src/IMD6900RobinhoodLaunch.sol:381: Costly operations inside loop (2 places)\n[low] large-numeric-literal at src/IMD6900.sol:11: Large Numeric Literal (8 places)\n[low] literal-instead-of-constant at src/IMD6900Hook.sol:109: Literal Instead of Constant (12 places)\n[low] non-reentrant-not-first at src/IMD6900RobinhoodLaunch.sol:301: `nonReentrant` is Not the First Modifier (4 places)\n[low] push-zero-opcode at src/IMD6900.sol:2: PUSH0 Opcode (4 places)\n[low] require-revert-in-loop at src/IMD6900RobinhoodLaunch.sol:381: Loop Contains `require`/`revert`\n[low] state-no-address-check at src/IMD6900LockedPool.sol:125: Address State Variable Set Without Checks (4 places)\n[low] unchecked-return at src/IMD6900LockedPool.sol:144: Unchecked Return (9 places)\n[low] uninitialized-local-variable at src/IMD6900RobinhoodLaunch.sol:579: Uninitialized Local Variable (2 places)\n[low] unspecific-solidity-pragma at src/IMD6900.sol:2: Unspecific Solidity Pragma (4 places)\n[low] unused-public-function at src/IMD6900Hook.sol:108: Public Function Not Used Internally (3 places)","passed":true},{"durationMs":12403,"exitCode":0,"name":"proof 4891b788d800","output":"Compiling 82 files with Solc 0.8.26\nSolc 0.8.26 finished in 11.51s\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-86ee84e5/Proof_4891b788d800.t.sol:67:49:\n   |\n67 |     function _hookSalt() internal view returns (bytes32) {\n   |                                                 ^^^^^^^\n\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-86ee84e5/Proof_4891b788d800.t.sol:78:49:\n   |\n78 |     function _coinSalt() internal view returns (bytes32) {\n   |                                                 ^^^^^^^\n\n\nRan 1 test for test/imd-proof-86ee84e5/Proof_4891b788d800.t.sol:SplitRefusedShareTest\n[PASS] test_RefusedShareIsNotResplitToOtherPayees() (gas: 475053)\nLogs:\n  burn bucket after ten splits: 0.100000000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 237.39ms (153.28µs CPU time)\n\nRan 1 test suite in 238.17ms (237.39ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true},{"durationMs":12098,"exitCode":0,"name":"proof 959b71d4fb20","output":"2026-10-13T11:04:09.241094Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-kkfCO9/repo/test/imd-proof-86ee84e5/Proof_4891b788d800.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 11.32s\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-2fecd4d6/Proof_959b71d4fb20.t.sol:126:49:\n    |\n126 |     function _hookSalt() internal view returns (bytes32) {\n    |                                                 ^^^^^^^\n\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-2fecd4d6/Proof_959b71d4fb20.t.sol:135:49:\n    |\n135 |     function _coinSalt() internal view returns (bytes32) {\n    |                                                 ^^^^^^^\n\n\nRan 1 test for test/imd-proof-2fecd4d6/Proof_959b71d4fb20.t.sol:LowerFeeNearTopTest\n[PASS] test_LowerFeeBurnsAThirdOfThePositionWhenOneWeiOfEthIsLeft() (gas: 4436484)\nLogs:\n  liquidity before: 138788983920567460422827\n  liquidity after : 138788983920567460422827\n  IMD6900 paid out of the position by the move (to coinFeeTo): 0.000000000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 126.34ms (2.78ms CPU time)\n\nRan 1 test suite in 127.09ms (126.34ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true},{"durationMs":12439,"exitCode":0,"name":"proof a8a1088f7ba1","output":"2026-10-13T11:04:21.368982Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-kkfCO9/repo/test/imd-proof-2fecd4d6/Proof_959b71d4fb20.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 11.55s\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-a550b693/Proof_a8a1088f7ba1.t.sol:127:49:\n    |\n127 |     function _hookSalt() internal view returns (bytes32) {\n    |                                                 ^^^^^^^\n\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-a550b693/Proof_a8a1088f7ba1.t.sol:138:49:\n    |\n138 |     function _coinSalt() internal view returns (bytes32) {\n    |                                                 ^^^^^^^\n\n\nRan 1 test for test/imd-proof-a550b693/Proof_a8a1088f7ba1.t.sol:NestedRefundTest\n[PASS] test_SaleStaysFeeFreeWhenTheSweepLiquidates() (gas: 559547)\nLogs:\n  coins of the sale's fee that were not refunded: 0.000000000000000000\n  4.44% of the sale: 2716114.297381638809234298\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 234.26ms (615.82µs CPU time)\n\nRan 1 test suite in 235.23ms (234.26ms 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":"5dc87eb5665dc4e7ed1d7074157c3f16f90ecf66c80a0a32ac12a5ba8b781f95","verifiedTreeHash":"d48f55b5340f44deff93803fece5608743ed0c65","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":75941,"exitCode":0,"name":"build","output":"Compiling 91 files with Solc 0.8.26\nSolc 0.8.26 finished in 75.76s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:81:44\n   │\n81 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:57\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:76\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:294:9\n    │\n294 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:128:28\n    │\n128 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:135:9\n    │\n135 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:141:9\n    │\n141 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:146:9\n    │\n146 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:188:77\n    │\n188 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:188:60\n    │\n188 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:212:9\n    │\n212 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:215:9\n    │\n215 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:236:9\n    │\n236 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:237:9\n    │\n237 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:247:27\n    │\n247 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:122:22\n    │\n122 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:255:26\n    │\n255 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:295:9\n    │\n295 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:304:9\n    │\n304 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:300:73\n    │\n300 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:318:9\n    │\n318 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:322:32\n    │\n322 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:343:9\n    │\n343 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:329:9\n    │\n329 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:348:62\n    │\n348 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:350:13\n    │\n350 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:359:9\n    │\n359 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:132:19\n    │\n132 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:363:75\n    │\n363 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:154:9\n    │\n154 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:368:9\n    │\n368 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:144:9\n    │\n144 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:149:15\n    │\n149 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:233:43\n    │\n233 │               (bool ok, bytes memory out) = engine.call{gas: g - reserve}(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n234 │ ┃                 abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit))\n235 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:258:39\n    │\n258 │         (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpSweep.openCount, ()));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:348:9\n    │\n348 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:180:9\n    │\n180 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:169:43\n    │\n169 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:176:9\n    │\n176 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:184:27\n    │\n184 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:195:9\n    │\n195 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:230:9\n    │\n230 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:385:13\n    │\n385 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:393:29\n    │\n393 │             for (uint256 j; j < n && !kept; ++j) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:393:39\n    │\n393 │             for (uint256 j; j < n && !kept; ++j) {\n    │                                       ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:383:38\n    │\n383 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:388:23\n    │\n388 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:415:17\n    │\n415 │                 emit OwedCancelled(owedTotal);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:420:9\n    │\n420 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:23\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:31\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:25\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:33\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:305:21\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:47\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:55\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:73\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:81\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:71\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:79\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:310:13\n    │\n310 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:60\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:68\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:331:60\n    │\n331 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:15\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:23\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:18\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:26\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:24\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:32\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:47\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:55\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:433:9\n    │\n433 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:458:34\n    │\n458 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:462:9\n    │\n462 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:474:27\n    │\n474 │     function setImdKeeper(address keeper) external {\n    │                           ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:511:9\n    │\n511 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-eth]: uncapped ETH transfer can be reentered before `owedTotal` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:541:17\n    │\n541 │                 emit PayFailed(to[i], pay);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:544:9\n    │\n544 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:565:9\n    │\n565 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:575:9\n    │\n575 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:17\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:602:17\n    │\n602 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:593:29\n    │\n593 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:594:17\n    │\n594 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:595:34\n    │\n595 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:36\n    │\n596 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:599:17\n    │\n599 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:601:17\n    │\n601 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:595:73\n    │\n595 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:36\n    │\n596 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:32\n    │\n597 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:40\n    │\n597 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:27\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:35\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:601:17\n    │\n601 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:610:66\n    │\n610 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:611:25\n    │\n611 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:611:33\n    │\n611 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:612:23\n    │\n612 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:612:31\n    │\n612 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:614:9\n    │\n614 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:622:16\n    │\n622 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":12293,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[SKIP] test_TheWholeLaunchOnRobinhood() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 336.24µs (42.09µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 16409170)\nLogs:\n  factory deployment gas: 7913684\n  factory deployment gas: 7913696\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.41ms (1.20ms CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 9 tests for test/LaunchFailures.t.sol:LaunchPreconditionTest\n[PASS] test_ClaimsRootAndTotalMustAgreeAndRejectionPreservesOldList() (gas: 100729)\n[PASS] test_MinimumBuyFailureRollsBackEthCoinAndPool() (gas: 2312174)\n[PASS] test_OneSecondShortClaimWindowRollsBackAndCanRetry() (gas: 1416848)\n[PASS] test_OnlyLauncherCanWireAndOpenAndHookCannotBeReplaced() (gas: 118765)\n[PASS] test_OperationsBeforeLaunchRejectWithoutMovingFunds() (gas: 484852)\n[PASS] test_PoolRejectsInvalidAndCollapsedPriceRanges() (gas: 130263)\n[PASS] test_PoolRejectsZeroLiquidityAtomically() (gas: 203316)\n[PASS] test_WithdrawFailureAndZeroBalanceAreAtomic() (gas: 337073)\n[PASS] test_ZeroEthLaunchRevertsAllCreationAndLiquidity() (gas: 2209265)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 75.84ms (3.09ms CPU time)\n\nRan 15 tests for test/LaunchReview.t.sol:LaunchReviewTest\n[PASS] test_AnEngineThatCantSayIsReplaceable() (gas: 1593177)\n[PASS] test_LowerFeeMovesAllOfItRightAfterCollect() (gas: 12273435)\n[PASS] test_LowerFeeMovesAllOfItWithOneWeiOfEthInThePosition() (gas: 6054159)\n[PASS] test_NoUnwiringWhilePerpsAreOpen() (gas: 2149567)\n[PASS] test_RecoverEthCancelsTheBooksOnlyWhenItReachesThem() (gas: 1931239)\n[PASS] test_RefusedShareIsBookedNotResplit() (gas: 2610193)\n[PASS] test_ReleasesToThisContractStayAccounted() (gas: 1439448)\n[PASS] test_SetPayeesCancelsTheBooksOfThoseItDrops() (gas: 1913089)\n[PASS] test_SplitPaysTheBooksAlone() (gas: 1753875)\n[PASS] test_TheBurnIsTheKeepersAtItsOwnFloor() (gas: 8436196)\n[PASS] test_TheOwnerCantRenounce() (gas: 64582)\n[PASS] test_TheSaleIsNotBrokenByANonRefundingEnginesLiquidation() (gas: 2841851)\n[PASS] test_TheSaleStaysFeeFreeWithARefundingEngineArmed() (gas: 3850866)\n[PASS] test_TheTimelockNamesTheKeeper() (gas: 3716792)\n[PASS] test_TooLowAnOpeningPriceIsBadPrice() (gas: 765401)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 121.89ms (25.38ms CPU time)\n\nRan 14 tests for test/HookFailures.t.sol:HookFailureTest\n[PASS] testFuzz_RefundedPerpQuoteRoundsWorstProtocolDirectionUp(uint16,uint16) (runs: 1000, μ: 159084, ~: 159110)\nLogs:\n  Bound result 710\n  Bound result 1000\n\n[PASS] test_AfterSweepIsBestEffortForEveryFailureModeAndLowGas() (gas: 493329)\n[PASS] test_AllEnabledCallbacksRejectSpoofedPoolManager() (gas: 158572)\n[PASS] test_EngineOwnSwapBypassesSweepEvenWhenSweepIsBroken() (gas: 222709)\n[PASS] test_FailedRealTradeRollsBackAndWorksAfterEngineRepair() (gas: 847682)\n[PASS] test_FeeMoveRefusesMalformedOrUnavailablePositionCountAtomically() (gas: 1130765)\n[PASS] test_FormerPoolCannotTradeAfterFeeMove() (gas: 757005)\n[PASS] test_InitializeRejectsImpostorAndMismatchedKeyFields() (gas: 355947)\n[PASS] test_LiquidityCallbacksRejectOtherOwnersAndWrongRanges() (gas: 143760)\n[PASS] test_LowGasChecksPositionsInsteadOfTradingBlind() (gas: 680823)\n[PASS] test_OnlyTimelockMayEnableSweepEscapeHatch() (gas: 75145)\n[PASS] test_PreSweepReceivesTradeAndOriginAndReturnsNoDeltas() (gas: 199077)\n[PASS] test_ReportedUnsafeTradeCannotBypassSweepWithFailOpen() (gas: 632342)\n[PASS] test_UnavailableAndMalformedSweepsFailClosedUnlessTimelockOptsIn() (gas: 481397)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 128.64ms (61.34ms CPU time)\n\nRan 10 tests for test/LaunchFailures.t.sol:LaunchFeeFailureTest\n[PASS] testFuzz_DefaultSplitConservesEthAndNeverResplitsBurnReserve(uint256) (runs: 1000, μ: 183940, ~: 188040)\nLogs:\n  Bound result 4761\n\n[PASS] test_DuplicateRefusingPayeeBooksEveryPartExactlyOnce() (gas: 1202645)\n[PASS] test_ListChangesWithoutDropsLeaveTheBooksAlone() (gas: 605652)\n[PASS] test_MalformedPayeesNeverReplaceTheWorkingSplit() (gas: 506067)\n[PASS] test_PerpFeesRejectBadDestinationsAndReturnFundsIfReceiverRefuses() (gas: 266160)\n[PASS] test_RecoveryClampsBurnBucketAndFailedRecoveryDoesNot() (gas: 444023)\n[PASS] test_RefusingPayeeLeavesEthRecoverableWithoutBlockingOthers() (gas: 424957)\n[PASS] test_RemovedPayeesBooksAreCancelledAndResplitKeptOnesAreNot() (gas: 836812)\n[PASS] test_SplitDustEdgesZeroOneAndTenWei() (gas: 250414)\n[PASS] test_SplitReceiverCannotReenterAndDoubleSpend() (gas: 602631)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 129.94ms (62.09ms CPU time)\n\nRan 11 tests for test/LaunchFailures.t.sol:LaunchCustodyFailureTest\n[PASS] testFuzz_ClaimPartitionExchangesExactlyOneForOne(uint256,uint8) (runs: 1000, μ: 399482, ~: 401466)\nLogs:\n  Bound result 23398\n\n[PASS] test_AllTimelockCustodyFunctionsRejectTeamAndStrangers() (gas: 613988)\n[PASS] test_ClaimZeroAndMaximumCannotConsumeReserve() (gas: 326835)\n[PASS] test_DeadlineBoundaryAndClaimClosureCannotReopen() (gas: 500137)\n[PASS] test_FailedOldTokenTransferDoesNotConsumeClaim() (gas: 596934)\n[PASS] test_LegacyReleaseChecksCustodyAndCannotSpendNewCoins() (gas: 391065)\n[PASS] test_OwnerFunctionsRejectTimelockAndStrangers() (gas: 244144)\n[PASS] test_ProofCannotBeReusedByAnotherAccountOrForAnotherAllocation() (gas: 144864)\n[PASS] test_RawCallbacksCannotBeSpoofed() (gas: 286203)\n[PASS] test_ReleaseExcessBurnsOnlyExcessAndRejectsOverdraw() (gas: 364344)\n[PASS] test_SellSlippageAndRefusingRecipientRollBackSwapAndRefund() (gas: 1632777)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 209.78ms (131.31ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1809759, ~: 1823692)\nLogs:\n  Bound result 20000000000000000000000000\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4364978)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3692614)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4471466)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1908695)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2210714)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2809206)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3822515)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4597715)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1808705)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3673932)\n[PASS] test_SingleBurnSandwichControl() (gas: 4218131)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3735515)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 234.09ms (154.44ms CPU time)\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 3000450)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1277301)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1479224)\n[PASS] test_ClaimsOneForOne() (gas: 1602431)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208739)\n[PASS] test_DeploysOnAFreshChain() (gas: 2338795)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 10970618)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2355811)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599549457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1318615)\n[PASS] test_FitsOneTransaction() (gas: 10949162)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1297482\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1866715)\nLogs:\n  pot bridge: 0.511887599999999100\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1448787)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1326684)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1318269)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2213038)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1986837)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288387119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2092674)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2016888)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 179032)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1982929)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1318619)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 68121)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91759)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117785)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1832242)\n[PASS] test_PassesTheAdmissionScan() (gas: 15409943)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1469541)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702428)\n[PASS] test_RefusesTheWrongAddress() (gas: 709963)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1293275)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214891)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1820053)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1251718)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1315078)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2684757)\n[PASS] test_TheFeeIsStatic() (gas: 1601281)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 19092505)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1363340)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21900)\n[PASS] test_TheLiquidityIsLocked() (gas: 2173553)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2335006)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2127011)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1669649)\n[PASS] test_TradesBothWays() (gas: 1573717)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 265.92ms (97.38ms CPU time)\n\nRan 5 tests for test/PoolProperties.t.sol:LockedPoolPropertyTest\n[PASS] testFuzz_FeeMigrationPreservesPriceAndPrincipalAcrossBothTradeDirections(uint24,uint256) (runs: 1000, μ: 2402524, ~: 2409285)\nLogs:\n  Bound result 23568\n  Bound result 9990000000000003576\n\n[PASS] testFuzz_OpeningLocksSupplyAsCoinOnlyAndFloorsOntoTick(int24) (runs: 1000, μ: 573668, ~: 574211)\nLogs:\n  Bound result 54057\n\n[PASS] testFuzz_OrdinaryBuySellRoundTripCannotCreateEth(uint256) (runs: 1000, μ: 1534876, ~: 1535597)\nLogs:\n  Bound result 3374607431768211455\n\n[PASS] test_MoveWithFeesBelowTheMarginKeepsThemAll() (gas: 1941737)\n[PASS] test_StandaloneCreationAndRuntimeOpcodesMeetAdmissionRule() (gas: 133616076)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 271.58ms (775.17ms CPU time)\n\nRan 5 tests for test/PoolProperties.t.sol:RefundProtocolTest\n[PASS] testFuzz_RefundIsOnlyThisTradeAndOrdinaryFeesRemainCollectible(uint256) (runs: 1000, μ: 647653, ~: 648987)\nLogs:\n  Bound result 4999999999999999998\n\n[PASS] test_CheckpointCannotBeUsedByAnotherCaller() (gas: 425113)\n[PASS] test_CheckpointRequiresUnlockedManagerAndLiveAuthorization() (gas: 121046)\n[PASS] test_CheckpointWithoutSwapCannotTakePreviousTradersFees() (gas: 494872)\n[PASS] test_RefundCannotBeReplayedAndFailedReplayRollsBackSwap() (gas: 704540)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 274.69ms (212.35ms CPU time)\n\nRan 2 tests for test/LaunchInvariant.t.sol:LaunchInvariantTest\n[PASS]\nLaunchInvariantTest invariants:\n[PASS] invariant_BurnIsTheKeepersAlone\n[PASS] invariant_ClaimsAndHeldCoinsStayFullyBacked\n[PASS] invariant_LiquidityStaysLockedAndRetiredPoolsStayEmpty\n[PASS] invariant_RefusedSharesStayBookedAndBacked\n[PASS] invariant_ValueIsConservedAndOnlyExplicitBurnsReduceSupply\n LaunchInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭-----------------------+-------------------+-------+---------+----------╮\n| Contract              | Selector          | Calls | Reverts | Discards |\n+========================================================================+\n| LaunchSequenceHandler | advance           | 837   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | burnCoin          | 807   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | burnImd           | 827   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | claim             | 1631  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | closeClaims       | 838   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | collect           | 855   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | configureCoinFees | 791   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | configurePayees   | 864   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | donateCoin        | 804   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | donateEth         | 795   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | lowerFee          | 828   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | perpFees          | 866   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | recoverEth        | 785   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | refundedTrade     | 835   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | rejectedCalls     | 782   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | releaseExcess     | 801   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | releaseLegacy     | 843   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | sellHeld          | 845   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | setKeeper         | 822   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | split             | 854   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | splitChecked      | 825   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | toggleRefusal     | 821   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | trade             | 748   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | transferCoin      | 776   | 0       | 0        |\n╰-----------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 467588\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 950537298\n  Bound result 0\n  Bound result 2721\n  Bound result 2000\n  Bound result 233\n  Bound result 20082\n  Bound result 60856431499502606286282828\n  Bound result 2318578\n  Bound result 2541\n  Bound result 8640000\n  Bound result 1675\n  Bound result 752\n  Bound result 14648\n  Bound result 0\n  Bound result 22221\n  Bound result 11808\n  Bound result 308\n  Bound result 39753769861542376334320054\n  Bound result 4739843575181921340447190\n  Bound result 13623\n  Bound result 0\n  Bound result 0\n  Bound result 9855\n  Bound result 0\n  Bound result 2061\n  Bound result 19400000000000000000\n  Bound result 19083\n  Bound result 100000000000\n  Bound result 8944\n\n[PASS] test_HandlerExercisesMixedCustodySequence() (gas: 7253247)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 2000000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 33300\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1450000000000000001\n  Bound result 1000000000000000000\n  Bound result 50000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 12.18s (12.10s CPU time)\n\nRan 12 test suites in 12.18s (13.89s CPU time): 129 tests passed, 0 failed, 1 skipped (130 total tests)\n","passed":true},{"durationMs":73,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdKeeper(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":228,\"README.md\":148,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":239,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":262,\"src/IMD6900LockedPool.sol\":368,\"src/IMD6900RobinhoodLaunch.sol\":634,\"test/HookFailures.t.sol\":309,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":1034,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":418,\"test/LaunchFailures.t.sol\":650,\"test/LaunchInvariant.t.sol\":831,\"test/LaunchReview.t.sol\":596,\"test/PoolProperties.t.sol\":297,\"test/RobinhoodFork.t.sol\":241,\"test/TESTING.md\":53,\"test/helpers/LaunchFixture.sol\":142},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"648dd7a3cd2af045ebccf652bbfeb9a1f3ee6dfc326bac035ca0b01fabdf3e18","verifiedTreeHash":"a228287cbc65e5b422cac369fe76bfa7c2d54398","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":68715,"exitCode":0,"name":"build","output":"Compiling 91 files with Solc 0.8.26\nSolc 0.8.26 finished in 68.54s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:81:44\n   │\n81 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:295:9\n    │\n295 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:57\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:76\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:128:28\n    │\n128 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:189:77\n    │\n189 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:135:9\n    │\n135 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:189:60\n    │\n189 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:141:9\n    │\n141 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:146:9\n    │\n146 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:213:9\n    │\n213 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:216:9\n    │\n216 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:237:9\n    │\n237 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:238:9\n    │\n238 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:248:27\n    │\n248 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:256:26\n    │\n256 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:296:9\n    │\n296 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:301:73\n    │\n301 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:306:9\n    │\n306 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:319:9\n    │\n319 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:323:32\n    │\n323 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:344:9\n    │\n344 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:330:9\n    │\n330 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:349:62\n    │\n349 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:351:13\n    │\n351 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:360:9\n    │\n360 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:364:75\n    │\n364 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:369:9\n    │\n369 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:122:22\n    │\n122 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:132:19\n    │\n132 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:154:9\n    │\n154 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:144:9\n    │\n144 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:149:15\n    │\n149 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:384:13\n    │\n384 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:382:38\n    │\n382 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:387:23\n    │\n387 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:233:43\n    │\n233 │               (bool ok, bytes memory out) = engine.call{gas: g - reserve}(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n234 │ ┃                 abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit))\n235 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:258:39\n    │\n258 │         (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpSweep.openCount, ()));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:348:9\n    │\n348 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:180:9\n    │\n180 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:169:43\n    │\n169 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:176:9\n    │\n176 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:402:17\n    │\n402 │                 emit OwedCancelled(owedTotal);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:407:9\n    │\n407 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:184:27\n    │\n184 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:195:9\n    │\n195 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:230:9\n    │\n230 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:420:9\n    │\n420 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:445:34\n    │\n445 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:449:9\n    │\n449 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:23\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:31\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:25\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:33\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:305:21\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:47\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:55\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:73\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:81\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:71\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:79\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:310:13\n    │\n310 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:60\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:68\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:331:60\n    │\n331 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:15\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:23\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:18\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:26\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:24\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:32\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:47\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:55\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:491:9\n    │\n491 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-eth]: uncapped ETH transfer can be reentered before `owedTotal` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:521:17\n    │\n521 │                 emit PayFailed(to[i], pay);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:9\n    │\n524 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:551:9\n    │\n551 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:561:9\n    │\n561 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:579:29\n    │\n579 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:17\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:588:17\n    │\n588 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:580:17\n    │\n580 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:581:34\n    │\n581 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:582:36\n    │\n582 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:585:17\n    │\n585 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:587:17\n    │\n587 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:581:73\n    │\n581 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:582:36\n    │\n582 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:583:32\n    │\n583 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:583:40\n    │\n583 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:27\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:35\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:587:17\n    │\n587 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:66\n    │\n596 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:25\n    │\n597 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:33\n    │\n597 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:23\n    │\n598 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:31\n    │\n598 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:600:9\n    │\n600 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:608:16\n    │\n608 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":9866,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 16395758)\nLogs:\n  factory deployment gas: 7907314\n  factory deployment gas: 7907326\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 979.04µs (842.66µs CPU time)\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[SKIP] test_TheWholeLaunchOnRobinhood() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 261.37µs (43.84µs CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 9 tests for test/LaunchFailures.t.sol:LaunchPreconditionTest\n[PASS] test_ClaimsRootAndTotalMustAgreeAndRejectionPreservesOldList() (gas: 100465)\n[PASS] test_MinimumBuyFailureRollsBackEthCoinAndPool() (gas: 2311778)\n[PASS] test_OneSecondShortClaimWindowRollsBackAndCanRetry() (gas: 1416408)\n[PASS] test_OnlyLauncherCanWireAndOpenAndHookCannotBeReplaced() (gas: 118765)\n[PASS] test_OperationsBeforeLaunchRejectWithoutMovingFunds() (gas: 357899)\n[PASS] test_PoolRejectsInvalidAndCollapsedPriceRanges() (gas: 130263)\n[PASS] test_PoolRejectsZeroLiquidityAtomically() (gas: 203316)\n[PASS] test_WithdrawFailureAndZeroBalanceAreAtomic() (gas: 336897)\n[PASS] test_ZeroEthLaunchRevertsAllCreationAndLiquidity() (gas: 2208913)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 60.38ms (3.37ms CPU time)\n\nRan 13 tests for test/LaunchReview.t.sol:LaunchReviewTest\n[PASS] test_AnEngineThatCantSayIsReplaceable() (gas: 1593001)\n[PASS] test_BurnOnADeepPoolSpendsTheCap() (gas: 3448510)\n[PASS] test_BurnOnAThinPoolCantBeSandwiched() (gas: 7318465)\nLogs:\n  attacker ETH after: 9.999980484383658601\n  attacker ETH after: 9.999961676952453405\n  attacker ETH after: 9.999892159036747908\n  attacker ETH after: 9.999690438057248353\n\n[PASS] test_LowerFeeMovesAllOfItRightAfterCollect() (gas: 12273281)\n[PASS] test_LowerFeeMovesAllOfItWithOneWeiOfEthInThePosition() (gas: 6054005)\n[PASS] test_NoUnwiringWhilePerpsAreOpen() (gas: 2149413)\n[PASS] test_RecoverEthCancelsTheBooksOnlyWhenItReachesThem() (gas: 1920557)\n[PASS] test_RefusedShareIsBookedNotResplit() (gas: 2268774)\n[PASS] test_ReleasesToThisContractStayAccounted() (gas: 1438920)\n[PASS] test_TheOwnerCantRenounce() (gas: 64428)\n[PASS] test_TheSaleIsNotBrokenByANonRefundingEnginesLiquidation() (gas: 2841459)\n[PASS] test_TheSaleStaysFeeFreeWithARefundingEngineArmed() (gas: 3850496)\n[PASS] test_TooLowAnOpeningPriceIsBadPrice() (gas: 765269)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 117.43ms (21.72ms CPU time)\n\nRan 9 tests for test/LaunchFailures.t.sol:LaunchFeeFailureTest\n[PASS] testFuzz_DefaultSplitConservesEthAndNeverResplitsBurnReserve(uint256) (runs: 1000, μ: 183669, ~: 187838)\nLogs:\n  Bound result 575761265493560529560\n\n[PASS] test_DuplicateRefusingPayeeBooksEveryPartExactlyOnce() (gas: 949181)\n[PASS] test_MalformedPayeesNeverReplaceTheWorkingSplit() (gas: 490479)\n[PASS] test_PerpFeesRejectBadDestinationsAndReturnFundsIfReceiverRefuses() (gas: 265874)\n[PASS] test_RecoveryClampsBurnBucketAndFailedRecoveryDoesNot() (gas: 443553)\n[PASS] test_RefusingPayeeLeavesEthRecoverableWithoutBlockingOthers() (gas: 414766)\n[PASS] test_RemovedPayeesBooksAreNeitherResplitNorLostUntilRecovery() (gas: 631525)\n[PASS] test_SplitDustEdgesZeroOneAndTenWei() (gas: 249958)\n[PASS] test_SplitReceiverCannotReenterAndDoubleSpend() (gas: 592416)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 141.08ms (63.07ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1808898, ~: 1823120)\nLogs:\n  Bound result 31809421143807014848388332\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4379346)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3634031)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4456237)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1908035)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2209882)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2808074)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3822164)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4597983)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1808177)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3675113)\n[PASS] test_SingleBurnSandwichControl() (gas: 4218644)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3734644)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 225.40ms (131.56ms CPU time)\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2998158)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1277081)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1478960)\n[PASS] test_ClaimsOneForOne() (gas: 1602079)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208607)\n[PASS] test_DeploysOnAFreshChain() (gas: 2338377)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 10970310)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2344984)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599549457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1318351)\n[PASS] test_FitsOneTransaction() (gas: 10949030)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1297438\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1866361)\nLogs:\n  pot bridge: 0.511887599999999100\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1448391)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1326376)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1318005)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2212818)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1976274)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288387119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2092476)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2016712)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1982731)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1318355)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 67989)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91539)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117785)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1821743)\n[PASS] test_PassesTheAdmissionScan() (gas: 15443819)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1469145)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702296)\n[PASS] test_RefusesTheWrongAddress() (gas: 709787)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1293055)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214715)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1819855)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1251542)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1314902)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2684559)\n[PASS] test_TheFeeIsStatic() (gas: 1600951)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 19092109)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1363164)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2173355)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2334808)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2126315)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1669297)\n[PASS] test_TradesBothWays() (gas: 1573541)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 235.96ms (94.33ms CPU time)\n\nRan 5 tests for test/PoolProperties.t.sol:RefundProtocolTest\n[PASS] testFuzz_RefundIsOnlyThisTradeAndOrdinaryFeesRemainCollectible(uint256) (runs: 1000, μ: 647791, ~: 648975)\nLogs:\n  Bound result 5000000000000000000\n\n[PASS] test_CheckpointCannotBeUsedByAnotherCaller() (gas: 424761)\n[PASS] test_CheckpointRequiresUnlockedManagerAndLiveAuthorization() (gas: 121046)\n[PASS] test_CheckpointWithoutSwapCannotTakePreviousTradersFees() (gas: 494850)\n[PASS] test_RefundCannotBeReplayedAndFailedReplayRollsBackSwap() (gas: 704188)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 253.95ms (195.66ms CPU time)\n\nRan 14 tests for test/HookFailures.t.sol:HookFailureTest\n[PASS] testFuzz_RefundedPerpQuoteRoundsWorstProtocolDirectionUp(uint16,uint16) (runs: 1000, μ: 159040, ~: 159110)\nLogs:\n  Bound result 23\n  Bound result 202\n\n[PASS] test_AfterSweepIsBestEffortForEveryFailureModeAndLowGas() (gas: 493329)\n[PASS] test_AllEnabledCallbacksRejectSpoofedPoolManager() (gas: 158572)\n[PASS] test_EngineOwnSwapBypassesSweepEvenWhenSweepIsBroken() (gas: 222709)\n[PASS] test_FailedRealTradeRollsBackAndWorksAfterEngineRepair() (gas: 847330)\n[PASS] test_FeeMoveRefusesMalformedOrUnavailablePositionCountAtomically() (gas: 1130039)\n[PASS] test_FormerPoolCannotTradeAfterFeeMove() (gas: 756983)\n[PASS] test_InitializeRejectsImpostorAndMismatchedKeyFields() (gas: 355947)\n[PASS] test_LiquidityCallbacksRejectOtherOwnersAndWrongRanges() (gas: 143760)\n[PASS] test_LowGasChecksPositionsInsteadOfTradingBlind() (gas: 680823)\n[PASS] test_OnlyTimelockMayEnableSweepEscapeHatch() (gas: 75145)\n[PASS] test_PreSweepReceivesTradeAndOriginAndReturnsNoDeltas() (gas: 199077)\n[PASS] test_ReportedUnsafeTradeCannotBypassSweepWithFailOpen() (gas: 632342)\n[PASS] test_UnavailableAndMalformedSweepsFailClosedUnlessTimelockOptsIn() (gas: 481397)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 296.81ms (239.60ms CPU time)\n\nRan 11 tests for test/LaunchFailures.t.sol:LaunchCustodyFailureTest\n[PASS] testFuzz_ClaimPartitionExchangesExactlyOneForOne(uint256,uint8) (runs: 1000, μ: 399322, ~: 401123)\nLogs:\n  Bound result 2\n\n[PASS] test_AllTimelockCustodyFunctionsRejectTeamAndStrangers() (gas: 613020)\n[PASS] test_ClaimZeroAndMaximumCannotConsumeReserve() (gas: 326395)\n[PASS] test_DeadlineBoundaryAndClaimClosureCannotReopen() (gas: 499697)\n[PASS] test_FailedOldTokenTransferDoesNotConsumeClaim() (gas: 596450)\n[PASS] test_LegacyReleaseChecksCustodyAndCannotSpendNewCoins() (gas: 390845)\n[PASS] test_OwnerFunctionsRejectTimelockAndStrangers() (gas: 243792)\n[PASS] test_ProofCannotBeReusedByAnotherAccountOrForAnotherAllocation() (gas: 144688)\n[PASS] test_RawCallbacksCannotBeSpoofed() (gas: 285763)\n[PASS] test_ReleaseExcessBurnsOnlyExcessAndRejectsOverdraw() (gas: 364036)\n[PASS] test_SellSlippageAndRefusingRecipientRollBackSwapAndRefund() (gas: 1631645)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 296.62ms (232.75ms CPU time)\n\nRan 5 tests for test/PoolProperties.t.sol:LockedPoolPropertyTest\n[PASS] testFuzz_FeeMigrationPreservesPriceAndPrincipalAcrossBothTradeDirections(uint24,uint256) (runs: 1000, μ: 2402487, ~: 2410339)\nLogs:\n  Bound result 5373\n  Bound result 19999999997997998\n\n[PASS] testFuzz_OpeningLocksSupplyAsCoinOnlyAndFloorsOntoTick(int24) (runs: 1000, μ: 573585, ~: 574211)\nLogs:\n  Bound result 4\n\n[PASS] testFuzz_OrdinaryBuySellRoundTripCannotCreateEth(uint256) (runs: 1000, μ: 1535502, ~: 1535453)\nLogs:\n  Bound result 11627\n\n[PASS] test_MoveWithFeesBelowTheMarginKeepsThemAll() (gas: 1941561)\n[PASS] test_StandaloneCreationAndRuntimeOpcodesMeetAdmissionRule() (gas: 133987869)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 297.81ms (851.71ms CPU time)\n\nRan 2 tests for test/LaunchInvariant.t.sol:LaunchInvariantTest\n[PASS]\nLaunchInvariantTest invariants:\n[PASS] invariant_ClaimsAndHeldCoinsStayFullyBacked\n[PASS] invariant_LiquidityStaysLockedAndRetiredPoolsStayEmpty\n[PASS] invariant_RefusedSharesStayBookedAndBacked\n[PASS] invariant_ValueIsConservedAndOnlyExplicitBurnsReduceSupply\n LaunchInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭-----------------------+-------------------+-------+---------+----------╮\n| Contract              | Selector          | Calls | Reverts | Discards |\n+========================================================================+\n| LaunchSequenceHandler | advance           | 884   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | burnCoin          | 889   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | burnImd           | 849   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | claim             | 1745  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | closeClaims       | 839   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | collect           | 863   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | configureCoinFees | 863   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | configurePayees   | 877   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | donateCoin        | 854   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | donateEth         | 789   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | lowerFee          | 892   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | perpFees          | 823   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | recoverEth        | 851   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | refundedTrade     | 850   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | rejectedCalls     | 832   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | releaseExcess     | 844   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | releaseLegacy     | 830   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | sellHeld          | 872   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | split             | 857   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | splitChecked      | 846   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | toggleRefusal     | 842   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | trade             | 840   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | transferCoin      | 849   | 0       | 0        |\n╰-----------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 8280000000187100\n  Bound result 14\n  Bound result 255\n  Bound result 8056\n  Bound result 0\n  Bound result 0\n  Bound result 785\n  Bound result 1000000000000000000\n  Bound result 136362367085612136\n  Bound result 0\n  Bound result 11406\n  Bound result 0\n  Bound result 0\n  Bound result 8655\n  Bound result 14712351196595827048142105\n  Bound result 126057421\n  Bound result 1000\n  Bound result 2971\n  Bound result 2919\n  Bound result 2000000000000000001\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1110\n  Bound result 65455030658842246913541473\n  Bound result 787\n  Bound result 3727754215\n  Bound result 0\n  Bound result 0\n  Bound result 2544\n  Bound result 29725996\n  Bound result 0\n  Bound result 0\n  Bound result 0\n\n[PASS] test_HandlerExercisesMixedCustodySequence() (gas: 5425507)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 2000000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 33300\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 900000000000000001\n  Bound result 50000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 9.74s (9.68s CPU time)\n\nRan 12 test suites in 9.74s (11.67s CPU time): 126 tests passed, 0 failed, 1 skipped (127 total tests)\n","passed":true},{"durationMs":60,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":177,\"README.md\":146,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":238,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":262,\"src/IMD6900LockedPool.sol\":368,\"src/IMD6900RobinhoodLaunch.sol\":620,\"test/HookFailures.t.sol\":309,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":1033,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":412,\"test/LaunchFailures.t.sol\":576,\"test/LaunchInvariant.t.sol\":707,\"test/LaunchReview.t.sol\":458,\"test/PoolProperties.t.sol\":297,\"test/RobinhoodFork.t.sol\":240,\"test/TESTING.md\":44,\"test/helpers/LaunchFixture.sol\":142},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"64bd8b26944cb8e80707512d06ab75fc968ebdfb8a6484b67037f772565f5e48","verifiedTreeHash":"34fda8c3f9449d762015d7c1245cc965a1dde46b","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":34724,"exitCode":0,"name":"build","output":"Compiling 86 files with Solc 0.8.26\nSolc 0.8.26 finished in 34.58s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:81:44\n   │\n81 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:57\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:294:9\n    │\n294 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:76\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:128:28\n    │\n128 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:135:9\n    │\n135 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:141:9\n    │\n141 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:146:9\n    │\n146 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:188:60\n    │\n188 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:188:77\n    │\n188 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:212:9\n    │\n212 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:215:9\n    │\n215 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:236:9\n    │\n236 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:237:9\n    │\n237 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:247:27\n    │\n247 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:255:26\n    │\n255 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:295:9\n    │\n295 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:304:9\n    │\n304 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:300:73\n    │\n300 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:122:22\n    │\n122 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:318:9\n    │\n318 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:322:32\n    │\n322 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:343:9\n    │\n343 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:329:9\n    │\n329 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:348:62\n    │\n348 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:350:13\n    │\n350 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:359:9\n    │\n359 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:363:75\n    │\n363 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:368:9\n    │\n368 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:233:43\n    │\n233 │               (bool ok, bytes memory out) = engine.call{gas: g - reserve}(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n234 │ ┃                 abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit))\n235 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:132:19\n    │\n132 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:258:39\n    │\n258 │         (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpSweep.openCount, ()));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:154:9\n    │\n154 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:144:9\n    │\n144 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:149:15\n    │\n149 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:348:9\n    │\n348 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:180:9\n    │\n180 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:169:43\n    │\n169 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:176:9\n    │\n176 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:393:29\n    │\n393 │             for (uint256 j; j < n && !kept; ++j) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:393:39\n    │\n393 │             for (uint256 j; j < n && !kept; ++j) {\n    │                                       ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:385:13\n    │\n385 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:383:38\n    │\n383 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:388:23\n    │\n388 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:184:27\n    │\n184 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:195:9\n    │\n195 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:230:9\n    │\n230 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:415:17\n    │\n415 │                 emit OwedCancelled(owedTotal);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:420:9\n    │\n420 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:23\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:31\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:25\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:33\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:305:21\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:47\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:55\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:73\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:81\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:71\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:79\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:310:13\n    │\n310 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:60\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:68\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:433:9\n    │\n433 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:331:60\n    │\n331 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:15\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:23\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:18\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:26\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:24\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:32\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:47\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:55\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:458:34\n    │\n458 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:462:9\n    │\n462 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:474:27\n    │\n474 │     function setImdKeeper(address keeper) external {\n    │                           ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:511:9\n    │\n511 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-eth]: uncapped ETH transfer can be reentered before `owedTotal` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:532:26\n    │\n532 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:541:17\n    │\n541 │                 emit PayFailed(to[i], pay);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:544:9\n    │\n544 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:565:9\n    │\n565 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:575:9\n    │\n575 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:17\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:593:29\n    │\n593 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:602:17\n    │\n602 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:594:17\n    │\n594 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:595:34\n    │\n595 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:36\n    │\n596 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:599:17\n    │\n599 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:601:17\n    │\n601 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:595:73\n    │\n595 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:36\n    │\n596 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:32\n    │\n597 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:40\n    │\n597 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:27\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:35\n    │\n598 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:601:17\n    │\n601 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:610:66\n    │\n610 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:611:25\n    │\n611 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:611:33\n    │\n611 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:612:23\n    │\n612 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:612:31\n    │\n612 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:614:9\n    │\n614 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:622:16\n    │\n622 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":213,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[PASS] test_TheWholeLaunchOnRobinhood() (gas: 2548)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 266.14µs (17.82µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 16409170)\nLogs:\n  factory deployment gas: 7913684\n  factory deployment gas: 7913696\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.01ms (863.48µs CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 15 tests for test/LaunchReview.t.sol:LaunchReviewTest\n[PASS] test_AnEngineThatCantSayIsReplaceable() (gas: 1593177)\n[PASS] test_LowerFeeMovesAllOfItRightAfterCollect() (gas: 12273435)\n[PASS] test_LowerFeeMovesAllOfItWithOneWeiOfEthInThePosition() (gas: 6054159)\n[PASS] test_NoUnwiringWhilePerpsAreOpen() (gas: 2149567)\n[PASS] test_RecoverEthCancelsTheBooksOnlyWhenItReachesThem() (gas: 1931239)\n[PASS] test_RefusedShareIsBookedNotResplit() (gas: 2610193)\n[PASS] test_ReleasesToThisContractStayAccounted() (gas: 1439448)\n[PASS] test_SetPayeesCancelsTheBooksOfThoseItDrops() (gas: 1913089)\n[PASS] test_SplitPaysTheBooksAlone() (gas: 1753875)\n[PASS] test_TheBurnIsTheKeepersAtItsOwnFloor() (gas: 8436196)\n[PASS] test_TheOwnerCantRenounce() (gas: 64582)\n[PASS] test_TheSaleIsNotBrokenByANonRefundingEnginesLiquidation() (gas: 2841851)\n[PASS] test_TheSaleStaysFeeFreeWithARefundingEngineArmed() (gas: 3850866)\n[PASS] test_TheTimelockNamesTheKeeper() (gas: 3716792)\n[PASS] test_TooLowAnOpeningPriceIsBadPrice() (gas: 765401)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 95.09ms (35.65ms CPU time)\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 3000450)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1277301)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1479224)\n[PASS] test_ClaimsOneForOne() (gas: 1602431)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208739)\n[PASS] test_DeploysOnAFreshChain() (gas: 2338795)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 10970618)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2355811)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599549457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1318615)\n[PASS] test_FitsOneTransaction() (gas: 10949162)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1297482\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1866715)\nLogs:\n  pot bridge: 0.511887599999999100\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1448787)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1326684)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1318269)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2213038)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1986837)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288387119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2092674)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2016888)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 179032)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1982929)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1318619)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 68121)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91759)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117785)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1832242)\n[PASS] test_PassesTheAdmissionScan() (gas: 15409943)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1469541)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702428)\n[PASS] test_RefusesTheWrongAddress() (gas: 709963)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1293275)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214891)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1820053)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1251718)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1315078)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2684757)\n[PASS] test_TheFeeIsStatic() (gas: 1601281)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 19092505)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1363340)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21900)\n[PASS] test_TheLiquidityIsLocked() (gas: 2173553)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2335006)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2127011)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1669649)\n[PASS] test_TradesBothWays() (gas: 1573717)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 110.87ms (110.55ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1811167, ~: 1823692)\nLogs:\n  Bound result 26317243086029759475046990\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4364978)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3692614)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4471466)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1908695)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2210714)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2809206)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3822515)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4597715)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1808705)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3673932)\n[PASS] test_SingleBurnSandwichControl() (gas: 4218131)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3735515)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 120.05ms (63.21ms CPU time)\n\nRan 5 test suites in 120.75ms (327.28ms CPU time): 74 tests passed, 0 failed, 0 skipped (74 total tests)\n","passed":true},{"durationMs":58,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdKeeper(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":228,\"README.md\":148,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":239,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":262,\"src/IMD6900LockedPool.sol\":368,\"src/IMD6900RobinhoodLaunch.sol\":634,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":1034,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":418,\"test/LaunchReview.t.sol\":596,\"test/RobinhoodFork.t.sol\":238},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":7936,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/IMD6900RobinhoodLaunch.sol:518: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#518-545) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/IMD6900LockedPool.sol:337: IMD6900LockedPool._payOutHeld() (src/IMD6900LockedPool.sol#337-349) sends eth to arbitrary user\n[high/medium] reentrancy-eth at src/IMD6900RobinhoodLaunch.sol:518: Reentrancy in IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#518-545):\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:314: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#314-344) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:300: IMD6900RobinhoodLaunch.withdrawEth(address,uint256) (src/IMD6900RobinhoodLaunch.sol#300-306) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:518: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#518-545) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:407: IMD6900RobinhoodLaunch.recoverEth(address,uint256) (src/IMD6900RobinhoodLaunch.sol#407-421) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMD6900RobinhoodLaunch.sol:518: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#518-545) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/IMD6900RobinhoodLaunch.sol:202: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#202-217):\n[medium/medium] reentrancy-no-eth at src/IMD6900RobinhoodLaunch.sol:453: Reentrancy in IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address) (src/IMD6900RobinhoodLaunch.sol#453-463):\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:381: IMD6900RobinhoodLaunch.setPayees(address[],uint16[]).sum (src/IMD6900RobinhoodLaunch.sol#381) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:592: IMD6900RobinhoodLaunch.unlockCallback(bytes).sold (src/IMD6900RobinhoodLaunch.sol#592) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:392: IMD6900RobinhoodLaunch.setPayees(address[],uint16[]).kept (src/IMD6900RobinhoodLaunch.sol#392) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMD6900RobinhoodLaunch.sol:591: IMD6900RobinhoodLaunch.unlockCallback(bytes).ethOut (src/IMD6900RobinhoodLaunch.sol#591) is a local variable never initialized\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:303: IMD6900LockedPool._settle(int128,int128) (src/IMD6900LockedPool.sol#303-314) ignores return value by poolManager.settle{value: uint256(uint128(- a0))}() (src/IMD6900LockedPool.sol#305)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:162: IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#162-181) ignores return value by poolManager.initialize(poolKey(),sqrtPriceX96) (src/IMD6900LockedPool.sol#176)\n[medium/medium] unused-return at src/IMD6900Hook.sol:108: IMD6900Hook.perpFeeBps() (src/IMD6900Hook.sol#108-114) ignores return value by (None,None,protocolFee,None) = StateLibrary.getSlot0(poolManager,poolId) (src/IMD6900Hook.sol#110)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:234: IMD6900LockedPool.state() (src/IMD6900LockedPool.sol#234-238) ignores return value by (sqrtPriceX96,tick,None,None) = poolManager.getSlot0(id) (src/IMD6900LockedPool.sol#236)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:303: IMD6900LockedPool._settle(int128,int128) (src/IMD6900LockedPool.sol#303-314) ignores return value by poolManager.settle() (src/IMD6900LockedPool.sol#310)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:317: IMD6900LockedPool._liquidityFor(uint256,uint256) (src/IMD6900LockedPool.sol#317-332) ignores return value by (p,None,None,None) = poolManager.getSlot0(poolKey().toId()) (src/IMD6900LockedPool.sol#318)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) ignores return value by (None,back) = pool.feeRefund(address(this)) (src/IMD6900RobinhoodLaunch.sol#596)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:193: IMD6900LockedPool.collect() (src/IMD6900LockedPool.sol#193-197) ignores return value by poolManager.unlock(abi.encode(COLLECT,uint128(0))) (src/IMD6900LockedPool.sol#195)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:162: IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#162-181) ignores return value by (sqrtPriceX96,None,None,None) = poolManager.getSlot0(old.toId()) (src/IMD6900LockedPool.sol#173)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:574: IMD6900RobinhoodLaunch.harvest() (src/IMD6900RobinhoodLaunch.sol#574-577) ignores return value by pool.collect() (src/IMD6900RobinhoodLaunch.sol#575)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) ignores return value by poolManager.settle() (src/IMD6900RobinhoodLaunch.sol#601)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) ignores return value by poolManager.settle{value: ethIn}() (src/IMD6900RobinhoodLaunch.sol#614)\n[medium/medium] unused-return at src/IMD6900RobinhoodLaunch.sol:314: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#314-344) ignores return value by pool.open(t,sqrtPriceX96,SUPPLY) (src/IMD6900RobinhoodLaunch.sol#329)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:132: IMD6900LockedPool.open(address,uint160,uint256) (src/IMD6900LockedPool.sol#132-155) ignores return value by poolManager.initialize(poolKey(),start) (src/IMD6900LockedPool.sol#144)\n[medium/medium] unused-return at src/IMD6900LockedPool.sol:284: IMD6900LockedPool._amountsFor(uint128) (src/IMD6900LockedPool.sol#284-296) ignores return value by (p,tick,None,None) = poolManager.getSlot0(poolKey().toId()) (src/IMD6900LockedPool.sol#285)\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:105: IMD6900LockedPool.constructor(IPoolManager,uint24,address,address).launcher_ (src/IMD6900LockedPool.sol#105) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:105: IMD6900LockedPool.constructor(IPoolManager,uint24,address,address).timelock_ (src/IMD6900LockedPool.sol#105) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:188: IMD6900RobinhoodLaunch.constructor(address,IPoolManager,address,address).imdstr_ (src/IMD6900RobinhoodLaunch.sol#188) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:474: IMD6900RobinhoodLaunch.setImdKeeper(address).keeper (src/IMD6900RobinhoodLaunch.sol#474) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:184: IMD6900LockedPool.setCoinFeeTo(address).to (src/IMD6900LockedPool.sol#184) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:122: IMD6900LockedPool.setHook(address).hook_ (src/IMD6900LockedPool.sol#122) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900LockedPool.sol:132: IMD6900LockedPool.open(address,uint160,uint256).token_ (src/IMD6900LockedPool.sol#132) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900Hook.sol:81: IMD6900Hook.constructor(IPoolManager,address,address).pool_ (src/IMD6900Hook.sol#81) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:489: IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address).hooks (src/IMD6900RobinhoodLaunch.sol#489) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMD6900RobinhoodLaunch.sol:188: IMD6900RobinhoodLaunch.constructor(address,IPoolManager,address,address).timelock_ (src/IMD6900RobinhoodLaunch.sol#188) lacks a zero-check on :\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) has external calls inside a loop: (None,back) = pool.feeRefund(address(this)) (src/IMD6900RobinhoodLaunch.sol#596)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:518: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#518-545) has external calls inside a loop: (ok,None) = to[i].call{value: pay}() (src/IMD6900RobinhoodLaunch.sol#532)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) has external calls inside a loop: s = poolManager.swap(k,SwapParams(false,- int256(left),TickMath.MAX_SQRT_PRICE - 1),) (src/IMD6900RobinhoodLaunch.sol#595)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:518: IMD6900RobinhoodLaunch.split() (src/IMD6900RobinhoodLaunch.sol#518-545) has external calls inside a loop: (ok,None) = to[i].call{value: pay}() (src/IMD6900RobinhoodLaunch.sol#532)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) has external calls inside a loop: pool.feeCheckpoint() (src/IMD6900RobinhoodLaunch.sol#594)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) has external calls inside a loop: poolManager.settle() (src/IMD6900RobinhoodLaunch.sol#601)\n[low/medium] calls-loop at src/IMD6900RobinhoodLaunch.sol:583: IMD6900RobinhoodLaunch.unlockCallback(bytes) (src/IMD6900RobinhoodLaunch.sol#583-617) has external calls inside a loop: poolManager.sync(k.currency1) (src/IMD6900RobinhoodLaunch.sol#599)\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:553: Reentrancy in IMD6900RobinhoodLaunch.burnImd(uint256) (src/IMD6900RobinhoodLaunch.sol#553-566):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:202: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#202-217):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:314: Reentrancy in IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#314-344):\n[low/medium] reentrancy-benign at src/IMD6900LockedPool.sol:162: Reentrancy in IMD6900LockedPool.lowerFee(uint24) (src/IMD6900LockedPool.sol#162-181):\n[low/medium] reentrancy-benign at src/IMD6900LockedPool.sol:132: Reentrancy in IMD6900LockedPool.open(address,uint160,uint256) (src/IMD6900LockedPool.sol#132-155):\n[low/medium] reentrancy-benign at src/IMD6900RobinhoodLaunch.sol:314: Reentrancy in IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#314-344):\n[low/medium] reentrancy-events at src/IMD6900RobinhoodLaunch.sol:574: Reentrancy in IMD6900RobinhoodLaunch.harvest() (src/IMD6900RobinhoodLaunch.sol#574-577):\n[low/medium] reentrancy-events at src/IMD6900LockedPool.sol:221: Reentrancy in IMD6900LockedPool.feeRefund(address) (src/IMD6900LockedPool.sol#221-231):\n[low/medium] reentrancy-events at src/IMD6900RobinhoodLaunch.sol:202: Reentrancy in IMD6900RobinhoodLaunch.createHook(bytes32) (src/IMD6900RobinhoodLaunch.sol#202-217):\n[low/medium] return-bomb at src/IMD6900Hook.sol:227: IMD6900Hook._sweep(address,int256,bool,uint160) (src/IMD6900Hook.sol#227-254) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] return-bomb at src/IMD6900Hook.sol:257: IMD6900Hook._openPositions(address) (src/IMD6900Hook.sol#257-261) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] timestamp at src/IMD6900RobinhoodLaunch.sol:314: IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address) (src/IMD6900RobinhoodLaunch.sol#314-344) uses timestamp for comparisons\n[low/medium] timestamp at src/IMD6900RobinhoodLaunch.sol:348: IMD6900RobinhoodLaunch.releaseUnclaimed(address) (src/IMD6900RobinhoodLaunch.sol#348-360) uses timestamp for comparisons","passed":true},{"durationMs":590,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/IMD6900RobinhoodLaunch.sol:247: `abi.encodePacked()` Hash Collision (3 places)\n[high] contract-locks-ether at src/IMD6900Hook.sol:42: Contract locks Ether without a withdraw function (2 places)\n[high] reentrancy-state-change at src/IMD6900LockedPool.sol:144: Reentrancy: State change after external call (11 places)\n[low] centralization-risk at src/IMD6900Hook.sol:42: Centralization Risk (12 places)\n[low] costly-loop at src/IMD6900RobinhoodLaunch.sol:382: Costly operations inside loop (3 places)\n[low] large-numeric-literal at src/IMD6900.sol:11: Large Numeric Literal (7 places)\n[low] literal-instead-of-constant at src/IMD6900Hook.sol:109: Literal Instead of Constant (12 places)\n[low] non-reentrant-not-first at src/IMD6900RobinhoodLaunch.sol:300: `nonReentrant` is Not the First Modifier (4 places)\n[low] push-zero-opcode at src/IMD6900.sol:2: PUSH0 Opcode (4 places)\n[low] require-revert-in-loop at src/IMD6900RobinhoodLaunch.sol:382: Loop Contains `require`/`revert`\n[low] state-no-address-check at src/IMD6900LockedPool.sol:125: Address State Variable Set Without Checks (5 places)\n[low] unchecked-return at src/IMD6900LockedPool.sol:144: Unchecked Return (9 places)\n[low] uninitialized-local-variable at src/IMD6900RobinhoodLaunch.sol:393: Uninitialized Local Variable (3 places)\n[low] unspecific-solidity-pragma at src/IMD6900.sol:2: Unspecific Solidity Pragma (4 places)\n[low] unused-public-function at src/IMD6900Hook.sol:108: Public Function Not Used Internally (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"756343e8a47363bef7fabd55d1e6190c59f7ea9bf8dab10be77e05a2f78fa59f","verifiedTreeHash":"caa8dbef7ea01ea8c604f926dc12033a695f7010","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":60378,"exitCode":0,"name":"build","output":"Compiling 90 files with Solc 0.8.26\nSolc 0.8.26 finished in 60.22s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:101:76\n    │\n101 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:270:9\n    │\n270 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:78:44\n   │\n78 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:101:57\n    │\n101 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:123:28\n    │\n123 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:125:9\n    │\n125 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:131:9\n    │\n131 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:174:77\n    │\n174 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:174:60\n    │\n174 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:136:9\n    │\n136 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:198:9\n    │\n198 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:201:9\n    │\n201 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:222:9\n    │\n222 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:223:9\n    │\n223 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:233:27\n    │\n233 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:241:26\n    │\n241 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:271:9\n    │\n271 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:280:9\n    │\n280 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:118:22\n    │\n118 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:276:73\n    │\n276 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:281:9\n    │\n281 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:294:9\n    │\n294 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:298:32\n    │\n298 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:319:9\n    │\n319 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:323:62\n    │\n323 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:325:13\n    │\n325 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:333:9\n    │\n333 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:337:75\n    │\n337 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:342:9\n    │\n342 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:128:19\n    │\n128 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:148:9\n    │\n148 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:140:9\n    │\n140 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:144:15\n    │\n144 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:222:17\n    │\n222 │                 engine.call{gas: g - reserve}(abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit)));\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:318:9\n    │\n318 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:174:9\n    │\n174 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:163:43\n    │\n163 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:170:9\n    │\n170 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:357:13\n    │\n357 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:355:38\n    │\n355 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:360:23\n    │\n360 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:178:27\n    │\n178 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:189:9\n    │\n189 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:224:9\n    │\n224 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:372:9\n    │\n372 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:384:9\n    │\n384 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:260:23\n    │\n260 │         uint256 eth = uint256(int256(out.amount0() - earned.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:261:25\n    │\n261 │         uint256 coins = uint256(int256(out.amount1() - earned.amount1()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:278:21\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:278:47\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:278:55\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:279:73\n    │\n279 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:279:81\n    │\n279 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:282:71\n    │\n282 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:282:79\n    │\n282 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:283:13\n    │\n283 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:285:60\n    │\n285 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:285:68\n    │\n285 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:304:60\n    │\n304 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:325:15\n    │\n325 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:325:23\n    │\n325 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:326:18\n    │\n326 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:326:26\n    │\n326 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:24\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:32\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:47\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:55\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:409:34\n    │\n409 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:413:9\n    │\n413 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:455:9\n    │\n455 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:473:26\n    │\n473 │             (bool ok,) = to[i].call{value: part}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:473:26\n    │\n473 │             (bool ok,) = to[i].call{value: part}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:474:22\n    │\n474 │             if (!ok) emit PayFailed(to[i], part);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:476:9\n    │\n476 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:493:9\n    │\n493 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:503:9\n    │\n503 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:17\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:530:17\n    │\n530 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:521:29\n    │\n521 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:522:17\n    │\n522 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:523:34\n    │\n523 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:36\n    │\n524 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:527:17\n    │\n527 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:529:17\n    │\n529 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:523:73\n    │\n523 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:36\n    │\n524 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:525:32\n    │\n525 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:525:40\n    │\n525 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:27\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:35\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:529:17\n    │\n529 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:538:66\n    │\n538 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:539:25\n    │\n539 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:539:33\n    │\n539 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:540:23\n    │\n540 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:540:31\n    │\n540 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:542:9\n    │\n542 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:550:16\n    │\n550 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":8399,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[SKIP] test_TheWholeLaunchOnRobinhood() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 269.99µs (49.20µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 15466229)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\nLogs:\n  factory deployment gas: 7445862\n  factory deployment gas: 7445874\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 958.76µs (809.40µs CPU time)\n\nRan 9 tests for test/LaunchFailures.t.sol:LaunchPreconditionTest\n[PASS] test_ClaimsRootAndTotalMustAgreeAndRejectionPreservesOldList() (gas: 100465)\n[PASS] test_MinimumBuyFailureRollsBackEthCoinAndPool() (gas: 2291610)\n[PASS] test_OneSecondShortClaimWindowRollsBackAndCanRetry() (gas: 1396352)\n[PASS] test_OnlyLauncherCanWireAndOpenAndHookCannotBeReplaced() (gas: 118765)\n[PASS] test_OperationsBeforeLaunchRejectWithoutMovingFunds() (gas: 349617)\n[PASS] test_PoolRejectsInvalidAndCollapsedPriceRanges() (gas: 130263)\n[PASS] test_PoolRejectsZeroLiquidityAtomically() (gas: 203283)\n[PASS] test_WithdrawFailureAndZeroBalanceAreAtomic() (gas: 336897)\n[PASS] test_ZeroEthLaunchRevertsAllCreationAndLiquidity() (gas: 2188769)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 82.09ms (2.41ms CPU time)\n\nRan 14 tests for test/HookFailures.t.sol:HookFailureTest\n[PASS] testFuzz_RefundedPerpQuoteRoundsWorstProtocolDirectionUp(uint16,uint16) (runs: 1000, μ: 159035, ~: 159110)\nLogs:\n  Bound result 518\n  Bound result 7\n\n[PASS] test_AfterSweepIsBestEffortForEveryFailureModeAndLowGas() (gas: 474213)\n[PASS] test_AllEnabledCallbacksRejectSpoofedPoolManager() (gas: 158572)\n[PASS] test_EngineOwnSwapBypassesSweepEvenWhenSweepIsBroken() (gas: 216843)\n[PASS] test_FailedRealTradeRollsBackAndWorksAfterEngineRepair() (gas: 840228)\n[PASS] test_FeeMoveRefusesMalformedOrUnavailablePositionCountAtomically() (gas: 1135151)\n[PASS] test_FormerPoolCannotTradeAfterFeeMove() (gas: 758311)\n[PASS] test_InitializeRejectsImpostorAndMismatchedKeyFields() (gas: 355815)\n[PASS] test_LiquidityCallbacksRejectOtherOwnersAndWrongRanges() (gas: 143760)\n[PASS] test_LowGasChecksPositionsInsteadOfTradingBlind() (gas: 661369)\n[PASS] test_OnlyTimelockMayEnableSweepEscapeHatch() (gas: 75145)\n[PASS] test_PreSweepReceivesTradeAndOriginAndReturnsNoDeltas() (gas: 195891)\n[PASS] test_ReportedUnsafeTradeCannotBypassSweepWithFailOpen() (gas: 622784)\n[PASS] test_UnavailableAndMalformedSweepsFailClosedUnlessTimelockOptsIn() (gas: 468653)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 127.05ms (63.07ms CPU time)\n\nRan 7 tests for test/LaunchFailures.t.sol:LaunchFeeFailureTest\n[PASS] testFuzz_DefaultSplitConservesEthAndNeverResplitsBurnReserve(uint256) (runs: 1000, μ: 170555, ~: 173486)\nLogs:\n  Bound result 749997012471648633132\n\n[PASS] test_MalformedPayeesNeverReplaceTheWorkingSplit() (gas: 490243)\n[PASS] test_PerpFeesRejectBadDestinationsAndReturnFundsIfReceiverRefuses() (gas: 265744)\n[PASS] test_RecoveryClampsBurnBucketAndFailedRecoveryDoesNot() (gas: 429709)\n[PASS] test_RefusingPayeeLeavesEthRecoverableWithoutBlockingOthers() (gas: 341216)\n[PASS] test_SplitDustEdgesZeroOneAndTenWei() (gas: 231256)\n[PASS] test_SplitReceiverCannotReenterAndDoubleSpend() (gas: 582976)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 134.90ms (56.01ms CPU time)\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2967968)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1257069)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1458948)\n[PASS] test_ClaimsOneForOne() (gas: 1582067)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208607)\n[PASS] test_DeploysOnAFreshChain() (gas: 38177422)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 20237263)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2318005)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599550457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1298339)\n[PASS] test_FitsOneTransaction() (gas: 20215983)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1218825\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1839252)\nLogs:\n  pot bridge: 0.511887600000000000\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1428307)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1306276)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1297993)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2197805)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1949295)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288388119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2077604)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 1996640)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1967760)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1296129)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 67989)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91495)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117731)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1794782)\n[PASS] test_PassesTheAdmissionScan() (gas: 14437694)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1449133)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702296)\n[PASS] test_RefusesTheWrongAddress() (gas: 709787)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1272999)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214603)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1799606)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1231530)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1294890)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2660410)\n[PASS] test_TheFeeIsStatic() (gas: 1580762)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 68503414)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1343152)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2153166)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2310685)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2106159)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1649144)\n[PASS] test_TradesBothWays() (gas: 1553481)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 229.54ms (155.79ms CPU time)\n\nRan 11 tests for test/LaunchFailures.t.sol:LaunchCustodyFailureTest\n[PASS] testFuzz_ClaimPartitionExchangesExactlyOneForOne(uint256,uint8) (runs: 1000, μ: 399280, ~: 401111)\nLogs:\n  Bound result 12806417838605959755339155\n\n[PASS] test_AllTimelockCustodyFunctionsRejectTeamAndStrangers() (gas: 612932)\n[PASS] test_ClaimZeroAndMaximumCannotConsumeReserve() (gas: 326351)\n[PASS] test_DeadlineBoundaryAndClaimClosureCannotReopen() (gas: 499545)\n[PASS] test_FailedOldTokenTransferDoesNotConsumeClaim() (gas: 596406)\n[PASS] test_LegacyReleaseChecksCustodyAndCannotSpendNewCoins() (gas: 390845)\n[PASS] test_OwnerFunctionsRejectTimelockAndStrangers() (gas: 243748)\n[PASS] test_ProofCannotBeReusedByAnotherAccountOrForAnotherAllocation() (gas: 144688)\n[PASS] test_RawCallbacksCannotBeSpoofed() (gas: 285713)\n[PASS] test_ReleaseExcessBurnsOnlyExcessAndRejectsOverdraw() (gas: 363916)\n[PASS] test_SellSlippageAndRefusingRecipientRollBackSwapAndRefund() (gas: 1631363)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 244.01ms (181.61ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1788294, ~: 1803064)\nLogs:\n  Bound result 2479897\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4318298)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3600546)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4425981)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1887925)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2189754)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2771837)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3790168)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4567708)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1787969)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3641651)\n[PASS] test_SingleBurnSandwichControl() (gas: 4188454)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3694297)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 260.02ms (204.80ms CPU time)\n\nRan 5 tests for test/PoolProperties.t.sol:RefundProtocolTest\n[PASS] testFuzz_RefundIsOnlyThisTradeAndOrdinaryFeesRemainCollectible(uint256) (runs: 1000, μ: 639023, ~: 640281)\nLogs:\n  Bound result 451715084474031598\n\n[PASS] test_CheckpointCannotBeUsedByAnotherCaller() (gas: 424691)\n[PASS] test_CheckpointRequiresUnlockedManagerAndLiveAuthorization() (gas: 117522)\n[PASS] test_CheckpointWithoutSwapCannotTakePreviousTradersFees() (gas: 409104)\n[PASS] test_RefundCannotBeReplayedAndFailedReplayRollsBackSwap() (gas: 704092)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 260.41ms (166.24ms CPU time)\n\nRan 4 tests for test/PoolProperties.t.sol:LockedPoolPropertyTest\n[PASS] testFuzz_FeeMigrationPreservesPriceAndPrincipalAcrossBothTradeDirections(uint24,uint256) (runs: 1000, μ: 2334672, ~: 2341797)\nLogs:\n  Bound result 3000\n  Bound result 9180000000000000000\n\n[PASS] testFuzz_OpeningLocksSupplyAsCoinOnlyAndFloorsOntoTick(int24) (runs: 1000, μ: 560592, ~: 561092)\nLogs:\n  Bound result 499154\n\n[PASS] testFuzz_OrdinaryBuySellRoundTripCannotCreateEth(uint256) (runs: 1000, μ: 1515340, ~: 1515375)\nLogs:\n  Bound result 705870014\n\n[PASS] test_StandaloneCreationAndRuntimeOpcodesMeetAdmissionRule() (gas: 121924527)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 272.16ms (745.45ms CPU time)\n\nRan 2 tests for test/LaunchInvariant.t.sol:LaunchInvariantTest\n[PASS]\nLaunchInvariantTest invariants:\n[PASS] invariant_ClaimsAndHeldCoinsStayFullyBacked\n[PASS] invariant_LiquidityStaysLockedAndRetiredPoolsStayEmpty\n[PASS] invariant_ValueIsConservedAndOnlyExplicitBurnsReduceSupply\n LaunchInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭-----------------------+-------------------+-------+---------+----------╮\n| Contract              | Selector          | Calls | Reverts | Discards |\n+========================================================================+\n| LaunchSequenceHandler | advance           | 951   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | burnCoin          | 1038  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | burnImd           | 999   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | claim             | 1899  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | closeClaims       | 942   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | collect           | 992   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | configureCoinFees | 992   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | donateCoin        | 967   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | donateEth         | 984   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | lowerFee          | 978   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | perpFees          | 979   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | recoverEth        | 942   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | refundedTrade     | 1002  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | rejectedCalls     | 963   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | releaseExcess     | 1003  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | releaseLegacy     | 1039  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | sellHeld          | 936   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | split             | 956   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | trade             | 918   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| LaunchSequenceHandler | transferCoin      | 1000  | 0       | 0        |\n╰-----------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 999999999999999951\n  Bound result 0\n  Bound result 0\n  Bound result 764605578337054489\n  Bound result 1499984\n  Bound result 0\n  Bound result 1792000\n  Bound result 8308561905155159253476852\n  Bound result 100000\n  Bound result 0\n  Bound result 129548394175826289085228106\n  Bound result 1\n  Bound result 125\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 7\n  Bound result 901836800791271187\n  Bound result 2550182\n  Bound result 2989\n  Bound result 895\n  Bound result 104745616808\n  Bound result 13251\n  Bound result 599\n  Bound result 0\n  Bound result 10\n  Bound result 0\n  Bound result 8304\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 18013\n  Bound result 4930\n  Bound result 9968\n  Bound result 1718\n  Bound result 9141\n  Bound result 144\n\n[PASS] test_HandlerExercisesMixedCustodySequence() (gas: 4154094)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 2000000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 33300\n  Bound result 100000000000000000000\n  Bound result 50000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000\n  Bound result 1\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.29s (8.23s CPU time)\n\nRan 11 test suites in 8.30s (9.90s CPU time): 110 tests passed, 0 failed, 1 skipped (111 total tests)\n","passed":true},{"durationMs":74,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":101,\"README.md\":136,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":238,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":242,\"src/IMD6900LockedPool.sol\":338,\"src/IMD6900RobinhoodLaunch.sol\":562,\"test/HookFailures.t.sol\":309,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":928,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":412,\"test/LaunchFailures.t.sol\":523,\"test/LaunchInvariant.t.sol\":526,\"test/PoolProperties.t.sol\":244,\"test/RobinhoodFork.t.sol\":240,\"test/TESTING.md\":33,\"test/helpers/LaunchFixture.sol\":139},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a0d79eea857dc23a82a9f9aecab06101cf298727f6247b0b2acc8284cf65509f","verifiedTreeHash":"fef50f4c2e938e2b57963d4c48de0d872b85121c","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":35117,"exitCode":0,"name":"build","output":"Compiling 85 files with Solc 0.8.26\nSolc 0.8.26 finished in 34.86s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:78:44\n   │\n78 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:123:28\n    │\n123 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:101:76\n    │\n101 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:101:57\n    │\n101 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:270:9\n    │\n270 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:125:9\n    │\n125 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:131:9\n    │\n131 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:136:9\n    │\n136 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:174:60\n    │\n174 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:174:77\n    │\n174 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:198:9\n    │\n198 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:201:9\n    │\n201 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:222:9\n    │\n222 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:223:9\n    │\n223 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:233:27\n    │\n233 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:241:26\n    │\n241 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:271:9\n    │\n271 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:118:22\n    │\n118 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:280:9\n    │\n280 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:276:73\n    │\n276 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:281:9\n    │\n281 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:294:9\n    │\n294 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:298:32\n    │\n298 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:319:9\n    │\n319 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:323:62\n    │\n323 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:325:13\n    │\n325 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:333:9\n    │\n333 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:337:75\n    │\n337 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:342:9\n    │\n342 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:128:19\n    │\n128 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:148:9\n    │\n148 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:140:9\n    │\n140 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:144:15\n    │\n144 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:222:17\n    │\n222 │                 engine.call{gas: g - reserve}(abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit)));\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:318:9\n    │\n318 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:174:9\n    │\n174 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:163:43\n    │\n163 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:170:9\n    │\n170 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:178:27\n    │\n178 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:189:9\n    │\n189 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:224:9\n    │\n224 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:357:13\n    │\n357 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:355:38\n    │\n355 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:360:23\n    │\n360 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:260:23\n    │\n260 │         uint256 eth = uint256(int256(out.amount0() - earned.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:261:25\n    │\n261 │         uint256 coins = uint256(int256(out.amount1() - earned.amount1()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:278:21\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:278:47\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:278:55\n    │\n278 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:372:9\n    │\n372 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:279:73\n    │\n279 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:279:81\n    │\n279 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:282:71\n    │\n282 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:282:79\n    │\n282 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:283:13\n    │\n283 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:285:60\n    │\n285 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:285:68\n    │\n285 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:304:60\n    │\n304 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:325:15\n    │\n325 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:325:23\n    │\n325 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:326:18\n    │\n326 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:326:26\n    │\n326 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:24\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:32\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:47\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:336:55\n    │\n336 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:384:9\n    │\n384 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:409:34\n    │\n409 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:413:9\n    │\n413 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:455:9\n    │\n455 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:473:26\n    │\n473 │             (bool ok,) = to[i].call{value: part}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:473:26\n    │\n473 │             (bool ok,) = to[i].call{value: part}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:474:22\n    │\n474 │             if (!ok) emit PayFailed(to[i], part);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:476:9\n    │\n476 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:493:9\n    │\n493 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:503:9\n    │\n503 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:521:29\n    │\n521 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:530:17\n    │\n530 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:17\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:522:17\n    │\n522 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:523:34\n    │\n523 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:36\n    │\n524 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:527:17\n    │\n527 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:529:17\n    │\n529 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:523:73\n    │\n523 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:36\n    │\n524 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:525:32\n    │\n525 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:525:40\n    │\n525 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:27\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:526:35\n    │\n526 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:529:17\n    │\n529 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:538:66\n    │\n538 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:539:25\n    │\n539 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:539:33\n    │\n539 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:540:23\n    │\n540 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:540:31\n    │\n540 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:542:9\n    │\n542 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:550:16\n    │\n550 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":338,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[PASS] test_TheWholeLaunchOnRobinhood() (gas: 2548)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 411.73µs (26.70µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 15466229)\nLogs:\n  factory deployment gas: 7445862\n  factory deployment gas: 7445874\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.29ms (1.12ms CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2967968)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1257069)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1458948)\n[PASS] test_ClaimsOneForOne() (gas: 1582067)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208607)\n[PASS] test_DeploysOnAFreshChain() (gas: 38177422)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 20237263)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2318005)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599550457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1298339)\n[PASS] test_FitsOneTransaction() (gas: 20215983)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1218825\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1839252)\nLogs:\n  pot bridge: 0.511887600000000000\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1428307)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1306276)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1297993)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2197805)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1949295)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288388119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2077604)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 1996640)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1967760)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1296129)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 67989)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91495)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117731)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1794782)\n[PASS] test_PassesTheAdmissionScan() (gas: 14437694)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1449133)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702296)\n[PASS] test_RefusesTheWrongAddress() (gas: 709787)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1272999)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214603)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1799606)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1231530)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1294890)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2660410)\n[PASS] test_TheFeeIsStatic() (gas: 1580762)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 68503414)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1343152)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2153166)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2310685)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2106159)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1649144)\n[PASS] test_TradesBothWays() (gas: 1553481)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 179.22ms (252.49ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1794199, ~: 1803064)\nLogs:\n  Bound result 1717131065388712324864397\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4318298)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3600546)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4425981)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1887925)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2189754)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2771837)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3790168)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4567708)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1787969)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3641651)\n[PASS] test_SingleBurnSandwichControl() (gas: 4188454)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3694297)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 201.96ms (87.79ms CPU time)\n\nRan 4 test suites in 202.93ms (382.88ms CPU time): 59 tests passed, 0 failed, 0 skipped (59 total tests)\n","passed":true},{"durationMs":64,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":101,\"README.md\":136,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"launch.json\":15,\"script/claims.py\":88,\"script/launch.sh\":238,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":242,\"src/IMD6900LockedPool.sol\":338,\"src/IMD6900RobinhoodLaunch.sol\":562,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":928,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":412,\"test/RobinhoodFork.t.sol\":217},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e4b58e68e4f6b60e13a391033667465857dd78f7a7b55adacea19730f074bbc2","verifiedTreeHash":"eeed0faa3920a4b8eea5dd2c083863046478168d","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":37286,"exitCode":0,"name":"build","output":"Compiling 86 files with Solc 0.8.26\nSolc 0.8.26 finished in 37.13s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMD6900Hook.sol:81:44\n   │\n81 │     constructor(IPoolManager poolManager_, address pool_, address owner_) BaseHook(poolManager_) {\n   │                                            ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:57\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:105:76\n    │\n105 │     constructor(IPoolManager poolManager_, uint24 fee_, address launcher_, address timelock_) {\n    │                                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-events-access-control]: `claimRoot` is changed without an event but is used for access control\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:295:9\n    │\n295 │         (claimRoot, claimTotal, claimDeadline) = (root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900Hook.sol:128:28\n    │\n128 │     function setPerpEngine(address engine) external onlyOwner {\n    │                            ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:135:9\n    │\n135 │         emit PerpEngineSet(engine);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:141:9\n    │\n141 │         emit PerpRefundedSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900Hook.sol:146:9\n    │\n146 │         emit SweepFailOpenSet(on);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:189:77\n    │\n189 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                                             ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:189:60\n    │\n189 │     constructor(address owner_, IPoolManager poolManager_, address imdstr_, address timelock_) {\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hook` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:213:9\n    │\n213 │         pool.setHook(h);\n    │         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:216:9\n    │\n216 │         emit HookCreated(h, salt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:237:9\n    │\n237 │         SafeTransferLib.safeTransferETH(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:238:9\n    │\n238 │         emit PerpFeesForwarded(to, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:248:27\n    │\n248 │                 keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))))\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:256:26\n    │\n256 │         return keccak256(abi.encodePacked(type(IMD6900).creationCode, abi.encode(address(this))));\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:296:9\n    │\n296 │         emit ClaimsSet(root, total, deadline);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:305:9\n    │\n305 │         SafeTransferLib.safeTransferETH(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:301:73\n    │\n301 │     function withdrawEth(address to, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:122:22\n    │\n122 │     function setHook(address hook_) external {\n    │                      ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:306:9\n    │\n306 │         emit EthWithdrawn(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:319:9\n    │\n319 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:323:32\n    │\n323 │         if (claimTotal != 0 && claimDeadline < block.timestamp + MIN_CLAIM_WINDOW) revert BadClaims();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:344:9\n    │\n344 │         emit Launched(t, sqrtPriceX96, pool.upperTick(), spend, bought, excess, excessTo);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:330:9\n    │\n330 │         pool.open(t, sqrtPriceX96, SUPPLY);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:349:62\n    │\n349 │     function releaseUnclaimed(address to) external onlyOwner nonReentrant {\n    │                                                              ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:351:13\n    │\n351 │         if (block.timestamp < claimDeadline) revert ClaimsOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:360:9\n    │\n360 │         emit UnclaimedReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:364:75\n    │\n364 │     function releaseImdstr(uint256 amount, address to) external onlyOwner nonReentrant {\n    │                                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:369:9\n    │\n369 │         emit ImdstrReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:132:19\n    │\n132 │     function open(address token_, uint160 sqrtPriceX96, uint256 amount) external nonReentrant returns (uint128 liq) {\n    │                   ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:154:9\n    │\n154 │         emit Opened(start, upper, used, liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:144:9\n    │\n144 │         poolManager.initialize(poolKey(), start);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:149:15\n    │\n149 │         liq = uint128(l - 1);\n    │               ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:233:43\n    │\n233 │               (bool ok, bytes memory out) = engine.call{gas: g - reserve}(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n234 │ ┃                 abi.encodeCall(IPerpSweep.sweepLiquidations, (tx.origin, spec, isBuy, limit))\n235 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900Hook.sol:258:39\n    │\n258 │         (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpSweep.openCount, ()));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:348:9\n    │\n348 │         emit Collected(eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:180:9\n    │\n180 │         emit FeeLowered(from, newFee, poolKey().toId(), liq);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/IMD6900LockedPool.sol:169:43\n    │\n169 │             (bool ok, bytes memory ret) = engine.staticcall{gas: 100_000}(abi.encodeCall(IPerpsWiring.openCount, ()));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:176:9\n    │\n176 │         poolManager.initialize(poolKey(), sqrtPriceX96); // the hook serves the new pool from here on\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:384:13\n    │\n384 │             sum += bps[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:382:38\n    │\n382 │             if (to[i] == address(0)) revert BadPayees();\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:387:23\n    │\n387 │         _payeeCount = uint8(n);\n    │                       ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMD6900LockedPool.sol:184:27\n    │\n184 │     function setCoinFeeTo(address to) external {\n    │                           ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:195:9\n    │\n195 │         poolManager.unlock(abi.encode(COLLECT, uint128(0)));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900LockedPool.sol:230:9\n    │\n230 │         emit FeeRefunded(msg.sender, to, eth, tokens);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:402:17\n    │\n402 │                 emit OwedCancelled(owedTotal);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:407:9\n    │\n407 │         emit EthRecovered(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:420:9\n    │\n420 │         emit ExcessReleased(to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:23\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:270:31\n    │\n270 │         uint256 eth = uint256(uint128(out.amount0())) + address(this).balance;\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:25\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:271:33\n    │\n271 │         uint256 coins = uint256(uint128(out.amount1())) + SafeTransferLib.balanceOf(token, address(this));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:305:21\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:47\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:305:55\n    │\n305 │         if (a0 < 0) poolManager.settle{value: uint256(uint128(-a0))}();\n    │                                                       ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:73\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:306:81\n    │\n306 │         else if (a0 > 0) poolManager.take(key.currency0, address(this), uint256(uint128(a0)));\n    │                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:71\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                       ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:309:79\n    │\n309 │             SafeTransferLib.safeTransfer(token, address(poolManager), uint256(uint128(-a1)));\n    │                                                                               ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900LockedPool.sol:310:13\n    │\n310 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:60\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:312:68\n    │\n312 │             poolManager.take(key.currency1, address(this), uint256(uint128(a1)));\n    │                                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:331:60\n    │\n331 │         return l > type(uint128).max ? type(uint128).max : uint128(l);\n    │                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:15\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:355:23\n    │\n355 │         eth = uint256(uint128(d.amount0()));\n    │                       ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:18\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:356:26\n    │\n356 │         tokens = uint256(uint128(d.amount1()));\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:24\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                        ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:32\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:47\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900LockedPool.sol:366:55\n    │\n366 │         return v < 0 ? uint256(uint128(-v)) : uint256(uint128(v));\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `excessHeld` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:445:34\n    │\n445 │         (eth, sold) = abi.decode(poolManager.unlock(abi.encode(uint8(2), amount)), (uint256, uint256));\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:449:9\n    │\n449 │         emit HeldSold(sold, eth, to);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:491:9\n    │\n491 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-eth]: uncapped ETH transfer can be reentered before `owedTotal` is updated\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:512:26\n    │\n512 │             (bool ok,) = to[i].call{value: pay}(\"\");\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:521:17\n    │\n521 │                 emit PayFailed(to[i], pay);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:524:9\n    │\n524 │         emit Split(amount);\n    │         ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:551:9\n    │\n551 │         emit ImdBurned(spend, imd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:561:9\n    │\n561 │         pool.collect();\n    │         ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:579:29\n    │\n579 │             for (uint256 i; i < 3 && left != 0; ++i) {\n    │                             ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:17\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                 ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:588:17\n    │\n588 │                 sold += paid - back;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:580:17\n    │\n580 │                 pool.feeCheckpoint();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:581:34\n    │\n581 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:582:36\n    │\n582 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:585:17\n    │\n585 │                 poolManager.sync(k.currency1);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:587:17\n    │\n587 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:581:73\n    │\n581 │                 BalanceDelta s = poolManager.swap(k, SwapParams(false, -int256(left), TickMath.MAX_SQRT_PRICE - 1), \"\");\n    │                                                                         ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:582:36\n    │\n582 │                 (, uint256 back) = pool.feeRefund(address(this));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:583:32\n    │\n583 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:583:40\n    │\n583 │                 uint256 paid = uint256(uint128(-s.amount1()));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:27\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:584:35\n    │\n584 │                 ethOut += uint256(uint128(s.amount0()));\n    │                                   ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:587:17\n    │\n587 │                 poolManager.settle();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:596:66\n    │\n596 │         BalanceDelta d = poolManager.swap(key, SwapParams(true, -int256(spend), TickMath.MIN_SQRT_PRICE + 1), \"\");\n    │                                                                  ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:25\n    │\n597 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:597:33\n    │\n597 │         uint256 ethIn = uint256(uint128(-d.amount0()));\n    │                                 ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:23\n    │\n598 │         uint256 out = uint256(uint128(d.amount1()));\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:598:31\n    │\n598 │         uint256 out = uint256(uint128(d.amount1()));\n    │                               ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:600:9\n    │\n600 │         poolManager.settle{value: ethIn}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/IMD6900RobinhoodLaunch.sol:608:16\n    │\n608 │         return abi.encodePacked(type(IMD6900Hook).creationCode, abi.encode(poolManager, address(pool), timelock));\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\n","passed":true},{"durationMs":263,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[PASS] test_TheWholeLaunchOnRobinhood() (gas: 2548)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 409.87µs (29.92µs CPU time)\n\nRan 1 test for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_FactoryDeploymentWithExactArgumentsAndNoDependencies() (gas: 16395758)\nLogs:\n  factory deployment gas: 7907314\n  factory deployment gas: 7907326\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.92ms (1.71ms CPU time)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n\nRan 13 tests for test/LaunchReview.t.sol:LaunchReviewTest\n[PASS] test_AnEngineThatCantSayIsReplaceable() (gas: 1593001)\n[PASS] test_BurnOnADeepPoolSpendsTheCap() (gas: 3448510)\n[PASS] test_BurnOnAThinPoolCantBeSandwiched() (gas: 7318465)\nLogs:\n  attacker ETH after: 9.999980484383658601\n  attacker ETH after: 9.999961676952453405\n  attacker ETH after: 9.999892159036747908\n  attacker ETH after: 9.999690438057248353\n\n[PASS] test_LowerFeeMovesAllOfItRightAfterCollect() (gas: 12273281)\n[PASS] test_LowerFeeMovesAllOfItWithOneWeiOfEthInThePosition() (gas: 6054005)\n[PASS] test_NoUnwiringWhilePerpsAreOpen() (gas: 2149413)\n[PASS] test_RecoverEthCancelsTheBooksOnlyWhenItReachesThem() (gas: 1920557)\n[PASS] test_RefusedShareIsBookedNotResplit() (gas: 2268774)\n[PASS] test_ReleasesToThisContractStayAccounted() (gas: 1438920)\n[PASS] test_TheOwnerCantRenounce() (gas: 64428)\n[PASS] test_TheSaleIsNotBrokenByANonRefundingEnginesLiquidation() (gas: 2841459)\n[PASS] test_TheSaleStaysFeeFreeWithARefundingEngineArmed() (gas: 3850496)\n[PASS] test_TooLowAnOpeningPriceIsBadPrice() (gas: 765269)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 117.48ms (28.72ms CPU time)\n\nRan 13 tests for test/LaunchAudit.t.sol:LaunchAuditTest\n[PASS] testFuzz_ClaimReserveBoundsBothClaimOrders(bool,uint256) (runs: 256, μ: 1809747, ~: 1823120)\nLogs:\n  Bound result 13844377205449690300297931\n\n[PASS] test_BucketCanDrainAcrossBlocksStartingAtBlockZero() (gas: 4379346)\n[PASS] test_BurnCapIsSharedAcrossCallersAndResetsOnNextBlock() (gas: 3634031)\n[PASS] test_BurnLoopCannotSandwichWholeBucket() (gas: 4456237)\nLogs:\n  looped-burn attacker ETH: 99.912966340529872311\n  burn bucket spent: 0.100000000000000000\n\n[PASS] test_ClaimsCanUseExactlyTheRemainingReserve() (gas: 1908035)\n[PASS] test_ClaimsCannotConsumeHeldExcess() (gas: 2209882)\n[PASS] test_EmptyImdPoolDoesNotWriteOffBucket() (gas: 2808074)\n[PASS] test_EmptyPoolFailureCanRetryAfterLiquidityReturns() (gas: 3822164)\n[PASS] test_PartialImdBuyRevertsAtomically() (gas: 4597983)\n[PASS] test_RejectedOverclaimDoesNotBlockUnclaimedRelease() (gas: 1808177)\n[PASS] test_RevertedSlippageDoesNotConsumeBurnAllowance() (gas: 3675113)\n[PASS] test_SingleBurnSandwichControl() (gas: 4218644)\nLogs:\n  single-burn attacker ETH: 99.912966340529872311\n\n[PASS] test_SmallBurnCannotBeRefilledAndRepeatedInSameBlock() (gas: 3734644)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 159.10ms (74.25ms CPU time)\n\nRan 44 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2998158)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1277081)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1478960)\n[PASS] test_ClaimsOneForOne() (gas: 1602079)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208607)\n[PASS] test_DeploysOnAFreshChain() (gas: 2338377)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 10970310)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2344984)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599549457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1318351)\n[PASS] test_FitsOneTransaction() (gas: 10949030)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 8088\n  createHook gas: 1297438\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1866361)\nLogs:\n  pot bridge: 0.511887599999999100\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1448391)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1326376)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1318005)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2212818)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1976274)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288387119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2092476)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2016712)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1982731)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1318355)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 67989)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91539)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117785)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1821743)\n[PASS] test_PassesTheAdmissionScan() (gas: 15443819)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1469145)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702296)\n[PASS] test_RefusesTheWrongAddress() (gas: 709787)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1293055)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214715)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1819855)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1251542)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1314902)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2684559)\n[PASS] test_TheFeeIsStatic() (gas: 1600951)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 19092109)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1363164)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2173355)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2334808)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2126315)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1669297)\n[PASS] test_TradesBothWays() (gas: 1573541)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 159.08ms (127.03ms CPU time)\n\nRan 5 test suites in 160.70ms (437.99ms CPU time): 72 tests passed, 0 failed, 0 skipped (72 total tests)\n","passed":true},{"durationMs":73,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMD6900.approve(address,uint256)\",\"IMD6900.burn(uint256)\",\"IMD6900.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMD6900.transfer(address,uint256)\",\"IMD6900.transferFrom(address,address,uint256)\",\"IMD6900Hook.afterAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMD6900Hook.afterRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),int256,int256,bytes)\",\"IMD6900Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMD6900Hook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeDonate(address,(address,address,uint24,int24,address),uint256,uint256,bytes)\",\"IMD6900Hook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"IMD6900Hook.beforeRemoveLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMD6900Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMD6900Hook.cancelOwnershipHandover()\",\"IMD6900Hook.completeOwnershipHandover(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.feeCheckpoint()\",\"IMD6900LockedPool.feeRefund(address)\",\"IMD6900LockedPool.lowerFee(uint24)\",\"IMD6900LockedPool.open(address,uint160,uint256)\",\"IMD6900LockedPool.receive()\",\"IMD6900LockedPool.setCoinFeeTo(address)\",\"IMD6900LockedPool.setHook(address)\",\"IMD6900LockedPool.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.addFees()\",\"IMD6900RobinhoodLaunch.addPerpFees()\",\"IMD6900RobinhoodLaunch.burnImd(uint256)\",\"IMD6900RobinhoodLaunch.cancelOwnershipHandover()\",\"IMD6900RobinhoodLaunch.claim(uint256,uint256,bytes32[])\",\"IMD6900RobinhoodLaunch.completeOwnershipHandover(address)\",\"IMD6900RobinhoodLaunch.createHook(bytes32)\",\"IMD6900RobinhoodLaunch.endClaims()\",\"IMD6900RobinhoodLaunch.harvest()\",\"IMD6900RobinhoodLaunch.launch(bytes32,address,uint160,uint256,address)\",\"IMD6900RobinhoodLaunch.receive()\",\"IMD6900RobinhoodLaunch.recoverEth(address,uint256)\",\"IMD6900RobinhoodLaunch.releaseExcess(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseImdstr(uint256,address)\",\"IMD6900RobinhoodLaunch.releaseUnclaimed(address)\",\"IMD6900RobinhoodLaunch.renounceOwnership()\",\"IMD6900RobinhoodLaunch.requestOwnershipHandover()\",\"IMD6900RobinhoodLaunch.sellHeld(uint256,uint256,address)\",\"IMD6900RobinhoodLaunch.setClaims(bytes32,uint256,uint256)\",\"IMD6900RobinhoodLaunch.setImdBurn(address)\",\"IMD6900RobinhoodLaunch.setImdPool(uint24,int24,address)\",\"IMD6900RobinhoodLaunch.setPayees(address[],uint16[])\",\"IMD6900RobinhoodLaunch.setPerpFeeTo(address)\",\"IMD6900RobinhoodLaunch.split()\",\"IMD6900RobinhoodLaunch.transferOwnership(address)\",\"IMD6900RobinhoodLaunch.unlockCallback(bytes)\",\"IMD6900RobinhoodLaunch.withdrawEth(address,uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":177,\"README.md\":146,\"foundry.toml\":25,\"jobs/swarm-launch.json\":27,\"launch.json\":15,\"script/claims.py\":88,\"script/launch.sh\":238,\"script/mine.sh\":12,\"script/params.py\":64,\"script/programmable_plan.py\":205,\"snapshots/rh-community-2026-10-09.json\":56,\"src/IMD6900.sol\":29,\"src/IMD6900Hook.sol\":262,\"src/IMD6900LockedPool.sol\":368,\"src/IMD6900RobinhoodLaunch.sol\":620,\"test/HookSalt.sol\":35,\"test/IMD6900RobinhoodLaunch.t.sol\":1033,\"test/LaunchAdmission.t.sol\":63,\"test/LaunchAudit.t.sol\":412,\"test/LaunchReview.t.sol\":458,\"test/RobinhoodFork.t.sol\":217},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e8f06b0ee8095d32f229d304dfa9b1e656f0312e6e96f41c6dca150da8cf6101","verifiedTreeHash":"a86dbd576458694116eaee2da70a9172797428bd","verifierVersion":"0.1.0+327e1e9f"}]}