{"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":"1b9f4da0-fc35-47b3-bb7e-deb4d47758ca","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":null,"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":"failed"},{"acceptedSubmissionHash":null,"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":"waiting"},{"acceptedSubmissionHash":null,"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":"waiting"},{"acceptedSubmissionHash":"2feac20e63a79c2e04be77bc193bf07b7f1b2cd598e3c9f44f1f7fb777a7fd6d","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":null,"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":"waiting"},{"acceptedSubmissionHash":null,"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":"waiting"},{"acceptedSubmissionHash":null,"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":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"waiting"},{"acceptedSubmissionHash":null,"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":"waiting"}],"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). The perps are part of this project and of every audit and test step: src/perps/PerpEngine.sol, PerpVault.sol and PerpSwapLib.sol (inlined, internal functions only: no DELEGATECALL anywhere, the engine under EIP-170 at about 24.4KB). They are not deployed with the launch (the engine's constructor binds to the live pool): IMD6900LockedPool.createPerps creates them right after launch() from exactly the code whose keccak256 is ENGINE_CODE_HASH / VAULT_CODE_HASH (test_ThePerpsCodeIsTheAuditedCode): any fix to src/perps must update those two constants, or the test fails; the engine stays owned by the Robinhood timelock and is wired into the hook at once (initPerpEngine), fee-free by refund; audit its no-bad-debt liquidation inside the hook's pre-trade sweep, the refund pair, the vault's accounting and the fee split (20% stakers, 10% insurance, 70% to the launch's addPerpFees). test/Perps.t.sol covers creation, longs, shorts, the sweep's liquidations and fees. 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, the perps created and traded, 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":"99396a0b8724ac395c474eed3c20b5dcb90783bc27c618f5800e7b201700b1ed","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"1b9f4da0-fc35-47b3-bb7e-deb4d47758ca","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1591-imd6900robinhoodlaunch"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52200","feedbackHash":"4b39e0805d2616d51b264d6d62b461624891d13fc5417e487002f0f700661dca","nodeKey":"audit_imported_code","submissionHash":"2feac20e63a79c2e04be77bc193bf07b7f1b2cd598e3c9f44f1f7fb777a7fd6d","tag1":"review:submission","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"312b112440c6d2af87a332bd50906bc1efb4016bb90f5d10fe0205dd220edbc0","state":"blocked","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fdbedee33322a6ef","findings":[{"citation":"resolved","description":"When a payee's call fails, its `part` simply stays in the contract's balance. The next split() recomputes `amount = address(this).balance - imdBucket` and divides that whole amount again by the current shares, so the refused payee's share is redistributed pro rata to everyone, not kept for that payee as the NatSpec says ('leaves it here for the next split'). split() and harvest() are permissionless, so anyone can loop them. With the default payees (POT_BRIDGE 90%, imdBurn 10%), each call while POT_BRIDGE reverts moves 10% of the pot's ETH into imdBucket, where burnImd spends it on $IMD: the pot's share is paid to the wrong party. With custom payees (setPayees) the same moves a reverting payee's share to the others.","line":455,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"After launch, contract holds 1 ETH of fees, imdBucket = 0, default payees. POT_BRIDGE's receive reverts (paused/upgraded bridge, or in a test: vm.etch(POT_BRIDGE, hex\"fe\")). Call split() 50 times. Expected: 0.1 ETH in imdBucket and 0.9 ETH kept for the pot bridge. Actual: call 1 imdBucket=0.1, call 2 amount=0.9 -> imdBucket=0.19, ... after n calls imdBucket = 1 - 0.9^n (0.995 ETH after 50 calls); burnImd then spends the pot's ETH buying $IMD. Fix: track per-payee owed amounts (or exclude unpaid shares from the next split's base).","severity":"medium","snippet":"            if (!ok) emit PayFailed(to[i], part);","title":"split() re-splits a refused payee's share among all payees: a reverting pot bridge drains the NFT pot's 90% into the $IMD bucket (or to other payees)"},{"citation":"resolved","description":"PerpSwapLib.swapLeg calls feeCheckpoint on the hook's launcher (the locked pool) before every engine swap, unconditionally whenever the hook exposes launcher(). isRefunded only accepts the engine currently wired in the hook. IMD6900Hook.setPerpEngine is documented as the escape hatch (replace an engine, or zero to turn perps off), but as soon as it points anywhere else, the old engine's close(), liquidate() and every settlement revert NotRefunded, so traders cannot exit and their collateral (and the vault's lent ETH/token in longOiEth/shortOiToken) stays locked in the engine. lowerFee refuses while openCount != 0, and any trader can hold a healthy minCollateral position open indefinitely, so the only route to a lower fee is setPerpEngine(0) and then lowerFee; after that the engine is bound to a pool with no liquidity and the positions can never be closed even if the engine is wired back.","line":252,"path":"src/IMD6900LockedPool.sol","reproduction":"Setup as test/Perps.t.sol setUp (launch, createPerps, staker deposits 10 ETH). ALICE: engine.openLong{value: 1 ether}(2, 0) -> id. Timelock: hook.setPerpEngine(address(0)). ALICE: engine.close(id, 0) -> reverts NotRefunded (from IMD6900LockedPool.feeCheckpoint via PerpSwapLib.swapLeg). Anyone: engine.liquidate(id) also reverts the same way. Then timelock: pool.lowerFee(33_300) succeeds (engine==0); timelock re-wires hook.setPerpEngine(engine): close(id) now reverts in the hook's _beforeSwap (NotOurPool, the engine's PoolKey is the old pool). Expected: positions closable at any time, or lowerFee/unwiring impossible while positions are open. Fix: let swapLeg skip the refund when the engine is not refunded (or let isRefunded accept LockedPool.perpsEngine), and make lowerFee check LockedPool.perpsEngine's openCount, not only the hook's current engine.","severity":"medium","snippet":"        if (!isRefunded(msg.sender)) revert NotRefunded();","title":"Unwiring or replacing the perps engine (the timelock's documented way out, and the only way to lowerFee while any position is open) freezes every open position: their closes and liquidations revert No"},{"citation":"resolved","description":"In unlockCallback(2) the launch arms feeCheckpoint, then swaps; the hook's afterSwap runs inside that window and calls engine.sweepLiquidations. A liquidation there runs PerpSwapLib.swapLeg, whose own feeCheckpoint calls _poke(address(this)) on the locked pool, collecting every fee accrued so far, including the 4.44% the launch's sale just paid, into the locked pool (later burned or sent to coinFeeTo by collect). The launch's feeRefund then pokes only what accrued after the engine's refund (about 0), so back = 0, sold = paid, and the timelock's sale pays the full pool fee despite the documented exemption.","line":501,"path":"src/IMD6900RobinhoodLaunch.sol","reproduction":"After createPerps, a long open at 5x near its liquidation price; launch holds excessHeld coins. Timelock: sellHeld(amount, 0, to) large enough that the post-swap price trips the long. Expected: the round's coin fee (~4.44% of amount) refunded (back > 0, sold = paid - back). Actual: the long is liquidated in afterSwap, back == 0 for that round, sold == paid, and the fee coins are burned at the next pool.collect(). Fix: have checkpoints nest per caller (book the engine's pre-poke amount to the outer armed caller), or skip the hook's sweeps for the launch's sellHeld swap.","severity":"low","snippet":"                (, uint256 back) = pool.feeRefund(address(this));","title":"sellHeld's 'fee-free' sale loses its refund whenever the hook's post-trade sweep liquidates: the engine's feeCheckpoint books the launch's fee as ordinary fees"},{"citation":"resolved","description":"Read in full: src/IMD6900RobinhoodLaunch.sol, src/IMD6900LockedPool.sol, src/IMD6900Hook.sol, src/IMD6900.sol; src/perps/PerpEngine.sol lines 400-1120 (opens, close/liquidate, the hook sweep, settlement, swaps, fee routing, vault funding/admin); src/perps/PerpSwapLib.sol swapLeg/_grossUp/_launcherOf/_settle (the refund pair); src/perps/PerpVault.sol depositEth/withdrawEth/_haircut. Not reached within the time budget: PerpEngine.sol constructor, funding and TWAP (lines 1-400), PerpSwapLib's projection/exitInsolvent/limit math, PerpVault's queue sync and token-side yield (lines 355-823), the tests and scripts. Nothing was compiled or executed: a via-IR build of this repository was not attempted on this machine (the last commit notes an OOM kill), so the findings' reproductions are traced by reading, not run. Checked without a finding: hook permissions/flags, pool initialization guarded by the hook, the coin (plain ERC20, no owner/mint), vanity check, no DELEGATECALL/CALLCODE/SELFDESTRUCT in src, timelock-only setters.","line":227,"path":"src/IMD6900LockedPool.sol","reproduction":"Not a defect: coverage statement for this review.","severity":"info","snippet":"        if (keccak256(engineCode) != ENGINE_CODE_HASH || keccak256(vaultCode) != VAULT_CODE_HASH) revert NotThePerpsCode();","title":"Review scope: contracts read and not reached"}],"hash":"2feac20e63a79c2e04be77bc193bf07b7f1b2cd598e3c9f44f1f7fb777a7fd6d","nodeId":"5f068e72-5ba1-4789-b60e-ba2f9e5f864f","outcome":"completed","summary":"I found two medium defects and one low one, and saved them to `.imd-findings.json` with a separate note on what I read. I didn't compile or run anything: the last commit says the build machine was killed (exit 137), so I didn't try a via-IR build here. Every reproduction was traced by reading the code, and none comes with a proof test. I changed no files.\n\n**Findings**\n\n1. **Medium – a payee that refuses its ETH has its share handed to the others** (`src/IMD6900RobinhoodLaunch.sol:455`). When a payee's transfer fails, the ETH stays in the contract. The next `split()` divides the whole balance again across all payees, so the refused share is spread out rather than kept for that payee, as the code comment says it should be. Anyone can call `split()` or `harvest()` repeatedly. With the default split and the pot bridge reverting, each call moves 10% of what's left into the $IMD buy fund. After 50 calls, 1 ETH of fees becomes about 0.995 ETH spent buying $IMD instead of going to the NFT pot.\n\n2. **Medium – replacing or removing the perps engine freezes every open position** (`src/IMD6900LockedPool.sol:252`). Every engine trade asks the locked pool for its fee refund first. The pool refuses any engine that isn't the one currently set on the hook. So after the timelock calls `hook.setPerpEngine(0)` (the documented way out), `close()` and `liquidate()` on the old engine both revert, and traders' collateral is stuck.\n   - Any trader can block `lowerFee` by keeping one small, healthy position open. The only way around that is to unwire the engine first.\n   - If the timelock then runs `lowerFee`, the old engine is tied to a pool with no liquidity. Its positions can't be closed even if it is wired back.\n\n3. **Low – the fee-free `sellHeld` can pay the full 4.44% fee anyway** (`src/IMD6900RobinhoodLaunch.sol:501`). If the sale pushes a perps position into liquidation, that liquidation runs after the sale's swap but before the sale claims its refund. The engine's own fee bookkeeping sweeps up the sale's fee, so the refund comes back as about 0 and those coins are burned at the next fee collection.\n\n**Contracts read**\n- **In full:** `IMD6900RobinhoodLaunch.sol`, `IMD6900LockedPool.sol`, `IMD6900Hook.sol` and `IMD6900.sol`.\n- **Perps engine:** `PerpEngine.sol` lines 400–1120, which cover opening, closing, liquidation, the pre-trade sweep, settlement, swaps and fee routing.\n- **Fee refund:** the refund pair in `PerpSwapLib.sol`.\n- **Vault:** the ETH-side deposit and withdraw functions in `PerpVault.sol`.\n\n**Not reached in the time available**\n- `PerpEngine.sol` lines 1–400: the constructor, funding and price averaging.\n- `PerpSwapLib.sol`: the price-projection and insolvency math.\n- `PerpVault.sol`: the exit-queue syncing and the token-side yield.\n- The tests and scripts.\n\n**Checked, no problems found:** the hook's permissions and address flags, pool setup being limited to the hook, the coin being a plain ERC20 with no owner or mint, the 0x6900 address check, no DELEGATECALL, CALLCODE or SELFDESTRUCT in `src`, and the setters being timelock-only.","treeHash":null,"usage":{"cachedInputTokens":992307,"inputTokens":26,"model":"claude-opus-5-5","outputTokens":23655,"runtime":"claude","turns":15,"wallClockMs":262287}},{"artifacts":[],"attempt":3,"bundleHash":"ee13558ca45bf3634f5e397857e230f0bd7b7310d71f6b4960babc9c89d02454","device":"fa8fc4653a9e883d","findings":[],"hash":"3c5e5da7344ebace507ded9faf9f6b2d1da8f0abd22dc3f9196be217ca2800f1","nodeId":"6727e47f-f3de-44cd-b2d1-d344d37042c2","outcome":"completed","summary":"The build is clean (the earlier exit code came from the grep finding no compile output, not from the build) and all 59 tests pass. The work is complete.\n\n**Outcome.** The launch contract already fit the factory as it arrived, so the launch-kind rules required no change to the constructor, compiler settings, hook, fee, coin, split defaults or timelock role. All three audit defects reproduced and are fixed, each with tests. The perps source is untouched, so the two code-hash constants still match the build.\n\n**What changed**\n\n- **Refused payee's share (medium, fixed).** The launch now books a failed payee's part to that payee alone, excludes it from every later split's base, and retries it at the next split or through a new permissionless retry call. The timelock's recovery clamps the owed total the way it already clamped the IMD bucket. Two tests cover the audit's 50-call reproduction, a replaced payee, and the recovery clamp.\n- **Unwired engine freezing positions (medium, fixed).** The locked pool keeps refunding the engine it created, so its closes and liquidations work after the timelock unwires or replaces it. The fee move now refuses while either the hook's engine or the created engine has positions open. Two tests on the real engine cover the audit's sequence and a replacement engine.\n- **Lost refund on the timelock's sale (low, fixed).** Fee checkpoints now nest in transient storage: a checkpoint taken inside another refunded caller's window credits what it collected to that caller, whose refund pays it on. A test runs a sweep that trades inside each of the sale's three rounds and checks both parties get exactly their own fee back.\n- **Pre-existing test failure (test only).** The perps code-hash test failed before any change because the salt miner allocated memory on every try and ran out of gas. The miners now hash in scratch memory.\n\n**Verification**\n\n- The exact protected harness was rehearsed locally with the four real constructor arguments and passed.\n- Launch runtime is 23,576 bytes, under the limit; deploy execution is 7.51M gas against 7.22M before the fixes.\n- The fork test was not run, since it needs a Robinhood RPC and the task's verification has no network.\n\nADAPTATION.md at the repository root lists each change, its file, the finding or rule behind it, and the coverage note for the info-level finding. Nothing was committed.","treeHash":"3e14befc3bc806e6b3a2dde2ad3527f7af6d7c50","usage":{"cachedInputTokens":4445823,"inputTokens":1026,"model":"claude-fable-5-1","outputTokens":55186,"runtime":"claude","turns":67,"wallClockMs":963692}},{"artifacts":[],"attempt":2,"bundleHash":"6664aa74aa684abe1dfbcf68bcd08735808cb395af1003654436c4a3074c97da","device":"39da99ded7f125c8","findings":[],"hash":"8b10676a12b14f0d0a23a6305a6f8ebdb282227412ec3a1bfa78e104fc60ef77","nodeId":"6727e47f-f3de-44cd-b2d1-d344d37042c2","outcome":"completed","summary":"Done. The project is launch-ready as it stood; the work was the three audit findings that reproduced, plus one test fix.\n\n**Launch shape, verified unchanged.** The single contract `IMD6900RobinhoodLaunch` keeps its four-argument nonpayable constructor, explicit owner, no external calls at construction, and no forbidden opcodes. I rehearsed the protected harness itself with the real arguments and chain id 4663 and it passes. Runtime is 23,465 bytes, under the EIP-170 bound. `src/perps/` is untouched, so both code-hash constants still match the build.\n\n**Fixes, each reproduced on the original source first (the new tests fail there with the audit's numbers) and passing now:**\n- **Split re-splitting a refused share** (medium) in `src/IMD6900RobinhoodLaunch.sol`. A refused payee's share is now booked to that payee alone, excluded from later splits' base, and paid with its next share or via a public `payOwed`. The timelock's `recoverEth` clamps the owed total so recovered ETH is owed to nobody.\n- **Unwiring the engine froze positions** (medium) in `src/IMD6900LockedPool.sol`. The engine the pool created stays refunded whether or not the hook serves it, and `lowerFee` refuses while that engine holds positions, not only the hook's current one. Opens remain blocked while unwired, as before.\n- **The sale's refund lost to the sweep's nested checkpoint** (low) in `src/IMD6900LockedPool.sol`. Checkpoints now nest: what an inner checkpoint takes during the outer caller's swap is handed to the outer caller at its refund.\n- **Test flakiness**: the hash test died with MemoryOOG in the coin-salt mining loop, whose iteration count depends on the launch's address. The loops in `test/HookSalt.sol` now hash in a fixed scratch buffer.\n\n**Checks.** `forge build` and `forge test` pass with the project's own configuration: 58 tests, 0 failures, the fork test skipping without an RPC. `ADAPTATION.md` lists each change, the finding or rule behind it, and that the info-level finding needed no change. The README's three affected sentences were updated. No build configuration, dependencies, scripts, hook, coin or perps source were touched, and nothing was committed.","treeHash":"3a8e813b8245fd73c69a0ed50943f5a61d6d7413","usage":{"cachedInputTokens":2604569,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":47556,"runtime":"claude","turns":54,"wallClockMs":849574}},{"artifacts":[],"attempt":1,"bundleHash":"c6e52e723a5b9edcd421e61972b4c74daa33f0c98e9e995d895e3b048014415c","device":"dc176559ff153c37","findings":[],"hash":"bd7d9ae50a2fba0386f6e4e3ac6c349198d8380e9a5f709e8147af82caf676cf","nodeId":"6727e47f-f3de-44cd-b2d1-d344d37042c2","outcome":"completed","summary":"Done. The project was already launchable as it stands, so the launch-side adaptation needed no change. All three reproducible audit findings are fixed with tests, one broken test was repaired, and the build and the full suite pass offline on a clean build.\n\n**What I verified first**\n- The constructor already fits the factory: four static arguments, nonpayable, owner from an argument, no external call, only the locked pool created. The protected admission test passes when rehearsed with the brief's four addresses.\n- No CALLCODE, DELEGATECALL or SELFDESTRUCT anywhere, creation code included. Every runtime is under EIP-170.\n- The code as it arrived built in 30 seconds here and 53 of 54 tests passed. The one failure was in a test's salt miner, not the contracts.\n\n**Audit findings, each reproduced and fixed**\n- **Re-split of a refused share** in `src/IMD6900RobinhoodLaunch.sol`: a refused share is now booked to that payee, excluded from later splits, and paid by a new permissionless `payOwed`. The timelock's recovery shrinks what is set aside, bucket first. Test: fifty splits against a reverting pot bridge leave the pot's 90% owed to the bridge only.\n- **Unwired engine froze positions** in `src/IMD6900LockedPool.sol`: the engine the pool created stays refunded after the timelock unwires or replaces it, and `lowerFee` refuses while either engine has positions open. No change to `src/perps`, so the audited code hashes are unchanged. Test: unwire, close fee-free, no new opens, rewire, replace, close, then the fee move goes through.\n- **Sale lost its refund during the post-trade sweep**: checkpoints now nest. A checkpoint opened inside another refunded caller's books the accrued fee to that caller. Test: a stand-in engine trades in each of the sale's three post-trade sweeps and the sale still gets all three refunds.\n- The scope-only finding needed nothing.\n\n**Test repair**\n- The salt miners in `test/HookSalt.sol` allocated memory per try, so the code-hash test ran out of EVM memory when it mined a second coin salt. They now hash in scratch memory, and the test passes: the hashes match the build.\n\n**Results**\n\n| Check | Result |\n|---|---|\n| forge build | passes, warnings only |\n| forge test | 57 passed, 0 failed |\n| Protected admission rehearsal | passes |\n\n`ADAPTATION.md` lists every change with its reason, and the README's test count and the two changed behaviours are updated. One caution is recorded there: a `forge inspect` or `--sizes` run leaves a perps artifact a few bytes off, which makes `createPerps` reject it until a clean rebuild. The fork test was not run, since no RPC was used. Nothing is committed, and `launch.json` is left to the manifest step.","treeHash":"8f3a5df117af9cd4c886f63b11f990aea395cc02","usage":{"cachedInputTokens":3960144,"inputTokens":1090,"model":"claude-fable-5-1","outputTokens":46475,"runtime":"claude","turns":58,"wallClockMs":960713}}],"verification":[{"checks":[{"durationMs":34430,"exitCode":0,"name":"build","output":"Compiling 91 files with Solc 0.8.26\nSolc 0.8.26 finished in 34.28s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/perps/PerpEngine.sol:349:5:\n    |\n349 |     function _quoteAt(uint256 size, uint256 sp) internal view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/perps/PerpVault.sol:364:5:\n    |\n364 |     function _toYieldUnit(uint256 v) private view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":362,"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 597.88µs (51.52µs CPU time)\n\nRan 47 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_ARefusedShareStaysOwedToItsPayee() (gas: 4245096)\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2950919)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1257507)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1459408)\n[PASS] test_ClaimsOneForOne() (gas: 1577827)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208651)\n[PASS] test_DeploysOnAFreshChain() (gas: 8061919)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 5407078)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2329211)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599550457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1298777)\n[PASS] test_FitsOneTransaction() (gas: 5385790)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 7825\n  createHook gas: 1266599\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1844552)\nLogs:\n  pot bridge: 0.511887600000000000\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1428767)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1306880)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1298431)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2201433)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1962808)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288388119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2081014)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2005496)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1971446)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1298908)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 68033)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91605)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117775)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1800035)\n[PASS] test_PassesTheAdmissionScan() (gas: 15635927)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1449657)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702362)\n[PASS] test_RefusesTheWrongAddress() (gas: 709831)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1273437)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214989)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1800481)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1231968)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1295350)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2670882)\n[PASS] test_TheFeeIsStatic() (gas: 1581561)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 6981734)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1343687)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21900)\n[PASS] test_TheLiquidityIsLocked() (gas: 2153964)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2311392)\n[PASS] test_TheSaleIsRefundedEvenWhenTheSweepTradesInsideIt() (gas: 2698126)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2123246)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1647319)\n[PASS] test_TradesBothWays() (gas: 1553924)\n[PASS] test_WhatIsOwedFollowsThePayeeNotTheSplit() (gas: 2018620)\nSuite result: ok. 47 passed; 0 failed; 0 skipped; finished in 109.86ms (156.89ms CPU time)\n\nRan 11 tests for test/Perps.t.sol:PerpsTest\n[PASS] test_ALongRoundTripPaysNoPoolFee() (gas: 1053309)\nLogs:\n  a 0.1 ETH 5x long, opened and closed: back: 0.093099999999999968\n\n[PASS] test_AReplacedEngineStillLiquidates() (gas: 2687108)\n[PASS] test_AShortRoundTrip() (gas: 1845395)\nLogs:\n  a 0.1 ETH 3x short, opened and closed: back: 0.093099999999999998\n\n[PASS] test_AWhaleDumpLiquidatesInTheHooksSweepFirst() (gas: 1884302)\n[PASS] test_AnUnwiredEngineStillClosesAndBlocksTheFeeMove() (gas: 1386566)\n[PASS] test_NoFeeMoveWithAPositionOpen() (gas: 653020)\n[PASS] test_OnlyTheTimelockTunesThePerps() (gas: 120171)\n[PASS] test_PerpFeesReachThePot() (gas: 697904)\n[PASS] test_ThePerpsAreCreatedAndWired() (gas: 145028)\n[PASS] test_ThePerpsCodeIsTheAuditedCode() (gas: 67540016)\n[PASS] test_ThePerpsPassTheAdmissionScan() (gas: 14696303)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 227.55ms (200.09ms CPU time)\n\nRan 3 test suites in 229.77ms (338.01ms CPU time): 59 tests passed, 0 failed, 0 skipped (59 total tests)\n","passed":true},{"durationMs":79,"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.initPerpEngine(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.createPerps(bytes,bytes)\",\"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.payOwed(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)\",\"PerpEngine.claimPayout()\",\"PerpEngine.close(uint256,uint256)\",\"PerpEngine.flushFees()\",\"PerpEngine.fundFromVault()\",\"PerpEngine.fundInsurance()\",\"PerpEngine.fundPlv()\",\"PerpEngine.fundPlvToken(uint256)\",\"PerpEngine.fundTokenFromVault(uint256)\",\"PerpEngine.liquidate(uint256)\",\"PerpEngine.openLong(uint8,uint256)\",\"PerpEngine.openShort(uint8,uint256)\",\"PerpEngine.poke()\",\"PerpEngine.receive()\",\"PerpEngine.selfSweep(address)\",\"PerpEngine.setFeeSink(address)\",\"PerpEngine.setFees(uint256,uint256,uint256)\",\"PerpEngine.setGuards(uint32,uint256,uint256)\",\"PerpEngine.setMinCollateral(uint256)\",\"PerpEngine.setRisk(uint8,uint256,uint256,uint256,uint256)\",\"PerpEngine.setShortCap(uint256)\",\"PerpEngine.setVault(address)\",\"PerpEngine.setVaultLimits(uint256,uint256)\",\"PerpEngine.setVaultSplit(uint256,uint256)\",\"PerpEngine.skimInsurance(uint256,address)\",\"PerpEngine.sweepLiquidations(address,int256,bool,uint160)\",\"PerpEngine.transferOwnership(address)\",\"PerpEngine.unlockCallback(bytes)\",\"PerpEngine.withdrawPlvTo(uint256,address)\",\"PerpEngine.withdrawPlvTokenTo(uint256,address)\",\"PerpEngine.withdrawTokYieldTo(uint256,address)\",\"PerpVault.claimPendingEth()\",\"PerpVault.claimPendingToken()\",\"PerpVault.claimTokYield()\",\"PerpVault.depositEth()\",\"PerpVault.depositToken(uint256)\",\"PerpVault.settlePendingEth(address)\",\"PerpVault.settlePendingToken(address)\",\"PerpVault.withdrawEth(uint256)\",\"PerpVault.withdrawToken(uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":90,\"README.md\":146,\"foundry.toml\":30,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":269,\"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\":255,\"src/IMD6900LockedPool.sol\":457,\"src/IMD6900RobinhoodLaunch.sol\":588,\"src/perps/PerpEngine.sol\":1158,\"src/perps/PerpSwapLib.sol\":728,\"src/perps/PerpVault.sol\":823,\"test/HookSalt.sol\":51,\"test/IMD6900RobinhoodLaunch.t.sol\":1180,\"test/Perps.t.sol\":285,\"test/RobinhoodFork.t.sol\":255},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"static analysis could not run: slither produced no report: ib/python3.11/site-packages/slither/slithir/convert.py\", line 1981, in convert_constant_types\n    assert len(types) == len(ir.arguments)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError\n'forge clean' running (wd: /tmp/imd-verify-Qk3Ey9/repo)\n'forge config --json' running\n'forge build --build-info --deny never --skip ./test/** ./script/** --force' running (wd: /tmp/imd-verify-Qk3Ey9/repo)\n","evaluation":"checks","profile":"foundry","status":"error","submissionHash":"3c5e5da7344ebace507ded9faf9f6b2d1da8f0abd22dc3f9196be217ca2800f1","verifiedTreeHash":"3e14befc3bc806e6b3a2dde2ad3527f7af6d7c50","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":45193,"exitCode":0,"name":"build","output":"Compiling 91 files with Solc 0.8.26\nSolc 0.8.26 finished in 45.01s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/perps/PerpEngine.sol:349:5:\n    |\n349 |     function _quoteAt(uint256 size, uint256 sp) internal view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/perps/PerpVault.sol:364:5:\n    |\n364 |     function _toYieldUnit(uint256 v) private view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":503,"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 496.60µs (24.91µs CPU time)\n\nRan 47 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_ARefusedShareStaysThePayeesOwn() (gas: 3519447)\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2951478)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1257507)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1459408)\n[PASS] test_ClaimsOneForOne() (gas: 1577827)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208651)\n[PASS] test_DeploysOnAFreshChain() (gas: 8061875)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 5407078)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2326729)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599550457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1298777)\n[PASS] test_FitsOneTransaction() (gas: 5385790)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 7825\n  createHook gas: 1266599\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1845133)\nLogs:\n  pot bridge: 0.511887600000000000\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1428767)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1306836)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1298387)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2201493)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1960326)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288388119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2081091)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2004141)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1971459)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1298864)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 68033)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91605)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117797)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1800616)\n[PASS] test_PassesTheAdmissionScan() (gas: 15580853)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1449657)\n[PASS] test_RecoveredEthIsOwedToNobody() (gas: 1639438)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702362)\n[PASS] test_RefusesTheWrongAddress() (gas: 709853)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1273437)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214945)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1800481)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1231990)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1295350)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2668800)\n[PASS] test_TheFeeIsStatic() (gas: 1581583)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 6981734)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1343643)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2153964)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2311392)\n[PASS] test_TheSaleStaysFeeFreeWhenTheSweepLiquidates() (gas: 2674110)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2117147)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1647319)\n[PASS] test_TradesBothWays() (gas: 1553946)\nSuite result: ok. 47 passed; 0 failed; 0 skipped; finished in 151.19ms (213.61ms CPU time)\n\nRan 10 tests for test/Perps.t.sol:PerpsTest\n[PASS] test_ALongRoundTripPaysNoPoolFee() (gas: 1051209)\nLogs:\n  a 0.1 ETH 5x long, opened and closed: back: 0.093099999999999968\n\n[PASS] test_AShortRoundTrip() (gas: 1843291)\nLogs:\n  a 0.1 ETH 3x short, opened and closed: back: 0.093099999999999998\n\n[PASS] test_AWhaleDumpLiquidatesInTheHooksSweepFirst() (gas: 1882206)\n[PASS] test_NoFeeMoveWithAPositionOpen() (gas: 651975)\n[PASS] test_OnlyTheTimelockTunesThePerps() (gas: 120149)\n[PASS] test_PerpFeesReachThePot() (gas: 696841)\n[PASS] test_ThePerpsAreCreatedAndWired() (gas: 145006)\n[PASS] test_ThePerpsCodeIsTheAuditedCode() (gas: 67539994)\n[PASS] test_ThePerpsPassTheAdmissionScan() (gas: 14696259)\n[PASS] test_UnwiringTheEngineLeavesItsPositionsClosable() (gas: 2266370)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 321.44ms (289.41ms CPU time)\n\nRan 3 test suites in 323.33ms (473.12ms CPU time): 58 tests passed, 0 failed, 0 skipped (58 total tests)\n","passed":true},{"durationMs":119,"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.initPerpEngine(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.createPerps(bytes,bytes)\",\"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.payOwed(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)\",\"PerpEngine.claimPayout()\",\"PerpEngine.close(uint256,uint256)\",\"PerpEngine.flushFees()\",\"PerpEngine.fundFromVault()\",\"PerpEngine.fundInsurance()\",\"PerpEngine.fundPlv()\",\"PerpEngine.fundPlvToken(uint256)\",\"PerpEngine.fundTokenFromVault(uint256)\",\"PerpEngine.liquidate(uint256)\",\"PerpEngine.openLong(uint8,uint256)\",\"PerpEngine.openShort(uint8,uint256)\",\"PerpEngine.poke()\",\"PerpEngine.receive()\",\"PerpEngine.selfSweep(address)\",\"PerpEngine.setFeeSink(address)\",\"PerpEngine.setFees(uint256,uint256,uint256)\",\"PerpEngine.setGuards(uint32,uint256,uint256)\",\"PerpEngine.setMinCollateral(uint256)\",\"PerpEngine.setRisk(uint8,uint256,uint256,uint256,uint256)\",\"PerpEngine.setShortCap(uint256)\",\"PerpEngine.setVault(address)\",\"PerpEngine.setVaultLimits(uint256,uint256)\",\"PerpEngine.setVaultSplit(uint256,uint256)\",\"PerpEngine.skimInsurance(uint256,address)\",\"PerpEngine.sweepLiquidations(address,int256,bool,uint160)\",\"PerpEngine.transferOwnership(address)\",\"PerpEngine.unlockCallback(bytes)\",\"PerpEngine.withdrawPlvTo(uint256,address)\",\"PerpEngine.withdrawPlvTokenTo(uint256,address)\",\"PerpEngine.withdrawTokYieldTo(uint256,address)\",\"PerpVault.claimPendingEth()\",\"PerpVault.claimPendingToken()\",\"PerpVault.claimTokYield()\",\"PerpVault.depositEth()\",\"PerpVault.depositToken(uint256)\",\"PerpVault.settlePendingEth(address)\",\"PerpVault.settlePendingToken(address)\",\"PerpVault.withdrawEth(uint256)\",\"PerpVault.withdrawToken(uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":90,\"README.md\":148,\"foundry.toml\":30,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":269,\"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\":255,\"src/IMD6900LockedPool.sol\":456,\"src/IMD6900RobinhoodLaunch.sol\":585,\"src/perps/PerpEngine.sol\":1158,\"src/perps/PerpSwapLib.sol\":728,\"src/perps/PerpVault.sol\":823,\"test/HookSalt.sol\":51,\"test/IMD6900RobinhoodLaunch.t.sol\":1166,\"test/Perps.t.sol\":274,\"test/RobinhoodFork.t.sol\":255},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"static analysis could not run: slither produced no report: ib/python3.11/site-packages/slither/slithir/convert.py\", line 1981, in convert_constant_types\n    assert len(types) == len(ir.arguments)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError\n'forge clean' running (wd: /tmp/imd-verify-fkkyWt/repo)\n'forge config --json' running\n'forge build --build-info --deny never --skip ./test/** ./script/** --force' running (wd: /tmp/imd-verify-fkkyWt/repo)\n","evaluation":"checks","profile":"foundry","status":"error","submissionHash":"8b10676a12b14f0d0a23a6305a6f8ebdb282227412ec3a1bfa78e104fc60ef77","verifiedTreeHash":"3a8e813b8245fd73c69a0ed50943f5a61d6d7413","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":27777,"exitCode":0,"name":"build","output":"Compiling 91 files with Solc 0.8.26\nSolc 0.8.26 finished in 27.64s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/perps/PerpEngine.sol:349:5:\n    |\n349 |     function _quoteAt(uint256 size, uint256 sp) internal view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/perps/PerpVault.sol:364:5:\n    |\n364 |     function _toYieldUnit(uint256 v) private view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":332,"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 292.32µs (23.19µs CPU time)\n\nRan 10 tests for test/Perps.t.sol:PerpsTest\n[PASS] test_ALongRoundTripPaysNoPoolFee() (gas: 1051591)\nLogs:\n  a 0.1 ETH 5x long, opened and closed: back: 0.093099999999999968\n\n[PASS] test_AShortRoundTrip() (gas: 1843644)\nLogs:\n  a 0.1 ETH 3x short, opened and closed: back: 0.093099999999999998\n\n[PASS] test_AWhaleDumpLiquidatesInTheHooksSweepFirst() (gas: 1882582)\n[PASS] test_NoFeeMoveWithAPositionOpen() (gas: 652145)\n[PASS] test_OnlyTheTimelockTunesThePerps() (gas: 120127)\n[PASS] test_PerpFeesReachThePot() (gas: 697029)\n[PASS] test_PositionsStayClosableOnceTheEngineIsUnwired() (gas: 2829139)\n[PASS] test_ThePerpsAreCreatedAndWired() (gas: 144972)\n[PASS] test_ThePerpsCodeIsTheAuditedCode() (gas: 67539972)\n[PASS] test_ThePerpsPassTheAdmissionScan() (gas: 14696259)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 216.94ms (179.33ms CPU time)\n\nRan 46 tests for test/IMD6900RobinhoodLaunch.t.sol:IMD6900RobinhoodLaunchTest\n[PASS] test_ARefusedShareIsOwedToItsPayeeAlone() (gas: 3337969)\n[PASS] test_BurnsImdThroughItsExecutor() (gas: 2948639)\n[PASS] test_ClaimsCantChangeAfterTheLaunch() (gas: 1257485)\n[PASS] test_ClaimsNeedTheSnapshot() (gas: 1459386)\n[PASS] test_ClaimsOneForOne() (gas: 1577827)\n[PASS] test_ClaimsStayOpenNinetyDays() (gas: 208629)\n[PASS] test_DeploysOnAFreshChain() (gas: 8061875)\n[PASS] test_EachDeployerMinesItsOwnHook() (gas: 5407056)\n[PASS] test_EndingTheClaimsBringsMostOfTheBuyBack() (gas: 2324391)\nLogs:\n  back of the 2.81 ETH buy (C's claim kept by C): 2.733687356599550457\n\n[PASS] test_EthComesBackBeforeTheLaunchOnly() (gas: 1298755)\n[PASS] test_FitsOneTransaction() (gas: 5385768)\nLogs:\n  launch deploy gas (the same for every deployer: no mining): 7825\n  createHook gas: 1266599\n\n[PASS] test_HarvestSplitsTheEthAndBurnsTheCoin() (gas: 1842269)\nLogs:\n  pot bridge: 0.511887600000000000\n\n[PASS] test_KeepsTheExcessForTheTimelock() (gas: 1428723)\n[PASS] test_LaunchesAtEthereumsPrice() (gas: 1306858)\nLogs:\n  opening buy, coins: 122347490.873046793208740802\n  market cap after the buy, ETH on 1B: 25.007184312087223619\n\n[PASS] test_LaunchesOnce() (gas: 1298387)\n[PASS] test_LowerFeeMovesTheLiquidity() (gas: 2201436)\n[PASS] test_NoClaimsAllOfItBack() (gas: 1957988)\nLogs:\n  back of the 2.81 ETH buy, nobody claimed: 2.809793719288388119\n\n[PASS] test_NoFeeMoveWhilePerpsAreOpen() (gas: 2080970)\n[PASS] test_OnlyTheEngineAndTheLaunchAreRefunded() (gas: 2004141)\n[PASS] test_OnlyTheOwnerLaunches() (gas: 178900)\n[PASS] test_OnlyTheTimelockLowersTheFeeAndOnlyDown() (gas: 1971402)\n[PASS] test_OnlyTheTimelockRecoversEth() (gas: 1298864)\n[PASS] test_OnlyTheTimelockRepointsImdsPool() (gas: 68011)\n[PASS] test_OnlyTheTimelockRepointsTheBurnExecutor() (gas: 91561)\n[PASS] test_OnlyTheTimelockRunsTheHook() (gas: 117753)\n[PASS] test_OnlyTheTimelockSetsTheSplit() (gas: 1797774)\n[PASS] test_PassesTheAdmissionScan() (gas: 15511600)\n[PASS] test_PerpFeesGoAllToThePot() (gas: 1449613)\n[PASS] test_RefusesAnAddressThatIsnt0x6900() (gas: 702318)\n[PASS] test_RefusesTheWrongAddress() (gas: 709809)\n[PASS] test_SendsTheExcessWhereTold() (gas: 1273437)\n[PASS] test_TheBuyMustCoverTheClaims() (gas: 1214967)\n[PASS] test_TheCoinFeeGoesWhereTheTimelockSays() (gas: 1800459)\n[PASS] test_TheCoinIsAt0x6900() (gas: 1231946)\nLogs:\n  the coin: 0x6900d11750039d7Ef0f8262b5a62152BB906B8E8\n\n[PASS] test_TheCoinIsPlain() (gas: 1295306)\n[PASS] test_TheEngineTradesFeeFree() (gas: 2669176)\n[PASS] test_TheFeeIsStatic() (gas: 1581539)\n[PASS] test_TheHookIsCreatedOnceAtAFittingSalt() (gas: 6981712)\n[PASS] test_TheHookReportsTheEnginesFee() (gas: 1343665)\n[PASS] test_TheHooksAddressAndPermissions() (gas: 21856)\n[PASS] test_TheLiquidityIsLocked() (gas: 2153964)\n[PASS] test_ThePerpsEngineTradesThroughTheHook() (gas: 2311370)\n[PASS] test_TheSaleKeepsItsRefundWhenTheSweepTrades() (gas: 2624190)\n[PASS] test_TheTimelockSellsTheExcessBack() (gas: 2118275)\nLogs:\n  the excess alone, sold back: ETH: 1.369450260279234059\n\n[PASS] test_TheUnclaimedRestAfterTheDeadline() (gas: 1647297)\n[PASS] test_TradesBothWays() (gas: 1553902)\nSuite result: ok. 46 passed; 0 failed; 0 skipped; finished in 217.13ms (137.10ms CPU time)\n\nRan 3 test suites in 217.95ms (434.36ms CPU time): 57 tests passed, 0 failed, 0 skipped (57 total tests)\n","passed":true},{"durationMs":61,"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.initPerpEngine(address)\",\"IMD6900Hook.renounceOwnership()\",\"IMD6900Hook.requestOwnershipHandover()\",\"IMD6900Hook.setPerpEngine(address)\",\"IMD6900Hook.setPerpRefunded(bool)\",\"IMD6900Hook.setSweepFailOpen(bool)\",\"IMD6900Hook.transferOwnership(address)\",\"IMD6900LockedPool.collect()\",\"IMD6900LockedPool.createPerps(bytes,bytes)\",\"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.payOwed(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)\",\"PerpEngine.claimPayout()\",\"PerpEngine.close(uint256,uint256)\",\"PerpEngine.flushFees()\",\"PerpEngine.fundFromVault()\",\"PerpEngine.fundInsurance()\",\"PerpEngine.fundPlv()\",\"PerpEngine.fundPlvToken(uint256)\",\"PerpEngine.fundTokenFromVault(uint256)\",\"PerpEngine.liquidate(uint256)\",\"PerpEngine.openLong(uint8,uint256)\",\"PerpEngine.openShort(uint8,uint256)\",\"PerpEngine.poke()\",\"PerpEngine.receive()\",\"PerpEngine.selfSweep(address)\",\"PerpEngine.setFeeSink(address)\",\"PerpEngine.setFees(uint256,uint256,uint256)\",\"PerpEngine.setGuards(uint32,uint256,uint256)\",\"PerpEngine.setMinCollateral(uint256)\",\"PerpEngine.setRisk(uint8,uint256,uint256,uint256,uint256)\",\"PerpEngine.setShortCap(uint256)\",\"PerpEngine.setVault(address)\",\"PerpEngine.setVaultLimits(uint256,uint256)\",\"PerpEngine.setVaultSplit(uint256,uint256)\",\"PerpEngine.skimInsurance(uint256,address)\",\"PerpEngine.sweepLiquidations(address,int256,bool,uint160)\",\"PerpEngine.transferOwnership(address)\",\"PerpEngine.unlockCallback(bytes)\",\"PerpEngine.withdrawPlvTo(uint256,address)\",\"PerpEngine.withdrawPlvTokenTo(uint256,address)\",\"PerpEngine.withdrawTokYieldTo(uint256,address)\",\"PerpVault.claimPendingEth()\",\"PerpVault.claimPendingToken()\",\"PerpVault.claimTokYield()\",\"PerpVault.depositEth()\",\"PerpVault.depositToken(uint256)\",\"PerpVault.settlePendingEth(address)\",\"PerpVault.settlePendingToken(address)\",\"PerpVault.withdrawEth(uint256)\",\"PerpVault.withdrawToken(uint256)\"],\"files\":{\".gitignore\":15,\"ADAPTATION.md\":92,\"README.md\":147,\"foundry.toml\":30,\"jobs/swarm-launch.json\":27,\"script/claims.py\":88,\"script/launch.sh\":269,\"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\":255,\"src/IMD6900LockedPool.sol\":459,\"src/IMD6900RobinhoodLaunch.sol\":581,\"src/perps/PerpEngine.sol\":1158,\"src/perps/PerpSwapLib.sol\":728,\"src/perps/PerpVault.sol\":823,\"test/HookSalt.sol\":50,\"test/IMD6900RobinhoodLaunch.t.sol\":1130,\"test/Perps.t.sol\":270,\"test/RobinhoodFork.t.sol\":255},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"static analysis could not run: slither produced no report: ib/python3.11/site-packages/slither/slithir/convert.py\", line 1981, in convert_constant_types\n    assert len(types) == len(ir.arguments)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAssertionError\n'forge clean' running (wd: /tmp/imd-verify-NhJ6oN/repo)\n'forge config --json' running\n'forge build --build-info --deny never --skip ./test/** ./script/** --force' running (wd: /tmp/imd-verify-NhJ6oN/repo)\n","evaluation":"checks","profile":"foundry","status":"error","submissionHash":"bd7d9ae50a2fba0386f6e4e3ac6c349198d8380e9a5f709e8147af82caf676cf","verifiedTreeHash":"8f3a5df117af9cd4c886f63b11f990aea395cc02","verifierVersion":"0.1.0+327e1e9f"}]}