{"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":"292d0dab-c9a9-4c74-951d-c36d9855680b","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"c0f15664d367ac7ce9a40b56dd59df741e90a1ecf4ad654c35ad28fc987bcde4","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":"cfde01f7c799b335c78396cdc3b04e8d32f56e71e9473131653ca02a1d02b832","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":"7a68673e452a01d5586e71bf3ac8a8730ea607fbe3049a04f72d0619a253bcbd","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":"b7a645e24f2b0ac156313f7afff2f1417fe57373760513be9d43a52141d7c1f1","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":"d140c777b3208c85353500553002d5eca6ea5b8cb351b8968258875106d55e1c","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":"3068f7d3e794625f78d192f7a46d0e6f273ecc5a1b41cdde2ba2fba65426bebe","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":"77cf852e136ff57ebb91fcc86c5b547b582c966772bcfa6b93eee49284192acf","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"9e8a1a9fae723f8aa2b68f1c5886150822a32880e59af7d9359d0ae7ee045749","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":"Deploy one contract, ReedGuardDeployer, on Robinhood Chain: its constructor takes the Robinhood Chain PoolManager 0x8366a39CC670B4001A1121B8F6A443A643e40951, $owner and the fee recipient 0x5Bff2a2FEcD1d6152676813b21346238733bEAB1, takes no salt argument, starts at salt 0 and increments until the CREATE2 address carries the hook's permission flags, then creates ReedGuard in the launch transaction, passing the PoolManager, $owner and fee recipient unchanged to the hook constructor; neither constructor calls any other contract (apart from the deployer creating the hook). There is no deploy function to call afterwards; hook() returns the hook's address. Enable only the callbacks the behavior below needs.\nReedGuard is a standalone Uniswap v4 hook with no new token and no pool of its own; anyone may initialize an eligible pool with it.\nOnly pools whose currency0 is native ETH may be initialized with this hook; any other initialization reverts.\nIn this hook, the token is the pool's non-ETH currency and its total supply is that token's totalSupply().\nEvery pool-dependent view, state, window and limit is keyed by PoolId and isolated per pool; pass the pool id to each pool-dependent function.\nThe hook does exactly the following, and nothing else:\n1. Take 1.0% of the ETH side of every buy and sell as a hook fee, settled in ETH inside the swap that paid it (mint a claim when the PoolManager cannot pay it directly), and send it to 0x5Bff2a2FEcD1d6152676813b21346238733bEAB1. Expose claimFees(PoolId poolId) that anyone may call to redeem that pool's claims using the same distribution. Fees are computed on the amount actually traded; when the swap specifies its ETH amount and the pool fills only part of it, the swap reverts rather than overpaying.\n2. The owner may pause and unpause swaps separately by PoolId. Liquidity can always be removed while paused. Expose pause(PoolId poolId) and unpause(PoolId poolId) for the owner and paused(PoolId poolId) as a view.\n3. A wallet must wait at least 30 seconds of block timestamp between its swaps in this pool. Track each wallet's next swap time separately by PoolId. Expose nextSwapAt(PoolId poolId, address wallet) as a view. A wallet means tx.origin; several wallets or a shared relayer can defeat the limit.\nOwner 0x5bff2a2fecd1d6152676813b21346238733beab1 may only: pause and unpause swaps, through the functions named above. No other admin function, no backend signer, no upgrade path.\nFees are always taken from the ETH (pair currency) side, never from the pool’s token; a fee the PoolManager cannot pay directly is minted as a claim the recipient can redeem. Fee recipient: 0x5Bff2a2FEcD1d6152676813b21346238733bEAB1.\nThe hook uses no outside pool, token, price feed or service; every price it needs comes from its own pool.\nUse mulDiv for every percentage calculation, including fees, shares, limits and price moves, to avoid intermediate multiplication overflow.\nKeep the function names exactly as written so the storefront can show them. Composed with The Hooks Store block builder.","parentJobId":null,"planHash":"d04fd19fac00b234a0a5e6c5e62717fdb16bd6ec05663b188fe1805155a4c5e3","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"292d0dab-c9a9-4c74-951d-c36d9855680b","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2449-deploy-one-contract-reedguarddeployer"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52678","feedbackHash":"d6f66ea8df1798d0d6ebfc8229e2fcef99f2d50cebadb8ab12c9b42aae76ebfe","nodeKey":"audit_economics","submissionHash":"c0f15664d367ac7ce9a40b56dd59df741e90a1ecf4ad654c35ad28fc987bcde4","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51027","feedbackHash":"55ffefca38cc753276fec5c7bc8c41274fa75062cafd262bafdab5538c6f11c5","nodeKey":"audit_flow","submissionHash":"cfde01f7c799b335c78396cdc3b04e8d32f56e71e9473131653ca02a1d02b832","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51043","feedbackHash":"360683dc15121216381da9f634f9fd0abffccf041ff00e7e15e810bf93ce78d2","nodeKey":"audit_judge","submissionHash":"7a68673e452a01d5586e71bf3ac8a8730ea607fbe3049a04f72d0619a253bcbd","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51534","feedbackHash":"ae4ce8cc329c96ad7c7f18a8687507093cc83324915bad274c2a2cc9d8005157","nodeKey":"audit_math","submissionHash":"b7a645e24f2b0ac156313f7afff2f1417fe57373760513be9d43a52141d7c1f1","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51163","feedbackHash":"feb4b7de5c2da24cc3b6d1ac97a63fa1935c2df770f9b05d177c020446ec12a3","nodeKey":"audit_permissions","submissionHash":"d140c777b3208c85353500553002d5eca6ea5b8cb351b8968258875106d55e1c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52022","feedbackHash":"823280acf83784f0de77249dd1b06eb43130a30f7380a87efe18dd461b801da0","nodeKey":"build_contract_project","submissionHash":"3068f7d3e794625f78d192f7a46d0e6f273ecc5a1b41cdde2ba2fba65426bebe","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52273","feedbackHash":"aaf2234a74749f26502cac351bd2c1011330137021b6f915a84ac4398ad245d4","nodeKey":"manifest","submissionHash":"77cf852e136ff57ebb91fcc86c5b547b582c966772bcfa6b93eee49284192acf","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52224","feedbackHash":"822e74d75ef9b0a0d3a57c44876b30c1ec562bf4754489afd12627fcbbcbbc7b","nodeKey":"write_foundry_tests","submissionHash":"9e8a1a9fae723f8aa2b68f1c5886150822a32880e59af7d9359d0ae7ee045749","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"152404e14d92fe94d555c12d7e1de3848e3881f79209ca81a17ef1974d591334","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"af1b82548c361f2b2dc5c1d3e92b59b9c04fb9dee410605f831494e0f5128df2","device":"30739b66307c87c9","findings":[],"hash":"3068f7d3e794625f78d192f7a46d0e6f273ecc5a1b41cdde2ba2fba65426bebe","nodeId":"3927e522-417e-4850-a809-1921b56a2301","outcome":"completed","summary":"Implemented `ReedGuard` and constructor-only `ReedGuardDeployer`, with offline dependencies and deployment documentation.\n\nValidation passed:\n\n- `forge build`\n- `forge test`: 42 passed with the supplied seed, including 8,192 invariant operations\n- `forge fmt --check`\n\nDeployment parameters, assumptions and operational responsibilities are documented in `README.md`. Live deployment remains with the launch pipeline.","treeHash":"1401ea722a29a050db40f0e18a1d7773295d6a26","usage":{"cachedInputTokens":3706880,"inputTokens":162309,"model":"gpt-6-astra","outputTokens":48997,"runtime":"codex","turns":9,"wallClockMs":1860385}},{"artifacts":[],"attempt":1,"bundleHash":"2517dccf901c8c1ca25a1b8e3425e7063c2f4b40797ac4840a0f665a0dcf976f","device":"d13d3bb393e39302","findings":[],"hash":"77cf852e136ff57ebb91fcc86c5b547b582c966772bcfa6b93eee49284192acf","nodeId":"93842430-9820-4b5e-8da8-ac0664c5ea06","outcome":"completed","summary":"Created [launch.json](/home/imd1/.identitymd/work/292d0dab-c9a9-4c74-951d-c36d9855680b/93842430-9820-4b5e-8da8-ac0664c5ea06/launch.json) with one `ReedGuardDeployer` entry and the required constructor arguments.\n\nVerified against the compiled ABI. `forge build` passed; all 42 tests passed with the supplied fuzz seed. Only `launch.json` changed.","treeHash":"7589fd47d4aab458ec635ea21a55c81d26edcace","usage":{"cachedInputTokens":489050,"inputTokens":58610,"model":"gpt-6.1-sol","outputTokens":2733,"runtime":"codex","turns":3,"wallClockMs":70477}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2565f234b0a569e9","findings":[{"citation":"resolved","description":"Merged from audit_math, audit_economics and audit_permissions (same root cause). The brief asks for 1.0% of the ETH side of every buy and sell, computed on the amount actually traded. The code uses two bases. When ETH is the specified currency, `_specifiedFee` (src/ReedGuard.sol:241) charges 1% of |amountSpecified| and beforeSwap's specified delta makes the pool trade amountSpecified +/- fee. When the token is specified, afterSwap (line 183) charges 1% of the pool's realized ETH delta and adds it on top. Measured against the ETH the pool actually traded, exact-input ETH buys pay 1.0101% and exact-output ETH sells pay 0.9901%, while token-specified swaps pay exactly 1.0000%. Measured against the swapper-facing ETH amount it is the mirror image. No funds are lost and conservation holds (verified: hook deltas net to zero and the recipient receives exactly the computed fee), but the brief's single rule describes neither basis, and a router that always specifies the cheaper side (exact-output token on buys, exact-output ETH on sells) pays 1% less hook fee than one specifying the other side for an identical pool trade; the recipient loses that 1%-of-fee on all such flow. The README documents both bases, so this is a design clarification against the brief rather than a loss of funds. Minimal fix preserving the design: pick one basis for all four modes (for example the pool's realized ETH delta, computing the ETH-specified fee as mulDiv(|S|, 100, 10_100) for exact-input and mulDiv(|S|, 100, 9_900) for exact-output so that fee = 1% of the pool-side amount), or state the swapper-facing basis in the brief/storefront.","line":183,"path":"src/ReedGuard.sol","reproduction":"Fixture: fresh PoolManager, ReedGuardDeployer(manager, OWNER, OWNER) with OWNER = 0x5Bff2a2FEcD1d6152676813b21346238733bEAB1 (EOA, so fees are paid directly), pool ETH/TestToken(18) fee 3000 spacing 60 initialized at sqrtPrice 1<<96, liquidity 10_000 ether in [-600, 600]. Take vm.snapshotState() and run each leg from the same state via the local TestRouter with tx.origin = alice. (A) buy zeroForOne=true, amountSpecified=-1e18: swapper delta amount0 = -1.000000e18, tokens out 986932586792885781, recipient receives 0.010000e18. (B) buy zeroForOne=true, amountSpecified=+986932586792885781 (exact-output the same tokens, identical pool trade of 0.99 ETH): swapper delta amount0 = -0.999900e18, recipient receives 0.009900e18. (C) sell zeroForOne=false, amountSpecified=+1e18 (exact-out 1 ETH): pool pays 1.01 ETH, swapper receives 1.000000e18, tokens in 1013141444637964604, fee 0.010000e18. (D) sell zeroForOne=false, amountSpecified=-1013141444637964604 (exact-in the same tokens, identical pool trade): swapper receives 0.999900e18, fee 0.010100e18. Expected under the brief: equal fees for A/B and for C/D (one rate on the ETH actually traded). Actual: 1.0000e16 vs 0.9900e16 and 1.0000e16 vs 1.0100e16, a 1% spread on the fee (1e14 wei per 1 ETH). Reproduced with test/scratch/Probe.t.sol::test_feeBasis on the current tree (logs A fee 10000000000000000, B fee 9900000000000000, C fee 10000000000000000, D fee 10100000000000000).","severity":"low","snippet":"            fee = FullMath.mulDiv(_abs(int256(delta.amount0())), FEE_BPS, BPS_DENOMINATOR);","title":"Hook fee basis differs by swap mode: ETH-specified swaps are charged on the caller's amount, token-specified swaps on the pool's realized ETH delta, so the same pool trade pays fees that differ by 1% "},{"citation":"resolved","description":"Merged from audit_flow (low) and audit_permissions (info). beforeInitialize only checks the currency pair and the hook address. A PoolKey with fee = 0x800000 (LPFeeLibrary.DYNAMIC_FEE_FLAG) passes Hooks.isValidHookAddress for any hook with permission bits, so PoolManager.initialize opens the pool with lpFee = 0 (getInitialLPFee returns 0 for the dynamic flag). Only the pool's hook may call PoolManager.updateDynamicLPFee, and ReedGuard has no code path that calls it; beforeSwap always returns lpFeeOverride = 0 without the override flag, so the stored 0 is used on every swap. Anyone can open such a pool under this hook; LPs who provide to it earn nothing on swaps while the hook still takes its 1% ETH fee and the owner's pause applies. No funds are lost and LPs choose their pool, so this stays low. The README notes the behaviour. Minimal fix preserving the design: in beforeInitialize revert when key.fee.isDynamicFee() (LPFeeLibrary), so only static-fee ETH pools are eligible.","line":105,"path":"src/ReedGuard.sol","reproduction":"Fixture: fresh PoolManager, ReedGuard via ReedGuardDeployer(manager, OWNER, OWNER), TestToken(18). Call manager.initialize(PoolKey(currency0 = address(0), currency1 = token, fee = 0x800000, tickSpacing = 60, hooks = hook), 1<<96) from any address. Expected (hook cannot operate a dynamic LP fee): revert in beforeInitialize. Actual: succeeds; StateLibrary.getSlot0(key.toId()) returns lpFee = 0; manager.updateDynamicLPFee(key, 3000) from any caller reverts with UnauthorizedDynamicLPFeeUpdate, and the hook never calls it. Reproduced with test/scratch/Probe.t.sol::test_dynamicFeePoolAccepted on the current tree (log 'dynamic pool lp fee 0').","severity":"low","snippet":"        if (!key.currency0.isAddressZero() || key.currency1.isAddressZero()) {","title":"beforeInitialize accepts the dynamic-fee flag although the hook never sets or overrides an LP fee, so such a pool trades at 0 LP fee permanently"},{"citation":"resolved","description":"Documentation is stale relative to the tree: a launch.json manifest (kind evm_contracts, one contract ReedGuardDeployer with constructorArgs [PoolManager, $owner, fee recipient]) was added by the manifest step, and the README still says there is none. The manifest itself is schema-valid and matches the brief (static PoolManager 0x8366a39CC670B4001A1121B8F6A443A643e40951, $owner, static recipient 0x5Bff2a2FEcD1d6152676813b21346238733bEAB1, three entries for three constructor parameters, notes under 4,000 characters, only schema keys). No code impact; an operator reading the README could look for the manifest elsewhere. Fix: update the sentence to describe the included launch.json.","line":38,"path":"README.md","reproduction":"ls launch.json at the repository root shows the file; README.md line 38 says 'It contains no `launch.json`'. Expected: README and tree agree. Actual: they contradict.","severity":"info","snippet":"This repository contains the launchable contracts and tests. It contains no `launch.json`, private key, signing flow, broadcast or assumed final contract address. The launch pipeline supplies the manifest and records the confirmed deployer and `hook()` address.","title":"README states the repository contains no launch.json, but launch.json is present at the repository root"}],"hash":"7a68673e452a01d5586e71bf3ac8a8730ea607fbe3049a04f72d0619a253bcbd","nodeId":"fdc0d9c6-1797-4d50-8317-8a6f4e8b88f6","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written. The working tree is clean apart from the ignored `test/scratch/` and the findings file.\n\n**Outcome:** no critical, high or medium defects. The hook's delta accounting, reentrancy guards, pause and cooldown isolation, claim ledger and the deployer's CREATE2 mining all hold under trace and under scratch tests run against the vendored v4 PoolManager. The existing suite passes 64 of 64.\n\n**Findings kept (3):**\n- **Low, fee basis differs by swap mode.** Three specialists reported the same root cause, merged into one. ETH-specified swaps charge 1% of the caller's amount, token-specified swaps charge 1% of the pool's realized ETH delta. Reproduced from one snapshot: identical pool trades paid 0.0100 vs 0.0099 ETH on buys and 0.0100 vs 0.0101 ETH on sells. No funds lost, but routers can pick the cheaper side.\n- **Low, dynamic-fee pools accepted.** Two specialists, merged. Initializing with fee 0x800000 succeeds and the pool sits at 0 LP fee forever because the hook never updates or overrides it. Reproduced: slot0 reports lpFee 0 and updateDynamicLPFee is unauthorized for anyone else.\n- **Info, stale README.** Line 38 says the repository contains no launch.json, but one is present and schema-valid.\n\n**Dropped:** the tx.origin shared-relayer note is the trust assumption the brief itself states, not a defect. All static-analysis leads were false positives or benign: the Yul shift order is correct, the encodePacked hash has fixed-size trailing args, the \"reentrancy\" sites are guarded by the paying flag, and the unused unlock return is empty bytes.\n\n**Coverage:** all 7 entry points answered, 5 hold, 2 carry findings, plus rows for the deployer constructor and the delta-conservation invariant.","treeHash":null,"usage":{"cachedInputTokens":1169311,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":36099,"runtime":"claude","turns":22,"wallClockMs":604018}},{"artifacts":[],"attempt":1,"bundleHash":"70c2eff340d6fea8f8a336b8faa0908ea9fedec0e1a76c7ba6bba5db087eb8cc","device":"2a2028177fd413f2","findings":[],"hash":"9e8a1a9fae723f8aa2b68f1c5886150822a32880e59af7d9359d0ae7ee045749","nodeId":"c5db562b-9f6c-481b-8d0c-d571830259eb","outcome":"completed","summary":"Added tests for batch rollback, fee and supply boundaries, claim recovery, and liquidity lifecycle invariants. Changes are confined to `test/`.\n\n`forge build` and `forge test` pass with the required seed: **64 passed, 0 failed, 0 skipped**, including 24,576 new invariant calls.\n\nNo implementation defect was reproduced. Testing used the local PoolManager; no live-chain fork was run.","treeHash":"3e915ff49f3652dcc27b7f0c977d5e28986059f9","usage":{"cachedInputTokens":3273344,"inputTokens":148645,"model":"gpt-6-astra","outputTokens":29653,"runtime":"codex","turns":7,"wallClockMs":1065160}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"739094f0e08668ee","findings":[{"citation":"resolved","description":"For token-specified swaps the fee is 1% of the pool's ETH delta (afterSwap, `FullMath.mulDiv(_abs(int256(delta.amount0())), FEE_BPS, BPS_DENOMINATOR)`), i.e. of the ETH the pool actually traded. For ETH-specified swaps the fee is 1% of |amountSpecified|, and beforeSwap's positive specified delta changes the pool's traded amount to amountSpecified + fee. Exact-input ETH buys therefore pay 1% of the gross input (= 1.0101% of the 0.99X the pool traded), and exact-output ETH sells pay 1% of the net output Y (= 0.990099% of the Y+fee the pool traded). The same pool-side trade is charged different fees depending only on how the router specifies it, contrary to 'Fees are computed on the amount actually traded' and a uniform 1.0% of the ETH side. The gap is 1% of the fee (~0.01% of volume), so it is low impact, but it is systematic and lets sellers choose exact-output ETH to pay less.","line":240,"path":"src/ReedGuard.sol","reproduction":"Pool ETH/TOKEN with ReedGuard, ample liquidity. (A) Buy with zeroForOne=true, amountSpecified=-1e18 (exact-in ETH): beforeSwap fee = mulDiv(1e18,100,10000)=1e16; pool trades amountToSwap=-1e18+1e16 = 0.99e18 ETH; recipient gets 1e16. (B) Buy with zeroForOne=true, amountSpecified=+T (exact-out token) where T is chosen so the pool consumes exactly 0.99e18 ETH: afterSwap fee = mulDiv(0.99e18,100,10000)=9.9e15. Same pool trade (0.99e18 ETH in, same tokens out), fees 1e16 vs 9.9e15 (diff 1e14 wei per ETH). Likewise sells: exact-out ETH Y=1e18 -> pool outputs 1.01e18, fee 1e16 (0.990099% of traded ETH) vs exact-in token sell whose pool ETH output is 1.01e18 -> fee 1.01e16. Expected: one rate on the ETH the pool actually traded (e.g. for ETH-specified swaps compute fee so that fee = 1% of (|amountSpecified| -/+ fee) i.e. mulDiv(|s|,100,10100) for exact-in and mulDiv(|s|,100,9900) for exact-out, or document that ETH-specified fees are on the user-facing amount).","severity":"low","snippet":"    function _specifiedFee(SwapParams calldata params) private pure returns (uint256) {\n        return FullMath.mulDiv(_abs(params.amountSpecified), FEE_BPS, BPS_DENOMINATOR);\n    }","title":"Effective fee rate depends on swap mode: ETH-specified swaps charge 1% of the user's gross/net amount, not of the ETH the pool actually traded"}],"hash":"b7a645e24f2b0ac156313f7afff2f1417fe57373760513be9d43a52141d7c1f1","nodeId":"fb1d6957-9cb4-4c2e-a898-f3fcdd4ebde1","outcome":"completed","summary":"I've written the review to `.imd-findings.json`. It has one low-severity finding and a coverage row for all 7 entry points, plus two rows for invariants I checked. No source files were changed. I didn't write or run a Foundry proof test, since that was only required for critical or high findings.\n\n**Finding 1 (low): the fee rate depends on how the swap is specified** (`src/ReedGuard.sol`, `_specifiedFee`)\n- **What's right:** when the swap specifies the token amount, `afterSwap` takes 1% of the ETH the pool actually traded.\n- **What's wrong:** when the swap specifies the ETH amount, the fee is 1% of the amount the user typed in, and the pool then trades that amount adjusted by the fee.\n- **Buys, exact ETH in:** `amountSpecified = -1e18` gives a fee of 1e16, but the pool trades only 0.99e18. That's 1.0101% of what was traded.\n- **Buys, exact tokens out:** a buy that makes the pool take the same 0.99e18 ETH pays 9.9e15.\n- **Sells, exact ETH out:** asking for 1e18 ETH out makes the pool pay out 1.01e18 and charges 1e16, which is 0.990099% of what was traded.\n- **Why it matters:** the brief says fees are computed on the amount actually traded. The gap is about 0.01% of volume, but it is systematic, and sellers can pay slightly less by asking for an exact ETH output.\n- **Suggested fix:** compute the ETH-specified fee as `mulDiv(|s|, 100, 10100)` for exact input and `mulDiv(|s|, 100, 9900)` for exact output, where `|s|` is the specified ETH amount. Alternatively, document that these fees are taken on the amount the user specifies.\n\n**What holds:**\n- **ETH-side fee:** the fee is always taken in ETH, never from the token. It is calculated with `mulDiv`, rounds down by under 1 wei in the swapper's favour, and amounts are range-checked before conversion.\n- **Partial fills:** `amountSpecified + fee` matches how Uniswap v4 adjusts the swap amount, so a partly filled ETH-specified swap reverts as the brief requires.\n- **Pool rules:**\n  - Only native-ETH `currency0` pools can be initialised.\n  - Pause is checked per pool.\n  - The 30-second cooldown allows the next swap exactly at timestamp + 30, as specified.\n  - Liquidity callbacks aren't enabled, so removing liquidity always works.\n- **Fee payout:** `_payOrDefer` either sends the fee or mints a claim. `claimFees`/`unlockCallback` burn the claim and send it to the fixed recipient, capped at the PoolManager's ETH balance, with the PoolManager's accounting netting to zero.\n- **Deployer:** the CREATE2 address calculation in `ReedGuardDeployer` is laid out correctly.\n\n**Static-analysis leads:** I checked them and none turned into findings. Aderyn's hash-collision and shift-order warnings are false positives. Its reentrancy warning and Slither's unused-return warning on `claimFees` are by design: the state is updated before the external call, and the ignored return value isn't needed.\n\n**Not covered:** I didn't measure gas costs, and I didn't run the mixed-route arithmetic on-chain; it is worked out by hand from v4-core's `Hooks.beforeSwap`.","treeHash":null,"usage":{"cachedInputTokens":236951,"inputTokens":10,"model":"claude-opus-5-5","outputTokens":9438,"runtime":"claude","turns":5,"wallClockMs":101283}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"96eeb8eb2acdbbf1","findings":[{"citation":"resolved","description":"The brief says the hook takes 1.0% of the ETH side of every buy and sell, computed on the amount actually traded. The code uses two different bases. When ETH is the specified currency (buy exact-input ETH, sell exact-output ETH) `_specifiedFee` (line 241) charges 1% of the caller's specified amount, which is the pool's ETH delta plus or minus the fee itself. When the token is specified (buy exact-output token, sell exact-input token) `afterSwap` line 183 charges 1% of the pool's realized ETH delta (`FullMath.mulDiv(_abs(int256(delta.amount0())), FEE_BPS, BPS_DENOMINATOR)`). The same pool trade therefore pays a different hook fee depending on which side the swapper specifies (Invariant guide: path divergence between two routes to the same outcome). A swapper who always specifies the token side pays 0.99% of the pool's ETH delta on buys and 1.00% on sells; a swapper who specifies ETH pays 1.01% on buys and 0.99% on sells. Net effect: for any trade the swapper can pick the cheaper mode and the fee recipient collects 1% less fee than the other mode would have paid. The README documents the two bases, so this is a design clarification rather than a loss of funds; it is reported because the brief's single-sentence fee rule does not describe the asymmetry and routers/aggregators will optimise toward the cheaper mode. Fix options (either preserves intent): compute the ETH-specified fee on the pool's realized ETH delta in `afterSwap` as well (fee = mulDiv(|delta.amount0()|, 100, 10_000)) and return it via the specified delta derived in beforeSwap from the same formula solved for the pool amount, or document the basis as 'the swapper-facing ETH amount' and accept the 1%-of-fee spread.","line":241,"path":"src/ReedGuard.sol","reproduction":"Fixture pool `key` (ETH/asset, LP fee 3000, 10_000 ether liquidity in [-600,600], price 1:1), run via test/scratch/FeeBasis.t.sol with vm.snapshotState between the two legs so both start from the same pool state.\nBuy leg A: _swap(alice, key, true, -1 ether) (exact-input 1 ETH). PoolManager Swap event: pool ETH delta -0.990000 ETH, tokens out 986932586792885781. Recipient receives fee 0.010000 ETH. User pays 1.000000 ETH.\nBuy leg B: revert snapshot, _swap(alice, key, true, 986932586792885781) (exact-output the same token amount). Swap event: pool ETH delta -0.990000 ETH (identical trade), tokens out identical. Recipient receives fee 0.009900 ETH. User pays 0.999900 ETH.\nExpected (1.0% of the ETH side of the same trade): equal fees. Actual: 0.010000 vs 0.009900 ETH, a 1% spread on the fee; the swapper saves 0.0001 ETH per 1 ETH by choosing exact-output.\nSell leg A: _swap(alice, key, false, 1 ether) (exact-output 1 ETH): pool ETH delta +1.010000, tokens in 1013141444637964604, fee 0.010000, user receives 1.000000.\nSell leg B: revert snapshot, _swap(alice, key, false, -1013141444637964604) (exact-input same tokens): pool ETH delta +1.010000 (identical trade), fee 0.010100, user receives 0.999900. Sellers save 1% of the fee by choosing exact-output ETH.","severity":"low","snippet":"        return FullMath.mulDiv(_abs(params.amountSpecified), FEE_BPS, BPS_DENOMINATOR);","title":"Hook fee basis differs by swap mode: identical pool trades pay fees that differ by 1% of the fee"}],"hash":"c0f15664d367ac7ce9a40b56dd59df741e90a1ecf4ad654c35ad28fc987bcde4","nodeId":"62ab5859-9324-428a-8acc-c6a0f1b0bac3","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the result: one low-severity finding and coverage rows for all seven entry points plus six checked invariants and leads. The scratch test directory was removed and the tree is otherwise unchanged.\n\n**What I checked, against the Economic Security, Invariant and Flow Gap guides:**\n\n- **Fee settlement and delta netting.** Traced all four swap modes through the pinned v4 `Hooks.beforeSwap`/`afterSwap` and `Pool.swap`. The hook's returned deltas always equal what it takes or mints, so its balance nets to zero. The ETH fee is settled inside the paying swap, never from the pool token. The token-only-seeded fresh-manager case correctly mints a claim.\n- **Partial-fill guarantee.** The afterSwap equality on the raw pool delta cannot be satisfied by any price-limit or empty-liquidity stop, so ETH-specified partial fills revert with fee, cooldown and price rolled back.\n- **Claim ledger invariant.** Per-pool ledger and the hook's ERC-6909 ETH balance move together in exactly two places, claims are always ETH-backed by the swapper's settlement, proceeds reach only the immutable recipient, and a rejecting recipient cannot block swaps or lose a claim.\n- **Dependency and reentrancy seams.** The recipient's receive hook runs mid-swap but the shared execution guard rejects re-entered swaps and claims. No oracle, outside pool or token call sits on the swap path.\n- **Deployment economics.** The unbounded salt search measured about 1.85M gas and 37,944 iterations in the two existing tests, well inside any transaction gas limit.\n- **Static-analysis leads.** All slither and aderyn lines were traced and are false positives or harmless redundancy.\n\n**The one finding (low):** the fee basis differs by swap mode. For an identical pool trade from the same state, exact-input ETH buys pay 0.0100 ETH while exact-output token buys pay 0.0099 ETH, and exact-output ETH sells pay 0.0100 ETH while exact-input token sells pay 0.0101 ETH. Swappers can pick the cheaper mode and the recipient collects 1% less fee. The README documents the two bases, so this is a clarification against the brief's single fee rule rather than a loss of funds. The reproduction with exact wei amounts is in the file.\n\n**Not reached:** nothing in my assigned area. I did not independently verify that the Robinhood Chain PoolManager address runs the pinned v4-core revision, which is outside the economics scope and needs a network check by the deployment rehearsal.","treeHash":null,"usage":{"cachedInputTokens":1044242,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":36360,"runtime":"claude","turns":35,"wallClockMs":607767}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"61b4050710026370","findings":[{"citation":"resolved","description":"beforeInitialize only checks the currency pair. A PoolKey whose fee is LPFeeLibrary.DYNAMIC_FEE_FLAG (0x800000) passes PoolManager.initialize because Hooks.isValidHookAddress allows the dynamic flag for any hook with permission bits. v4 opens a dynamic-fee pool with lpFee = 0 and only the pool's hook may later call PoolManager.updateDynamicLPFee; ReedGuard has no code path that calls it, and beforeSwap always returns lpFeeOverride = 0 without the override flag. The result is a pool that advertises a hook-managed fee but trades at 0 LP fee forever: LPs who provide liquidity to it earn nothing on swaps while the hook still takes its 1% ETH fee. The brief says anyone may initialize an eligible pool with this hook and enumerates everything the hook does; rejecting (or refusing to override) a fee mode the hook cannot operate is the control-flow gap. docs/README.md acknowledges the behaviour, which is why this is low rather than medium: it is a footgun for third-party LPs rather than a loss to the owner or fee recipient. Minimal fix that preserves the design: in beforeInitialize add `if (key.fee.isDynamicFee()) revert NativeETHPairRequired();` (or a dedicated error) using LPFeeLibrary, so only static-fee ETH pools are eligible.","line":105,"path":"src/ReedGuard.sol","reproduction":"Deploy PoolManager and ReedGuardDeployer(manager, owner, recipient). Build key = PoolKey(currency0 = address(0), currency1 = any ERC-20, fee = 0x800000, tickSpacing = 60, hooks = hook). Call manager.initialize(key, 1<<96). Expected: revert (the hook cannot operate a dynamic LP fee). Actual: initialize succeeds, StateLibrary.getSlot0(key.toId()) reports lpFee == 0, and manager.updateDynamicLPFee(key, 3000) from any caller reverts with UnauthorizedDynamicLPFeeUpdate because only the hook may call it and the hook never does. Verified with a scratch Foundry test on the vendored v4-core (test passes, i.e. the pool opens at 0 fee).","severity":"low","snippet":"        if (!key.currency0.isAddressZero() || key.currency1.isAddressZero()) {\n            revert NativeETHPairRequired();\n        }","title":"beforeInitialize accepts the dynamic-fee flag although the hook never manages an LP fee, so such a pool is permanently at 0 LP fee"}],"hash":"cfde01f7c799b335c78396cdc3b04e8d32f56e71e9473131653ca02a1d02b832","nodeId":"bfde102d-911d-415e-8fb9-a7f64bbddcbf","outcome":"completed","summary":"Review complete. The findings file is written and validated, and the working tree holds no source changes.\n\n**Outcome**\n\nThe ReedGuard control flow holds under the Execution Trace, Periphery and First Principles passes. I traced every entry point, re-derived the v4 delta arithmetic for all four swap modes, and probed the two riskiest paths with scratch tests on the vendored PoolManager. Both passed: a multi-hop through two ReedGuard pools in one unlock settles cleanly with both fees paid, and enabling a protocol fee does not break the exact-fill check for ETH-specified swaps.\n\n**One finding, low severity**\n\n- `beforeInitialize` accepts a pool key carrying the dynamic-fee flag. Such a pool opens at a zero LP fee, and only the hook could ever change it, which it never does. LPs in that pool earn nothing while the hook still takes its 1% ETH fee. The README acknowledges this, so it is a footgun for third parties rather than a loss to the owner. The fix is a one-line rejection of dynamic-fee keys in `beforeInitialize`.\n\n**What held, and why**\n\n- The ETH-specified fee path is sound: the specified-side delta from `beforeSwap`, the partial-fill comparison in `afterSwap`, and the take-or-mint settlement net the hook's delta to zero on every path.\n- Claims are isolated per pool, decremented before the unlock, restored on any revert, and the callback is usable only during a hook-initiated claim.\n- Reentrancy from a paying recipient is blocked for swaps and claims through the shared guard.\n- The deployer's CREATE2 preimage layout, salt progression, mask and argument forwarding are correct. The aderyn shift-order and hash-collision leads are false positives, and the slither leads are all intended behavior.\n\n**Coverage**\n\nAll seven listed entry points have rows, plus rows for the deployer constructor, two invariants and the static-analysis leads. Nothing was left unreached.\n\n**Not a finding, but worth the launch operator's attention**\n\nThe pinned `univ4_hook` protected tests initialize the launch pool with whatever paired currency the environment names. This hook rejects any pool whose currency0 is not native ETH, as the brief requires, so if those tests run with an ERC-20 pair they fail in the initialization check. That is a service-configuration question for a contracts-only launch, not a code defect.","treeHash":null,"usage":{"cachedInputTokens":1162269,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":43048,"runtime":"claude","turns":31,"wallClockMs":631960}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8af9903f4ad1eed0","findings":[{"citation":"resolved","description":"Asymmetry / Trust-gap seam 2 (economics x asymmetry). The brief asks for 1.0% of the ETH side of every buy and sell, computed on the amount actually traded. The four swap modes use two different bases. ETH-specified swaps (src/ReedGuard.sol:241, `_specifiedFee`) charge 1% of the caller-specified ETH amount S and adjust the pool trade to S-F (exact input) or S+F (exact output). Token-specified swaps (src/ReedGuard.sol:183) charge 1% of the pool's realized ETH delta X and add it on top, so the swapper pays X+F or receives X-F. Measured against the gross ETH that actually moved, the fee is exactly 100.00 bps for an exact-input ETH buy and for an exact-input token sell, but 99.00 bps (1/101) for an exact-output token buy and for an exact-output ETH sell: in the exact-output ETH sell the pool trades S+F = 1.01 ETH yet the fee is S/100 = 0.01 ETH, 1% of 1.0 rather than 1% of the 1.01 actually traded; in the exact-output token buy the user pays X+F but the fee is X/100 instead of (X+F)/100. The formula is otherwise correct and conservation holds, so no funds are lost, but whoever picks the specification mode picks the cheaper fee: a trader who always submits exact-output orders pays 1% less hook fee than one submitting exact-input orders for the same gross ETH, and the fee recipient receives 1 bp of volume less than the stated 1.0% on all exact-output flow. The README documents the two bases, so this may be an accepted convention; it is reported because the brief's wording ('amount actually traded') matches neither the exact-input basis (pool trades S-F, fee on S) nor the exact-output basis (pool trades S+F, fee on S). Minimal fix preserving the design: for the token-specified branch compute the fee so that fee = 1% of (X + fee), i.e. mulDiv(X, FEE_BPS, BPS_DENOMINATOR - FEE_BPS) on buys and keep mulDiv(X, FEE_BPS, BPS_DENOMINATOR) on sells (or the mirror choice), and for exact-output ETH sells charge 1% of S+F by using mulDiv(S, FEE_BPS, BPS_DENOMINATOR - FEE_BPS); then document one basis for all four modes.","line":183,"path":"src/ReedGuard.sol","reproduction":"Fixture: fresh PoolManager, ReedGuard via ReedGuardDeployer(manager, OWNER, OWNER), pool ETH/TestToken(18) fee 3000 spacing 60 at sqrtPrice 1<<96, liquidity 10_000 ether in [-600, 600]; recipient is an EOA so every fee is paid directly. (a) Buy exact-input 1 ETH (zeroForOne=true, amountSpecified=-1e18): user pays 1.000000000000000000 ETH, recipient receives 0.010000000000000000 ETH = 100.00 bps of what the user paid. (b) Buy exact-output 1e18 tokens (zeroForOne=true, amountSpecified=+1e18): user pays 1.013340451268470242 ETH, recipient receives 0.010033073774935348 ETH = 99.00 bps of what the user paid; 1.0% of the ETH side actually paid would be 0.010133404512684702 ETH, a 0.000100330737749354 ETH shortfall on this one swap. (c) Sell exact-input 1e18 tokens: user receives 0.987323893591425040 ETH, fee 0.009972968622135606 ETH = 99.99 bps of gross output (1.00%, rounding down). (d) Sell exact-output 1 ETH (zeroForOne=false, amountSpecified=+1e18): pool pays out 1.01 ETH, user receives 1.000000000000000000 ETH, fee 0.010000000000000000 ETH = 99.00 bps of the 1.01 ETH actually traded; 1% of the traded amount would be 0.0101 ETH. Expected: one basis for all modes so that identical gross ETH volume pays an identical fee. Actual: exact-output orders pay 1/101 while exact-input orders pay 1/100. Measured with test/scratch/Probe.t.sol::test_feeBasisAcrossModes (logs above) against the current tree.","severity":"low","snippet":"            fee = FullMath.mulDiv(_abs(int256(delta.amount0())), FEE_BPS, BPS_DENOMINATOR);","title":"Hook fee basis differs by swap specification mode: 1.00% of gross ETH on exact-input swaps, 0.99% on exact-output swaps"},{"citation":"resolved","description":"Asymmetry between what the hook accepts and what it can serve. The only initialization check is that currency0 is native ETH. A PoolKey with fee = 0x800000 (LPFeeLibrary.DYNAMIC_FEE_FLAG) passes, the PoolManager stores an initial dynamic LP fee of 0, and because ReedGuard neither calls updateDynamicLPFee nor returns a fee with the override flag from beforeSwap, the pool's LP fee is 0 permanently. Anyone can open such a pool; LPs who add liquidity to it earn nothing while the hook still collects its 1% and the owner's pause applies. No funds are lost and LPs choose their pool, so this is informational; the README already notes a dynamic-fee pool 'retains v4's initial LP fee'. If the storefront lists pools under this hook, rejecting key.fee.isDynamicFee() in beforeInitialize (one extra condition) would close the mismatch; otherwise document that dynamic-fee pools under this hook are zero-LP-fee pools.","line":105,"path":"src/ReedGuard.sol","reproduction":"Fixture as above. Call manager.initialize(PoolKey(ETH, token, 0x800000, 60, hook), 1<<96) from any address. Expected (if the hook is meant only for fee tiers it can serve): revert in beforeInitialize. Actual: succeeds; StateLibrary.getSlot0(poolId) returns lpFee = 0; swaps proceed charging only the 1% hook fee. Observed with test/scratch/Probe.t.sol::test_dynamicFeePoolAccepted (log 'dynamic pool lp fee: 0').","severity":"info","snippet":"        if (!key.currency0.isAddressZero() || key.currency1.isAddressZero()) {\n            revert NativeETHPairRequired();\n        }","title":"beforeInitialize accepts the dynamic-fee flag although the hook never sets an LP fee, so such pools trade at a 0 LP fee forever"},{"citation":"resolved","description":"Trust assumption, recorded rather than reported as a defect because the brief defines a wallet as tx.origin and acknowledges that a shared relayer defeats the limit. The flip side is the asymmetry worth stating for the storefront: distinct end users whose transactions share an origin (a bundler, a relayer, a Gelato/Safe executor, a batch-sending bot) share one cooldown per pool, so the second user's swap in a 30-second window reverts with SwapTooSoon even though they have never traded, while a single person with many EOAs is not limited at all. The owner has no lever to exempt an origin. No fix is suggested that changes the agreed design; if a per-user limit is ever wanted, the sender argument or hookData-carried identity would be the hook-level alternative.","line":149,"path":"src/ReedGuard.sol","reproduction":"Fixture as above. vm.prank(alice, relayer); router.swap(key, SwapParams(true, -1e18, MIN_SQRT_PRICE+1)) succeeds and sets nextSwapAt(poolId, relayer) = now + 30. In the same block vm.prank(bob, relayer); router.swap(key, same params) reverts with SwapTooSoon(poolId, relayer, now+30), although nextSwapAt(poolId, bob) is 0. Observed with test/scratch/Probe.t.sol::test_sharedOriginBlocksSecondUser.","severity":"info","snippet":"        address wallet = tx.origin;","title":"Cooldown keyed by tx.origin lets one relayer or ERC-4337 bundler origin block every user it serves for 30 seconds per pool"}],"hash":"d140c777b3208c85353500553002d5eca6ea5b8cb351b8968258875106d55e1c","nodeId":"2d557070-b65f-4303-b154-bf39432764c8","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written at the repository root with 3 findings and 11 coverage rows. All 7 listed entry points have a row.\n\n**Outcome.** The access-control, trust-gap and asymmetry surface of ReedGuard holds. Every hook callback and the unlock callback accept only the PoolManager. The owner can do nothing but pause and unpause, and both are checked on `msg.sender`. The claim ledger is decremented before the external unlock, the hook never grants ERC-6909 approvals, and the delta accounting matches the vendored v4 `Hooks.beforeSwap`/`afterSwap` on all four swap modes. On Robinhood Chain the recipient is a plain EOA and the PoolManager holds about 24,000 ETH, so fees will be paid directly in production. The static-analysis leads were all false positives when traced, including aderyn's two \"high\" lines on the deployer's CREATE2 preimage.\n\n**Findings reported:**\n- **Low, fee basis asymmetry** at `src/ReedGuard.sol:183`. Exact-input swaps pay 1.00% of gross ETH and exact-output swaps pay 0.99%. A trader who submits exact-output orders pays one basis point less on volume, and the recipient receives less than the stated 1.0% on that flow. Measured with a scratch test; concrete amounts are in the file.\n- **Info, dynamic-fee flag accepted** at `beforeInitialize`. Such a pool has a permanent zero LP fee because the hook never sets one.\n- **Info, shared `tx.origin` cooldown.** One relayer or bundler origin blocks every user it serves for 30 seconds per pool. This is the agreed design, recorded as a trust assumption.\n\n**Not reached.** Nothing in my assigned area. The unbounded salt search gas and the exact-input price-limit revert are both behaviors the brief asks for, so I did not report them. No critical or high finding exists, so no proof test is attached. The probe test under `test/scratch/` is not part of the submission.","treeHash":null,"usage":{"cachedInputTokens":1832309,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":41392,"runtime":"claude","turns":34,"wallClockMs":824510}}],"verification":[{"checks":[{"durationMs":65485,"exitCode":0,"name":"build","output":"Compiling 80 files with Solc 0.8.26\nSolc 0.8.26 finished in 65.30s\nCompiler run successful!\n","passed":true},{"durationMs":3947,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 8 tests for test/ReedGuardClaims.t.sol:ReedGuardClaimsTest\n[PASS] test_claimBalancesAreIsolatedEvenForSameToken() (gas: 2298740)\n[PASS] test_emptyClaimDoesNotRequireUnlockOrChangeBalances() (gas: 168221)\n[PASS] test_exactOutputTokenBuyAlsoMintsOnFreshManager() (gas: 470577)\n[PASS] test_freshManagerBuyMintsETHClaimThenAnyoneRedeems() (gas: 648082)\n[PASS] test_laterFundedSwapPaysImmediatelyAndPreservesEarlierClaim() (gas: 584209)\n[PASS] test_nonzeroButInsufficientManagerETHAlsoDefers() (gas: 365713)\n[PASS] test_reentrantRecipientCannotReenterSwapsOrClaims() (gas: 1833190)\n[PASS] test_rejectingRecipientCannotBlockSwapsAndFailedClaimIsRetryable() (gas: 1524480)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 19.39ms (23.86ms CPU time)\n\nRan 12 tests for test/ReedGuardControls.t.sol:ReedGuardControlsTest\n[PASS] test_anyoneMayInitializeNativePoolAndTokenSupplyIsLive() (gas: 248241)\n[PASS] test_cooldownBoundaryAndBothSwapDirections() (gas: 559692)\n[PASS] test_cooldownIsByOriginAndPoolNotTokenOrRouter() (gas: 2015911)\n[PASS] test_erc20PairInitializationReverts() (gas: 58186)\n[PASS] test_everyImplementedCallbackRefusesNonManager() (gas: 151612)\n[PASS] test_liquidityCanAlsoBeAddedWhilePaused() (gas: 279589)\n[PASS] test_onlyRequiredPermissionsAndCorrectAddress() (gas: 14483)\n[PASS] test_ownerHasNoOtherAdministrativeFunctions() (gas: 205163)\n[PASS] test_pauseIsOwnerOnlyAndPoolSpecific() (gas: 958469)\n[PASS] test_pauseNeverBlocksWithdrawalOrLPFeeCollection() (gas: 585825)\n[PASS] test_unknownPoolCannotBeConfiguredOrClaimed() (gas: 138486)\n[PASS] test_unpausingDoesNotResetCooldown() (gas: 396947)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 57.51ms (11.36ms CPU time)\n\nRan 14 tests for test/ReedGuardSwaps.t.sol:ReedGuardSwapsTest\n[PASS] testFuzz_feesAndConservationAcrossAllFourModes(uint96,bool,bool) (runs: 256, μ: 445020, ~: 446529)\nLogs:\n  Bound result 243255\n\n[PASS] testFuzz_largeSpecifiedFeeDoesNotOverflowMultiplication(uint256,bool) (runs: 256, μ: 83195, ~: 81417)\nLogs:\n  Bound result 11479\n\n[PASS] test_buyExactInputETH() (gas: 442745)\n[PASS] test_buyExactOutputToken() (gas: 439504)\n[PASS] test_feeRoundsDownToWei() (gas: 402065)\n[PASS] test_int256MinimumRevertsCleanlyWithoutCooldown() (gas: 83269)\n[PASS] test_noLiquidityETHSpecifiedReverts() (gas: 564042)\n[PASS] test_partialBuyWithETHSpecifiedRevertsAndRollsBack() (gas: 441091)\n[PASS] test_partialBuyWithTokenSpecifiedChargesActualETH() (gas: 310334)\n[PASS] test_partialSellWithETHSpecifiedRevertsAndRollsBack() (gas: 462024)\n[PASS] test_partialSellWithTokenSpecifiedChargesActualETH() (gas: 312181)\n[PASS] test_sellExactInputToken() (gas: 440779)\n[PASS] test_sellExactOutputETH() (gas: 443449)\n[PASS] test_zeroSwapRevertsWithoutCooldownOrFee() (gas: 76514)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 57.57ms (63.02ms CPU time)\n\nRan 7 tests for test/ReedGuardDeployer.t.sol:ReedGuardDeployerTest\n[PASS] test_deployedRuntimesContainNoEscapeOpcodes() (gas: 1424256)\n[PASS] test_factoryCreatesApplicationAndHookAtomically() (gas: 2033195)\nLogs:\n  factory application creation gas (local address only): 1845952\n\n[PASS] test_launchConstructorWorksOnEmptyChainAndCreatesHook() (gas: 150031392)\n[PASS] test_neitherConstructorCallsAnExternalContract() (gas: 28625)\n[PASS] test_noDeploymentOrAdminFunctionAfterConstruction() (gas: 79849)\n[PASS] test_parametersArePassedUnchangedNotReplacedByCallerOrOrigin() (gas: 43334)\n[PASS] test_zeroConfigurationRejectedByHookConstructor() (gas: 4245)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 194.29ms (309.00ms CPU time)\n\nRan 1 test for test/ReedGuardInvariant.t.sol:ReedGuardInvariantTest\n[PASS]\nReedGuardInvariantTest invariants:\n[PASS] invariant_ETHAndBothTokensAreConserved\n[PASS] invariant_eachPoolsClaimsAndControlsRemainIsolated\n ReedGuardInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------------+---------------+-------+---------+----------╮\n| Contract         | Selector      | Calls | Reverts | Discards |\n+===============================================================+\n| InvariantHandler | advance       | 1637  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | claim         | 1636  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | pausePool     | 1643  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | rejectPayment | 1616  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | trade         | 1660  | 0       | 0        |\n╰------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8969\n  Bound result 43\n  Bound result 3728\n  Bound result 99999999999999909\n  Bound result 4\n  Bound result 53089941531846623\n  Bound result 8\n  Bound result 1523750434220126\n  Bound result 11553\n  Bound result 10722\n  Bound result 99999999999999218\n  Bound result 283484481935\n  Bound result 4\n  Bound result 64\n  Bound result 59\n  Bound result 30988\n  Bound result 59\n  Bound result 1000\n  Bound result 19\n  Bound result 1797\n  Bound result 60\n  Bound result 5070\n  Bound result 13882\n  Bound result 68\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.75s (3.73s CPU time)\n\nRan 5 test suites in 3.75s (4.08s CPU time): 42 tests passed, 0 failed, 0 skipped (42 total tests)\n","passed":true},{"durationMs":103,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"ReedGuard.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"ReedGuard.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"ReedGuard.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"ReedGuard.claimFees(bytes32)\",\"ReedGuard.pause(bytes32)\",\"ReedGuard.unlockCallback(bytes)\",\"ReedGuard.unpause(bytes32)\"],\"files\":{\".gitignore\":4,\"LICENSE\":23,\"README.md\":99,\"docs/DEPENDENCIES.md\":13,\"docs/SECURITY.md\":47,\"foundry.toml\":22,\"remappings.txt\":3,\"src/HookFlags.sol\":35,\"src/ReedGuard.sol\":248,\"src/ReedGuardDeployer.sol\":42,\"test/ReedGuardClaims.t.sol\":192,\"test/ReedGuardControls.t.sol\":235,\"test/ReedGuardDeployer.t.sol\":161,\"test/ReedGuardInvariant.t.sol\":95,\"test/ReedGuardSwaps.t.sol\":223,\"test/helpers/FeeRecipients.sol\":47,\"test/helpers/Fixture.sol\":132,\"test/helpers/InvariantHandler.sol\":135,\"test/helpers/TestRouter.sol\":90,\"test/helpers/TestToken.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":3896,"exitCode":0,"name":"slither","output":"[medium/medium] unused-return at src/ReedGuard.sol:195: ReedGuard.claimFees(PoolId) (src/ReedGuard.sol#195-210) ignores return value by poolManager.unlock(abi.encode(poolId,amount)) (src/ReedGuard.sol#208)\n[low/medium] reentrancy-benign at src/ReedGuard.sol:195: Reentrancy in ReedGuard.claimFees(PoolId) (src/ReedGuard.sol#195-210):\n[low/medium] reentrancy-benign at src/ReedGuard.sol:223: Reentrancy in ReedGuard._payOrDefer(PoolId,uint256) (src/ReedGuard.sol#223-234):\n[low/medium] reentrancy-events at src/ReedGuard.sol:212: Reentrancy in ReedGuard.unlockCallback(bytes) (src/ReedGuard.sol#212-221):\n[low/medium] timestamp at src/ReedGuard.sol:138: ReedGuard.beforeSwap(address,PoolKey,SwapParams,bytes) (src/ReedGuard.sol#138-161) uses timestamp for comparisons","passed":true},{"durationMs":581,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/ReedGuardDeployer.sol:19: `abi.encodePacked()` Hash Collision\n[high] incorrect-shift-order at src/ReedGuardDeployer.sol:29: Incorrect Assembly Shift Parameter Order\n[high] reentrancy-state-change at src/ReedGuard.sol:208: Reentrancy: State change after external call\n[low] centralization-risk at src/ReedGuard.sol:126: Centralization Risk (2 places)\n[low] internal-function-used-once at src/HookFlags.sol:28: Internal Function Used Only Once\n[low] large-numeric-literal at src/ReedGuard.sol:27: Large Numeric Literal\n[low] non-reentrant-not-first at src/ReedGuard.sol:169: `nonReentrant` is Not the First Modifier\n[low] state-change-without-event at src/ReedGuard.sol:195: State Change Without Event\n[low] unchecked-return at src/ReedGuard.sol:127: Unchecked Return (6 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"3068f7d3e794625f78d192f7a46d0e6f273ecc5a1b41cdde2ba2fba65426bebe","verifiedTreeHash":"1401ea722a29a050db40f0e18a1d7773295d6a26","verifierVersion":"0.1.0+560ab6a2"},{"checks":[{"durationMs":30084,"exitCode":0,"name":"build","output":"Compiling 80 files with Solc 0.8.26\nSolc 0.8.26 finished in 29.99s\nCompiler run successful!\n","passed":true},{"durationMs":2135,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 12 tests for test/ReedGuardControls.t.sol:ReedGuardControlsTest\n[PASS] test_anyoneMayInitializeNativePoolAndTokenSupplyIsLive() (gas: 248241)\n[PASS] test_cooldownBoundaryAndBothSwapDirections() (gas: 559692)\n[PASS] test_cooldownIsByOriginAndPoolNotTokenOrRouter() (gas: 2015911)\n[PASS] test_erc20PairInitializationReverts() (gas: 58186)\n[PASS] test_everyImplementedCallbackRefusesNonManager() (gas: 151612)\n[PASS] test_liquidityCanAlsoBeAddedWhilePaused() (gas: 279589)\n[PASS] test_onlyRequiredPermissionsAndCorrectAddress() (gas: 14483)\n[PASS] test_ownerHasNoOtherAdministrativeFunctions() (gas: 205163)\n[PASS] test_pauseIsOwnerOnlyAndPoolSpecific() (gas: 958469)\n[PASS] test_pauseNeverBlocksWithdrawalOrLPFeeCollection() (gas: 585825)\n[PASS] test_unknownPoolCannotBeConfiguredOrClaimed() (gas: 138486)\n[PASS] test_unpausingDoesNotResetCooldown() (gas: 396947)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 9.63ms (5.75ms CPU time)\n\nRan 8 tests for test/ReedGuardClaims.t.sol:ReedGuardClaimsTest\n[PASS] test_claimBalancesAreIsolatedEvenForSameToken() (gas: 2298740)\n[PASS] test_emptyClaimDoesNotRequireUnlockOrChangeBalances() (gas: 168221)\n[PASS] test_exactOutputTokenBuyAlsoMintsOnFreshManager() (gas: 470577)\n[PASS] test_freshManagerBuyMintsETHClaimThenAnyoneRedeems() (gas: 648082)\n[PASS] test_laterFundedSwapPaysImmediatelyAndPreservesEarlierClaim() (gas: 584209)\n[PASS] test_nonzeroButInsufficientManagerETHAlsoDefers() (gas: 365713)\n[PASS] test_reentrantRecipientCannotReenterSwapsOrClaims() (gas: 1833190)\n[PASS] test_rejectingRecipientCannotBlockSwapsAndFailedClaimIsRetryable() (gas: 1524480)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 10.73ms (12.36ms CPU time)\n\nRan 14 tests for test/ReedGuardSwaps.t.sol:ReedGuardSwapsTest\n[PASS] testFuzz_feesAndConservationAcrossAllFourModes(uint96,bool,bool) (runs: 256, μ: 445020, ~: 446529)\nLogs:\n  Bound result 18924\n\n[PASS] testFuzz_largeSpecifiedFeeDoesNotOverflowMultiplication(uint256,bool) (runs: 256, μ: 83195, ~: 81417)\nLogs:\n  Bound result 57896044618658097711785492504343953926634992332820282019728792003956564819964\n\n[PASS] test_buyExactInputETH() (gas: 442745)\n[PASS] test_buyExactOutputToken() (gas: 439504)\n[PASS] test_feeRoundsDownToWei() (gas: 402065)\n[PASS] test_int256MinimumRevertsCleanlyWithoutCooldown() (gas: 83269)\n[PASS] test_noLiquidityETHSpecifiedReverts() (gas: 564042)\n[PASS] test_partialBuyWithETHSpecifiedRevertsAndRollsBack() (gas: 441091)\n[PASS] test_partialBuyWithTokenSpecifiedChargesActualETH() (gas: 310334)\n[PASS] test_partialSellWithETHSpecifiedRevertsAndRollsBack() (gas: 462024)\n[PASS] test_partialSellWithTokenSpecifiedChargesActualETH() (gas: 312181)\n[PASS] test_sellExactInputToken() (gas: 440779)\n[PASS] test_sellExactOutputETH() (gas: 443449)\n[PASS] test_zeroSwapRevertsWithoutCooldownOrFee() (gas: 76514)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 37.69ms (44.36ms CPU time)\n\nRan 7 tests for test/ReedGuardDeployer.t.sol:ReedGuardDeployerTest\n[PASS] test_deployedRuntimesContainNoEscapeOpcodes() (gas: 1424256)\n[PASS] test_factoryCreatesApplicationAndHookAtomically() (gas: 2033195)\nLogs:\n  factory application creation gas (local address only): 1845952\n\n[PASS] test_launchConstructorWorksOnEmptyChainAndCreatesHook() (gas: 150031392)\n[PASS] test_neitherConstructorCallsAnExternalContract() (gas: 28625)\n[PASS] test_noDeploymentOrAdminFunctionAfterConstruction() (gas: 79849)\n[PASS] test_parametersArePassedUnchangedNotReplacedByCallerOrOrigin() (gas: 43334)\n[PASS] test_zeroConfigurationRejectedByHookConstructor() (gas: 4245)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 107.05ms (178.67ms CPU time)\n\nRan 1 test for test/ReedGuardInvariant.t.sol:ReedGuardInvariantTest\n[PASS]\nReedGuardInvariantTest invariants:\n[PASS] invariant_ETHAndBothTokensAreConserved\n[PASS] invariant_eachPoolsClaimsAndControlsRemainIsolated\n ReedGuardInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------------+---------------+-------+---------+----------╮\n| Contract         | Selector      | Calls | Reverts | Discards |\n+===============================================================+\n| InvariantHandler | advance       | 1637  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | claim         | 1636  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | pausePool     | 1643  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | rejectPayment | 1616  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | trade         | 1660  | 0       | 0        |\n╰------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8969\n  Bound result 43\n  Bound result 3728\n  Bound result 99999999999999909\n  Bound result 4\n  Bound result 53089941531846623\n  Bound result 8\n  Bound result 1523750434220126\n  Bound result 11553\n  Bound result 10722\n  Bound result 99999999999999218\n  Bound result 283484481935\n  Bound result 4\n  Bound result 64\n  Bound result 59\n  Bound result 30988\n  Bound result 59\n  Bound result 1000\n  Bound result 19\n  Bound result 1797\n  Bound result 60\n  Bound result 5070\n  Bound result 13882\n  Bound result 68\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.04s (2.03s CPU time)\n\nRan 5 test suites in 2.04s (2.20s CPU time): 42 tests passed, 0 failed, 0 skipped (42 total tests)\n","passed":true},{"durationMs":63,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"ReedGuard.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"ReedGuard.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"ReedGuard.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"ReedGuard.claimFees(bytes32)\",\"ReedGuard.pause(bytes32)\",\"ReedGuard.unlockCallback(bytes)\",\"ReedGuard.unpause(bytes32)\"],\"files\":{\".gitignore\":4,\"LICENSE\":23,\"README.md\":99,\"docs/DEPENDENCIES.md\":13,\"docs/SECURITY.md\":47,\"foundry.toml\":22,\"launch.json\":14,\"remappings.txt\":3,\"src/HookFlags.sol\":35,\"src/ReedGuard.sol\":248,\"src/ReedGuardDeployer.sol\":42,\"test/ReedGuardClaims.t.sol\":192,\"test/ReedGuardControls.t.sol\":235,\"test/ReedGuardDeployer.t.sol\":161,\"test/ReedGuardInvariant.t.sol\":95,\"test/ReedGuardSwaps.t.sol\":223,\"test/helpers/FeeRecipients.sol\":47,\"test/helpers/Fixture.sol\":132,\"test/helpers/InvariantHandler.sol\":135,\"test/helpers/TestRouter.sol\":90,\"test/helpers/TestToken.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"77cf852e136ff57ebb91fcc86c5b547b582c966772bcfa6b93eee49284192acf","verifiedTreeHash":"7589fd47d4aab458ec635ea21a55c81d26edcace","verifierVersion":"0.1.0+560ab6a2"},{"checks":[{"durationMs":43139,"exitCode":0,"name":"build","output":"Compiling 86 files with Solc 0.8.26\nSolc 0.8.26 finished in 43.06s\nCompiler run successful!\n","passed":true},{"durationMs":7941,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 12 tests for test/ReedGuardControls.t.sol:ReedGuardControlsTest\n[PASS] test_anyoneMayInitializeNativePoolAndTokenSupplyIsLive() (gas: 248241)\n[PASS] test_cooldownBoundaryAndBothSwapDirections() (gas: 559692)\n[PASS] test_cooldownIsByOriginAndPoolNotTokenOrRouter() (gas: 2015911)\n[PASS] test_erc20PairInitializationReverts() (gas: 58186)\n[PASS] test_everyImplementedCallbackRefusesNonManager() (gas: 151612)\n[PASS] test_liquidityCanAlsoBeAddedWhilePaused() (gas: 279589)\n[PASS] test_onlyRequiredPermissionsAndCorrectAddress() (gas: 14483)\n[PASS] test_ownerHasNoOtherAdministrativeFunctions() (gas: 205163)\n[PASS] test_pauseIsOwnerOnlyAndPoolSpecific() (gas: 958469)\n[PASS] test_pauseNeverBlocksWithdrawalOrLPFeeCollection() (gas: 585825)\n[PASS] test_unknownPoolCannotBeConfiguredOrClaimed() (gas: 138486)\n[PASS] test_unpausingDoesNotResetCooldown() (gas: 396947)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 104.60ms (6.69ms CPU time)\n\nRan 7 tests for test/ReedGuardDeployer.t.sol:ReedGuardDeployerTest\n[PASS] test_deployedRuntimesContainNoEscapeOpcodes() (gas: 1424256)\n[PASS] test_factoryCreatesApplicationAndHookAtomically() (gas: 2033195)\nLogs:\n  factory application creation gas (local address only): 1845952\n\n[PASS] test_launchConstructorWorksOnEmptyChainAndCreatesHook() (gas: 150031392)\n[PASS] test_neitherConstructorCallsAnExternalContract() (gas: 28625)\n[PASS] test_noDeploymentOrAdminFunctionAfterConstruction() (gas: 79849)\n[PASS] test_parametersArePassedUnchangedNotReplacedByCallerOrOrigin() (gas: 43334)\n[PASS] test_zeroConfigurationRejectedByHookConstructor() (gas: 4245)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 104.98ms (164.99ms CPU time)\n\nRan 8 tests for test/ReedGuardClaims.t.sol:ReedGuardClaimsTest\n[PASS] test_claimBalancesAreIsolatedEvenForSameToken() (gas: 2298740)\n[PASS] test_emptyClaimDoesNotRequireUnlockOrChangeBalances() (gas: 168221)\n[PASS] test_exactOutputTokenBuyAlsoMintsOnFreshManager() (gas: 470577)\n[PASS] test_freshManagerBuyMintsETHClaimThenAnyoneRedeems() (gas: 648082)\n[PASS] test_laterFundedSwapPaysImmediatelyAndPreservesEarlierClaim() (gas: 584209)\n[PASS] test_nonzeroButInsufficientManagerETHAlsoDefers() (gas: 365713)\n[PASS] test_reentrantRecipientCannotReenterSwapsOrClaims() (gas: 1833190)\n[PASS] test_rejectingRecipientCannotBlockSwapsAndFailedClaimIsRetryable() (gas: 1524480)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 107.93ms (15.11ms CPU time)\n\nRan 14 tests for test/ReedGuardSwaps.t.sol:ReedGuardSwapsTest\n[PASS] testFuzz_feesAndConservationAcrossAllFourModes(uint96,bool,bool) (runs: 256, μ: 445020, ~: 446529)\nLogs:\n  Bound result 130429\n\n[PASS] testFuzz_largeSpecifiedFeeDoesNotOverflowMultiplication(uint256,bool) (runs: 256, μ: 83169, ~: 81417)\nLogs:\n  Bound result 965\n\n[PASS] test_buyExactInputETH() (gas: 442745)\n[PASS] test_buyExactOutputToken() (gas: 439504)\n[PASS] test_feeRoundsDownToWei() (gas: 402065)\n[PASS] test_int256MinimumRevertsCleanlyWithoutCooldown() (gas: 83269)\n[PASS] test_noLiquidityETHSpecifiedReverts() (gas: 564042)\n[PASS] test_partialBuyWithETHSpecifiedRevertsAndRollsBack() (gas: 441091)\n[PASS] test_partialBuyWithTokenSpecifiedChargesActualETH() (gas: 310334)\n[PASS] test_partialSellWithETHSpecifiedRevertsAndRollsBack() (gas: 462024)\n[PASS] test_partialSellWithTokenSpecifiedChargesActualETH() (gas: 312181)\n[PASS] test_sellExactInputToken() (gas: 440779)\n[PASS] test_sellExactOutputETH() (gas: 443449)\n[PASS] test_zeroSwapRevertsWithoutCooldownOrFee() (gas: 76514)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 107.99ms (121.50ms CPU time)\n\nRan 12 tests for test/ReedGuardBoundaries.t.sol:ReedGuardBoundariesTest\n[PASS] testFuzz_feeCastAtSigned128BitBoundary(uint8,bool) (runs: 1000, μ: 101069, ~: 101239)\n[PASS] testFuzz_redemptionRespectsAvailableCashAndRetainsRemainder(uint96,uint96) (runs: 1000, μ: 611067, ~: 613891)\nLogs:\n  Bound result 2850\n  Bound result 22\n\n[PASS] testFuzz_supplyReadsRemainLiveAcrossMintAndBurn(uint256) (runs: 1000, μ: 1000668, ~: 1001286)\n[PASS] test_donationsWhilePausedAreUntaxedAndDoNotAlterCooldownOrClaims() (gas: 801227)\n[PASS] test_duplicateInitializationCannotResetPauseCooldownOrClaims() (gas: 453794)\n[PASS] test_feeRoundingAtOneWeiAndEachSideOfWholeFeeBoundaries() (gas: 1326197)\n[PASS] test_invalidPriceCannotLeavePhantomPoolRegistered() (gas: 266204)\n[PASS] test_maximumRepresentableBeforeSwapFeeAndFirstOverflow() (gas: 184296)\n[PASS] test_maximumTokenSupplyCanBeReadThenBurnedToZero() (gas: 1001820)\n[PASS] test_supplyReadFailureDoesNotBecomeATradingOrLiquidityDependency() (gas: 1098190)\n[PASS] test_unsolicitedClaimsCannotIncreaseAnyPoolsEntitlement() (gas: 658055)\n[PASS] test_zeroTokenSupplyIsEligibleAndReadWithoutInventedMinimum() (gas: 962135)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 109.60ms (303.12ms CPU time)\n\nRan 9 tests for test/ReedGuardTransactions.t.sol:ReedGuardTransactionsTest\n[PASS] testFuzz_batchPaymentTimingAndPoolIsolation(uint96,uint96,bool) (runs: 1000, μ: 915734, ~: 906978)\nLogs:\n  Bound result 2990000000000025568\n  Bound result 70606960849542726\n\n[PASS] test_batchDefersBothPoolsBeforeRouterSettlesETH() (gas: 918267)\n[PASS] test_batchWithSettlementBetweenSwapsPaysSecondFeeDirectly() (gas: 898451)\n[PASS] test_claimDuringExistingUnlockFailsAtomicallyAndCanBeRetried() (gas: 701279)\n[PASS] test_repeatedPoolInOneTransactionRevertsEntireBatch() (gas: 746000)\n[PASS] test_secondPoolFailureRollsBackFirstPoolsClaimsAndPrice() (gas: 539529)\n[PASS] test_twoPoolsWithDifferentTokensShareOnlyETHSettlement() (gas: 636039)\n[PASS] test_unsettledSwapCannotLeaveMintedFeesOrCooldownBehind() (gas: 1503892)\n[PASS] test_unsettledSwapRollsBackFeeAlreadySentToRecipient() (gas: 1127210)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 109.56ms (114.53ms CPU time)\n\nRan 1 test for test/ReedGuardInvariant.t.sol:ReedGuardInvariantTest\n[PASS]\nReedGuardInvariantTest invariants:\n[PASS] invariant_ETHAndBothTokensAreConserved\n[PASS] invariant_eachPoolsClaimsAndControlsRemainIsolated\n ReedGuardInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------------+---------------+-------+---------+----------╮\n| Contract         | Selector      | Calls | Reverts | Discards |\n+===============================================================+\n| InvariantHandler | advance       | 1637  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | claim         | 1636  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | pausePool     | 1643  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | rejectPayment | 1616  | 0       | 0        |\n|------------------+---------------+-------+---------+----------|\n| InvariantHandler | trade         | 1660  | 0       | 0        |\n╰------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8969\n  Bound result 43\n  Bound result 3771\n  Bound result 99999999999999909\n  Bound result 0\n  Bound result 8301\n  Bound result 90\n  Bound result 166878278704\n  Bound result 11563\n  Bound result 10709\n  Bound result 3227\n  Bound result 283484481935\n  Bound result 0\n  Bound result 9\n  Bound result 24\n  Bound result 2594636414\n  Bound result 11\n  Bound result 1881\n  Bound result 9\n  Bound result 2148\n  Bound result 4\n  Bound result 4983\n  Bound result 1126409558\n  Bound result 68\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.92s (1.90s CPU time)\n\nRan 1 test for test/ReedGuardLiquidityInvariant.t.sol:ReedGuardLiquidityInvariantTest\n[PASS]\nReedGuardLiquidityInvariantTest invariants:\n[PASS] invariant_liquidityAndTradingConserveETHAndBothTokens\n[PASS] invariant_poolLiabilitiesAreBackedWithoutCreditingDonatedClaims\n ReedGuardLiquidityInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+---------------------+-------+---------+----------╮\n| Contract         | Selector            | Calls | Reverts | Discards |\n+=====================================================================+\n| LiquidityHandler | addLiquidity        | 3049  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| LiquidityHandler | advance             | 2922  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| LiquidityHandler | claim               | 3076  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| LiquidityHandler | donateClaims        | 3102  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| LiquidityHandler | pausePool           | 3110  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| LiquidityHandler | removeLiquidity     | 3112  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| LiquidityHandler | trade               | 3097  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| LiquidityHandler | unauthorizedControl | 3108  | 0       | 0        |\n╰------------------+---------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10000000000000000\n  Bound result 10000000000000000\n  Bound result 10000000000000000000000\n  Bound result 1\n  Bound result 3451\n  Bound result 30\n  Bound result 233\n  Bound result 134010803906418617\n  Bound result 7651\n  Bound result 3950\n  Bound result 41\n  Bound result 71844861519894164\n  Bound result 31\n  Bound result 2886\n  Bound result 383779999\n  Bound result 9192\n  Bound result 27\n  Bound result 6731\n  Bound result 6724194435074992\n  Bound result 8844\n  Bound result 3384\n  Bound result 11418\n  Bound result 55787325955778\n  Bound result 807\n  Bound result 2115\n  Bound result 9952\n  Bound result 9944\n  Bound result 76451220580677978\n  Bound result 10108\n  Bound result 42\n  Bound result 431\n  Bound result 2551\n  Bound result 31\n  Bound result 9353\n  Bound result 39\n  Bound result 7194\n  Bound result 10000000000000000000000\n  Bound result 37\n  Bound result 649889\n  Bound result 6\n  Bound result 8925\n  Bound result 10266\n  Bound result 27\n  Bound result 4041\n  Bound result 9600\n  Bound result 62981515346206052\n  Bound result 15512\n  Bound result 8210\n  Bound result 6943\n  Bound result 7424\n  Bound result 3483\n  Bound result 18\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.85s (7.83s CPU time)\n\nRan 8 test suites in 7.85s (10.41s CPU time): 64 tests passed, 0 failed, 0 skipped (64 total tests)\n","passed":true},{"durationMs":45,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"ReedGuard.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"ReedGuard.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"ReedGuard.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"ReedGuard.claimFees(bytes32)\",\"ReedGuard.pause(bytes32)\",\"ReedGuard.unlockCallback(bytes)\",\"ReedGuard.unpause(bytes32)\"],\"files\":{\".gitignore\":4,\"LICENSE\":23,\"README.md\":99,\"docs/DEPENDENCIES.md\":13,\"docs/SECURITY.md\":47,\"foundry.toml\":22,\"remappings.txt\":3,\"src/HookFlags.sol\":35,\"src/ReedGuard.sol\":248,\"src/ReedGuardDeployer.sol\":42,\"test/README.md\":33,\"test/ReedGuardBoundaries.t.sol\":226,\"test/ReedGuardClaims.t.sol\":192,\"test/ReedGuardControls.t.sol\":235,\"test/ReedGuardDeployer.t.sol\":161,\"test/ReedGuardInvariant.t.sol\":95,\"test/ReedGuardLiquidityInvariant.t.sol\":130,\"test/ReedGuardSwaps.t.sol\":223,\"test/ReedGuardTransactions.t.sol\":201,\"test/helpers/BatchFixture.sol\":63,\"test/helpers/BatchProbe.sol\":149,\"test/helpers/FeeRecipients.sol\":47,\"test/helpers/Fixture.sol\":132,\"test/helpers/InvariantHandler.sol\":135,\"test/helpers/LiquidityHandler.sol\":215,\"test/helpers/TestRouter.sol\":90,\"test/helpers/TestToken.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"9e8a1a9fae723f8aa2b68f1c5886150822a32880e59af7d9359d0ae7ee045749","verifiedTreeHash":"3e915ff49f3652dcc27b7f0c977d5e28986059f9","verifierVersion":"0.1.0+560ab6a2"}]}