{"assessments":[],"deployments":[{"attestationHash":"aea964a579d95c0f92e5c58d664e5f11c8b9a5d45e2bd0daa5b4cc9c823989c9","chainId":4663,"contracts":[{"address":"0x33abd5871b2b6d6e1b65540be177c81d2088f2c2","blockNumber":91096893,"name":"SuperIMD","role":"other","txHash":"0x857c64103a0c185b16fe61c9aee6c41ebe0df6b587a305d3bd3dba04856cbf50"},{"address":"0x4fefe7a7f4845d66c91da662a1f6d551670bae2c","blockNumber":91096893,"name":"SuperIMDHookFactory","role":"other","txHash":"0x857c64103a0c185b16fe61c9aee6c41ebe0df6b587a305d3bd3dba04856cbf50"}],"id":"7b944eb2-1ef8-449b-b6cd-2cb8bc401024","manifestHash":"c37a8763082242793f6336d63dc80690eea1920c1839dd38275ee459acf2d3ff","status":"live"}],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"f81a6758-3b32-4268-9a9e-4117f6f3d950","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"530a454aea84aad1ee32cc76e4052ec8853097464c09c8eefd80db3dd28a8d1c","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"59a4e5d3cc1c4e894c6e124c8ea2efa93481c7a7148fbe44e5eedcff453b22f0","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"cf0e17d8192d406d282ff1e39f673bf3608f7dfd8d81e43fa67de83d3261b63f","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"5329bd38340a0a8ff82fe5efff801ba4ec16b2904d3feaff8c6484627513907f","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"0a1c7b34ddd261333e3de522fa2fca094a6ad2230ad7c7ab91746f3205903cfa","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"4c511571596ec08b9ba807199821df8337d86bfbd666ec6051e42c8481a0a081","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"32ffdd445cd6491e483333b180bd216460ed78a7b23a948fc5ffd4dcaaa07a98","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"a019a2570bc77831ad0b18340d324baa182b92d259457cec31c71230aeb5e52b","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {ERC20Permit} from \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol\";\n\n/// @title Super IMD\n/// @notice Super IMD ERC-20. Ticker: SIMD. Fixed supply: the entire supply is minted in the constructor.\n///         Website: https://www.si-md.xyz/\n///         Twitter / X: https://x.com/SuperIMD_eth\n///         Normal transfers have no fee. Swap fees (sell antisniper, etc.) are charged only\n///         through the Uniswap v4 hook (see SIMDhook.sol).\ncontract SuperIMD is ERC20, ERC20Permit {\n    constructor(uint256 initialSupply, address recipient)\n        ERC20(\"Super IMD\", \"SIMD\")\n        ERC20Permit(\"Super IMD\")\n    {\n        _mint(recipient, initialSupply);\n    }\n}\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {BaseHook} from \"./base/BaseHook.sol\";\nimport {Hooks} from \"v4-core/src/libraries/Hooks.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {SwapParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {SafeCast} from \"v4-core/src/libraries/SafeCast.sol\";\n\n/// @title SuperIMDHook\n/// @notice Uniswap v4 hook for Super IMD / SIMD.\n///         Website: https://www.si-md.xyz/\n///         Twitter / X: https://x.com/SuperIMD_eth\n///         Immutable 2% fee on every swap (buy and sell). Cannot be changed.\n///         Works for ETH or IMD quote tokens.\ncontract SuperIMDHook is BaseHook {\n    using SafeCast for uint256;\n\n    uint256 public constant FEE_BIPS = 200;\n    uint256 public constant TOTAL_BIPS = 10_000;\n\n    address public immutable feeRecipient;\n    address public immutable projectToken;\n\n    error ZeroAddress();\n\n    constructor(IPoolManager _manager, address _feeRecipient, address _projectToken) BaseHook(_manager) {\n        if (_feeRecipient == address(0) || _projectToken == address(0)) revert ZeroAddress();\n        feeRecipient = _feeRecipient;\n        projectToken = _projectToken;\n    }\n\n    function getHookPermissions() public pure override returns (Hooks.Permissions memory) {\n        return Hooks.Permissions({\n            beforeInitialize: false,\n            afterInitialize: false,\n            beforeAddLiquidity: false,\n            afterAddLiquidity: false,\n            beforeRemoveLiquidity: false,\n            afterRemoveLiquidity: false,\n            beforeSwap: false,\n            afterSwap: true,\n            beforeDonate: false,\n            afterDonate: false,\n            beforeSwapReturnDelta: false,\n            afterSwapReturnDelta: true,\n            afterAddLiquidityReturnDelta: false,\n            afterRemoveLiquidityReturnDelta: false\n        });\n    }\n\n    function _afterSwap(\n        address,\n        PoolKey calldata key,\n        SwapParams calldata params,\n        BalanceDelta delta,\n        bytes calldata\n    ) internal override returns (bytes4, int128) {\n        (Currency feeCurrency, int128 unspecifiedAmount) = (params.amountSpecified < 0 == params.zeroForOne)\n            ? (key.currency1, delta.amount1())\n            : (key.currency0, delta.amount0());\n\n        if (unspecifiedAmount < 0) unspecifiedAmount = -unspecifiedAmount;\n\n        uint256 feeAmount = (uint128(unspecifiedAmount) * FEE_BIPS) / TOTAL_BIPS;\n        if (feeAmount == 0) return (IHooks.afterSwap.selector, 0);\n\n        poolManager.take(feeCurrency, feeRecipient, feeAmount);\n        return (IHooks.afterSwap.selector, feeAmount.toInt128());\n    }\n}\n\n\naudit those contracts\n\nTotal supply: 1000000000","parentJobId":null,"planHash":"87dbd4491dd4948d3fdeaac37bebc9c89673a0b428084eac72f07042a61aad43","previousHash":"032421379a78162de4a5fef5c11b406406145df9f9078c952b166742bfc08c27","projectId":"f81a6758-3b32-4268-9a9e-4117f6f3d950","publication":{"commit":"62910b06bf09d3d8895146bfaccff151b94b78f5","deliveredAt":"2026-10-17T17:17:08.790Z","repoUrl":"https://github.com/identity-md-launches/launch-2093-spdx-license-identifier-mit-pragma"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"fc93f5b85ae335009d63139688d3a52ebd5da93a113e6c560ac0771648e20407","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"be3be4cc237417f9","findings":[{"citation":"resolved","description":"Trust-gap between the brief and the deployment input. The brief states \"Total supply: 1000000000\" (whole tokens). The constructor keeps a uint256 initialSupply parameter but accepts exactly one value, 10**27 base units; every other value, including the brief's own figure, reverts. The parameter therefore carries no information and acts only as a tripwire. In the IMD launch flow, constructors are rehearsed by the protected ContractsProtectedTest (deployAll via CREATE2 on an empty chain); a manifest step that writes the brief's figure \"1000000000\" into constructorArgs makes the SuperIMD constructor revert, the probe fails with \"application 0 constructor failed\", and the whole launch is parked. No funds are at risk and the state is recoverable by resubmitting the 28-digit value, which README.md documents, but the ABI invites the error and nothing before the launch rehearsal validates it. Minimal fix that preserves the agreed economics and ABI shape: either drop the parameter and mint INITIAL_SUPPLY unconditionally (constructor(address recipient)), or accept the whole-token figure by scaling (require initialSupply == 1_000_000_000 and mint initialSupply * 10**decimals()). Either way the manifest can no longer carry a value that compiles, deploys in tests, and fails only at the launch rehearsal.","line":22,"path":"src/SuperIMD.sol","reproduction":"Call `new SuperIMD(1000000000, owner)` (the brief's literal). Expected by a manifest author reading the brief: a token with one billion whole SIMD. Actual: revert IncorrectInitialSupply(1000000000); no contract is created. Only `new SuperIMD(1000000000000000000000000000, owner)` succeeds. Verified with a scratch Foundry test: vm.expectRevert(abi.encodeWithSelector(SuperIMD.IncorrectInitialSupply.selector, 1_000_000_000)); new SuperIMD(1_000_000_000, owner); passes, and the 10**27 value deploys with totalSupply() == 10**27.","severity":"low","snippet":"        if (initialSupply != INITIAL_SUPPLY) {\n            revert IncorrectInitialSupply(initialSupply);\n        }","title":"SuperIMD constructor rejects the brief's literal supply figure, so a manifest copying it parks the launch"}],"hash":"0a1c7b34ddd261333e3de522fa2fca094a6ad2230ad7c7ab91746f3205903cfa","nodeId":"08a53e63-cc28-47c6-8de0-7d353c134bca","outcome":"completed","summary":"The review is complete and written to `.imd-findings.json`. The tree is otherwise untouched: the scratch test was removed and no source, config or test file changed.\n\n**Outcome.** The permission model holds across all nine entry points. I traced each against the Access Control, Trust Gap and Asymmetry guides and against the pinned v4 PoolManager code, and confirmed the key claims with the existing suite and with a scratch test on the real manager.\n\n**What holds, with the reason:**\n- **afterSwap** is manager-only and pool-scoped to the project token. The claim mint debit is exactly offset by the returned delta the swapper pays, so the hook never ends a swap with an open delta. The hook never calls swap, so the self-call exemption that would skip the fee is unreachable.\n- **collectFees and unlockCallback** can only be driven by the immutable fee recipient. The manager calls back only its own locker, the hook only unlocks from collectFees, and its claims cannot be burned or moved by anyone else because it never grants an operator or allowance. Reentry by the payout recipient is blocked twice, by the collection guard and by the manager's single-unlock rule.\n- **Factory** roles are explicit constructor arguments, the manager can only be set before the one-time deployment, and nobody else can occupy the CREATE2 address.\n- **Token** entry points are unmodified OpenZeppelin code with no admin, tax or mint path.\n\n**One finding, low severity.** The token constructor accepts exactly one supply value, ten to the twenty-seventh base units, and reverts on anything else. The brief states the supply as one billion whole tokens. A manifest that copies that literal into the constructor arguments fails the protected constructor rehearsal and parks the launch. The reproduction is `new SuperIMD(1000000000, owner)` reverting with `IncorrectInitialSupply`. No funds are at risk and it is recoverable, but the parameter now only serves as a tripwire. The suggested fix keeps the economics: drop the parameter or scale a whole-token input.\n\n**Noted but not reported as a defect.** Exact-input swaps pay 2% of output while exact-output swaps pay 2% of gross input, so an exact-output trader saves roughly four hundredths of a percent. That asymmetry is dust-level, non-compounding and documented in the README.\n\n**Not run.** The protected owner-check test imports a floor file that is not in the tree, so it could not execute here. Nothing in the factory or token derives ownership from the deploying factory or transaction origin, which is what it checks.","treeHash":null,"usage":{"cachedInputTokens":1239181,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":28837,"runtime":"claude","turns":38,"wallClockMs":438699}},{"artifacts":[],"attempt":1,"bundleHash":"28b96fd5b5d806c207903d832a057ae75011cbde54f8a5393d2893476fbe8e60","device":"1d142f9c9d30c62a","findings":[],"hash":"32ffdd445cd6491e483333b180bd216460ed78a7b23a948fc5ffd4dcaaa07a98","nodeId":"b654ad00-42cd-4253-aa56-a4346cdbcd20","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/f81a6758-3b32-4268-9a9e-4117f6f3d950/b654ad00-42cd-4253-aa56-a4346cdbcd20/launch.json) with `SuperIMD` followed by `SuperIMDHookFactory`, the exact billion-token supply, and `$owner` beneficiaries.\n\nConstructor ABI checks passed. `forge build` succeeded; all 55 tests passed with the required seed. Only the manifest changed.\n\nNotes document that hook activation requires later owner configuration of a verified PoolManager.","treeHash":"946168cefa969114b4788c14358e08c8929e2eeb","usage":{"cachedInputTokens":282880,"inputTokens":37328,"model":"gpt-6-astra","outputTokens":3436,"runtime":"codex","turns":4,"wallClockMs":102521}},{"artifacts":[],"attempt":1,"bundleHash":"96f66891ac7ae657c60a4522e5f62756605ea535079127bca582784fb52d54f5","device":"20c10dbba93106ff","findings":[],"hash":"4c511571596ec08b9ba807199821df8337d86bfbd666ec6051e42c8481a0a081","nodeId":"2b56e626-2a01-4dc5-959b-058635966ae4","outcome":"completed","summary":"Completed the audit and repaired Foundry project.\n\n- Enforced exactly **1 billion SIMD**.\n- Added pool validation and safe fee arithmetic.\n- Replaced immediate fee payouts with beneficiary-controlled collection.\n- Added a factory for deploying hooks at valid addresses.\n\n`forge build`, `forge fmt --check`, and all **55 tests** pass.\n\nFindings: [AUDIT.md](AUDIT.md). Deployment parameters and owner responsibilities: [README.md](README.md). Activation requires configuring a verified PoolManager and mining the hook salt.","treeHash":"4d16fb53956dd9fd66f4fcf3614a97435b11c5d8","usage":{"cachedInputTokens":1563904,"inputTokens":110863,"model":"gpt-6-astra","outputTokens":41920,"runtime":"codex","turns":8,"wallClockMs":1201671}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f494611affb5524c","findings":[{"citation":"resolved","description":"Economic Security / Flow Gap (execution x first principles). The stated guarantee is an immutable 2% fee on every buy and sell of SIMD in the hooked pool. The hook only enables afterSwap and afterSwapReturnDelta, so modifyLiquidity never touches the hook and is never charged. A holder who wants to sell SIMD for ETH can add a SIMD-only position just below the current price, wait for an ordinary buyer to swap through that range, then remove the position, which is now entirely ETH. The holder has converted SIMD to ETH inside the hooked pool and paid zero hook fee (they even collect LP fees). The mirror image works for buying SIMD: deposit an ETH-only position just above the price and let sellers fill it. Only the active counterparty pays the 2%. This is inherent to concentrated-liquidity AMMs and cannot be closed without liquidity-hook permissions (a design change: beforeAddLiquidity/beforeRemoveLiquidity with a fee on single-sided positions, or restricting LP positions to a whitelisted manager). The project should decide whether 'every sell pays 2%' is a promise it makes publicly; the current README and AUDIT.md mention dust splitting and other venues but not this route.","line":47,"path":"src/SIMDhook.sol","reproduction":"State: ETH/SIMD pool (currency0 = native, currency1 = SIMD, fee 0, tickSpacing 60, hooks = SuperIMDHook) initialized at sqrtPrice 1<<96 (tick 0) with 100_000e18 liquidity in [-600, 600]. Steps (reproduced in a local Foundry test against the real PoolManager at the pinned commit): (1) Seller calls modifyLiquidity(key, {tickLower:-120, tickUpper:-60, liquidityDelta:+1000e18}). Returned delta: amount0 = 0, amount1 = -2_986_382_804_598_881_662 (2.986 SIMD deposited, no ETH). No hook call occurs. (2) An unrelated buyer swaps exact-input 2000 ETH zeroForOne through the pool; the price crosses below tick -120; the buyer pays the 2% SIMD fee (39.2 SIMD accrued). (3) Seller calls modifyLiquidity with liquidityDelta -1000e18. Returned delta: amount0 = +3_013_380_206_076_239_568 ETH, amount1 = 0. hook.accruedFees(ETH) is unchanged across steps (1) and (3): the seller paid 0 hook fee on a 2.986 SIMD -> 3.013 ETH conversion. Expected under the stated economics: a sell of 2.986 SIMD pays 2% of its ETH proceeds (about 0.06 ETH; a direct exact-input swap of the same SIMD in the same state accrues 62_135_089_169_206_971 wei to the hook). Actual: 0 fee.","severity":"low","snippet":"    function getHookPermissions() public pure override returns (Hooks.Permissions memory permissions) {\n        permissions.afterSwap = true;\n        permissions.afterSwapReturnDelta = true;\n    }","title":"Project token can be sold or bought into the hooked pool with no 2% fee via single-sided liquidity (range orders)"}],"hash":"530a454aea84aad1ee32cc76e4052ec8853097464c09c8eefd80db3dd28a8d1c","nodeId":"e5eb4427-78e4-494c-b3fb-5a339e2cd8c1","outcome":"completed","summary":"The findings file is valid, the snippet matches the tree exactly, and no tracked file changed (the scratch test and findings file are gitignored or untracked, which is the allowed state).\n\n## Recap\n\n**Area covered:** Economic Security, Invariant and Flow Gap guides from the Pashov reference, applied to the token, the hook, its base, and the factory, plus the v4 PoolManager code paths the hook depends on at the pinned commit.\n\n**Result:** one low-severity finding, written to `.imd-findings.json` with 14 coverage rows (all 9 listed entry points answered, plus 5 invariant and economic rows).\n\n**Finding 1 (low), range-order fee bypass.** The hook enables only afterSwap, so liquidity operations never reach it. A holder can convert SIMD to ETH inside the hooked pool by placing a single-sided position just below the price, letting an ordinary buyer's swap fill it, and withdrawing ETH. Reproduced against the real PoolManager: a seller converted 2.986 SIMD into 3.013 ETH with zero hook fee, where a direct swap of the same amount accrues about 0.062 ETH to the hook. Only the active counterparty pays the 2%. This is inherent to concentrated-liquidity pools and closing it would be a design change needing liquidity-hook permissions, so it is reported as a documented gap in the \"every buy and sell pays 2%\" promise rather than a code bug.\n\n**What held, with evidence:**\n- Fee accounting nets to zero per swap in every mode and both token orderings; multiple hooked swaps inside one unlock settle cleanly; claims are always backed by the swapper's reduced delta.\n- Collection is beneficiary-only and atomic; failed transfers restore claims; nested collection and nested unlock both revert; the callback runs only for the hook's own unlock.\n- Token is a plain fixed-supply OZ ERC20 with standard permit; no economic surface beyond that.\n- The full existing suite passes, 55 tests including the two stateful invariants.\n\n**Not reached or out of scope:** no fork test against a live chain-4663 PoolManager, no nonstandard quote tokens beyond reasoning (fee-on-transfer, blacklisting are documented as unsupported), and the Slither and Aderyn leads all concern `collectFees` reentrancy, which I traced and found guarded, so none became findings.\n\nOne operational note for the manifest step, not a defect: the token constructor accepts only `1000000000000000000000000000` base units, so a manifest entry of `1000000000` would revert at deployment.","treeHash":null,"usage":{"cachedInputTokens":1023256,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":35723,"runtime":"claude","turns":33,"wallClockMs":530517}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4ebee02fc506f27c","findings":[{"citation":"resolved","description":"The 2% fee is floor(magnitude * 200 / 10000) = floor(magnitude / 50). The Math Precision guide's rule is that fees round up; here they round down, so the trader keeps the fractional unit on every swap and any swap whose unspecified-side magnitude is 1..49 base units pays nothing. This is the only rounding point in the fee path and the loss is bounded at 49 base units of the fee currency per swap (less than 5e-17 ETH or SIMD at 18 decimals), so it is not economically farmable: gas for even one swap exceeds the dust saved by orders of magnitude, and the invariant suite (earned == claims + collected) is defined with the same floor so it does not detect the gap versus exact 2%. The README already documents that rounding favors traders and that there is no minimum fee. Reported so the judge has the concrete numbers and so the design choice is explicit; no code change is required unless the author wants a ceiling fee (feeAmount = (magnitude * FEE_BIPS + TOTAL_BIPS - 1) / TOTAL_BIPS), which would make every nonzero swap pay at least 1 base unit.","line":78,"path":"src/SIMDhook.sol","reproduction":"Real PoolManager, SIMD/ETH pool, 100000e18 liquidity in [-600,600], price 1:1, LP fee 0. Exact-input sells (zeroForOne=false, amountSpecified=-N SIMD) measured against an identical no-hook pool: N=49 -> gross ETH out 48, exact 2% = 0.96, charged 0, net out 48 (fee 0%). N=99 -> gross out 98, exact 2% = 1.96, charged 1, net out 97 (fee 1.02%). N=149 -> gross out 148, exact 2% = 2.96, charged 2, net out 146 (fee 1.35%). Expected under 'immutable 2% fee on every swap': a nonzero fee on every nonzero output. Actual: zero fee for any output <= 49 base units and floor truncation above it. Reproduced by test/scratch/MathBoundary.t.sol::test_roundingBoundary and by the existing test/SIMDhook.Integration.t.sol::test_tinySwapRoundsFeeDown (amount 49 -> accrued 0).","severity":"info","snippet":"        uint256 feeAmount = magnitude * FEE_BIPS / TOTAL_BIPS;\n        if (feeAmount == 0) return (IHooks.afterSwap.selector, 0);","title":"Hook fee truncates toward the trader: unspecified amounts below 50 base units pay no fee, and every swap under-collects by up to 49 base units"}],"hash":"5329bd38340a0a8ff82fe5efff801ba4ec16b2904d3feaff8c6484627513907f","nodeId":"a3b670f6-2164-4db2-a6d7-30445f5d10d5","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written. No tracked file was changed; the only file I created besides the findings record is the scratch test under the ignored `test/scratch/` directory.\n\n**Outcome.** The hook's arithmetic holds under all three assigned guides. I found no defect above informational severity, and I recorded one informational finding with concrete numbers.\n\n**What I checked, against the pinned v4-core and OpenZeppelin sources.**\n- Fee currency selection matches v4's own unspecified-currency mapping for all four swap modes.\n- Magnitude is widened to int256 before negation, so the minus 2^127 input no longer panics. Multiplication by 200 cannot overflow, and the result fits the int128 return.\n- The mint debit inside `afterSwap` is exactly cancelled by the returned positive delta. The manager accounts the hook delta before the swapper delta, so the nonzero-delta counter returns to zero.\n- Collection burns and takes net to zero. Overcollection reverts on checked underflow. Amounts at or above 2^127 revert in SafeCast, which the README documents as needing tranches.\n- Reentry through the recipient is blocked by the guard, and nested unlock is blocked by the manager. The Slither and Aderyn reentrancy and unused-return leads reproduce as non-exploitable.\n- The factory's CREATE2 preimage, flag mask and one-shot deployment are correct.\n- The token is unmodified OpenZeppelin code with a fixed supply that fits v4's int128 settlement range.\n\n**The one finding, informational.** The fee is floor(magnitude / 50), so it rounds toward the trader. A scratch test on the real manager measured these exact-input sells against a no-hook pool:\n\n| Input (base units) | Gross out | Exact 2% | Charged |\n|---|---|---|---|\n| 49 | 48 | 0.96 | 0 |\n| 99 | 98 | 1.96 | 1 |\n| 149 | 148 | 2.96 | 2 |\n\nThe loss is bounded at 49 base units per swap and is not farmable, since gas dwarfs it. The README already documents the rounding direction, so this needs no change unless the author prefers a ceiling fee.\n\n**Coverage.** All nine listed entry points have a row, plus three invariant rows. Eight are `holds` and `afterSwap` is `finding` for the informational item. Nothing was left unreached. The exact-output fee base including the LP fee was measured and confirmed as documented behaviour, not a defect.","treeHash":null,"usage":{"cachedInputTokens":1248691,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":33352,"runtime":"claude","turns":37,"wallClockMs":501420}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7e50667f872c7f5e","findings":[{"citation":"resolved","description":"The destination filter in collectFees rejects address(0) and the hook itself but not address(poolManager). In unlockCallback the hook first burns its ERC-6909 claims (poolManager.burn) and then calls poolManager.take(currency, recipient, amount). For an ERC-20 fee currency, take executes currency.transfer(poolManager, amount), i.e. an ERC-20 transfer from the PoolManager to the PoolManager: it succeeds, moves nothing, and the manager's reserves are unchanged. The hook's delta nets to zero (+amount from burn, -amount from take), so unlock completes and FeesCollected is emitted, but the claims that represented the fee are gone and the underlying tokens remain in the PoolManager with no owner. There is no path to recover them: the hook has no claims left to burn and the PoolManager only pays out against deltas. This is the same class of operator mistake the existing recipient == address(this) check guards against, and the asymmetry (guarding the hook but not the manager, while unlockCallback routes the transfer through the manager) is the defect. The native path does not lose funds because the pinned PoolManager has no receive function, so take(ETH, poolManager, x) reverts with NativeTransferFailed. Only the immutable feeRecipient can trigger this, so impact is limited to the fee recipient's own accrued fees (self-inflicted, trusted role); severity is low. Minimal fix: add `|| recipient == address(poolManager)` to the InvalidCollection condition.","line":98,"path":"src/SIMDhook.sol","reproduction":"State: real v4 PoolManager; SIMD token; hook deployed by SuperIMDHookFactory at a mined address with feeRecipient = B; a SIMD/QUOTE pool (QUOTE a standard 18-decimal ERC-20, lpFee 3000, tickSpacing 60) initialized at price 1 and funded with 100_000e18 liquidity over ticks [-600, 600]. Step 1: a router performs an exact-output buy of 1000e18 SIMD paying QUOTE. The hook mints QUOTE claims to itself; hook.accruedFees(QUOTE) = 20262808627903913761 (about 20.26 QUOTE). Step 2: B calls hook.collectFees(QUOTE, 20262808627903913761, address(poolManager)). Expected: revert InvalidCollection (the destination can never receive value), as for recipient == address(this). Actual: the call succeeds, FeesCollected is emitted, hook.accruedFees(QUOTE) becomes 0, and QUOTE.balanceOf(poolManager) is unchanged before and after. The 20.26 QUOTE of fees is unrecoverable. Reproduced in test/scratch/Probe.t.sol test_collectToPoolManagerDestroysQuoteFees (passes on current code, asserting the loss). For the native currency the same call reverts (test_collectNativeToPoolManager), so only ERC-20 fee currencies are affected.","severity":"low","snippet":"        if (recipient == address(0) || recipient == address(this) || amount == 0) revert InvalidCollection();","title":"collectFees accepts the PoolManager itself as recipient: ERC-20 fee claims are burned while the tokens stay in the manager, permanently stranding the fee"},{"citation":"resolved","description":"The constructor keeps a uint256 initialSupply parameter but accepts exactly one value, INITIAL_SUPPLY = 1_000_000_000 * 10**18. The task brief states the supply as 'Total supply: 1000000000' (whole tokens). A manifest that copies that figure into constructorArgs makes the constructor revert with IncorrectInitialSupply(1000000000), and the protected deployment probe reports 'application 0 constructor failed', parking the launch; because the factory deploys SuperIMDHookFactory with $contract:SuperIMD, the whole launch fails. The parameter adds no configurability (every value other than the constant reverts) while adding one way to brick deployment. The README documents the base-unit value, so this is a deployment-hazard note rather than a code defect. Minimal fix options that preserve the fixed 1e27 supply: either drop the parameter and mint INITIAL_SUPPLY, or accept both the whole-token figure (1_000_000_000) and the base-unit figure and mint INITIAL_SUPPLY in both cases.","line":22,"path":"src/SuperIMD.sol","reproduction":"Input: new SuperIMD(1000000000, owner) with owner a nonzero address. Expected by a reader of the brief: a token with 1,000,000,000 whole SIMD minted to owner. Actual: revert IncorrectInitialSupply(1000000000); no contract is created. Only new SuperIMD(1000000000000000000000000000, owner) succeeds. Reproduced in test/scratch/Probe.t.sol test_wholeTokenSupplyFigureReverts (vm.expectRevert with the exact selector and argument passes on current code).","severity":"info","snippet":"        if (initialSupply != INITIAL_SUPPLY) {\n            revert IncorrectInitialSupply(initialSupply);\n        }","title":"SuperIMD constructor rejects the brief's whole-token supply figure (1000000000); only the base-unit constant is accepted, so the parameter can only park the launch"}],"hash":"59a4e5d3cc1c4e894c6e124c8ea2efa93481c7a7148fbe44e5eedcff453b22f0","nodeId":"e7566e4d-9171-4261-84fd-ed3acc5001d0","outcome":"completed","summary":"The review is complete. The findings file is written and validated, with both snippets matching the source lines exactly.\n\n**Outcome:** the SuperIMD token and hook hold up under the Execution Trace, Periphery and First Principles checks. I found no critical, high or medium defect. Two issues are recorded in `.imd-findings.json`, both reproduced with a scratch Foundry test that passes on the current code by asserting the bad behavior.\n\n**Findings**\n\n- **Low, fee collection to the PoolManager address strands ERC-20 fees.** The destination filter in `collectFees` rejects the zero address and the hook itself but not the PoolManager. The callback burns the claims, then the manager transfers tokens to itself, which succeeds and moves nothing. The claims are gone and the tokens sit in the manager with no owner. Only the fee recipient can trigger it, so it is a self-inflicted loss by a trusted role. The native path reverts because the pinned PoolManager has no receive function. Fix is one extra condition on the recipient check.\n- **Info, the token constructor rejects the brief's whole-token figure.** Passing 1000000000 reverts, and only the base-unit constant is accepted. Because the hook factory depends on the token, a manifest copying the brief's number parks the whole launch. The README documents the base-unit value, so this is a deployment hazard rather than a code defect.\n\n**What held, with the reasoning traced**\n\n- The swap fee path nets the hook's delta to exactly zero: the claim mint debits the hook and the returned positive delta credits it back. Currency selection matches v4's hook-delta placement in all four swap modes, and the sign checks cannot fire on a legitimate swap.\n- Fee collection sets its guard before the unlock and resets it only on success. Reentrant collection, direct callback calls and third-party burns of the hook's claims are all blocked.\n- The factory enforces the exact permission bits before CREATE2, the hook constructor re-validates them, and the manager setting freezes after deployment.\n- The token is unmodified OpenZeppelin ERC20 and ERC20Permit with no mint, tax or admin surface.\n- A dynamic-fee pool keyed to this hook still pays the 2% hook fee; the zero LP fee is a liquidity provider choice, not a hook defect.\n\n**Coverage:** all nine listed entry points have a row, eight hold and one carries finding 1, plus four invariant and periphery rows. Not reached: a live-chain check of the target chain's PoolManager and the real IMD quote token, which the repository documents as operator responsibilities.","treeHash":null,"usage":{"cachedInputTokens":788625,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":27862,"runtime":"claude","turns":29,"wallClockMs":389504}},{"artifacts":[],"attempt":1,"bundleHash":"a1590df929904064fcfef967fb862c664f31f3526514ccf02a58d3266ca314f8","device":"1f9cb1750ebf47ed","findings":[{"description":"feeAmount = magnitude * 200 / 10_000 floors, so any swap with an unspecified-side amount of 1..49 base units pays no hook fee. The brief says the 2% fee applies to every swap with no exceptions. Because SIMD and most quote tokens have 18 decimals, this only matters economically where gas is close to free. It is a deviation from 'every swap', not a loss of funds. The README already lists it as a residual risk. Rounding the fee up (ceil) would close it without changing the rate.","line":78,"path":"src/SIMDhook.sol","reproduction":"In a native/SIMD pool using the hook, make an exact-input SIMD->ETH swap of 49 wei, three times. Expected: some fee on each swap, if every swap is charged. Actual: hook.accruedFees(ETH) == 0 after all three. A single 10_000-wei swap afterwards accrues a nonzero fee of at most 2% of its output. See test/SIMDhook.Edges.t.sol::test_feeStillChargedWhenDustSwapsAreBatchedInOneLargeSwap and test/SIMDhook.Integration.t.sol::test_tinySwapRoundsFeeDown.","severity":"low","title":"2% fee rounds to zero for swaps whose unspecified amount is below 50 base units"},{"description":"The fee is always taken in the unspecified currency. Exact-input swaps pay it from the output; exact-output swaps add it to the input. So the same economic 'buy' can pay its fee in SIMD or in the quote token depending on how the router specifies it. Exact-output also charges 2% of the gross input, which is about 1.96% of what the trader finally pays. Any token paired with SIMD is accepted as the quote, not only ETH/IMD, so permissionless SIMD/<arbitrary token> pools accrue fees in that arbitrary token. None of this breaks accounting: the multi-pool invariants hold, with claims plus collections equal to modelled fees and claims fully backed by manager balances. It is a design note for the requester.","line":66,"path":"src/SIMDhook.sol","reproduction":"In test/SIMDhook.MultiPoolInvariant.t.sol::test_handlerSequenceEarnsAndCollectsInEveryPool, four swap modes in SIMD/upperQuote and lowerQuote/SIMD pools accrue fees in both the quote tokens and SIMD.","severity":"info","title":"Fee currency follows exact-in/exact-out, not buy/sell, and any quote token is accepted"},{"description":"collectFees calls poolManager.unlock, so a beneficiary contract that tries to collect from inside its own unlock (for example, batching collection with a swap) gets IPoolManager.AlreadyUnlocked. The failure is atomic: claims and the collecting guard are restored, and a later collection outside the unlock succeeds. This is documented in NatSpec and listed here only so integrators are aware.","line":102,"path":"src/SIMDhook.sol","reproduction":"test/SIMDhook.Edges.t.sol::test_collectionInsideAnotherUnlockFailsAndLeavesGuardUsable: the nested collectFees reverts with AlreadyUnlocked(), accruedFees is unchanged, and the next direct collection pays the full amount.","severity":"info","title":"Fee collection cannot run inside another PoolManager unlock"}],"hash":"a019a2570bc77831ad0b18340d324baa182b92d259457cec31c71230aeb5e52b","nodeId":"d0bcf8e1-6113-4d94-9958-043986f2edfd","outcome":"completed","summary":"I audited `SuperIMD`, `SuperIMDHook` and the hook factory that earlier contributors added, and found no critical, high or medium defect. I added 12 tests in three new files under `test/`. `forge build` succeeds and `forge test` passes 67 tests, 0 failing, using the required fuzz seed.\n\n**What the earlier work already had:** 55 tests, including runs against a real Uniswap v4 PoolManager, comparisons against identical pools without the hook, permit replay and expiry cases, and one hook invariant suite. What was missing: invariant tests on the token, a hook invariant covering more than one pool, and a few failure paths.\n\n**What I added:**\n- **`test/SuperIMD.Invariant.t.sol`** (token): five signing accounts make random transfers, transferFroms, approvals, time jumps and permits. Permits are sent valid, tampered, with an old nonce, expired, signed by the wrong key, or replayed. After every call:\n  - total supply stays exactly 10²⁷ (one billion SIMD at 18 decimals);\n  - the accounts' balances add up to the full supply;\n  - every balance, allowance and nonce matches a separately kept record.\n\n  Every rejected call must fail with the exact expected error and change nothing. The suite runs 128 sequences of 64 calls.\n- **`test/SIMDhook.MultiPoolInvariant.t.sol`** (hook): three hooked pools — SIMD against ETH, and SIMD against tokens sorting on each side of it, with different LP fee tiers. Each is mirrored by an identical pool without the hook, so the fee can be checked exactly. Random calls include all four swap modes, very small and normal sizes, adding and removing liquidity, partial collection, collecting more than is owed, and outsiders trying to collect or fake the PoolManager callbacks. After every call:\n  - for each currency, uncollected fees plus collected fees equal the fees earned;\n  - the PoolManager holds enough to cover the hook's fees, and the hook holds no tokens or ETH directly;\n  - no swap debt is left unsettled;\n  - every currency is fully accounted for across all holders.\n- **`test/SIMDhook.Edges.t.sol`**: these failure paths all revert cleanly and leave nothing changed:\n  - collecting from inside another PoolManager unlock, after which a normal collection still works;\n  - outsiders trying to collect fees that a third party sent to the hook;\n  - collecting a currency that has no fees;\n  - pools on a different PoolManager trying to swap through the hook;\n  - non-owners calling the factory, and deploying from random salts.\n\n  Both invariant files also include a fixed sequence that confirms every handler path is actually reached, so the random runs aren't checking nothing.\n\n**Findings** (in `.imd-findings.json` in the repo root; none needs a failing proof):\n- **Low:** the fee rounds down, so any swap whose fee-bearing side is under 50 base units pays nothing (`src/SIMDhook.sol:78`). That falls short of \"2% on every swap\". With 18 decimals this only matters where gas is nearly free. Rounding the fee up would close it.\n- **Info:** the fee is taken in whichever currency the trader didn't fix the amount of. That depends on how the router builds the swap, not on whether it is a buy or a sell. On exact-output swaps, 2% of the pre-fee input works out to about 1.96% of what the trader pays. The hook also accepts any token paired with SIMD, not only ETH or IMD.\n- **Info:** the fee recipient can't collect from inside its own PoolManager unlock (`src/SIMDhook.sol:102`). The attempt fails without side effects.\n\nThe new tests are committed on a new branch, `audit-tests-simd`, since the work started on a detached HEAD. `.imd-findings.json` is git-ignored, so it is on disk but not in the commit. Nothing ran against a live chain fork.","treeHash":"45422c60a2a959b35372e313d72acb85d9564adb","usage":{"cachedInputTokens":2247162,"inputTokens":48,"model":"claude-opus-5-5","outputTokens":38246,"runtime":"claude","turns":26,"wallClockMs":476357}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c872aaeb2e58b080","findings":[{"citation":"resolved","description":"The recipient filter rejects zero and the hook but not address(poolManager). unlockCallback burns the hook's ERC-6909 claims (+amount delta) and then calls poolManager.take(currency, poolManager, amount), which for an ERC-20 is a transfer from the manager to itself (-amount delta). The deltas net to zero, unlock succeeds and FeesCollected is emitted, but the claims are gone and the tokens remain in the PoolManager with no owner: no claims or delta can recover them (sync/settle only credits balance increases after sync). Only the immutable feeRecipient can trigger it, so it is a self-inflicted loss of accrued fees by a trusted role, hence low. The native path reverts (PoolManager has no receive). Merged from audit_flow. Fix: add `|| recipient == address(poolManager)` to the InvalidCollection condition.","line":98,"path":"src/SIMDhook.sol","reproduction":"Real v4 PoolManager; SuperIMD(1e27, owner); SuperIMDHookFactory(owner, owner, simd); owner setPoolManager(pm) and deployHook(mined salt). Give the hook 20e18 claims of an 18-decimal ERC-20 Q (as _afterSwap's poolManager.mint does). owner calls hook.collectFees(Q, 20e18, address(pm)). Expected: revert InvalidCollection, as for address(this). Actual: succeeds, hook.accruedFees(Q) goes 20e18 -> 0, Q.balanceOf(pm) unchanged; 20e18 Q of fees unrecoverable. Verified with a scratch Foundry test (test/scratch/CollectToManager.t.sol): the post-call assertions that the claims are burned and the manager balance is unchanged pass, and the test then fails with 'burned 20e18 fee claims and paid nobody'.","severity":"low","snippet":"        if (recipient == address(0) || recipient == address(this) || amount == 0) revert InvalidCollection();","title":"collectFees accepts the PoolManager as recipient: ERC-20 fee claims are burned and the tokens are stranded in the manager"},{"citation":"resolved","description":"feeAmount = floor(magnitude/50), so a swap whose unspecified-side amount is under 50 base units pays 0, and every swap under-collects by at most 49 base units. With 18-decimal tokens this is dust far below gas cost, so it cannot be farmed; the README and manifest notes already state it. It deviates only literally from '2% fee on every swap'. Merged from audit_math and write_foundry_tests (same root cause). Optional fix: ceiling division, (magnitude * FEE_BIPS + TOTAL_BIPS - 1) / TOTAL_BIPS.","line":78,"path":"src/SIMDhook.sol","reproduction":"Exact-input swap whose output (unspecified) delta is 49: magnitude=49, 49*200/10000 = 0, so _afterSwap returns (selector, 0) at line 79 and hook.accruedFees stays 0. Expected under 'every swap': a nonzero fee. Existing test/SIMDhook.Integration.t.sol::test_tinySwapRoundsFeeDown asserts it (amount 49 -> accrued 0) and passes.","severity":"info","snippet":"        uint256 feeAmount = magnitude * FEE_BIPS / TOTAL_BIPS;","title":"2% hook fee rounds down: unspecified amounts of 1..49 base units pay no fee"}],"hash":"cf0e17d8192d406d282ff1e39f673bf3608f7dfd8d81e43fa67de83d3261b63f","nodeId":"d7c8f58b-8510-4a62-95a5-7f9447a0059b","outcome":"completed","summary":"The review is done and the findings are in `.imd-findings.json`. Of the specialists' seven findings, two remain after merging and five were dropped. Nothing is critical, high or medium. The 67 existing tests pass, the build succeeds, and no tracked files were changed (the scratch test has been deleted).\n\n**Findings kept**\n\n1. **Low: fee collection can destroy fees if the recipient is the PoolManager.** At `src/SIMDhook.sol:98`, `collectFees` rejects a zero address and the hook itself as recipient, but not the PoolManager. If the fee recipient sends ERC-20 fees there, the hook's fee claims are burned, but the tokens never leave the PoolManager and can't be recovered. I reproduced this with the real PoolManager in a scratch test: collecting 20e18 of a test token to the PoolManager succeeded, the hook's balance went to 0, and the PoolManager's token balance didn't change. It's low because only the fee recipient can trigger it, and only against their own fees. Native ETH isn't affected, because the transfer reverts. The fix is to add `|| recipient == address(poolManager)` to that check.\n2. **Info: the 2% fee rounds down.** At `src/SIMDhook.sol:78`, any swap whose unspecified-side amount is 1–49 base units pays no fee, and every swap under-collects by at most 49 base units. With 18-decimal tokens this is far below gas cost and can't be exploited, and the README and manifest notes already say so. This merges the math specialist's finding and the test writer's, which share the same cause. The existing test `test_tinySwapRoundsFeeDown` shows it.\n\n**Specialist findings dropped**\n- **Constructor rejects a supply of 1000000000** (reported by two specialists): `launch.json` passes the correct value, 10^27 base units. Rejecting any other value is a safety check, not a defect.\n- **Fees bypassed through single-sided liquidity (range orders):** this is how concentrated-liquidity pools work. The original hook in the brief had the same permissions, and adding liquidity isn't a swap.\n- **Which currency the fee is charged in, and any quote token being accepted:** this is the intended design. Accounting holds and no one loses money.\n- **Collecting fees from inside another PoolManager unlock reverts:** the revert leaves fees and state intact and a later collection works. The code comments already document it.\n- **Static-analysis reentrancy and unchecked-return warnings:** these don't reproduce. The `collecting` flag blocks re-entry, and nothing needs to be read from the `unlock` return value.\n\n**Coverage:** all 9 entry points have a row, plus one for the manifest.\n- **Holds (7):** the four token functions (standard OpenZeppelin ERC-20 and permit), `unlockCallback`, and both factory functions.\n- **Finding:** `afterSwap` (finding 2) and `collectFees` (finding 1).\n- **Manifest:** `launch.json` matches both constructors.\n- **Deployability:** the contracts deploy within size limits (5.2 KB and 8.2 KB deployed). Their constructors make no external calls, and the hook is deployed later by the owner through the factory.","treeHash":null,"usage":{"cachedInputTokens":535015,"inputTokens":20,"model":"claude-opus-5-5","outputTokens":10363,"runtime":"claude","turns":10,"wallClockMs":162861}}],"verification":[{"checks":[{"durationMs":5754,"exitCode":0,"name":"build","output":"Compiling 98 files with Solc 0.8.26\nSolc 0.8.26 finished in 5.57s\nCompiler run successful!\n","passed":true},{"durationMs":1150,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 13 tests for test/SuperIMD.t.sol:SuperIMDTest\n[PASS] testFuzz_rejectsEveryOtherSupply(uint256) (runs: 256, μ: 6731, ~: 6731)\n[PASS] testFuzz_transferFromHasNoFeeAndSpendsAllowance(uint256) (runs: 256, μ: 159609, ~: 160411)\nLogs:\n  Bound result 100\n\n[PASS] testFuzz_transferHasNoFeeAndConservesSupply(uint256) (runs: 256, μ: 96519, ~: 96889)\nLogs:\n  Bound result 291919049629459\n\n[PASS] test_infiniteAllowanceRemainsUnchanged() (gas: 123228)\n[PASS] test_metadataAndExactSupply() (gas: 65571)\n[PASS] test_noPublicMintBurnOrAdmin() (gas: 82610)\n[PASS] test_permitRejectsAlteredValueAndWrongNonce() (gas: 160021)\n[PASS] test_permitRejectsCrossContractAndCrossChainReplay() (gas: 154113)\n[PASS] test_permitRejectsZeroSpenderAndMalformedSignature() (gas: 131283)\n[PASS] test_permitRelayedThenSpentAndReplayRejected() (gas: 224551)\n[PASS] test_permitValidAtDeadlineButNotAfter() (gas: 161283)\n[PASS] test_rejectsZeroRecipient() (gas: 4246)\n[PASS] test_transferFailureDoesNotChangeBalances() (gas: 112860)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 19.25ms (42.22ms CPU time)\n\nRan 11 tests for test/SuperIMDHookFactory.t.sol:HookFactoryTest\n[PASS] test_configurationRejectsZeroAndNoCode() (gas: 64911)\n[PASS] test_constructorDoesNotRequireExternalContracts() (gas: 38506351)\n[PASS] test_deploymentMatchesPredictionAndFreezesConfiguration() (gas: 10797096)\n[PASS] test_factoryDeploymentKeepsExplicitOwnerAndBeneficiary() (gas: 6950339)\n[PASS] test_managerCanBeCorrectedBeforeDeploymentAndEmitsEvents() (gas: 359014)\n[PASS] test_notConfiguredFailsClearly() (gas: 59338)\n[PASS] test_offlineScriptMatchesFactoryAndFailsIfSearchExhausted() (gas: 5940457)\n[PASS] test_onlyOwnerCanConfigureAndDeploy() (gas: 5822191)\n[PASS] test_rechecksManagerCodeAtDeployment() (gas: 5774589)\n[PASS] test_rejectsWrongSalt() (gas: 111886)\n[PASS] test_rejectsZeroConstructorArguments() (gas: 8316)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 58.12ms (165.79ms CPU time)\n\nRan 15 tests for test/SIMDhook.Unit.t.sol:HookUnitTest\n[PASS] testFuzz_feeArithmeticAllFourModes(bool,bool,uint128) (runs: 256, μ: 166868, ~: 172145)\nLogs:\n  Bound result 1\n\n[PASS] test_disabledCallbacksFailClosedForEveryCaller() (gas: 498026)\n[PASS] test_minInt128ArithmeticDoesNotPanic() (gas: 116127)\n[PASS] test_permissionsAndImmutableParameters() (gas: 61989)\n[PASS] test_regressionOriginalAllowsWrongSupply() (gas: 1007912)\n[PASS] test_regressionOriginalChargesUnrelatedPool() (gas: 18995492)\n[PASS] test_regressionOriginalMinInt128Panics() (gas: 18917408)\n[PASS] test_rejectsInvalidCollections() (gas: 89420)\n[PASS] test_rejectsUnauthorizedAfterSwapAndCallback() (gas: 100163)\n[PASS] test_rejectsUnauthorizedFeeCollection() (gas: 32805)\n[PASS] test_rejectsUnexpectedDeltaSignAndZeroSpecifiedAmount() (gas: 103318)\n[PASS] test_rejectsUnminedAddress() (gas: 10402)\n[PASS] test_rejectsWrongPoolOrHook() (gas: 128317)\n[PASS] test_rejectsZeroAddresses() (gas: 8238)\n[PASS] test_roundingThresholds() (gas: 288070)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 58.21ms (77.95ms CPU time)\n\nRan 15 tests for test/SIMDhook.Integration.t.sol:HookIntegrationTest\n[PASS] testFuzz_realSwapFeeAndSettlement(bool,bool,bool,bool,uint96) (runs: 256, μ: 396748, ~: 381271)\nLogs:\n  Bound result 6954383334062550707\n\n[PASS] test_collectNativeAndERC20FeesWithPartialWithdrawal() (gas: 672770)\n[PASS] test_erc20BothTokenOrdersAndAllSwapModes() (gas: 3258103)\n[PASS] test_failedCollectionPreservesClaimsAndDoesNotBlockSwap() (gas: 668918)\n[PASS] test_lpFeeIsAdditionalAndHookRateUnchanged() (gas: 1375767)\n[PASS] test_nativeBuySellExactInputAndExactOutput() (gas: 1458185)\n[PASS] test_overcollectionAndDoubleCollectionRevertWithoutLoss() (gas: 403880)\n[PASS] test_partialFillsChargeExecutedAmountOnly() (gas: 729608)\n[PASS] test_reentrantCollectionCannotSpendClaimsTwice() (gas: 2907921)\n[PASS] test_regressionOriginalRecipientRejectionRevertsNativeFeeSwap() (gas: 8939331)\n[PASS] test_rejectingBeneficiaryDoesNotBlockNativeFeeSwaps() (gas: 2632691)\n[PASS] test_routerEnforcesSlippageAfterHookFeesAndRollsBack() (gas: 434903)\n[PASS] test_tinySwapRoundsFeeDown() (gas: 362311)\n[PASS] test_unrelatedPoolCannotSwapThroughHook() (gas: 507400)\n[PASS] test_zeroLiquiditySwapDoesNotAccrueFees() (gas: 615387)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 75.74ms (97.69ms CPU time)\n\nRan 1 test for test/SIMDhook.Invariant.t.sol:HookInvariantTest\n[PASS]\nHookInvariantTest invariants:\n[PASS] invariant_currencyConservationAndNoUnsettledDebts\n[PASS] invariant_feeClaimsPlusCollectionsEqualEarnedFees\n HookInvariantTest invariants (runs: 64, calls: 2048, reverts: 0)\n\n╭--------------------+----------+-------+---------+----------╮\n| Contract           | Selector | Calls | Reverts | Discards |\n+============================================================+\n| FeeSequenceHandler | collect  | 1021  | 0       | 0        |\n|--------------------+----------+-------+---------+----------|\n| FeeSequenceHandler | swap     | 1027  | 0       | 0        |\n╰--------------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 935.16ms (929.84ms CPU time)\n\nRan 5 test suites in 937.27ms (1.15s CPU time): 55 tests passed, 0 failed, 0 skipped (55 total tests)\n","passed":true},{"durationMs":121,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SuperIMD.approve(address,uint256)\",\"SuperIMD.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"SuperIMD.transfer(address,uint256)\",\"SuperIMD.transferFrom(address,address,uint256)\",\"SuperIMDHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"SuperIMDHook.collectFees(address,uint256,address)\",\"SuperIMDHook.unlockCallback(bytes)\",\"SuperIMDHookFactory.deployHook(bytes32)\",\"SuperIMDHookFactory.setPoolManager(address)\"],\"files\":{\".gitignore\":4,\"AUDIT.md\":87,\"DEPENDENCIES.json\":41,\"LICENSE\":23,\"README.md\":106,\"VALIDATION.md\":33,\"foundry.toml\":22,\"launch.json\":21,\"remappings.txt\":4,\"script/MineHookSalt.s.sol\":15,\"src/SIMDhook.sol\":115,\"src/SuperIMD.sol\":27,\"src/SuperIMDHookFactory.sol\":78,\"src/base/BaseHook.sol\":132,\"src/libraries/HookSaltMiner.sol\":30,\"test/SIMDhook.Integration.t.sol\":333,\"test/SIMDhook.Invariant.t.sol\":141,\"test/SIMDhook.Unit.t.sol\":234,\"test/SuperIMD.t.sol\":177,\"test/SuperIMDHookFactory.t.sol\":200,\"test/helpers/HookFixtures.sol\":117,\"test/helpers/PoolHarness.sol\":90},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"32ffdd445cd6491e483333b180bd216460ed78a7b23a948fc5ffd4dcaaa07a98","verifiedTreeHash":"946168cefa969114b4788c14358e08c8929e2eeb","verifierVersion":"0.1.0+c3fba9eb"},{"checks":[{"durationMs":2870,"exitCode":0,"name":"build","output":"Compiling 98 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.76s\nCompiler run successful!\n","passed":true},{"durationMs":643,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 13 tests for test/SuperIMD.t.sol:SuperIMDTest\n[PASS] testFuzz_rejectsEveryOtherSupply(uint256) (runs: 256, μ: 6731, ~: 6731)\n[PASS] testFuzz_transferFromHasNoFeeAndSpendsAllowance(uint256) (runs: 256, μ: 159609, ~: 160411)\nLogs:\n  Bound result 3758364715924700851519\n\n[PASS] testFuzz_transferHasNoFeeAndConservesSupply(uint256) (runs: 256, μ: 96519, ~: 96889)\nLogs:\n  Bound result 291919049629459\n\n[PASS] test_infiniteAllowanceRemainsUnchanged() (gas: 123228)\n[PASS] test_metadataAndExactSupply() (gas: 65571)\n[PASS] test_noPublicMintBurnOrAdmin() (gas: 82610)\n[PASS] test_permitRejectsAlteredValueAndWrongNonce() (gas: 160021)\n[PASS] test_permitRejectsCrossContractAndCrossChainReplay() (gas: 154113)\n[PASS] test_permitRejectsZeroSpenderAndMalformedSignature() (gas: 131283)\n[PASS] test_permitRelayedThenSpentAndReplayRejected() (gas: 224551)\n[PASS] test_permitValidAtDeadlineButNotAfter() (gas: 161283)\n[PASS] test_rejectsZeroRecipient() (gas: 4246)\n[PASS] test_transferFailureDoesNotChangeBalances() (gas: 112860)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 13.06ms (19.95ms CPU time)\n\nRan 15 tests for test/SIMDhook.Unit.t.sol:HookUnitTest\n[PASS] testFuzz_feeArithmeticAllFourModes(bool,bool,uint128) (runs: 256, μ: 166868, ~: 172145)\nLogs:\n  Bound result 1\n\n[PASS] test_disabledCallbacksFailClosedForEveryCaller() (gas: 498026)\n[PASS] test_minInt128ArithmeticDoesNotPanic() (gas: 116127)\n[PASS] test_permissionsAndImmutableParameters() (gas: 61989)\n[PASS] test_regressionOriginalAllowsWrongSupply() (gas: 1007912)\n[PASS] test_regressionOriginalChargesUnrelatedPool() (gas: 18995492)\n[PASS] test_regressionOriginalMinInt128Panics() (gas: 18917408)\n[PASS] test_rejectsInvalidCollections() (gas: 89420)\n[PASS] test_rejectsUnauthorizedAfterSwapAndCallback() (gas: 100163)\n[PASS] test_rejectsUnauthorizedFeeCollection() (gas: 32805)\n[PASS] test_rejectsUnexpectedDeltaSignAndZeroSpecifiedAmount() (gas: 103318)\n[PASS] test_rejectsUnminedAddress() (gas: 10402)\n[PASS] test_rejectsWrongPoolOrHook() (gas: 128317)\n[PASS] test_rejectsZeroAddresses() (gas: 8238)\n[PASS] test_roundingThresholds() (gas: 288070)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 26.13ms (48.18ms CPU time)\n\nRan 11 tests for test/SuperIMDHookFactory.t.sol:HookFactoryTest\n[PASS] test_configurationRejectsZeroAndNoCode() (gas: 64911)\n[PASS] test_constructorDoesNotRequireExternalContracts() (gas: 38506351)\n[PASS] test_deploymentMatchesPredictionAndFreezesConfiguration() (gas: 10797096)\n[PASS] test_factoryDeploymentKeepsExplicitOwnerAndBeneficiary() (gas: 6950339)\n[PASS] test_managerCanBeCorrectedBeforeDeploymentAndEmitsEvents() (gas: 359014)\n[PASS] test_notConfiguredFailsClearly() (gas: 59338)\n[PASS] test_offlineScriptMatchesFactoryAndFailsIfSearchExhausted() (gas: 5940457)\n[PASS] test_onlyOwnerCanConfigureAndDeploy() (gas: 5822191)\n[PASS] test_rechecksManagerCodeAtDeployment() (gas: 5774589)\n[PASS] test_rejectsWrongSalt() (gas: 111886)\n[PASS] test_rejectsZeroConstructorArguments() (gas: 8316)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 27.84ms (100.04ms CPU time)\n\nRan 15 tests for test/SIMDhook.Integration.t.sol:HookIntegrationTest\n[PASS] testFuzz_realSwapFeeAndSettlement(bool,bool,bool,bool,uint96) (runs: 256, μ: 396748, ~: 381271)\nLogs:\n  Bound result 14912\n\n[PASS] test_collectNativeAndERC20FeesWithPartialWithdrawal() (gas: 672770)\n[PASS] test_erc20BothTokenOrdersAndAllSwapModes() (gas: 3258103)\n[PASS] test_failedCollectionPreservesClaimsAndDoesNotBlockSwap() (gas: 668918)\n[PASS] test_lpFeeIsAdditionalAndHookRateUnchanged() (gas: 1375767)\n[PASS] test_nativeBuySellExactInputAndExactOutput() (gas: 1458185)\n[PASS] test_overcollectionAndDoubleCollectionRevertWithoutLoss() (gas: 403880)\n[PASS] test_partialFillsChargeExecutedAmountOnly() (gas: 729608)\n[PASS] test_reentrantCollectionCannotSpendClaimsTwice() (gas: 2907921)\n[PASS] test_regressionOriginalRecipientRejectionRevertsNativeFeeSwap() (gas: 8939331)\n[PASS] test_rejectingBeneficiaryDoesNotBlockNativeFeeSwaps() (gas: 2632691)\n[PASS] test_routerEnforcesSlippageAfterHookFeesAndRollsBack() (gas: 434903)\n[PASS] test_tinySwapRoundsFeeDown() (gas: 362311)\n[PASS] test_unrelatedPoolCannotSwapThroughHook() (gas: 507400)\n[PASS] test_zeroLiquiditySwapDoesNotAccrueFees() (gas: 615387)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 65.89ms (69.72ms CPU time)\n\nRan 1 test for test/SIMDhook.Invariant.t.sol:HookInvariantTest\n[PASS]\nHookInvariantTest invariants:\n[PASS] invariant_currencyConservationAndNoUnsettledDebts\n[PASS] invariant_feeClaimsPlusCollectionsEqualEarnedFees\n HookInvariantTest invariants (runs: 64, calls: 2048, reverts: 0)\n\n╭--------------------+----------+-------+---------+----------╮\n| Contract           | Selector | Calls | Reverts | Discards |\n+============================================================+\n| FeeSequenceHandler | collect  | 1021  | 0       | 0        |\n|--------------------+----------+-------+---------+----------|\n| FeeSequenceHandler | swap     | 1027  | 0       | 0        |\n╰--------------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 543.58ms (540.24ms CPU time)\n\nRan 5 test suites in 545.23ms (676.50ms CPU time): 55 tests passed, 0 failed, 0 skipped (55 total tests)\n","passed":true},{"durationMs":50,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SuperIMD.approve(address,uint256)\",\"SuperIMD.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"SuperIMD.transfer(address,uint256)\",\"SuperIMD.transferFrom(address,address,uint256)\",\"SuperIMDHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"SuperIMDHook.collectFees(address,uint256,address)\",\"SuperIMDHook.unlockCallback(bytes)\",\"SuperIMDHookFactory.deployHook(bytes32)\",\"SuperIMDHookFactory.setPoolManager(address)\"],\"files\":{\".gitignore\":4,\"AUDIT.md\":87,\"DEPENDENCIES.json\":41,\"LICENSE\":23,\"README.md\":106,\"VALIDATION.md\":33,\"foundry.toml\":22,\"remappings.txt\":4,\"script/MineHookSalt.s.sol\":15,\"src/SIMDhook.sol\":115,\"src/SuperIMD.sol\":27,\"src/SuperIMDHookFactory.sol\":78,\"src/base/BaseHook.sol\":132,\"src/libraries/HookSaltMiner.sol\":30,\"test/SIMDhook.Integration.t.sol\":333,\"test/SIMDhook.Invariant.t.sol\":141,\"test/SIMDhook.Unit.t.sol\":234,\"test/SuperIMD.t.sol\":177,\"test/SuperIMDHookFactory.t.sol\":200,\"test/helpers/HookFixtures.sol\":117,\"test/helpers/PoolHarness.sol\":90},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1830,"exitCode":0,"name":"slither","output":"[medium/medium] reentrancy-no-eth at src/SIMDhook.sol:95: Reentrancy in SuperIMDHook.collectFees(Currency,uint256,address) (src/SIMDhook.sol#95-105):\n[medium/medium] unused-return at src/SIMDhook.sol:95: SuperIMDHook.collectFees(Currency,uint256,address) (src/SIMDhook.sol#95-105) ignores return value by poolManager.unlock(abi.encode(currency,amount,recipient)) (src/SIMDhook.sol#102)\n[low/medium] reentrancy-events at src/SIMDhook.sol:95: Reentrancy in SuperIMDHook.collectFees(Currency,uint256,address) (src/SIMDhook.sol#95-105):\n[low/medium] reentrancy-events at src/SIMDhook.sol:52: Reentrancy in SuperIMDHook._afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/SIMDhook.sol#52-86):","passed":true},{"durationMs":531,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/SIMDhook.sol:102: Reentrancy: State change after external call\n[low] centralization-risk at src/SuperIMDHookFactory.sol:44: Centralization Risk (2 places)\n[low] large-numeric-literal at src/SIMDhook.sol:25: Large Numeric Literal (2 places)\n[low] push-zero-opcode at src/SIMDhook.sol:2: PUSH0 Opcode (5 places)\n[low] unchecked-return at src/SIMDhook.sol:102: Unchecked Return\n[low] unspecific-solidity-pragma at src/SIMDhook.sol:2: Unspecific Solidity Pragma (4 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"4c511571596ec08b9ba807199821df8337d86bfbd666ec6051e42c8481a0a081","verifiedTreeHash":"4d16fb53956dd9fd66f4fcf3614a97435b11c5d8","verifierVersion":"0.1.0+c3fba9eb"},{"checks":[{"durationMs":4056,"exitCode":0,"name":"build","output":"Compiling 101 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.95s\nCompiler run successful!\n","passed":true},{"durationMs":4105,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/SuperIMDHookFactory.t.sol:HookFactoryTest\n[PASS] test_configurationRejectsZeroAndNoCode() (gas: 64911)\n[PASS] test_constructorDoesNotRequireExternalContracts() (gas: 38506351)\n[PASS] test_deploymentMatchesPredictionAndFreezesConfiguration() (gas: 10797096)\n[PASS] test_factoryDeploymentKeepsExplicitOwnerAndBeneficiary() (gas: 6950339)\n[PASS] test_managerCanBeCorrectedBeforeDeploymentAndEmitsEvents() (gas: 359014)\n[PASS] test_notConfiguredFailsClearly() (gas: 59338)\n[PASS] test_offlineScriptMatchesFactoryAndFailsIfSearchExhausted() (gas: 5940457)\n[PASS] test_onlyOwnerCanConfigureAndDeploy() (gas: 5822191)\n[PASS] test_rechecksManagerCodeAtDeployment() (gas: 5774589)\n[PASS] test_rejectsWrongSalt() (gas: 111886)\n[PASS] test_rejectsZeroConstructorArguments() (gas: 8316)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 29.32ms (81.46ms CPU time)\n\nRan 13 tests for test/SuperIMD.t.sol:SuperIMDTest\n[PASS] testFuzz_rejectsEveryOtherSupply(uint256) (runs: 256, μ: 6731, ~: 6731)\n[PASS] testFuzz_transferFromHasNoFeeAndSpendsAllowance(uint256) (runs: 256, μ: 159831, ~: 160411)\nLogs:\n  Bound result 3758364715924700851519\n\n[PASS] testFuzz_transferHasNoFeeAndConservesSupply(uint256) (runs: 256, μ: 96669, ~: 96889)\nLogs:\n  Bound result 3758364715924700851519\n\n[PASS] test_infiniteAllowanceRemainsUnchanged() (gas: 123228)\n[PASS] test_metadataAndExactSupply() (gas: 65571)\n[PASS] test_noPublicMintBurnOrAdmin() (gas: 82610)\n[PASS] test_permitRejectsAlteredValueAndWrongNonce() (gas: 160021)\n[PASS] test_permitRejectsCrossContractAndCrossChainReplay() (gas: 154113)\n[PASS] test_permitRejectsZeroSpenderAndMalformedSignature() (gas: 131283)\n[PASS] test_permitRelayedThenSpentAndReplayRejected() (gas: 224551)\n[PASS] test_permitValidAtDeadlineButNotAfter() (gas: 161283)\n[PASS] test_rejectsZeroRecipient() (gas: 4246)\n[PASS] test_transferFailureDoesNotChangeBalances() (gas: 112860)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 46.73ms (82.67ms CPU time)\n\nRan 15 tests for test/SIMDhook.Unit.t.sol:HookUnitTest\n[PASS] testFuzz_feeArithmeticAllFourModes(bool,bool,uint128) (runs: 256, μ: 167552, ~: 172139)\nLogs:\n  Bound result 1550\n\n[PASS] test_disabledCallbacksFailClosedForEveryCaller() (gas: 498026)\n[PASS] test_minInt128ArithmeticDoesNotPanic() (gas: 116127)\n[PASS] test_permissionsAndImmutableParameters() (gas: 61989)\n[PASS] test_regressionOriginalAllowsWrongSupply() (gas: 1007912)\n[PASS] test_regressionOriginalChargesUnrelatedPool() (gas: 18995492)\n[PASS] test_regressionOriginalMinInt128Panics() (gas: 18917408)\n[PASS] test_rejectsInvalidCollections() (gas: 89420)\n[PASS] test_rejectsUnauthorizedAfterSwapAndCallback() (gas: 100163)\n[PASS] test_rejectsUnauthorizedFeeCollection() (gas: 32805)\n[PASS] test_rejectsUnexpectedDeltaSignAndZeroSpecifiedAmount() (gas: 103318)\n[PASS] test_rejectsUnminedAddress() (gas: 10402)\n[PASS] test_rejectsWrongPoolOrHook() (gas: 128317)\n[PASS] test_rejectsZeroAddresses() (gas: 8238)\n[PASS] test_roundingThresholds() (gas: 288070)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 46.78ms (51.78ms CPU time)\n\nRan 8 tests for test/SIMDhook.Edges.t.sol:HookEdgeTest\n[PASS] testFuzz_factoryDeploysOnlyAtPredictedFlaggedAddress(bytes32) (runs: 512, μ: 117114, ~: 117218)\n[PASS] testFuzz_factoryRejectsEveryNonOwner(address,bytes32) (runs: 512, μ: 331754, ~: 331861)\n[PASS] test_claimsMintedToHookByThirdPartyOnlyReachBeneficiary() (gas: 4564216)\n[PASS] test_collectingNeverAccruedCurrencyRevertsWithoutSideEffects() (gas: 4620093)\n[PASS] test_collectionInsideAnotherUnlockFailsAndLeavesGuardUsable() (gas: 17870686)\n[PASS] test_factoryFlagsMatchHookPermissions() (gas: 4018073)\n[PASS] test_feeStillChargedWhenDustSwapsAreBatchedInOneLargeSwap() (gas: 4803649)\n[PASS] test_poolOnForeignManagerCannotSwapThroughHook() (gas: 9989208)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 49.36ms (177.66ms CPU time)\n\nRan 15 tests for test/SIMDhook.Integration.t.sol:HookIntegrationTest\n[PASS] testFuzz_realSwapFeeAndSettlement(bool,bool,bool,bool,uint96) (runs: 256, μ: 396748, ~: 381271)\nLogs:\n  Bound result 1619329236839796504\n\n[PASS] test_collectNativeAndERC20FeesWithPartialWithdrawal() (gas: 672770)\n[PASS] test_erc20BothTokenOrdersAndAllSwapModes() (gas: 3258103)\n[PASS] test_failedCollectionPreservesClaimsAndDoesNotBlockSwap() (gas: 668918)\n[PASS] test_lpFeeIsAdditionalAndHookRateUnchanged() (gas: 1375767)\n[PASS] test_nativeBuySellExactInputAndExactOutput() (gas: 1458185)\n[PASS] test_overcollectionAndDoubleCollectionRevertWithoutLoss() (gas: 403880)\n[PASS] test_partialFillsChargeExecutedAmountOnly() (gas: 729608)\n[PASS] test_reentrantCollectionCannotSpendClaimsTwice() (gas: 2907921)\n[PASS] test_regressionOriginalRecipientRejectionRevertsNativeFeeSwap() (gas: 8939331)\n[PASS] test_rejectingBeneficiaryDoesNotBlockNativeFeeSwaps() (gas: 2632691)\n[PASS] test_routerEnforcesSlippageAfterHookFeesAndRollsBack() (gas: 434903)\n[PASS] test_tinySwapRoundsFeeDown() (gas: 362311)\n[PASS] test_unrelatedPoolCannotSwapThroughHook() (gas: 507400)\n[PASS] test_zeroLiquiditySwapDoesNotAccrueFees() (gas: 615387)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 52.08ms (61.06ms CPU time)\n\nRan 1 test for test/SIMDhook.Invariant.t.sol:HookInvariantTest\n[PASS]\nHookInvariantTest invariants:\n[PASS] invariant_currencyConservationAndNoUnsettledDebts\n[PASS] invariant_feeClaimsPlusCollectionsEqualEarnedFees\n HookInvariantTest invariants (runs: 64, calls: 2048, reverts: 0)\n\n╭--------------------+----------+-------+---------+----------╮\n| Contract           | Selector | Calls | Reverts | Discards |\n+============================================================+\n| FeeSequenceHandler | collect  | 1021  | 0       | 0        |\n|--------------------+----------+-------+---------+----------|\n| FeeSequenceHandler | swap     | 1027  | 0       | 0        |\n╰--------------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 649.10ms (646.85ms CPU time)\n\nRan 2 tests for test/SIMDhook.MultiPoolInvariant.t.sol:HookMultiPoolInvariantTest\n[PASS]\nHookMultiPoolInvariantTest invariants:\n[PASS] invariant_claimsAreBackedAndHookHoldsNoCurrency\n[PASS] invariant_claimsPlusCollectedEqualsEarnedPerCurrency\n[PASS] invariant_currencyConservedAcrossRouterManagerAndDestinations\n HookMultiPoolInvariantTest invariants (runs: 64, calls: 3072, reverts: 0)\n\n╭------------------+-------------------+-------+---------+----------╮\n| Contract         | Selector          | Calls | Reverts | Discards |\n+===================================================================+\n| MultiPoolHandler | addLiquidity      | 422   | 0       | 0        |\n|------------------+-------------------+-------+---------+----------|\n| MultiPoolHandler | collect           | 415   | 0       | 0        |\n|------------------+-------------------+-------+---------+----------|\n| MultiPoolHandler | outsiderCallbacks | 437   | 0       | 0        |\n|------------------+-------------------+-------+---------+----------|\n| MultiPoolHandler | outsiderCollect   | 438   | 0       | 0        |\n|------------------+-------------------+-------+---------+----------|\n| MultiPoolHandler | overCollect       | 476   | 0       | 0        |\n|------------------+-------------------+-------+---------+----------|\n| MultiPoolHandler | removeLiquidity   | 423   | 0       | 0        |\n|------------------+-------------------+-------+---------+----------|\n| MultiPoolHandler | swap              | 461   | 0       | 0        |\n╰------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 200\n  Bound result 4959984980\n  Bound result 1\n  Bound result 200\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 100\n  Bound result 4046830250\n  Bound result 4999000000000000001455\n  Bound result 2994\n  Bound result 1\n  Bound result 3265362413483893850956\n  Bound result 50\n  Bound result 12475\n  Bound result 4999000000000000000100\n  Bound result 1\n  Bound result 105351\n  Bound result 4999000000000000000010\n  Bound result 4999000000000000000245\n  Bound result 200\n  Bound result 3097\n  Bound result 59\n  Bound result 44\n\n[PASS] test_handlerSequenceEarnsAndCollectsInEveryPool() (gas: 4556610)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 40000799984000000\n  Bound result 1\n  Bound result 119999386552994844\n  Bound result 1\n  Bound result 40000979332979563\n  Bound result 1\n  Bound result 39999205218276884\n  Bound result 1\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.24s (1.23s CPU time)\n\nRan 2 tests for test/SuperIMD.Invariant.t.sol:SuperIMDInvariantTest\n[PASS]\nSuperIMDInvariantTest invariants:\n[PASS] invariant_balancesAllowancesAndNoncesMatchModel\n[PASS] invariant_supplyIsFixedAndFullyHeldByActors\n SuperIMDInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------+-------+---------+----------╮\n| Contract     | Selector     | Calls | Reverts | Discards |\n+==========================================================+\n| TokenHandler | approve      | 1646  | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| TokenHandler | permit       | 1631  | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| TokenHandler | transfer     | 1618  | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| TokenHandler | transferFrom | 1664  | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| TokenHandler | warp         | 1633  | 0       | 0        |\n╰--------------+--------------+-------+---------+----------╯\n\nLogs:\n  Bound result 6273\n  Bound result 823593\n  Bound result 0\n  Bound result 2462\n  Bound result 2\n  Bound result 99\n  Bound result 1000000000\n  Bound result 4\n  Bound result 10000\n  Bound result 100\n  Bound result 2\n  Bound result 43\n  Bound result 600\n  Bound result 27\n  Bound result 1\n  Bound result 469231731687303545742922268\n  Bound result 317\n  Bound result 11125\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 1\n  Bound result 49\n  Bound result 626\n  Bound result 2\n  Bound result 9579\n  Bound result 42\n  Bound result 2\n  Bound result 2000000000000000000\n  Bound result 2189492\n  Bound result 21\n  Bound result 5\n  Bound result 48879\n  Bound result 2\n  Bound result 0\n  Bound result 2\n  Bound result 31054256\n  Bound result 600\n  Bound result 4\n  Bound result 873\n  Bound result 0\n  Bound result 43\n  Bound result 4920\n  Bound result 1\n  Bound result 1\n  Bound result 10838\n  Bound result 60\n  Bound result 2\n  Bound result 393173220784122881369338702\n  Bound result 5\n  Bound result 1\n  Bound result 11114462\n  Bound result 1\n  Bound result 0\n  Bound result 127\n  Bound result 4810\n  Bound result 1047854\n  Bound result 0\n  Bound result 4\n  Bound result 10631\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 13\n  Bound result 1588\n  Bound result 2\n  Bound result 5245\n  Bound result 12865\n\n[PASS] test_handlerReachesEveryPath() (gas: 2292067)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 60000000000000000000\n  Bound result 60000000000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 86400\n  Bound result 1\n  Bound result 86400\n  Bound result 2\n  Bound result 86400\n  Bound result 3\n  Bound result 4\n  Bound result 86400\n  Bound result 5\n  Bound result 86400\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.99s (3.99s CPU time)\n\nRan 8 test suites in 3.99s (6.10s CPU time): 67 tests passed, 0 failed, 0 skipped (67 total tests)\n","passed":true},{"durationMs":61,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SuperIMD.approve(address,uint256)\",\"SuperIMD.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"SuperIMD.transfer(address,uint256)\",\"SuperIMD.transferFrom(address,address,uint256)\",\"SuperIMDHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"SuperIMDHook.collectFees(address,uint256,address)\",\"SuperIMDHook.unlockCallback(bytes)\",\"SuperIMDHookFactory.deployHook(bytes32)\",\"SuperIMDHookFactory.setPoolManager(address)\"],\"files\":{\".gitignore\":4,\"AUDIT.md\":87,\"DEPENDENCIES.json\":41,\"LICENSE\":23,\"README.md\":106,\"VALIDATION.md\":33,\"foundry.toml\":22,\"remappings.txt\":4,\"script/MineHookSalt.s.sol\":15,\"src/SIMDhook.sol\":115,\"src/SuperIMD.sol\":27,\"src/SuperIMDHookFactory.sol\":78,\"src/base/BaseHook.sol\":132,\"src/libraries/HookSaltMiner.sol\":30,\"test/SIMDhook.Edges.t.sol\":256,\"test/SIMDhook.Integration.t.sol\":333,\"test/SIMDhook.Invariant.t.sol\":141,\"test/SIMDhook.MultiPoolInvariant.t.sol\":318,\"test/SIMDhook.Unit.t.sol\":234,\"test/SuperIMD.Invariant.t.sol\":294,\"test/SuperIMD.t.sol\":177,\"test/SuperIMDHookFactory.t.sol\":200,\"test/helpers/HookFixtures.sol\":117,\"test/helpers/PoolHarness.sol\":90},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a019a2570bc77831ad0b18340d324baa182b92d259457cec31c71230aeb5e52b","verifiedTreeHash":"45422c60a2a959b35372e313d72acb85d9564adb","verifierVersion":"0.1.0+c3fba9eb"}]}