{"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":"bac702e7-6c0d-41de-aa6d-ad7cb75e6e9a","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"62a0a6aec3dae5cf59b3270801e123c540ae06e5a1aa28f705aef127cc8578f3","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":"ec783d9234eece3824dcdf0fc1b1724b79189e06658916df77eefee3f4b4ea77","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 FirstSwapOfDayHook, a simple, creative Uniswap v4 hook: a dynamic-fee hook where the first swap of each UTC day in a pool pays zero LP fee and every later swap that day pays the pool's base fee set at construction. Tests cover the day rollover and a second swap in the same day. 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":"0f1e767e0a4ca17bb1f869c592995126f17f880d393b0707d3e756f1c34318a8","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"bac702e7-6c0d-41de-aa6d-ad7cb75e6e9a","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/Identity-md/launch-66-build-firstswapofdayhook-simple-creative"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"50957","feedbackHash":"e99c22df2e246243ba516943d52066a4fc538ca6ed40897476813ba97b1bab51","nodeKey":"adversarial_review","submissionHash":"62a0a6aec3dae5cf59b3270801e123c540ae06e5a1aa28f705aef127cc8578f3","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50955","feedbackHash":"f443109364260a29ff4b922ed68c725cbb7ad1a5173ae97e816644216b2bb3b7","nodeKey":"build_contract_project","submissionHash":"ec783d9234eece3824dcdf0fc1b1724b79189e06658916df77eefee3f4b4ea77","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"e62de76d48b611a8a4689e75f0554dd272a6001f8e7e38f8cdbd25a05464828e","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0256823ae36e7900","findings":[{"description":"The constructor accepts LPFeeLibrary.MAX_LP_FEE (1,000,000), and beforeSwap returns that value as the override after the daily free swap. Uniswap v4 Pool.swap explicitly reverts exact-output swaps when the combined swap fee is 100%, so this supported construction value contradicts the advertised direction-and-size-agnostic exact-output behavior and prevents a class of trades for the rest of every day. A nonzero protocol fee can produce the same result with an LP baseFee slightly below the maximum when the composed fee rounds to 100%.","line":57,"path":"src/FirstSwapOfDayHook.sol","reproduction":"Deploy the hook with baseFee=1_000_000, initialize a dynamic-fee pool with liquidity, and execute one successful exact-input swap on day N (it uses the zero-fee allowance). In the same day call PoolManager.swap through PoolSwapTest with SwapParams({zeroForOne:true, amountSpecified:1 ether, sqrtPriceLimitX96:TickMath.MIN_SQRT_PRICE+1}). Expected: the later exact-output swap executes and pays the configured base LP fee, as promised for every later swap. Actual: Pool.swap reverts with Pool.InvalidFeeForExactOut because the override is 1_000_000.","severity":"medium","title":"Accepted 100% base fee makes every later exact-output swap revert"},{"description":"beforeSwap marks the allowance used before knowing whether any tokens were exchanged. PoolManager rejects a zero requested amount, but it does not reject a nonzero request that produces a zero BalanceDelta. On an initialized pool with no liquidity, a suitably bounded swap succeeds with zero token movement, commits _lastFreeDay, and makes the first real trade after liquidity is added pay baseFee. This also contradicts the README claim that a zero-liquidity swap reverts and retains the allowance.","line":106,"path":"src/FirstSwapOfDayHook.sol","reproduction":"Initialize a dynamic-fee pool using this hook at SQRT_PRICE_1_1, add no liquidity, then call PoolSwapTest.swap with SwapParams({zeroForOne:true, amountSpecified:-1, sqrtPriceLimitX96:SQRT_PRICE_1_1-1}). Expected: the ineffective call reverts or leaves freeSwapAvailable(poolId)==true because no swap occurred. Actual: v4 swap math moves to the nearby price limit with liquidity zero, returns BalanceDelta(0,0), PoolSwapTest settles nothing and succeeds, while _lastFreeDay is committed and freeSwapAvailable(poolId)==false. Add liquidity during the same UTC day and the first token-moving swap is charged baseFee.","severity":"low","title":"A zero-delta call on a pool with no liquidity consumes the daily free swap"}],"hash":"62a0a6aec3dae5cf59b3270801e123c540ae06e5a1aa28f705aef127cc8578f3","nodeId":"d8cecb6b-cb19-401c-807d-fd20673287a3","outcome":"completed","summary":"Review complete. Wrote two ranked, reproducible findings to [.imd-findings.json](/home/imd-worker/.identitymd/work/bac702e7-6c0d-41de-aa6d-ad7cb75e6e9a/d8cecb6b-cb19-401c-807d-fd20673287a3/.imd-findings.json). JSON validation passed; no project files were modified.","treeHash":null,"usage":{"cachedInputTokens":276352,"inputTokens":41909,"model":null,"outputTokens":3041,"runtime":"codex","turns":4,"wallClockMs":97390}},{"artifacts":[],"attempt":1,"bundleHash":"fcc11f9e46e716fe3c52c7ff4b1fbfc806ef5efee4a6f9a581a585f9266ce5ed","device":"3c7630b22a73c1fb","findings":[],"hash":"ec783d9234eece3824dcdf0fc1b1724b79189e06658916df77eefee3f4b4ea77","nodeId":"f84d46b2-ffff-4022-8289-be6221e5b1bc","outcome":"completed","summary":"`FirstSwapOfDayHook` is built and its tests pass against a real v4 `PoolManager`. With the network off, `forge build` and `forge test` succeed (40 tests, 0 failures) and `forge fmt --check` is clean.\n\nI also ran the two protected files. The three hook checks in `Hook.protected.t.sol` pass, using a scratch copy fed with the compiled creation code. I only ran that copy with `baseFee` 3000, the `0x1080` flags, and a placeholder manager address. The `Token.protected.t.sol` suite is skipped when no token creation code is supplied, and this task has no token. I did not run it, so it is unchecked.\n\n**Design**\n- **Permissions:** the hook uses only `afterInitialize` and `beforeSwap`, so its address needs the low bits `0x1080`.\n- **Fees:** the first swap in a pool on a UTC day gets a zero LP fee through the fee override, and later swaps that day get `baseFee`.\n- **State:** a pool's last free day is stored per `PoolId`, so pools that share the hook don't affect each other.\n- **Validation:** `afterInitialize` reverts unless `key.fee == DYNAMIC_FEE_FLAG`.\n- **Authentication:** both callbacks revert `NotPoolManager` unless the caller is the immutable `poolManager`. `sender` and `hookData` are ignored, so the free swap belongs to the pool, not to an account.\n- **No admin or exits blocked:** there is no owner, no upgrade path, and no liquidity callbacks, so LP exits are never blocked. The runtime code has no `DELEGATECALL`, `CALLCODE` or `SELFDESTRUCT`.\n- **Views and event:** `currentDay`, `freeSwapAvailable`, `nextSwapFee` and `lastFreeSwapDay`, plus a `FreeSwapGranted` event.\n\n**Tests**\n`test/FirstSwapOfDayHook.t.sol` initializes pools, adds liquidity, swaps through `PoolSwapTest` and removes liquidity through `PoolModifyLiquidityTest`. It measures the fee charged from the pool's fee-growth accumulators rather than assuming it. It covers:\n- **Fees and time:** the day rollover (one second before and exactly at midnight, multi-day gaps) and a second swap in the same day, in both directions and for exact-in and exact-out.\n- **Failure paths:** static-fee, zero-fee and max-static-fee pools reverting at initialization, direct callers being refused, and reverted swaps not consuming the free swap.\n- **Isolation and exits:** per-pool isolation, different routers and arbitrary `hookData` not changing the outcome, and LPs being able to add and remove liquidity.\n- **Fuzzing:** over base fee, swap size and timestamps.\n\n**Things to know**\n- **Vendored dependencies:** `lib/` holds v4-core, solmate and forge-std as ordinary files, with no submodules. I pinned v4-core to `46c6834`, not the `v4.0.0` tag, because only that commit has `types/PoolOperation.sol`, which the protected test imports. The pins and licenses are in the README.\n- **Support files the protected tests import:** I added `src/HookFlags.sol` and `test/mocks/MockERC20.sol`.\n- **Gaming is inherent to the design:** anyone can take the day's free swap at any size, and a dust swap can burn it so everyone else pays `baseFee` that day. The README documents this.\n- **Deployer choices:** the `poolManager` address, `baseFee` and address mining are the deployer's job and are listed in the README. The lifecycle needs a fork rehearsal against the real manager, which I did not run.\n- **Not audited:** this is not an audit. The README says an independent review is needed before real liquidity.\n- **Nothing committed:** I left everything uncommitted, since you didn't ask for a commit.","treeHash":"3c5345871d0b09b45da51902ab0157d976cd480f","usage":{"cachedInputTokens":1197320,"inputTokens":40,"model":"claude-sonnet-5","outputTokens":35941,"runtime":"claude","turns":20,"wallClockMs":434149}}],"verification":[{"checks":[{"durationMs":13260,"exitCode":0,"name":"build","output":"Compiling 78 files with Solc 0.8.26\nSolc 0.8.26 finished in 13.15s\nCompiler run successful!\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:112:42\n    │\n112 │         return _swap(router, key, true, -int256(SWAP_IN), \"\");\n    │                                          ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:266:32\n    │\n266 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0, \"first real swap must still be free\");\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:274:32\n    │\n274 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0);\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:282:41\n    │\n282 │         assertApproxEqAbs(_feeOf(true, -int256(SWAP_IN)), _expectedBaseFee(), 1e6);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:290:51\n    │\n290 │             assertApproxEqAbs(_feeOf(i % 2 == 0, -int256(SWAP_IN)), _expectedBaseFee(), 1e6);\n    │                                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:295:33\n    │\n295 │         assertEq(_feeOf(false, -int256(SWAP_IN)), 0, \"first swap, oneForZero\");\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:296:41\n    │\n296 │         assertApproxEqAbs(_feeOf(true, -int256(SWAP_IN)), _expectedBaseFee(), 1e6, \"second swap, zeroForOne\");\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:300:31\n    │\n300 │         assertEq(_feeOf(true, int256(SWAP_IN)), 0);\n    │                               ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:301:31\n    │\n301 │         assertGt(_feeOf(true, int256(SWAP_IN)), 0);\n    │                               ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:306:32\n    │\n306 │         assertEq(d.amount0(), -int128(int256(SWAP_IN)));\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[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:306:39\n    │\n306 │         assertEq(d.amount0(), -int128(int256(SWAP_IN)));\n    │                                       ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:338:32\n    │\n338 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0, \"first swap of the new day is free\");\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:339:41\n    │\n339 │         assertApproxEqAbs(_feeOf(true, -int256(SWAP_IN)), _expectedBaseFee(), 1e6, \"then base fee again\");\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:345:41\n    │\n345 │         assertApproxEqAbs(_feeOf(true, -int256(SWAP_IN)), _expectedBaseFee(), 1e6);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:350:32\n    │\n350 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0);\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:352:32\n    │\n352 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0, \"one second later it is a new day\");\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:358:32\n    │\n358 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0, \"day N+10 free\");\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:359:41\n    │\n359 │         assertApproxEqAbs(_feeOf(true, -int256(SWAP_IN)), _expectedBaseFee(), 1e6, \"but only one free swap\");\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:365:42\n    │\n365 │             assertEq(_feeOf(d % 2 == 0, -int256(SWAP_IN)), 0);\n    │                                          ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:366:42\n    │\n366 │             assertGt(_feeOf(d % 2 == 0, -int256(SWAP_IN)), 0);\n    │                                          ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:367:42\n    │\n367 │             assertGt(_feeOf(d % 2 == 0, -int256(SWAP_IN)), 0);\n    │                                          ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:385:32\n    │\n385 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0);\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:387:40\n    │\n387 │         _swap(otherRouter, key, true, -int256(SWAP_IN), \"\");\n    │                                        ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:400:39\n    │\n400 │             _swap(router, key, true, -int256(SWAP_IN), payloads[i]);\n    │                                       ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:407:35\n    │\n407 │         _swap(router, key, true, -int256(SWAP_IN), abi.encode(address(0xBEEF), uint256(999)));\n    │                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:420:32\n    │\n420 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0);\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:421:32\n    │\n421 │         assertGt(_feeOf(true, -int256(SWAP_IN)), 0);\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:426:34\n    │\n426 │         _swap(router, kb, true, -int256(SWAP_IN), \"\");\n    │                                  ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:433:34\n    │\n433 │         _swap(router, kb, true, -int256(SWAP_IN), \"\");\n    │                                  ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:443:34\n    │\n443 │         _swap(router, kb, true, -int256(SWAP_IN), \"\");\n    │                                  ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:453:51\n    │\n453 │         SwapParams memory bad = SwapParams(true, -int256(SWAP_IN), SQRT_PRICE_1_1 + 1);\n    │                                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:457:32\n    │\n457 │         assertEq(_feeOf(true, -int256(SWAP_IN)), 0);\n    │                                ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:470:33\n    │\n470 │         _swap(router, k, true, -int256(SWAP_IN), \"\");\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n    ╭▸ test/FirstSwapOfDayHook.t.sol:525:47\n    │\n525 │             uint256 fee = _feeOf(i % 2 == 0, -int256(SWAP_IN));\n    │                                               ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\n","passed":true},{"durationMs":229,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 40 tests for test/FirstSwapOfDayHook.t.sol:FirstSwapOfDayHookTest\n[PASS] testFuzz_baseFeeIsWhatConstructionFixed(uint24,uint128) (runs: 256, μ: 837636, ~: 838989)\nLogs:\n  Bound result 772\n  Bound result 49000000002643123207\n\n[PASS] testFuzz_oneFreeSwapPerUtcDay(uint32[6]) (runs: 256, μ: 552403, ~: 551891)\nLogs:\n  Bound result 43200\n  Bound result 9151\n  Bound result 0\n  Bound result 3\n  Bound result 7622\n  Bound result 40\n\n[PASS] test_afterInitialize_revertsWhenCalledDirectly() (gas: 15415)\n[PASS] test_allowanceBelongsToThePoolNotTheCaller() (gas: 250710)\n[PASS] test_beforeSwap_revertsWhenCalledAsThePoolManagerLookalike() (gas: 30977)\n[PASS] test_beforeSwap_revertsWhenCalledDirectly() (gas: 21677)\n[PASS] test_consecutiveDaysEachHaveExactlyOneFreeSwap() (gas: 951071)\n[PASS] test_constructor_acceptsBoundaryFees() (gas: 724062)\n[PASS] test_constructor_revertsOnFeeAboveMax() (gas: 38978)\n[PASS] test_constructor_revertsOnZeroManager() (gas: 36796)\n[PASS] test_directCallCannotPreConsumeTheFreeSwap() (gas: 161619)\n[PASS] test_emitsFreeSwapGrantedOnlyOnTheFirstSwap() (gas: 236763)\n[PASS] test_exactOutputFirstSwapIsFreeAndSecondIsNot() (gas: 241885)\n[PASS] test_firstSwapOfDayPaysZeroLpFee() (gas: 168788)\n[PASS] test_freeSwapIsDirectionAgnostic() (gas: 239792)\n[PASS] test_freeSwapIsNotBankedAcrossIdleDays() (gas: 305121)\n[PASS] test_freeSwapJustBeforeMidnightThenFreeSwapAtMidnight() (gas: 227740)\n[PASS] test_freeSwapPaysNoFeeButStillMovesThePoolAndPaysTheTrader() (gas: 152951)\n[PASS] test_hookDataCannotClaimAFreeSwap() (gas: 372551)\n[PASS] test_hookDataOnTheFirstSwapChangesNothing() (gas: 161475)\n[PASS] test_immutablesReflectConstruction() (gas: 11984)\n[PASS] test_initialize_dynamicFeePoolSucceeds() (gas: 52918)\n[PASS] test_initialize_maxStaticFeePoolReverts() (gas: 50012)\n[PASS] test_initialize_staticFeePoolReverts() (gas: 50342)\n[PASS] test_initialize_zeroFeePoolReverts() (gas: 50738)\n[PASS] test_lastFreeSwapDayTracksTheDay() (gas: 213534)\n[PASS] test_lpCanAddAndRemoveOnAnyDay() (gas: 206576)\n[PASS] test_lpCanRemoveLiquidityAfterSwaps() (gas: 310306)\n[PASS] test_lpCanRemoveLiquidityWhenPoolIsOutOfRange() (gas: 525602)\n[PASS] test_manySwapsSameDayAllPayBaseFee() (gas: 529834)\n[PASS] test_nextUtcDayGrantsAnotherFreeSwap() (gas: 369725)\n[PASS] test_oneSecondBeforeMidnightIsStillTheSameDay() (gas: 235410)\n[PASS] test_permissionsAreExactlyAfterInitializeAndBeforeSwap() (gas: 18538)\n[PASS] test_poolsHaveIndependentDailyAllowance() (gas: 690538)\n[PASS] test_revertedSwapDoesNotConsumeTheFreeSwap() (gas: 229600)\n[PASS] test_rolloverIsPerPool() (gas: 492732)\n[PASS] test_runtimeCodeHasNoDelegatecallOrSelfdestruct() (gas: 607268)\n[PASS] test_secondSwapSameDayPaysBaseFee() (gas: 242234)\n[PASS] test_swapOnUninitializedPoolReverts() (gas: 55956)\n[PASS] test_zeroAmountSwapCannotBurnTheFreeSwap() (gas: 57420)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 114.81ms (218.00ms CPU time)\n\nRan 1 test suite in 115.67ms (114.81ms CPU time): 40 tests passed, 0 failed, 0 skipped (40 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ec783d9234eece3824dcdf0fc1b1724b79189e06658916df77eefee3f4b4ea77","verifiedTreeHash":"3c5345871d0b09b45da51902ab0157d976cd480f","verifierVersion":"0.1.0+eab70f1b"}]}