{"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":"c541f569-e702-4b1c-9ab0-99079a35f69b","kind":"skill:build-contract-project","nodes":[{"acceptedSubmissionHash":"2c2ac22cd15e1c29885056da59be97ac5541d13d74dbabd4fb490a853466cea6","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"}],"objective":"Keel v2 contracts, part 2b: KeelV2Router, so every buyer pays and receives plain ETH in one transaction. Continue the Keel v2 project after part 2a. Same rules: immutable, no proxies, no sweep, Solidity 0.8.26, Cancun, via IR, bytecode_hash none, vendored deps, offline tests plus mainnet-fork tests that skip without a fork.\n\n1. Purpose. Keel v2 pools pair a meme token with an allowlisted quote (ETH, USDC, IMD, wrapped tokens such as wSOL or wBTC). Buyers must never hold the quote. The router swaps ETH -> quote -> token on buy and token -> quote -> ETH on sell, atomically, inside one PoolManager unlock where possible.\n\n2. Routes. The router owner (two-step ownership, separate from funds) sets one route per quote with setRoute(quote, route):\n- NATIVE: the quote is ETH itself (address 0), so there is no first hop.\n- V4: a Uniswap v4 PoolKey between native ETH and the quote (any fee, tick spacing and hooks; hooks must be address 0 or explicitly allowlisted by the owner; the hook allowlist starts empty and every change emits an event).\n- V3: a Uniswap v3 pool address for WETH/quote. The router wraps and unwraps WETH itself and implements uniswapV3SwapCallback, accepting it only from that exact pool during an active swap.\nRoutes can be replaced or removed by the owner. A route change never touches user funds; the router holds no balance between transactions.\n\n3. buy(address token, uint256 minTokensOut, uint256 deadline) payable. Look up the Keel pool by token (hook.poolIdOf, factory.launchInfo for the PoolKey). Swap all msg.value ETH to the quote by the route (exact input), then swap the full quote output into the Keel pool (exact input, as the hook requires) with hookData = abi.encode(msg.sender) so the buyer gets heart credit. Send tokens to msg.sender. Revert if tokensOut < minTokensOut or block.timestamp > deadline. Settle input before take, as the part 1 README requires for quotes with no PoolManager inventory.\n\n4. sell(address token, uint256 amountIn, uint256 minEthOut, uint256 deadline). Pull tokens from msg.sender only (transferFrom). Swap token -> quote in the Keel pool (exact input, hookData empty: sells never touch the heart), then quote -> ETH by the route, send ETH to msg.sender. Revert on minEthOut or deadline.\n\nEvents: Bought(address indexed buyer, address indexed token, uint256 ethIn, uint256 tokensOut) and Sold(address indexed seller, address indexed token, uint256 tokensIn, uint256 ethOut).\n\n5. Quotes. quoteBuy(token, ethIn) and quoteSell(token, amountIn) for the site, implemented as revert-with-result simulations (callable via eth_call), covering both hops and the current hook fee. In the same block and state, quoteBuy and quoteSell must return exactly what buy and sell then deliver: test equality for every route type, not an approximation.\n\n6. Safety. nonReentrant on buy and sell. No leftover tokens, quote or ETH stay in the router after a call: assert zero balance deltas at the end (dust from rounding goes to the user). Unlock callback accepts only PoolManager during the router's own active call. No arbitrary call targets. ETH sends use call and revert on failure.\n\n7. Tests. Buy and sell for each route type (NATIVE, V4 with a mock v4 ETH/quote pool, V3 with a mock v3 pool), heart credit going to msg.sender and never to the router, spoof attempts (calling the Keel pool directly with someone else's address in hookData gives no credit), slippage and deadline reverts, fee-on-transfer and partial-fill rejection inherited from the hook, router balances zero after every call (including 1 wei buys, tiny sells that round to zero, which must revert, and the largest amounts a pool takes), route replacement, ownership. A quote with a transfer fee or rebasing balance is refused when its route is set or reverts the trade; it never leaves dust in the router. Fork tests against mainnet USDC and WETH pools when a fork URL is given.\n\n8. Gas. Measure with forge snapshot and document in the README: buy and sell for each route type (NATIVE, V4, V3) at small and typical amounts, next to a direct single-pool swap of the same size. Report the router's overhead per route.\n\nDeliver: source, tests, README section for part 2b, REVIEW.md update. Do not deploy.","parentJobId":"f16cb00c-f00d-4fb2-833f-de627e488f57","planHash":"84e3c8fc4823d8d248a683234b0cdc7d35ca709cea56a340aabd7bb62958669b","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"f4c6c94f-30c2-45be-8a4d-313ff9cf3b3d","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2320-kkkkk"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51135","feedbackHash":"e5a763cb27c4871bc1f3950d9b6cc338e06f3396af09cb57498326b9ed1d7ac7","nodeKey":"build_contract_project","submissionHash":"2c2ac22cd15e1c29885056da59be97ac5541d13d74dbabd4fb490a853466cea6","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"700548f719d9685998d049b139947d7b13543e147e4fa8ddf278196a804c8235","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"d5bfecbc59c228f8f0c059ed971f03b66ee21776a811e331e811da3070b690c0","device":"c872aaeb2e58b080","findings":[],"hash":"2c2ac22cd15e1c29885056da59be97ac5541d13d74dbabd4fb490a853466cea6","nodeId":"a9d6292d-33b8-4076-87f8-a281bf8b7cbb","outcome":"completed","summary":"`KeelV2Router` is in place: buyers pay ETH and get tokens back, and sellers get ETH back, in one transaction on all three route types. With the verifier's fuzz seed, `forge build` and `forge test` pass: 164 tests pass, 0 fail, and 4 are skipped because they only run on a fork. `forge fmt --check` is clean. Nothing was deployed, and no part 1 or 2a source was changed.\n\n**What it does**\n- **Routes:** the owner sets one route per quote: NATIVE for ETH, V4 for an ETH/quote v4 pool, or V3 for a WETH/quote v3 pool, where the router wraps and unwraps WETH itself. Routes can be replaced or removed. The quote must already be enabled in the factory. A v4 pool with a hook needs that hook on an allowlist, which starts empty, emits an event on every change and is re-checked on every trade.\n- **Buy:** ETH is settled before the Keel swap on every route. On NATIVE and V4 the whole buy happens in one PoolManager unlock. The buyer's address goes in as hook data, so heart credit goes to them.\n- **Sell:** tokens come only from `msg.sender`, and each route runs in one unlock. ETH is sent with `call`, and a failed send reverts.\n- **Safety:** buys, sells and quotes share one reentrancy lock. Both callbacks only accept calls during the router's own active swap. The router reverts if any hop doesn't use its full input, if any hop returns nothing, or if any balance change doesn't match what the pool reported. At the end of every call it checks that its ETH, token, quote and WETH balances are unchanged.\n- **Quotes:** `quoteBuy` and `quoteSell` run the same code as the trade and then revert with the result. Tests check exact equality with the real trade on every route, at large sizes, during launch-fee decay, and in a fuzz test.\n\n**Limits you should know about**\n- **NATIVE `quoteBuy` can fail on large amounts.** An `eth_call` carries no ETH, but the hook takes its fee in ETH from PoolManager during the simulated swap. The simulation therefore fails unless PoolManager already holds that much ETH. In the tests a 5,000 ETH quote failed for that reason; the buy itself still worked. Mainnet PoolManager holds far more ETH, so this should only matter for very large quotes. The V4 and V3 routes don't have this problem.\n- **The pool key is derived, not read from `factory.launchInfo`.** The router rebuilds the Keel pool key and checks it against the hook's registered pool id. It is the same key, and this avoids loading the launch metadata string on every trade.\n- **V3 pools are trusted to be real.** On chain the router only checks that a v3 pool holds WETH and the quote. The owner has to make sure it is a genuine Uniswap v3 pool. A bad route can't take more than the trade's own input, and the user's minimum output still applies.\n\n**Fork tests:** the three fork tests (NATIVE, V3 through the USDC/WETH 0.05% pool, V4 through the ETH/USDC pool) passed against the latest mainnet block through a public RPC. Block 22,000,000, which part 1 used, wasn't reachable because no archive node was available. Without a fork URL these tests skip.\n\n**Gas** (recorded in `.gas-snapshot`; the README has the full table):\n\n| Route | Router buy | Direct single-pool swap | Overhead |\n|---|---|---|---|\n| NATIVE | ~352k | ~324k | about +28k, including the heart credit |\n| V4 | ~408k | ~412k, plus ~125k for a separate ETH→USDC swap | about −3k against the Keel swap alone, −129k against doing both swaps separately |\n| V3 | ~433k | ~412k | about +22k |\n\nThe direct rows go through the part 1 test router, which has its own overhead, so negative numbers mean the production router is leaner than that test harness. The V3 numbers use a mock pool; a real v3 swap costs more and wasn't measured.\n\n**Not done:** Slither wasn't run in this part, and the router still needs an independent review before it handles real funds. I haven't committed anything.\n\n**After launch**, the README lists the owner's steps:\n- Deploy with `KeelV2Router(poolManager, factory, hook, weth, owner)`.\n- Call `factory.setRouter(rou","treeHash":"c106ab7e2a75138c76969ef458a6063ad98dd4d8","usage":{"cachedInputTokens":4412772,"inputTokens":68,"model":"claude-opus-5-5","outputTokens":84262,"runtime":"claude","turns":45,"wallClockMs":1408780}}],"verification":[{"checks":[{"durationMs":316547,"exitCode":0,"name":"build","output":"Compiling 103 files with Solc 0.8.26\nSolc 0.8.26 finished in 316.30s\nCompiler run successful!\n","passed":true},{"durationMs":1755,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/Gas.t.sol:GasWithoutHeartTest\n[PASS] test_gas_nonRouterBuyNamed() (gas: 345311)\n[PASS] test_gas_plainBuyNoHookData() (gas: 319609)\n[PASS] test_gas_routerBuyNamed() (gas: 345370)\n[PASS] test_gas_sell() (gas: 428684)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 61.28ms (2.07ms CPU time)\n\nRan 3 tests for test/RouterMainnetFork.t.sol:RouterMainnetForkTest\n[SKIP] test_fork_nativeRoute() (gas: 0)\n[SKIP] test_fork_v3UsdcRoute() (gas: 0)\n[SKIP] test_fork_v4UsdcRoute() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 61.91ms (135.89µs CPU time)\n\nRan 1 test for test/MainnetFork.t.sol:MainnetForkTest\n[SKIP] test_mainnetRealUSDCAndETH() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 76.29ms (51.24µs CPU time)\n\nRan 2 tests for test/Deploy.t.sol:DeployTest\n[PASS] test_dryRunRejectsWrongChainAndMissingOwner() (gas: 6873103)\n[PASS] test_dryRunWiringExplicitOwnerAndPermissions() (gas: 14452074)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 88.50ms (4.70ms CPU time)\n\nRan 6 tests for test/Heart.t.sol:HeartWinnerTest\n[PASS] test_endLongAfterDeadlineStillChecksPreviousBlock() (gas: 703049)\n[PASS] test_holderWins() (gas: 690752)\n[PASS] test_movesInsideEndBlockDoNotCount() (gas: 2194952)\n[PASS] test_receivedByTransferCounts() (gas: 1511596)\n[PASS] test_soldAndBoughtBackBeforeEndWins() (gas: 2947357)\n[PASS] test_soldPartBeforeEndLoses() (gas: 1033507)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 122.88ms (28.72ms CPU time)\n\nRan 3 tests for test/Pulse.t.sol:PulseRateModuleTest\n[PASS] testFuzz_alwaysWithinRateBounds(uint16,uint256) (runs: 256, μ: 1394308, ~: 1394360)\nLogs:\n  Bound result 419\n\n[PASS] test_boundsAtZeroHotAndAbove() (gas: 1545919)\n[PASS] test_liveFeeFollowsRealPulseAndCreatorControls() (gas: 4445698)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 161.99ms (80.12ms CPU time)\n\nRan 8 tests for test/Permit.t.sol:PermitTest\n[PASS] test_domainSeparatorBindsChainAndContract() (gas: 133177)\n[PASS] test_feeForwardFailureRevertsLaunch() (gas: 2775917)\n[PASS] test_permitBindsCreatorQuoteTickDeadlineAndSigner() (gas: 2072492)\n[PASS] test_routerHeartSignerWiringGuards() (gas: 444289)\n[PASS] test_signerReplacementInvalidatesOldPermits() (gas: 1462352)\n[PASS] test_tickBoundsStillApplyWithValidPermit() (gas: 1426103)\n[PASS] test_validPermitConsumesNonceAndForwardsFee() (gas: 2684987)\n[PASS] test_wrongFeeAndFeeChanges() (gas: 2904031)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 232.91ms (25.42ms CPU time)\n\nRan 1 test for test/HeartInvariant.t.sol:SwapIdentityTest\n[PASS] testFuzz_swapResultIdenticalWithOrWithoutHeart(uint96[4],uint8) (runs: 256, μ: 4714499, ~: 4708671)\nLogs:\n  Bound result 5336793259480494\n  Bound result 99000000000003446\n  Bound result 99000000000001496\n  Bound result 99000000000002032\n  Bound result 5336793259480494\n  Bound result 99000000000003446\n  Bound result 99000000000001496\n  Bound result 99000000000002032\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 425.50ms (355.91ms CPU time)\n\nRan 9 tests for test/Rules.t.sol:RulesTest\n[PASS] test_allCreatorActionsRefreshActivity() (gas: 1889254)\n[PASS] test_creatorTransferAndPendingRaiseControl() (gas: 1846049)\n[PASS] test_lowerImmediateCancelsPending() (gas: 1592520)\n[PASS] test_moduleImmutablePerPool() (gas: 2977324)\n[PASS] test_pingAndModuleActionDelayTakeover() (gas: 1693072)\n[PASS] test_raiseDelayAndBoundaryAndCancellation() (gas: 1792351)\n[PASS] test_rateGuardsAndUnauthorized() (gas: 1836359)\n[PASS] test_rescheduleRestartsRaiseDelay() (gas: 1644046)\n[PASS] test_takeoverUnknownEarlyBoundaryAndSuccess() (gas: 2702567)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 436.67ms (27.24ms CPU time)\n\nRan 6 tests for test/Gas.t.sol:GasWithHeartTest\n[PASS] test_gas_nonRouterBuyNamed() (gas: 354438)\n[PASS] test_gas_plainBuyNoHookData() (gas: 324064)\n[PASS] test_gas_routerBuyEndsRoundInsideOnBuy() (gas: 781900)\n[PASS] test_gas_routerBuyNamed() (gas: 404615)\n[PASS] test_gas_routerBuyRoundRunning() (gas: 662489)\n[PASS] test_gas_sell() (gas: 428615)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 487.44ms (5.13ms CPU time)\n\nRan 22 tests for test/Fees.t.sol:FeesTest\n[PASS] testFuzz_balanceInvariant(uint96[6],uint8,uint16) (runs: 256, μ: 5197285, ~: 5489735)\nLogs:\n  Bound result 1\n  Bound result 117\n  Bound result 6635\n  Bound result 2818\n  Bound result 6355\n  Bound result 9012\n  Bound result 3725\n  Bound result 5099\n\n[PASS] testFuzz_roundingConserves(uint128,uint16,uint16) (runs: 256, μ: 19907, ~: 19836)\nLogs:\n  Bound result 314\n  Bound result 9669\n\n[PASS] test_buySellFeeSplitForAllDecimals() (gas: 9371822)\n[PASS] test_buyUsesSingleRateSnapshot() (gas: 2280344)\n[PASS] test_creatorAndTeamClaimsToContractsReentrancyAndFailure() (gas: 2474152)\n[PASS] test_creatorTransferPreservesOldCreditAndActivity() (gas: 2280647)\n[PASS] test_erc20ClaimsAndInvalidRecipients() (gas: 2309352)\n[PASS] test_exactOutputAndTinyBuyRevert() (gas: 1618122)\n[PASS] test_invalidModuleRateCannotCollectFees() (gas: 1678259)\n[PASS] test_lowerDuringScheduleDoesNotRestartClock() (gas: 1984145)\n[PASS] test_multiplePoolsSameQuoteAggregateClaims() (gas: 3784244)\n[PASS] test_negativeRebasePreventsPreferentialClaim() (gas: 2146790)\n[PASS] test_noCreatorOwnerOrTeamExemption() (gas: 2409782)\n[PASS] test_partialBuyRevertsWithoutAccruingFee() (gas: 1756909)\n[PASS] test_raiseChangesSwapRateAfterExplicitApplication() (gas: 1977923)\n[PASS] test_reentrancyCannotClaimAnotherLiveCredit() (gas: 2218156)\n[PASS] test_scheduleAtSeveralTimesAndExtraAllToTeam() (gas: 3022315)\n[PASS] test_scheduledRateRoundsUp() (gas: 1397293)\n[PASS] test_taxedOrFailedPayoutPreservesCredit() (gas: 2489056)\n[PASS] test_taxedReceiptRollsBackSwapAndFeeCredits() (gas: 1932266)\n[PASS] test_teamRecipientChangePreservesAccruedOwnership() (gas: 2296281)\n[PASS] test_unauthorizedClaimsCannotRedirectCredits() (gas: 1929171)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 487.59ms (630.96ms CPU time)\n\nRan 5 tests for test/Token.t.sol:TokenTest\n[PASS] testFuzz_balanceAtMatchesHistory(uint8,uint256) (runs: 256, μ: 2375343, ~: 1392345)\nLogs:\n  Bound result 2\n  Bound result 769526629336765295259002681\n  Bound result 394284335121017711206380347\n\n[PASS] test_allowanceAndTransferFailures() (gas: 272217)\n[PASS] test_checkpointsSameBlockPoolManagerAndSelfTransfer() (gas: 612594)\n[PASS] test_erc20AndExactBalances() (gas: 402310)\n[PASS] test_noOwnerMintOrReinitialize() (gas: 81339)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 487.34ms (488.15ms CPU time)\n\nRan 13 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_bothAddressOrderings() (gas: 35355033)\n[PASS] test_callbackAndUnknownPoolGuards() (gas: 1573131)\n[PASS] test_canDisableQuoteWhoseMetadataBreaks() (gas: 54600)\n[PASS] test_decayModuleAndTakeoverGuards() (gas: 351132)\n[PASS] test_launch6and8and18DecimalQuotes() (gas: 6977962)\n[PASS] test_launchETHWholeSupplyLockedAndCheckpointed() (gas: 1500987)\n[PASS] test_launchValidation() (gas: 699106)\n[PASS] test_outsideAddAndRemoveRevert() (gas: 1549663)\n[PASS] test_ownerGuardsAndTwoStep() (gas: 389904)\n[PASS] test_ownerPowersApplyOnlyToFuturePools() (gas: 2058744)\n[PASS] test_pauseOnlyNewLaunches() (gas: 3291570)\n[PASS] test_quoteClassificationAndBounds() (gas: 2136370)\n[PASS] test_realSwapsCheckpointPoolManagerAndTrader() (gas: 2263912)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 484.99ms (59.85ms CPU time)\n\nRan 6 tests for test/Pulse.t.sol:PulseTest\n[PASS] testFuzz_decayNeverRevertsAndIsMonotone(uint128,uint256,uint256) (runs: 256, μ: 16748, ~: 16335)\nLogs:\n  Bound result 1926268739835554890288682571254610\n\n[PASS] testFuzz_wholeHalfLivesAreExactShifts(uint128,uint8) (runs: 256, μ: 12717, ~: 12586)\nLogs:\n  Bound result 22\n\n[PASS] test_decayExactHalfLivesAndCap() (gas: 90131)\n[PASS] test_pulseAccumulatesDecaysAndIgnoresSmallBuys() (gas: 2996060)\n[PASS] test_pulseCountsEveryBuyWithoutHeart() (gas: 2046340)\n[PASS] test_pulseSaturatesInsteadOfOverflowing() (gas: 2338517)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 541.74ms (849.32ms CPU time)\n\nRan 19 tests for test/RouterGas.t.sol:RouterGasTest\n[PASS] test_gas_directKeelBuy_eth_small() (gas: 323822)\n[PASS] test_gas_directKeelBuy_eth_typical() (gas: 324033)\n[PASS] test_gas_directKeelBuy_usdc_small() (gas: 411621)\n[PASS] test_gas_directKeelBuy_usdc_typical() (gas: 412041)\n[PASS] test_gas_directKeelSell_eth_small() (gas: 425201)\n[PASS] test_gas_directKeelSell_eth_typical() (gas: 429972)\n[PASS] test_gas_directV4Hop_ethToUsdc_typical() (gas: 125408)\n[PASS] test_gas_routerBuy_native_small() (gas: 351820)\n[PASS] test_gas_routerBuy_native_typical() (gas: 351606)\n[PASS] test_gas_routerBuy_v3_small() (gas: 433298)\n[PASS] test_gas_routerBuy_v3_typical() (gas: 433914)\n[PASS] test_gas_routerBuy_v4_small() (gas: 408340)\n[PASS] test_gas_routerBuy_v4_typical() (gas: 408882)\n[PASS] test_gas_routerSell_native_small() (gas: 370814)\n[PASS] test_gas_routerSell_native_typical() (gas: 375860)\n[PASS] test_gas_routerSell_v3_small() (gas: 484014)\n[PASS] test_gas_routerSell_v3_typical() (gas: 483860)\n[PASS] test_gas_routerSell_v4_small() (gas: 434381)\n[PASS] test_gas_routerSell_v4_typical() (gas: 440779)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 541.82ms (13.72ms CPU time)\n\nRan 3 tests for test/Math.t.sol:MathTest\n[PASS] testFuzz_bitScansAgainstDivisionReference(uint256) (runs: 256, μ: 14653, ~: 11664)\n[PASS] testFuzz_fullWidthMultiplicationAndDivision(uint256,uint256) (runs: 256, μ: 5343, ~: 5083)\n[PASS] test_allPowerOfTwoBoundaries() (gas: 697936)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 541.91ms (252.65ms CPU time)\n\nRan 38 tests for test/KeelV2Router.t.sol:KeelV2RouterTest\n[PASS] testFuzz_quotesExact(uint8,uint256,uint256) (runs: 256, μ: 1802848, ~: 1861240)\nLogs:\n  Bound result 11880945807675741716\n  Bound result 4610\n\n[PASS] test_buyBelowHeartMinimumStillTrades() (gas: 527371)\n[PASS] test_constructorAndWiring() (gas: 13474)\n[PASS] test_deadlineReverts() (gas: 962280)\n[PASS] test_feeOnTransferQuoteReverts_v3() (gas: 1289483)\n[PASS] test_feeOnTransferQuoteReverts_v4() (gas: 1420045)\n[PASS] test_forcedBalanceDoesNotBreakOrLeak() (gas: 1301068)\n[PASS] test_heartCreditGoesToBuyer_native() (gas: 892716)\n[PASS] test_heartCreditGoesToBuyer_v4Quote() (gas: 631340)\n[PASS] test_hookAllowlist() (gas: 248908)\n[PASS] test_largestAmounts() (gas: 7523888)\n[PASS] test_native_buySell_matchesQuotes() (gas: 2995302)\n[PASS] test_oneWeiBuysRevertAndLeaveNothing() (gas: 992214)\n[PASS] test_onlyOwnerSetsRoutes() (gas: 36466)\n[PASS] test_quoteCoversLaunchFee() (gas: 2838470)\n[PASS] test_quotesAreNotStateChanging() (gas: 1145442)\n[PASS] test_rebasingQuoteReverts() (gas: 4040517)\n[PASS] test_reentrancyBlocked() (gas: 1364646)\n[PASS] test_rejectsStrayEther() (gas: 18849)\n[PASS] test_routeReplacementAndRemoval() (gas: 6553740)\n[PASS] test_routeValidation() (gas: 343436)\n[PASS] test_sellNeverTouchesHeart() (gas: 1016240)\n[PASS] test_sellToEthRejectingContractReverts() (gas: 1357432)\n[PASS] test_sellingMoreThanBoughtRevertsAsPartialFill() (gas: 1551913)\n[PASS] test_simulateIsSelfOnly() (gas: 36519)\n[PASS] test_slippageReverts() (gas: 7329616)\n[PASS] test_spoofedHookDataGivesNoCredit() (gas: 1145413)\n[PASS] test_tinySellsRoundingToZeroRevert() (gas: 3374450)\n[PASS] test_twoStepOwnership() (gas: 286746)\n[PASS] test_unattestedQuoteRefusedAtSetRoute() (gas: 990031)\n[PASS] test_unknownToken() (gas: 72033)\n[PASS] test_unlockCallbackOnlyDuringOwnCall() (gas: 63882)\n[PASS] test_v3CallbackOnlyFromActivePool() (gas: 61215)\n[PASS] test_v3ForgedDeltaAndSkippedCallbackRejected() (gas: 779575)\n[PASS] test_v3PartialFillReverts() (gas: 1008130)\n[PASS] test_v3_buySell_matchesQuotes() (gas: 3596056)\n[PASS] test_v4PartialFillReverts() (gas: 3925932)\n[PASS] test_v4_buySell_matchesQuotes() (gas: 3478707)\nSuite result: ok. 38 passed; 0 failed; 0 skipped; finished in 542.10ms (319.88ms CPU time)\n\nRan 7 tests for test/Heart.t.sol:HeartPotTest\n[PASS] test_fundingRules() (gas: 774309)\n[PASS] test_ineligibleRoundCarriesWholePotAndCannotClaim() (gas: 1611483)\n[PASS] test_manyEmptyRoundsThenFunding() (gas: 3107243)\n[PASS] test_onBuyGasOnEveryPath() (gas: 124684507)\nLogs:\n  onBuy gas: 25433\n  onBuy gas: 25645\n  onBuy gas: 73885\n  onBuy gas: 39677\n  onBuy gas: 39773\n  onBuy gas: 96760\n  onBuy gas: 44197\n  onBuy gas: 119766\n\n[PASS] test_ownerPowersAndLimits() (gas: 1456251)\n[PASS] test_rejectedRecipientAndTaxedPayoutRollBack() (gas: 1677353)\n[PASS] test_splitClaimAndCarryAcrossRounds() (gas: 2288836)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 542.09ms (159.39ms CPU time)\n\nRan 10 tests for test/Heart.t.sol:HeartTimerTest\n[PASS] test_belowMinBuyOrUnlistedThresholdIgnored() (gas: 4122381)\n[PASS] test_buyAfterDeadlineEndsInsideOnBuyAndStartsNext() (gas: 2351638)\n[PASS] test_endRequiresExpiredRound() (gas: 2515443)\n[PASS] test_extensionAndCap() (gas: 7616977)\n[PASS] test_gasBurningAndRevertingHeartsBoundedByStipend() (gas: 516669199)\n[PASS] test_nonRouterAndSpoofedHookDataNeverCount() (gas: 2965028)\n[PASS] test_onlyHookCallsOnBuy() (gas: 35415)\n[PASS] test_revertingHeartNeverBreaksSwap() (gas: 2144611)\n[PASS] test_routerBuyStartsRoundAndRecordsBuy() (gas: 1902840)\n[PASS] test_sellsNeverTouchTimer() (gas: 2599015)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 542.70ms (478.54ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:FeeInvariantTest\n[PASS]\nFeeInvariantTest invariants:\n[PASS] invariant_feesFullyBackedAndExactlyAttributed\n[PASS] invariant_fixedSupplyAndLockedPosition\n FeeInvariantTest invariants (runs: 128, calls: 4096, reverts: 0)\n\n╭------------+-----------------+-------+---------+----------╮\n| Contract   | Selector        | Calls | Reverts | Discards |\n+===========================================================+\n| FeeHandler | advance         | 596   | 0       | 0        |\n|------------+-----------------+-------+---------+----------|\n| FeeHandler | buy             | 584   | 0       | 0        |\n|------------+-----------------+-------+---------+----------|\n| FeeHandler | claim           | 616   | 0       | 0        |\n|------------+-----------------+-------+---------+----------|\n| FeeHandler | lower           | 570   | 0       | 0        |\n|------------+-----------------+-------+---------+----------|\n| FeeHandler | sell            | 583   | 0       | 0        |\n|------------+-----------------+-------+---------+----------|\n| FeeHandler | transferCreator | 631   | 0       | 0        |\n|------------+-----------------+-------+---------+----------|\n| FeeHandler | transferTeam    | 516   | 0       | 0        |\n╰------------+-----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 96\n  Bound result 7132\n  Bound result 19900000000005821\n  Bound result 5223\n  Bound result 400\n  Bound result 19900000000002305\n  Bound result 19900000000005986\n  Bound result 113339300051930479884922080\n  Bound result 2989\n  Bound result 269\n  Bound result 5233612229251126\n  Bound result 3189\n  Bound result 185\n  Bound result 19900000000014434\n  Bound result 4711\n  Bound result 19900000000002385\n  Bound result 19900000000010160\n  Bound result 10376\n  Bound result 160\n  Bound result 115\n  Bound result 19900000000005990\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.37s (1.24s CPU time)\n\nRan 1 test for test/HeartInvariant.t.sol:HeartInvariantTest\n[PASS]\nHeartInvariantTest invariants:\n[PASS] invariant_heartSolventAndConserved\n[PASS] invariant_hookSolvent\n HeartInvariantTest invariants (runs: 128, calls: 4096, reverts: 0)\n\n╭--------------+----------+-------+---------+----------╮\n| Contract     | Selector | Calls | Reverts | Discards |\n+======================================================+\n| HeartHandler | advance  | 706   | 0       | 0        |\n|--------------+----------+-------+---------+----------|\n| HeartHandler | buy      | 702   | 0       | 0        |\n|--------------+----------+-------+---------+----------|\n| HeartHandler | claim    | 674   | 0       | 0        |\n|--------------+----------+-------+---------+----------|\n| HeartHandler | end      | 681   | 0       | 0        |\n|--------------+----------+-------+---------+----------|\n| HeartHandler | fund     | 635   | 0       | 0        |\n|--------------+----------+-------+---------+----------|\n| HeartHandler | sell     | 698   | 0       | 0        |\n╰--------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 543950335\n  Bound result 200\n  Bound result 0\n  Bound result 2768\n  Bound result 38336005805222595\n  Bound result 371998963325884167\n  Bound result 49900000000005383\n  Bound result 38336005805222595\n  Bound result 1791\n  Bound result 38336005805222595\n  Bound result 1\n  Bound result 38336005805222595\n  Bound result 543950335\n  Bound result 3\n  Bound result 1\n  Bound result 14056\n  Bound result 543950335\n  Bound result 19433801\n  Bound result 39\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.45s (1.35s CPU time)\n\nRan 21 test suites in 1.46s (9.69s CPU time): 164 tests passed, 0 failed, 4 skipped (168 total tests)\n","passed":true},{"durationMs":157,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"FixedRateModule.applyRaise(bytes32)\",\"FixedRateModule.cancelRaise(bytes32)\",\"FixedRateModule.initialize(bytes32,uint16)\",\"FixedRateModule.lowerRate(bytes32,uint16)\",\"FixedRateModule.scheduleRaise(bytes32,uint16)\",\"KeelHeart.acceptOwnership()\",\"KeelHeart.addQuote(address)\",\"KeelHeart.claim(uint256,address)\",\"KeelHeart.end()\",\"KeelHeart.fund(address,uint256)\",\"KeelHeart.onBuy(address,address,address,uint256,uint256)\",\"KeelHeart.setMinBuy(address,uint256)\",\"KeelHeart.transferOwnership(address)\",\"KeelV2Factory.acceptOwnership()\",\"KeelV2Factory.configureQuote(address,bool,int24,int24,bool,bool)\",\"KeelV2Factory.initialize(address,address)\",\"KeelV2Factory.launch(string,string,string,address,int24,uint16,uint256,bytes)\",\"KeelV2Factory.registerModule(address)\",\"KeelV2Factory.setDecaySeconds(uint32)\",\"KeelV2Factory.setHeart(address)\",\"KeelV2Factory.setLaunchFee(uint256)\",\"KeelV2Factory.setLaunchesPaused(bool)\",\"KeelV2Factory.setRouter(address)\",\"KeelV2Factory.setSigner(address)\",\"KeelV2Factory.setTakeoverContract(address)\",\"KeelV2Factory.setTeamRecipient(address)\",\"KeelV2Factory.transferOwnership(address)\",\"KeelV2Factory.unlockCallback(bytes)\",\"KeelV2Hook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"KeelV2Hook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"KeelV2Hook.claimCreator(address,address)\",\"KeelV2Hook.claimTeam(address,address)\",\"KeelV2Hook.creatorAction(bytes32,address)\",\"KeelV2Hook.ping(address)\",\"KeelV2Hook.receive()\",\"KeelV2Hook.registerPool((address,address,uint24,int24,address),address,address,address,address,uint16,uint32)\",\"KeelV2Hook.setCreatorByTakeover(address,address)\",\"KeelV2Hook.transferCreator(address,address)\",\"KeelV2Router.acceptOwnership()\",\"KeelV2Router.buy(address,uint256,uint256)\",\"KeelV2Router.quoteBuy(address,uint256)\",\"KeelV2Router.quoteSell(address,uint256)\",\"KeelV2Router.receive()\",\"KeelV2Router.sell(address,uint256,uint256,uint256)\",\"KeelV2Router.setHookAllowed(address,bool)\",\"KeelV2Router.setRoute(address,(uint8,(address,address,uint24,int24,address),address))\",\"KeelV2Router.simulate(bool,address,uint256,address)\",\"KeelV2Router.transferOwnership(address)\",\"KeelV2Router.uniswapV3SwapCallback(int256,int256,bytes)\",\"KeelV2Router.unlockCallback(bytes)\",\"KeelV2Token.approve(address,uint256)\",\"KeelV2Token.transfer(address,uint256)\",\"KeelV2Token.transferFrom(address,address,uint256)\",\"PulseRateModule.applyRaise(bytes32)\",\"PulseRateModule.cancelRaise(bytes32)\",\"PulseRateModule.initialize(bytes32,uint16)\",\"PulseRateModule.lowerRate(bytes32,uint16)\",\"PulseRateModule.scheduleRaise(bytes32,uint16)\"],\"files\":{\".gas-snapshot\":29,\".gitignore\":5,\"README.md\":332,\"REVIEW.md\":139,\"foundry.toml\":26,\"script/Deploy.s.sol\":70,\"src/FixedRateModule.sol\":13,\"src/KeelHeart.sol\":330,\"src/KeelV2Factory.sol\":400,\"src/KeelV2Hook.sol\":426,\"src/KeelV2Router.sol\":530,\"src/KeelV2Token.sol\":94,\"src/PulseRateModule.sol\":20,\"src/RateModuleBase.sol\":111,\"src/interfaces/IKeelHeart.sol\":10,\"src/interfaces/IRulesModule.sol\":25,\"src/libraries/Guard.sol\":14,\"src/libraries/PulseMath.sol\":56,\"src/libraries/QuoteTransfer.sol\":35,\"test/Deploy.t.sol\":55,\"test/Fees.t.sol\":445,\"test/Gas.t.sol\":78,\"test/Heart.t.sol\":534,\"test/HeartInvariant.t.sol\":198,\"test/Invariant.t.sol\":185,\"test/KeelV2Router.t.sol\":627,\"test/Launch.t.sol\":265,\"test/MainnetFork.t.sol\":34,\"test/Math.t.sol\":45,\"test/Permit.t.sol\":191,\"test/Pulse.t.sol\":195,\"test/RouterGas.t.sol\":130,\"test/RouterMainnetFork.t.sol\":92,\"test/Rules.t.sol\":198,\"test/Token.t.sol\":113,\"test/support/HeartTest.sol\":91,\"test/support/KeelTest.sol\":204,\"test/support/MockQuote.sol\":67,\"test/support/Router.sol\":101,\"test/support/RouterMocks.sol\":225,\"test/support/RouterTest.sol\":155,\"test/support/TestModules.sol\":37},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":18571,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/KeelV2Router.sol:263: Reentrancy in KeelV2Router.sell(address,uint256,uint256,uint256) (src/KeelV2Router.sol#263-281):\n[high/medium] reentrancy-eth at src/KeelHeart.sol:195: Reentrancy in KeelHeart.claim(uint256,address) (src/KeelHeart.sol#195-212):\n[high/high] uninitialized-state at src/KeelHeart.sol:158: KeelHeart._anchors (src/KeelHeart.sol#74) is never initialized. It is used in:\n[medium/high] incorrect-equality at src/RateModuleBase.sol:95: RateModuleBase._creator(bytes32) (src/RateModuleBase.sol#95-98) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/RateModuleBase.sol:90: RateModuleBase.currentRate(bytes32) (src/RateModuleBase.sol#90-93) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/KeelHeart.sol:133: KeelHeart.onBuy(address,address,address,uint256,uint256) (src/KeelHeart.sol#133-155) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/KeelV2Token.sol:86: KeelV2Token._checkpoint(address) (src/KeelV2Token.sol#86-93) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/RateModuleBase.sol:50: Reentrancy in RateModuleBase.lowerRate(bytes32,uint16) (src/RateModuleBase.sol#50-58):\n[medium/medium] reentrancy-no-eth at src/RateModuleBase.sol:60: Reentrancy in RateModuleBase.scheduleRaise(bytes32,uint16) (src/RateModuleBase.sol#60-68):\n[medium/medium] reentrancy-no-eth at src/RateModuleBase.sol:70: Reentrancy in RateModuleBase.cancelRaise(bytes32) (src/RateModuleBase.sol#70-75):\n[medium/medium] reentrancy-no-eth at src/KeelV2Factory.sol:337: Reentrancy in KeelV2Factory.unlockCallback(bytes) (src/KeelV2Factory.sol#337-367):\n[medium/medium] reentrancy-no-eth at src/RateModuleBase.sol:78: Reentrancy in RateModuleBase.applyRaise(bytes32) (src/RateModuleBase.sol#78-87):\n[medium/medium] uninitialized-local at src/KeelHeart.sol:269: KeelHeart._finish(KeelHeart.Live).ordinal (src/KeelHeart.sol#269) is a local variable never initialized\n[medium/medium] uninitialized-local at src/KeelV2Router.sol:204: KeelV2Router.setRoute(address,KeelV2Router.Route).v4Id (src/KeelV2Router.sol#204) is a local variable never initialized\n[medium/medium] uninitialized-local at src/KeelHeart.sol:305: KeelHeart._anchorBefore(address,uint256).low (src/KeelHeart.sol#305) is a local variable never initialized\n[medium/medium] uninitialized-local at src/KeelV2Token.sol:62: KeelV2Token.balanceAt(address,uint256).low (src/KeelV2Token.sol#62) is a local variable never initialized\n[medium/medium] uninitialized-local at src/KeelV2Hook.sol:344: KeelV2Hook._beat(bytes32,KeelV2Hook.Pool,address,uint256,uint256,bytes).threshold (src/KeelV2Hook.sol#344) is a local variable never initialized\n[medium/medium] unused-return at src/KeelV2Factory.sol:271: KeelV2Factory.launch(string,string,string,address,int24,uint16,uint256,bytes) (src/KeelV2Factory.sol#271-330) ignores return value by poolManager.initialize(key,TickMath.getSqrtPriceAtTick(startTick)) (src/KeelV2Factory.sol#319)\n[medium/medium] unused-return at src/KeelV2Router.sol:188: KeelV2Router.setRoute(address,KeelV2Router.Route) (src/KeelV2Router.sol#188-237) ignores return value by (sqrtPriceX96,None,None,None) = poolManager.getSlot0(id) (src/KeelV2Router.sol#217)\n[medium/medium] unused-return at src/KeelV2Router.sol:188: KeelV2Router.setRoute(address,KeelV2Router.Route) (src/KeelV2Router.sol#188-237) ignores return value by (enabled,None,None,None) = f.quotes(quote) (src/KeelV2Router.sol#197)\n[medium/medium] unused-return at src/KeelV2Factory.sol:271: KeelV2Factory.launch(string,string,string,address,int24,uint16,uint256,bytes) (src/KeelV2Factory.sol#271-330) ignores return value by poolManager.unlock(abi.encode(token)) (src/KeelV2Factory.sol#321)\n[medium/medium] unused-return at src/KeelV2Factory.sol:337: KeelV2Factory.unlockCallback(bytes) (src/KeelV2Factory.sol#337-367) ignores return value by (delta,None) = poolManager.modifyLiquidity(info.key,ModifyLiquidityParams(info.tickLower,info.tickUpper,int256(uint256(info.liquidity)),bytes32(0)),) (src/KeelV2Factory.sol#343-349)\n[medium/medium] unused-return at src/KeelV2Factory.sol:271: KeelV2Factory.launch(string,string,string,address,int24,uint16,uint256,bytes) (src/KeelV2Factory.sol#271-330) ignores return value by poolManager.initialize(key,TickMath.getSqrtPriceAtTick(- startTick)) (src/KeelV2Factory.sol#319)\n[medium/medium] unused-return at src/KeelV2Factory.sol:337: KeelV2Factory.unlockCallback(bytes) (src/KeelV2Factory.sol#337-367) ignores return value by poolManager.settle() (src/KeelV2Factory.sol#361)\n[medium/medium] unused-return at src/KeelV2Router.sol:359: KeelV2Router._executeBuy(KeelV2Router.Op) (src/KeelV2Router.sol#359-374) ignores return value by poolManager.settle{value: quoteIn}() (src/KeelV2Router.sol#368)\n[low/medium] reentrancy-benign at src/KeelV2Factory.sol:271: Reentrancy in KeelV2Factory.launch(string,string,string,address,int24,uint16,uint256,bytes) (src/KeelV2Factory.sol#271-330):\n[low/medium] reentrancy-benign at src/KeelV2Factory.sol:271: Reentrancy in KeelV2Factory.launch(string,string,string,address,int24,uint16,uint256,bytes) (src/KeelV2Factory.sol#271-330):\n[low/medium] reentrancy-benign at src/KeelHeart.sol:158: Reentrancy in KeelHeart.fund(address,uint256) (src/KeelHeart.sol#158-183):\n[low/medium] reentrancy-events at src/RateModuleBase.sol:50: Reentrancy in RateModuleBase.lowerRate(bytes32,uint16) (src/RateModuleBase.sol#50-58):\n[low/medium] reentrancy-events at src/KeelV2Factory.sol:337: Reentrancy in KeelV2Factory.unlockCallback(bytes) (src/KeelV2Factory.sol#337-367):\n[low/medium] reentrancy-events at src/RateModuleBase.sol:78: Reentrancy in RateModuleBase.applyRaise(bytes32) (src/RateModuleBase.sol#78-87):\n[low/medium] reentrancy-events at src/RateModuleBase.sol:70: Reentrancy in RateModuleBase.cancelRaise(bytes32) (src/RateModuleBase.sol#70-75):\n[low/medium] reentrancy-events at src/RateModuleBase.sol:60: Reentrancy in RateModuleBase.scheduleRaise(bytes32,uint16) (src/RateModuleBase.sol#60-68):\n[low/medium] timestamp at src/KeelV2Router.sol:246: KeelV2Router.buy(address,uint256,uint256) (src/KeelV2Router.sol#246-260) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelHeart.sol:299: KeelHeart._anchorBefore(address,uint256) (src/KeelHeart.sol#299-315) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Factory.sol:271: KeelV2Factory.launch(string,string,string,address,int24,uint16,uint256,bytes) (src/KeelV2Factory.sol#271-330) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Router.sol:263: KeelV2Router.sell(address,uint256,uint256,uint256) (src/KeelV2Router.sol#263-281) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelHeart.sol:133: KeelHeart.onBuy(address,address,address,uint256,uint256) (src/KeelHeart.sol#133-155) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelHeart.sol:186: KeelHeart.end() (src/KeelHeart.sol#186-192) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelHeart.sol:263: KeelHeart._finish(KeelHeart.Live) (src/KeelHeart.sol#263-278) uses timestamp for comparisons\n[low/medium] timestamp at src/RateModuleBase.sol:90: RateModuleBase.currentRate(bytes32) (src/RateModuleBase.sol#90-93) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Hook.sol:237: KeelV2Hook.splitFee(uint256,uint16,uint16) (src/KeelV2Hook.sol#237-246) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelHeart.sol:281: KeelHeart._potAt(address,uint256) (src/KeelHeart.sol#281-290) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Hook.sol:186: KeelV2Hook.beforeSwap(address,PoolKey,SwapParams,bytes) (src/KeelV2Hook.sol#186-205) uses timestamp for comparisons\n[low/medium] timestamp at src/RateModuleBase.sol:95: RateModuleBase._creator(bytes32) (src/RateModuleBase.sol#95-98) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Hook.sol:334: KeelV2Hook._beat(bytes32,KeelV2Hook.Pool,address,uint256,uint256,bytes) (src/KeelV2Hook.sol#334-366) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Hook.sol:368: KeelV2Hook._accrue(bytes32,KeelV2Hook.Pool,uint256,uint256) (src/KeelV2Hook.sol#368-382) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Hook.sol:286: KeelV2Hook.setCreatorByTakeover(address,address) (src/KeelV2Hook.sol#286-292) uses timestamp for comparisons\n[low/medium] timestamp at src/RateModuleBase.sol:78: RateModuleBase.applyRaise(bytes32) (src/RateModuleBase.sol#78-87) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Hook.sol:384: KeelV2Hook._pay(address,address,uint256) (src/KeelV2Hook.sol#384-399) uses timestamp for comparisons\n[low/medium] timestamp at src/KeelV2Hook.sol:314: KeelV2Hook._rates(bytes32,KeelV2Hook.Pool,bool,bytes) (src/KeelV2Hook.sol#314-331) uses timestamp for comparisons\n[low/medium] timestamp at src/RateModuleBase.sol:42: RateModuleBase.initialize(bytes32,uint16) (src/RateModuleBase.sol#42-48) uses timestamp for comparisons","passed":true},{"durationMs":1285,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/KeelV2Factory.sol:142: Reentrancy: State change after external call (10 places)\n[low] centralization-risk at src/KeelHeart.sol:105: Centralization Risk (17 places)\n[low] costly-loop at src/KeelHeart.sol:204: Costly operations inside loop\n[low] ecrecover at src/KeelV2Factory.sol:379: `ecrecover` Signature Malleability\n[low] internal-function-used-once at src/libraries/PulseMath.sol:37: Internal Function Used Only Once\n[low] large-numeric-literal at src/KeelHeart.sol:36: Large Numeric Literal (5 places)\n[low] literal-instead-of-constant at src/KeelV2Factory.sol:186: Literal Instead of Constant (38 places)\n[low] missing-inheritance at src/KeelV2Token.sol:5: Missing Inheritance\n[low] non-reentrant-not-first at src/KeelV2Hook.sol:189: `nonReentrant` is Not the First Modifier (2 places)\n[low] require-revert-in-loop at src/KeelHeart.sol:204: Loop Contains `require`/`revert` (2 places)\n[low] state-change-without-event at src/KeelV2Router.sol:287: State Change Without Event (2 places)\n[low] state-variable-could-be-immutable at src/KeelV2Token.sol:11: State Variable Could Be Immutable (2 places)\n[low] unchecked-return at src/KeelV2Factory.sol:319: Unchecked Return (8 places)\n[low] uninitialized-local-variable at src/KeelHeart.sol:204: Uninitialized Local Variable (2 places)\n[low] unsafe-erc20-operation at src/KeelV2Factory.sol:360: Unsafe ERC20 Operation\n[low] unused-public-function at src/KeelV2Hook.sol:257: Public Function Not Used Internally","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"2c2ac22cd15e1c29885056da59be97ac5541d13d74dbabd4fb490a853466cea6","verifiedTreeHash":"c106ab7e2a75138c76969ef458a6063ad98dd4d8","verifierVersion":"0.1.0+560ab6a2"}]}