{"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":"cb5d1c79-a800-4ec6-b017-6421a429669e","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"2441a75a0d480fc509874f95410de0d136a7e8e14eef6325fc116b8ea0c2c66f","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"c26edc76dc7a76e09a42c3634054429c1679c6e247747d647a03f77e5b332d7e","skillId":"adversarial-review","tools":[]},"key":"adversarial_review","kind":"code","role":"review","skillHash":"c26edc76dc7a76e09a42c3634054429c1679c6e247747d647a03f77e5b332d7e","skillId":"adversarial-review","state":"accepted"},{"acceptedSubmissionHash":"7fa17b8ea9f9bd2947eef7fb6bb52c51b25117f7ca372ed1f9a083cd718172dc","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"fb6887b34514bcb194265fa403f0195c6a83eaef269da1e6189e1e9c4b372a7d","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"fb6887b34514bcb194265fa403f0195c6a83eaef269da1e6189e1e9c4b372a7d","skillId":"build-contract-project","state":"accepted"}],"objective":"Build CooldownHook, a simple, creative Uniswap v4 hook: a hook that lets each address swap at most once per pool every N blocks (N fixed at construction, between 1 and 1000): beforeSwap records the caller's last swap block per PoolId and reverts a second swap inside the window. The swap router's sender is what the PoolManager reports, so document the router assumption. Tests cover the boundary block and two pools being independent. Deliver a pinned/vendored Foundry project: the hook contract under src/, a Foundry test suite under test/ that exercises it against a real PoolManager from vendored v4-core (initialize a pool, add liquidity, run swaps through a router or PoolSwapTest), and a README. Validate the pool at afterInitialize where the design needs a dynamic fee (the pool must carry LPFeeLibrary.DYNAMIC_FEE_FLAG) and revert otherwise. Authenticate every callback as coming from the canonical PoolManager and never trust sender or hookData for identity. Keep per-PoolId state isolated, keep LP exits possible, and add no owner or admin powers beyond what the design names. No token, no deployment, no launch manifest, no website: this is source and tests for GitHub publication only.","parentJobId":null,"planHash":"f1fbd9dba9d3396901da08ea9f747e0918845767a7e4f4e8718ce030dbb0968a","previousHash":"4a15e9925da42dce7e0946dc6ec221f2e0d13de12f78f8e8ea7e9cc28f3a72b0","projectId":"cb5d1c79-a800-4ec6-b017-6421a429669e","publication":{"commit":"a47a71f6802f34e7a7d4481ee9b90cd16f7dbd98","deliveredAt":"2026-09-21T04:27:09.261Z","repoUrl":"https://github.com/Identity-md/launch-65-build-cooldownhook-simple-creative"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"39d2e05efb337725989a0e7bedce6f21cfc99763b5848f1d8c837d47297c50fb","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3f6a9bdd601cb99f","findings":[],"hash":"2441a75a0d480fc509874f95410de0d136a7e8e14eef6325fc116b8ea0c2c66f","nodeId":"b656fc30-af68-4e7b-966d-f4849c01f444","outcome":"completed","summary":"Created `.imd-findings.json` with no findings:\n\n```json\n{\"findings\":[]}\n```\n\nThe prior high finding is fixed: the hook now advertises `afterInitialize`, mines for flags `0x1080`, authenticates the callback, and rejects non-dynamic fees via `LPFeeLibrary.isDynamicFee`.\n\nVerification run: `forge test` passed, 36/36 tests.","treeHash":null,"usage":{"cachedInputTokens":216704,"inputTokens":39078,"model":null,"outputTokens":2369,"runtime":"codex","turns":6,"wallClockMs":61122}},{"artifacts":[],"attempt":1,"bundleHash":"221947aee813f0c33129648c8b27d9db5e262f426b2c4d1d0783189d555a6fed","device":"0256823ae36e7900","findings":[],"hash":"7fa17b8ea9f9bd2947eef7fb6bb52c51b25117f7ca372ed1f9a083cd718172dc","nodeId":"33368403-51a7-4b73-bafa-c4b659fafc21","outcome":"completed","summary":"Implemented and verified the revision.\n\n- Added authenticated `afterInitialize`.\n- Static-fee pools now revert with `DynamicFeeRequired`.\n- Hook flags updated to `0x1080` (`afterInitialize + beforeSwap`).\n- Converted lifecycle tests to dynamic-fee pools.\n- Added initialization success/failure coverage.\n- Updated README deployment and operational documentation.\n- Recorded the fixed verdict in `.imd-responses.json`.\n\nValidation passed:\n\n- `forge build`\n- `forge test` — 36 passed\n- `forge fmt --check`\n- `git diff --check`","treeHash":"b909fd56c2cdbf8f28b83ab151bf7e95e1ffd3c6","usage":{"cachedInputTokens":694912,"inputTokens":49711,"model":null,"outputTokens":5821,"runtime":"codex","turns":4,"wallClockMs":147576}},{"artifacts":[],"attempt":1,"bundleHash":"4d2186ccc248c576e59bfe333b8320576de758a4123f3f5fee31a52d0207c1a2","device":"98b4506bef931d13","findings":[],"hash":"c419f7dfdfc0474f86824e58e356e596900d4442867b23598c79c89f67267692","nodeId":"33368403-51a7-4b73-bafa-c4b659fafc21","outcome":"completed","summary":"Done. `CooldownHook` is implemented, tested, documented, and committed (`934ebf1`) with all dependencies vendored as plain files.\n\n## What was delivered\n\n**`src/CooldownHook.sol`** — a `beforeSwap`-only hook. If `sender` last swapped in pool P at block B, swaps in `[B, B+N)` revert with `SwapCooldownActive(poolId, sender, last, nextAllowed)`; block `B+N` is accepted and restarts the window. State is `mapping(PoolId => mapping(address => uint256))`, so pools are isolated. `N ∈ [1, 1000]` is an immutable checked in the constructor, along with a non-zero manager and `Hooks.validateHookPermissions`. Every callback checks `msg.sender == poolManager`; the nine undeclared callbacks revert for everyone. `hookData` is ignored. No owner, no setters, no delegatecall, no external calls, returns `ZERO_DELTA` and no fee override.\n\n**`src/HookFlags.sol`** — the 14 flag constants plus `flagsOf`/`matches`, defined in terms of v4-core's `Hooks` constants so they can't drift. Required by the protected suite.\n\n**`test/CooldownHook.t.sol`** — 35 tests against a real `PoolManager`: mined CREATE2 deployment, two pools + two `PoolSwapTest` routers, boundary walk over every block in the window, fuzz over `N ∈ [1,1000] × elapsed ∈ [0,2N]` with a fresh hook per run (also passed at 1500 runs), pool/sender isolation, shared-router semantics, `hookData` spoofing, LP add/remove and full exit mid-cooldown, dynamic-fee pool compatibility, and all-callback authentication. Three mutations (off-by-one, no auth, state not keyed by pool) each fail multiple tests.\n\n**`README.md`** — the rule, the router assumption and its consequences (shared router = one swapper; not anti-Sybil), security posture, deployment parameters (flags `0x80`/128, mining, `bytecode_hash = \"none\"`), operational responsibilities, and the admission-suite env vars.\n\n## Verification\n- `forge build`, `forge test` (35/35), `forge fmt --check` all pass from a clean `out/`/`cache/`.\n- The protected `Hook.protected.t.sol` was run against the hook's creation code with `IMD_HOOK_FLAGS=128`: 3/3 pass; the token suite skips as designed. The copies were removed afterwards since they can't run without env vars.\n\n## Two decisions worth knowing\n1. **No dynamic-fee requirement / no `afterInitialize`.** The task says to validate at `afterInitialize` *where the design needs a dynamic fee*; this design doesn't, and the protected suite's own pool key uses a static 3000 fee. The hook works on both pool kinds (tested) and declares only `beforeSwap`.\n2. **Identity = PoolManager's `sender` (the router).** That is the only attested identity available, so it's what's rate-limited; the README is explicit that users behind a shared router share one window and that a per-user window needs a per-user `sender`.\n\nOne vendoring note: `v4-core/src/test/ProxyPoolManager.sol` (a delegatecall test proxy, the only file importing OpenZeppelin) was dropped rather than pulling in OZ; everything else under v4-core `src/` is byte-for-byte v4.0.0. Recorded in `lib/VENDOR.md`.","treeHash":"1bdddf7e2b9694511333d7ff631f206c00291dee","usage":{"cachedInputTokens":4161758,"inputTokens":92,"model":"claude-opus-5","outputTokens":61520,"runtime":"claude","turns":46,"wallClockMs":1038828}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0256823ae36e7900","findings":[{"description":"The hook declares `afterInitialize: false`, and its `afterInitialize` implementation always reverts as unimplemented, so PoolManager never gives the hook an opportunity to enforce the required `LPFeeLibrary.DYNAMIC_FEE_FLAG`. Consequently any static-fee PoolKey can be initialized with this hook, permanently creating a pool that violates the required pool invariant. The committed tests encode the opposite behavior (`test_initialize_doesNotInvolveTheHook`) and initialize the main fixtures with fee 3000, so they affirm rather than detect the defect. The hook must advertise an authenticated afterInitialize callback and reject keys whose fee lacks DYNAMIC_FEE_FLAG; the mined address/declared flags and tests must include that callback.","line":91,"path":"src/CooldownHook.sol","reproduction":"Deploy the hook at its currently required beforeSwap-only flagged address, then construct `PoolKey({currency0: token0, currency1: token1, fee: 3000, tickSpacing: 60, hooks: IHooks(hook)})` and call `PoolManager.initialize(key, 2**96)`. Expected: initialization reverts because `3000 & LPFeeLibrary.DYNAMIC_FEE_FLAG == 0`. Actual: initialization succeeds because `afterInitialize` is not advertised or invoked; this exact state is exercised successfully by `setUp()` at test/CooldownHook.t.sol:80-81 and again by `test_initialize_doesNotInvolveTheHook`.","severity":"high","title":"Static-fee pools are accepted instead of being rejected during initialization"}],"hash":"f81cc9be675d5836252f005897425545c5672df9491a58d4bbb138e133a85ddc","nodeId":"b656fc30-af68-4e7b-966d-f4849c01f444","outcome":"completed","summary":"Review complete. Wrote one high-severity, concretely reproducible finding to [.imd-findings.json](/home/imd-worker/.identitymd/work/cb5d1c79-a800-4ec6-b017-6421a429669e/b656fc30-af68-4e7b-966d-f4849c01f444/.imd-findings.json). No other files were changed.","treeHash":null,"usage":{"cachedInputTokens":164864,"inputTokens":30756,"model":null,"outputTokens":1956,"runtime":"codex","turns":4,"wallClockMs":57919}}],"verification":[{"checks":[{"durationMs":2270,"exitCode":0,"name":"build","output":"Compiling 77 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.16s\nCompiler run successful!\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:180:35\n    │\n180 │         assertEq(delta.amount0(), int128(SWAP_AMOUNT));\n    │                                   ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n    ╭▸ test/CooldownHook.t.sol:378:9\n    │\n378 │         token0.transfer(alice, 10 ether);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n    ╭▸ test/CooldownHook.t.sol:379:9\n    │\n379 │         token0.transfer(bob, 10 ether);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:431:29\n    │\n431 │         assertEq(liquidity, uint128(uint256(LIQUIDITY)));\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:431:37\n    │\n431 │         assertEq(liquidity, uint128(uint256(LIQUIDITY)));\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:541:22\n    │\n541 │             assertEq(bytes4(ret), CooldownHook.HookNotImplemented.selector);\n    │                      ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes4' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\n","passed":true},{"durationMs":1179,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 36 tests for test/CooldownHook.t.sol:CooldownHookTest\n[PASS] testFuzz_constructor_rejectsCooldownOutsideRange(uint256) (runs: 256, μ: 39801, ~: 39802)\n[PASS] testFuzz_swap_boundaryHoldsForAnyCooldown(uint256,uint256) (runs: 64, μ: 20289523, ~: 6239033)\n[PASS] test_afterInitialize_acceptsDynamicFeeFromPoolManager() (gas: 16240)\n[PASS] test_allCallbacks_refuseCallersOtherThanThePoolManager() (gas: 33556)\n[PASS] test_beforeSwap_acceptsThePoolManager() (gas: 51813)\n[PASS] test_beforeSwap_refusesCallersOtherThanThePoolManager() (gas: 28105)\n[PASS] test_constructor_acceptsBothBounds() (gas: 6980023)\n[PASS] test_constructor_identicalParametersYieldASecondInstance() (gas: 85701342)\n[PASS] test_constructor_rejectsAddressWithoutTheRightFlags() (gas: 41601)\n[PASS] test_constructor_rejectsCooldownAboveMax() (gas: 39313)\n[PASS] test_constructor_rejectsZeroCooldown() (gas: 39322)\n[PASS] test_constructor_rejectsZeroPoolManager() (gas: 36766)\n[PASS] test_constructor_storesParameters() (gas: 9985)\n[PASS] test_donate_isUnaffected() (gas: 236344)\n[PASS] test_dynamicFeePool_isAcceptedAndRateLimited() (gas: 407891)\n[PASS] test_hookData_isIgnoredForIdentity() (gas: 200338)\n[PASS] test_initialize_rejectsStaticFeePool() (gas: 50379)\n[PASS] test_liquidity_canBeAddedAndRemovedWhileACooldownIsActive() (gas: 305329)\n[PASS] test_liquidity_fullExitIsAlwaysPossible() (gas: 222548)\n[PASS] test_permissions_addressCarriesExactlyDeclaredCallbacks() (gas: 2679)\n[PASS] test_permissions_declareAfterInitializeAndBeforeSwap() (gas: 9001)\n[PASS] test_pools_areIndependent() (gas: 312157)\n[PASS] test_pools_samePairDifferentSpacingAreIndependent() (gas: 506569)\n[PASS] test_pools_swapInOneDoesNotStartACooldownInTheOther() (gas: 289110)\n[PASS] test_senders_areIndependent() (gas: 280264)\n[PASS] test_senders_usersOfASharedRouterShareOneCooldown() (gas: 300638)\n[PASS] test_swap_allowedExactlyAtTheBoundaryBlock() (gas: 209746)\n[PASS] test_swap_allowedWellAfterTheBoundary() (gas: 206628)\n[PASS] test_swap_blockedOneBlockBeforeTheBoundary() (gas: 170884)\n[PASS] test_swap_everyBlockInsideTheWindowReverts() (gas: 484985)\n[PASS] test_swap_firstSwapSucceedsAndRecordsBlock() (gas: 156586)\n[PASS] test_swap_oppositeDirectionIsStillASwap() (gas: 167918)\n[PASS] test_swap_rejectedSwapDoesNotMoveThePool() (gas: 182554)\n[PASS] test_swap_secondSwapInTheSameBlockReverts() (gas: 167885)\n[PASS] test_swap_windowRestartsFromTheLatestSwap() (gas: 290863)\n[PASS] test_undeclaredCallbacks_refuseEvenThePoolManager() (gas: 38794)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 1.07s (1.15s CPU time)\n\nRan 1 test suite in 1.07s (1.07s CPU time): 36 tests passed, 0 failed, 0 skipped (36 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"7fa17b8ea9f9bd2947eef7fb6bb52c51b25117f7ca372ed1f9a083cd718172dc","verifiedTreeHash":"b909fd56c2cdbf8f28b83ab151bf7e95e1ffd3c6","verifierVersion":"0.1.0+eab70f1b"},{"checks":[{"durationMs":2368,"exitCode":0,"name":"build","output":"Compiling 77 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.26s\nCompiler run successful!\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:180:35\n    │\n180 │         assertEq(delta.amount0(), int128(SWAP_AMOUNT));\n    │                                   ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n    ╭▸ test/CooldownHook.t.sol:378:9\n    │\n378 │         token0.transfer(alice, 10 ether);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n    ╭▸ test/CooldownHook.t.sol:379:9\n    │\n379 │         token0.transfer(bob, 10 ether);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:431:29\n    │\n431 │         assertEq(liquidity, uint128(uint256(LIQUIDITY)));\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:431:37\n    │\n431 │         assertEq(liquidity, uint128(uint256(LIQUIDITY)));\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/CooldownHook.t.sol:530:22\n    │\n530 │             assertEq(bytes4(ret), CooldownHook.HookNotImplemented.selector);\n    │                      ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes4' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\n","passed":true},{"durationMs":1098,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 35 tests for test/CooldownHook.t.sol:CooldownHookTest\n[PASS] testFuzz_constructor_rejectsCooldownOutsideRange(uint256) (runs: 256, μ: 39719, ~: 39720)\n[PASS] testFuzz_swap_boundaryHoldsForAnyCooldown(uint256,uint256) (runs: 64, μ: 22425186, ~: 7980137)\n[PASS] test_allCallbacks_refuseCallersOtherThanThePoolManager() (gas: 33507)\n[PASS] test_beforeSwap_acceptsThePoolManager() (gas: 51742)\n[PASS] test_beforeSwap_refusesCallersOtherThanThePoolManager() (gas: 28035)\n[PASS] test_constructor_acceptsBothBounds() (gas: 18975461)\n[PASS] test_constructor_identicalParametersYieldASecondInstance() (gas: 7131833)\n[PASS] test_constructor_rejectsAddressWithoutTheRightFlags() (gas: 41510)\n[PASS] test_constructor_rejectsCooldownAboveMax() (gas: 39231)\n[PASS] test_constructor_rejectsZeroCooldown() (gas: 39218)\n[PASS] test_constructor_rejectsZeroPoolManager() (gas: 36701)\n[PASS] test_constructor_storesParameters() (gas: 9963)\n[PASS] test_donate_isUnaffected() (gas: 236349)\n[PASS] test_dynamicFeePool_isAcceptedAndRateLimited() (gas: 406176)\n[PASS] test_hookData_isIgnoredForIdentity() (gas: 220219)\n[PASS] test_initialize_doesNotInvolveTheHook() (gas: 45069)\n[PASS] test_liquidity_canBeAddedAndRemovedWhileACooldownIsActive() (gas: 345134)\n[PASS] test_liquidity_fullExitIsAlwaysPossible() (gas: 262309)\n[PASS] test_permissions_addressCarriesExactlyBeforeSwap() (gas: 2679)\n[PASS] test_permissions_declareOnlyBeforeSwap() (gas: 8995)\n[PASS] test_pools_areIndependent() (gas: 351899)\n[PASS] test_pools_samePairDifferentSpacingAreIndependent() (gas: 544681)\n[PASS] test_pools_swapInOneDoesNotStartACooldownInTheOther() (gas: 328919)\n[PASS] test_senders_areIndependent() (gas: 300106)\n[PASS] test_senders_usersOfASharedRouterShareOneCooldown() (gas: 320498)\n[PASS] test_swap_allowedExactlyAtTheBoundaryBlock() (gas: 229612)\n[PASS] test_swap_allowedWellAfterTheBoundary() (gas: 246394)\n[PASS] test_swap_blockedOneBlockBeforeTheBoundary() (gas: 190766)\n[PASS] test_swap_everyBlockInsideTheWindowReverts() (gas: 504886)\n[PASS] test_swap_firstSwapSucceedsAndRecordsBlock() (gas: 176469)\n[PASS] test_swap_oppositeDirectionIsStillASwap() (gas: 187800)\n[PASS] test_swap_rejectedSwapDoesNotMoveThePool() (gas: 202478)\n[PASS] test_swap_secondSwapInTheSameBlockReverts() (gas: 187745)\n[PASS] test_swap_windowRestartsFromTheLatestSwap() (gas: 310711)\n[PASS] test_undeclaredCallbacks_refuseEvenThePoolManager() (gas: 41474)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 985.05ms (1.05s CPU time)\n\nRan 1 test suite in 986.13ms (985.05ms CPU time): 35 tests passed, 0 failed, 0 skipped (35 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c419f7dfdfc0474f86824e58e356e596900d4442867b23598c79c89f67267692","verifiedTreeHash":"1bdddf7e2b9694511333d7ff631f206c00291dee","verifierVersion":"0.1.0+eab70f1b"}]}