{"assessments":[],"deployments":[{"attestationHash":"c526ed30452d80f082cf0598310fb018ef0e3bcec1caafecd93c4f6cb97c393f","chainId":1,"contracts":[],"id":"483690bf-88a1-4f01-ba09-3d4b43c0bd1a","manifestHash":"69007446b9818b121652b03e44b9987ab3fa6fc8a5dab9de04fd60820f6bd2a8","status":"parked"}],"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":"019d5d85-5f0a-4d6a-aeae-93163ae147fb","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"9e13024659960e331faf63026c45168d4b1da4190c6c846252718557113ecd48","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"615e352d79b89c2bd6e09418b7e5fb3839ae6f91b6764668b828af5ebe735cc1","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"1778763b7295cd41405e533a221b7bd5269c0866011af6404f514d5020ea2afb","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"3cdf5ce95280910864ecdf10513e1b04ca769276672c5281ab07e5100d3fa573","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"30371f3ea006815a9e1723b5c0bc5a0ec10ef8940320694a83a2d6fe268911cc","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"0d1b46897950bd873a5a1fb9bfacd06fe37764f1ecf2aa8ba7ba62e15bbb76a1","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"9eb588784d4871df6bcfd741af933829b283ed33abce76a26531d1c6b678bcbd","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"d13a894d87d06800e5d8d44e6e62326dd7dc62ebfee21bfe7555450a84e35faf","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"A custom token: Swarminu.xyz (SI).\nToken name: Swarminu.xyz\nToken symbol: SI\nToken supply: 1,000,000,000 with 18 decimals, all minted once to the deployer in the constructor.\nWhat it does: A custom token: Swarm Inu (SI), the INU for the IMD swarm.\n\nToken name: Swarm Inu\n\nToken symbol: SI\n\nToken supply: 1,000,000,000 with 18 decimals, all minted once to the deployer in the constructor.\n\nWhat it does: The token itself is a plain ERC20. No minting after launch, no owner powers, no transfer rules, no fee inside the token. All fee logic lives in the pool hook below.\n\nHook (Uniswap v4, SI/IMD pool): 2% fee on every swap, immutable, taken in the token the trader pays in. No swaps inside the hook or the vault.\nBuys (trader pays IMD, fee in IMD): 80% to the SI Community Vault, 20% to the creator receiver <YOUR_WALLET>.\nSells (trader pays SI, fee in SI): 50% burned forever to 0x000000000000000000000000000000000000dEaD, 50% locked in the SI Community Vault.\n\nSI Community Vault:\nHolds IMD and SI forever. No withdraw, no owner, no release time, no redeem or claim for holders. Its only function is to receive, so funds can never leave.\nAnyone can donate IMD or SI straight into it.\nPublic views: total IMD held, total SI locked, total SI burned.\nThe hook must never brick swaps if a transfer to the vault or receiver fails.\n\nPool: 88% Starting market cap: 2500 IMD Rest of supply to: 0x66522f25035C3FAFd2c6D950a506FDa457E06344\n\nput socials twitter: https://x.com/swarminu  website: https://www.swarminu.xyz/","parentJobId":null,"planHash":"28f00863853902a92eabfea227bb3d03e5a8ef946fb6b5c9472d0a03f9e4bb45","previousHash":"5b89fc4b1357d9c94fdb67b1058b9384075efff89d7d27e37d8d1b0637fb6534","projectId":"019d5d85-5f0a-4d6a-aeae-93163ae147fb","publication":{"commit":"e873a63e3ef5f2864cc4387812313d6ecaf53755","deliveredAt":"2026-10-06T18:20:37.250Z","repoUrl":"https://github.com/identity-md-launches/launch-826-swarm-inu"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"7103c9545fa2907877941124728fe6ca8a2dec3706b57914c366fe8b6530e4bf","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"75c6d4728922d69075f47152b79aeee37dba2c68f266b8831618f4f451feaf50","device":"76ce625b2d0c8171","findings":[],"hash":"0d1b46897950bd873a5a1fb9bfacd06fe37764f1ecf2aa8ba7ba62e15bbb76a1","nodeId":"2dc39020-f6af-4f62-bdb7-60cdb0c86bcd","outcome":"completed","summary":"Implemented the fixed-supply SI token, permanent vault, 2% fee hook, partial-fill router, and deployment planner with vendored dependencies.\n\nValidation passed: `forge build`, all **39 tests**, and `forge fmt --check`.\n\n[README](./README.md) documents deployment and assumptions: on-chain name is **Swarminu.xyz**; creator wallet and chain addresses remain explicit deployment inputs; partial exact-input fills require the supplied router. No transactions were broadcast.","treeHash":"5bb54a1552f46f945c2872c455343efcd4371f8a","usage":{"cachedInputTokens":1122048,"inputTokens":73786,"model":"gpt-6-astra","outputTokens":16175,"runtime":"codex","turns":5,"wallClockMs":516259}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"78f562a53c16db4c","findings":[{"citation":"resolved","description":"The executable manifest deploys SwarmInu and SICommunityVault only: neither SIFeeHook nor its required SISwapRouter is deployed. It also selects pool.fee = 3000, whereas SIFeeHook._checkPool requires fee = 0. All requested 2% input fees, buy-side 80/20 distributions, and sell-side burn/lock distributions exist exclusively in SIFeeHook. The supplied protected launch path initializes the pool with PoolInitializationGuard, which has no swap callbacks. Consequently a successful launch from these fields cannot provide the requested economics; the explanatory integration-blocker text in notes does not change execution. This merges the three specialists' launch-wiring reports and strengthens their conditional concern with the present manifest. Before admission, provide a supported factory/deployer path that actually deploys both contracts, initializes and seeds the pool with SIFeeHook, and reconciles the zero-LP-fee requirement with the accepted launch policy. Verify the approved creator receiver and constructor dependencies as part of that path; do not silently substitute a 0.3% LP fee for the requested charge.","line":11,"path":"launch.json","reproduction":"Trace launch.json: resolve token.constructorArgs = [] and deploy SwarmInu; iterate contracts and deploy only SICommunityVault($token, pairedCurrency). The list ends without constructing a hook or router. The protected harness at Token.protected.t.sol:165-175 deploys PoolInitializationGuard, and _key at :345-350 uses it with the manifest fee 3000 and spacing 60. Initialize that key at 2^96, seed a single-sided SI position with liquidity 1_000_000e18 over [0,60000] if SI is currency0 (otherwise [-60000,0]), then buy SI with exact input 1000e18 IMD and a nonbinding price limit. Expected: 20e18 IMD charged for the requested hook, 16e18 delivered or owed to the vault and 4e18 delivered or owed to the creator. Actual: SI is received but neither recipient receives or accrues any hook fee, because the launch never deploys or calls SIFeeHook. A local real-PoolManager scratch reproduction independently confirms that even deploying the omitted hook alongside a guard-key pool leaves vault and creator receipts and pending debts at zero; an outsider cannot initialize its separate fee pool because beforeInitialize reverts OnlyInitializer. Initializing that separate pool from the factory succeeds but does not move the liquidity from the guard-key pool. Production factory code is not supplied, so no undocumented hook-selection mechanism is assumed.","severity":"medium","snippet":"  \"contracts\": [\n    {\n      \"contract\": \"SICommunityVault\",\n      \"constructorArgs\": [\n        \"$token\",\n        \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\"\n      ]\n    }\n  ],","title":"The submitted launch manifest omits the entire required swap-fee system"},{"citation":"resolved","description":"beforeSwap reserves grossBudget/50 in the input currency. When the AMM stops at a price limit or liquidity boundary, afterSwap reaches this caller restriction even though a partial fill is otherwise valid. Standard callers therefore cannot execute these trades; the same parameters succeed through the configured SISwapRouter. The rollback is atomic and does not lose funds, so this is low severity. This merges the flow, permissions and math specialists' reports. The limitation is documented but still prevents ordinary router integration for oversized buys/sells. Provide a compatible execution and quoting path for the launch, or redesign partial-fill refunds while preserving input-currency fees; charging the unfilled budget or switching to an output-currency fee would violate the brief.","line":145,"path":"src/SIFeeHook.sol","reproduction":"Use test/SIFeeHook.t.sol setUp: SI is currency0, price = 2^96, fee = 0, tickSpacing = 60, liquidity = 1_000_000e18 over [-60000,60000], hook.partialFillRouter = router, and TRADER has IMD. Deploy alternate = new SISwapRouter(manager), and from TRADER approve alternate. Call alternate.swap(key, SwapParams(false, -1_000_000e18, TickMath.getSqrtPriceAtTick(60)), 1_000_000e18, 1, TRADER, block.timestamp). Expected: spend less than the budget, return the available SI up to the limit, and charge floor(actualGrossSpend/50). Actual: the transaction reverts with the nested SIFeeHook.PartialFillRequiresRouter selector. Calling the original router with the identical parameters succeeds, spends a positive amount below the budget, and its delivered fee equals actualGrossSpend/50. Executed in a focused scratch test against the real vendored PoolManager; the test explicitly checks the nested error selector, successful control trade, and fee-claim conservation.","severity":"low","snippet":"        if (sender != partialFillRouter) revert PartialFillRequiresRouter();","title":"Partial exact-input fills revert through every router except the immutable refund router"}],"hash":"0fdad288a9bab976df46e478c03dd87294a264c19bff55b653821b1aebb9e6dc","nodeId":"5b492bd8-b5d0-4ac0-903e-7ac787021a8d","outcome":"completed","summary":"Wrote [`.imd-findings.json`](/home/imd-worker-551/.identitymd/work/019d5d85-5f0a-4d6a-aeae-93163ae147fb/5b492bd8-b5d0-4ac0-903e-7ac787021a8d/.imd-findings.json) with two reproduced, deduplicated findings:\n\n- **Medium:** Launch manifest omits the required fee hook and router.\n- **Low:** Partial exact-input fills revert through alternate routers.\n\nCovered all 10 entry points. Existing tests and focused reproductions passed. Production files remain unchanged.","treeHash":null,"usage":{"cachedInputTokens":1463552,"inputTokens":126490,"model":"gpt-6-astra","outputTokens":13090,"runtime":"codex","turns":5,"wallClockMs":442828}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4ebee02fc506f27c","findings":[{"citation":"resolved","description":"ROUND THREE: STILL OPEN, NOT FIXED. Settling finding 39dbf63f292f3fdf9676a53eeaa6ee74c8bb9a76223d12f15502999c494f5d01. The tree is byte-identical in src/ and launch.json to the two previous rounds (git diff d47c44e..HEAD -- src is empty; the only commits since add tests and a merge). The author's answer is marked [disputed] but does not claim the defect fails to reproduce: it confirms reproduction and disputes only that a launch.json-only edit can close it. I agree with that factual point and have re-run both my reproduction and the author's four steps this round; every assertion-of-defect still passes. As submitted, launch.json deploys SwarmInu and SICommunityVault only; `contracts` (line 11) lists neither SIFeeHook nor SISwapRouter, and pool.fee (line 22) is 3000 while SIFeeHook._checkPool (src/SIFeeHook.sol:221, `key.fee != 0`) reverts InvalidPool for any non-zero fee tier and SIFeeHook.beforeInitialize (src/SIFeeHook.sol:94, `if (sender != initializer) revert OnlyInitializer();`) lets only the hook's CREATE2 deployer open the fee pool. Every economic rule the brief commissions (2% input-currency fee, 80/20 IMD to vault and creator on buys, 50/50 SI burn and lock on sells, vault accrual) lives exclusively in SIFeeHook, and the admission harness initialises and seeds the 88% liquidity in a pool hooked to PoolInitializationGuard, which has no swap callbacks. A launch from these manifest fields therefore ships a plain token with an empty vault, no creator revenue and no burn, while the project's name, notes and socials describe a fee. The author documents this honestly in the manifest notes and README, but notes carry no deployment authority. The severity stays medium: no funds are lost or misdirected, but the commissioned guarantee is broken for the launched liquidity and cannot be repaired afterwards by anyone other than the factory. Resolution is a scope decision outside the author's write budget and I record it as such rather than restating a manifest demand: (a) the network confirms a supported factory path that deploys SISwapRouter and a hook mined to low bits 0x20cc, initialises PoolKey{SI, IMD, fee 0, spacing 60, hooks = SIFeeHook} from the same address that executed the hook's CREATE2, and seeds the 88% there; then the manifest lists SISwapRouter and SIFeeHook with a verified PoolManager address and the requester's real creator receiver in place of <YOUR_WALLET>, and pool.fee becomes 0; or (b) the requester accepts a fee-free launch, which changes the commissioned deliverable and only they can decide it. Until one of these is on record, the implementation does not do what the brief commissions. No change in src/ alone bridges the gap: a hook that accepted fee 3000 or permissionless initialisation would still leave the seeded liquidity in the guard-hooked pool. This merges the flow, economics and permissions specialists' reports and the author's own reproduction.","line":11,"path":"launch.json","reproduction":"Re-executed this round in test/scratch/RoundThreeSettle.t.sol (3 passing assertions-of-defect against the vendored PoolManager). State: a factory stand-in shaped like the protected harness's LaunchProbe CREATE2-deploys SwarmInu, SICommunityVault(si, imd), SISwapRouter(manager), PoolInitializationGuard (low 14 bits 0x2000) and SIFeeHook (low 14 bits 0x20cc, creator 0xC0FFEE); IMD is a plain ERC20 etched at the manifest's pairedCurrency 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7; hook.initializer() == factory. Step 1, the manifest's pool: factory initialises PoolKey(SI, IMD, 3000, 60, guard) at sqrtPriceX96 2^96 and seeds 1_000_000e18 single-sided SI ([0,60000] when SI is currency0, else [-60000,0]). A plain unlock-callback trader (TraderProbe shape) buys with exact input 1000e18 IMD at a non-binding limit. Expected per brief: 20e18 IMD fee, 16e18 to vault, 4e18 to creator. Actual: trader receives SI and spends all 1000e18 IMD; vault.totalIMDHeld() == 0, imd.balanceOf(creator) == 0, hook.pending(imd, vault) == 0, the hook's ERC6909 IMD claims == 0. Selling the acquired SI back succeeds with vault.totalSILocked() == 0 and vault.totalSIBurned() == 0. Step 2: factory initialises PoolKey(SI, IMD, 3000, 60, SIFeeHook) -> reverts with CustomRevert.WrappedError(hook, beforeInitialize.selector, InvalidPool(), HookCallFailed()) (matched exactly). Step 3: address 0xBAD initialises PoolKey(SI, IMD, 0, 60, SIFeeHook) -> reverts WrappedError(hook, beforeInitialize.selector, OnlyInitializer(), HookCallFailed()). Step 4: after the factory seeds the guard pool, it initialises the fee-0 hook key successfully, but StateLibrary.getLiquidity(feePoolId) == 0 while getLiquidity(guardPoolId) == 1_000_000e18: the launched liquidity stays in the fee-free pool. The author's four tests in test/scratch/ManifestWiringReproduction.t.sol describe the same steps and outcomes.","severity":"medium","snippet":"  \"contracts\": [","title":"The submitted launch manifest omits the entire required swap-fee system (launch.json line 11)"},{"citation":"resolved","description":"ROUND THREE: NOT FIXED, code unchanged, advisory severity retained. Settling finding 91f0f3722f8b6f65a2eb58cfd27ab725b414c4a13ce60f549594546d190e7ed4. beforeSwap (src/SIFeeHook.sol:111) reserves grossBudget/50 of the specified input currency before the core swap. When the AMM stops at a price limit or at the edge of the single-sided range, afterSwap enters _exactInputFee with netInput != gross - reserved and can return the over-reserved input only by minting an ERC6909 refund claim to `sender`; for any sender other than the immutable SISwapRouter it reverts the whole swap at line 145. Standard v4 callers (a plain unlock-callback trader, Universal Router, V4Quoter) therefore cannot execute or quote an oversized exact-input buy or sell into this pool, which is the ordinary large market order at launch, and once the pool's IMD reserve is thin every non-router exact-input sell larger than that reserve reverts. The revert is atomic, no funds move, and README line 35 documents the restriction, so this stays low. The author did not answer it in either round and no code changed. Resolution remains a design choice: keep it as a documented integration constraint (offer only SISwapRouter in the frontend and quote through it), or, for non-router senders, keep the full reserved amount as the fee instead of reverting (over-charging by at most 2% of the unfilled remainder the trader already bounded with amountIn). Charging in the output currency would violate the brief. This merges the flow, permissions and math specialists' reports.","line":145,"path":"src/SIFeeHook.sol","reproduction":"Re-executed this round in test/scratch/RoundThreeSettle.t.sol test_partialFillRevertsThroughAlternateRouter: factory-deployed system as above, pool PoolKey(SI, IMD, 0, 60, SIFeeHook) initialised by the factory at 2^96, two-sided liquidity 1_000_000e18 over [-60000, 60000], hook.partialFillRouter() == router. Deploy alternate = new SISwapRouter(manager); trader 0xB0B holds 4_000_000e18 IMD and approves both routers. Call alternate.swap(key, SwapParams(zeroForOne = IMD is currency0, amountSpecified = -1_000_000e18, sqrtPriceLimitX96 = getSqrtPriceAtTick(-60) or getSqrtPriceAtTick(60)), 1_000_000e18, 1, trader, block.timestamp). Expected for a 2%-of-input fee pool: partial fill up to the limit, fee = floor(actualAmmInput/49). Actual: revert with CustomRevert.WrappedError(hook, afterSwap.selector, PartialFillRequiresRouter(), HookCallFailed()) (matched exactly with expectRevert). Control: router.swap with identical parameters succeeds, spends a positive amount strictly below 1_000_000e18, the returned delta's input component equals the IMD actually taken from the trader, and vault + creator deliveries plus pending equal floor((spent - fee)/49), i.e. 2% of the gross actually paid.","severity":"low","snippet":"        if (sender != partialFillRouter) revert PartialFillRequiresRouter();","title":"Partial exact-input fills revert through every router except the immutable refund router (src/SIFeeHook.sol line 145)"}],"hash":"1778763b7295cd41405e533a221b7bd5269c0866011af6404f514d5020ea2afb","nodeId":"5b492bd8-b5d0-4ac0-903e-7ac787021a8d","outcome":"completed","summary":"Review settled. The findings file is written and no tracked file was changed.\n\n**Outcome: both earlier findings remain open.** The code and manifest the author submitted this round are byte-identical to the previous two rounds in `src/` and `launch.json`. The only new commits add tests and a merge. I re-ran both reproductions in a scratch test against the vendored PoolManager, and every assertion-of-defect still passes.\n\n- **Medium, still open: the manifest omits the swap-fee system.** The author's answer confirms the defect reproduces and disputes only that a manifest-only edit can close it. I agree with that factual point, and it does not close the finding. As submitted, the launch deploys the token and vault only, with pool fee 3000. The hook rejects any non-zero fee tier, only the hook's deployer may open the fee pool, and the harness seeds the 88% liquidity in a pool hooked to the guard, which has no swap callbacks. A buy of 1000 IMD on that pool leaves the vault, creator and hook claims at zero. Opening the fee-0 hook pool from the factory succeeds but holds zero liquidity. Resolution is a scope decision outside the author's write budget, and I recorded it as such: either the network confirms a factory path that opens and seeds the hooked pool and the manifest then lists the router and hook, or the requester accepts a fee-free launch.\n\n- **Low, still open: partial exact-input fills revert except through the immutable router.** Unchanged code, unanswered in both rounds. An alternate router hitting a price limit reverts with the wrapped `PartialFillRequiresRouter` error. The project's own router completes the same partial fill and charges 2% of the gross actually paid. Atomic, no funds move, documented in the README, so it stays advisory.\n\n**Nothing new reported.** I traced all ten listed entry points plus two invariants and recorded them in the coverage block: eight hold, one carries finding 2, and the manifest gap is anchored to the `contracts` array rather than to a hook function. The full suite passes 58 of 58 tests. The static-analysis leads were reentrancy warnings on paths guarded by the swapping and flushing flags and ignored return values on settlement helpers whose return is checked elsewhere, and none reproduced as defects.","treeHash":null,"usage":{"cachedInputTokens":908657,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":17308,"runtime":"claude","turns":22,"wallClockMs":352768}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"47470357c74e4755","findings":[{"citation":"resolved","description":"Trust gap (access x economics). Every economic guarantee in the brief (2% fee, 80/20 IMD split to vault and creator, 50/50 SI burn/lock) lives in SIFeeHook, which only takes effect if the SI/IMD pool is initialised with PoolKey.hooks == SIFeeHook. Nothing in the delivered tree or in the launch manifest schema (pool has only pairedCurrency, fee, tickSpacing, initialPrice; no hooks field) carries that choice to the factory. The network's own admission harness (.imd/reads/protected/custom_token/Token.protected.t.sol lines 165-175 and 345-350) initialises the launch pool with a PoolInitializationGuard it mines itself, and src/PoolInitializationGuard.sol:9 admits 'This guard does not collect SI fees'. If the factory follows that pattern (the harness is described as doing it 'exactly as the factory will'), the 88% liquidity is seeded into a fee-free pool: no IMD ever reaches the vault, the creator receives nothing, no SI is burned, and SICommunityVault's three views stay at zero forever. The gap is unrecoverable after launch because SIFeeHook.beforeInitialize (line 94) only lets the hook's constructor deployer initialise the fee pool, so no community member can later open the intended pool, and the factory has no second launch step. README.md line 98 lists 'confirm that its launch factory can select this custom fee hook' as an open operator item, so this is a known service/configuration gap, but it is the one that decides whether the commissioned economics exist at all. Needed evidence before admission: confirmation that ProjectFactory.launchCustom can set PoolKey.hooks to $contract:SIFeeHook (with fee 0 and tickSpacing 60, which the hook hard-requires in _checkPool at lines 218-226) and that the address calling PoolManager.initialize is the same address that executed the hook's CREATE2 (so initializer matches). If it cannot, the author must either accept a fee-free launch pool or move the fee logic into the token, which the brief forbids.","line":94,"path":"src/SIFeeHook.sol","reproduction":"State: factory deploys SwarmInu, SICommunityVault, SISwapRouter and SIFeeHook (mined 0x20cc flags) exactly as PrepareLaunch plans, then initialises PoolKey(SI, IMD, 0, 60, PoolInitializationGuard) at sqrtPriceX96 = 2^96 and seeds 1_000_000e18 liquidity in ticks [0, 60000], the shape the protected harness uses. Input: a third-party router buys with exact input 1000e18 IMD (zeroForOne=false, limit MAX_SQRT_PRICE-1). Expected per brief: 20e18 IMD fee, 16e18 to vault, 4e18 to creator. Actual: vault.totalIMDHeld() == 0, imd.balanceOf(creator) == 0, hook.pending(imd, vault) == 0, and the hook's beforeSwap/afterSwap were never invoked. Then: any address other than the factory calling PoolManager.initialize(PoolKey(SI, IMD, 0, 60, SIFeeHook), 2^96) reverts through OnlyInitializer, so the fee pool can never be created afterwards. Executed in test/scratch/AccessProbe.t.sol (test_guardPoolChargesNoFeeAndVaultStaysEmpty, test_onlyFactoryInitialisesFeePool) against the vendored PoolManager.","severity":"medium","snippet":"        if (sender != initializer) revert OnlyInitializer();","title":"Fee hook is not attached by the launch flow the network models; a pool hooked to PoolInitializationGuard charges no fee and only the factory can ever create the fee pool"},{"citation":"resolved","description":"Access x asymmetry. The hook reserves 2% of an exact-input budget in beforeSwap and, when the core swap stops short of the budget (price limit reached or liquidity exhausted), can only hand the unused reservation back to one hard-coded caller. Any other msg.sender of PoolManager.swap (Uniswap's Universal Router / V4Router, aggregators, or the TraderProbe pattern the network harness uses) sees the whole swap revert instead of the partial fill v4 normally returns. Exact-output swaps and full exact-input fills are not affected, and nothing is lost: the revert is atomic. The condition is reachable in ordinary use whenever the pool holds less of the output currency than the trade needs, which after a single-sided launch is every sell larger than the IMD the pool has accumulated. This is documented in README.md line 35 as intended, so it is reported as a behavioural asymmetry for the author to weigh, not as a loss.","line":145,"path":"src/SIFeeHook.sol","reproduction":"State: fee pool initialised and seeded single-sided with SI only (ticks [0, 60000], 1_000_000e18 liquidity), so the pool holds ~0 IMD. Input A: a plain router (manager.swap then LaunchLiquidity.settle for both currencies, as TraderProbe does) sells exact input 1000e18 SI (zeroForOne=true, limit MIN_SQRT_PRICE+1). Expected under standard v4 semantics: partial (here zero) fill, no revert. Actual: the whole swap reverts with PartialFillRequiresRouter from afterSwap line 145. Input B: the same sell through SISwapRouter.swap(key, params, 1000e18, 0, trader, deadline) succeeds, charges 0 input and returns 0 output, trader's SI balance unchanged. Executed in test/scratch/AccessProbe.t.sol test_partialExactInputThroughPlainRouterReverts.","severity":"low","snippet":"        if (sender != partialFillRouter) revert PartialFillRequiresRouter();","title":"Exact-input swaps that cannot fully fill revert for every router except the trusted SISwapRouter"},{"citation":"resolved","description":"Trust gap (economics x asymmetry, no loss). The fee is always charged and always backed by ERC6909 claims held by the hook, and flush() lets anyone deliver it to the fixed recipient, so funds cannot be lost or redirected. But the trader, not the recipient, decides whether delivery happens in the swap: a swap transaction sent with a tight gas limit skips the self-call at line 201 and leaves the vault and creator shares in pending; every early buy also defers because PoolManager holds no IMD until the trader settles after afterSwap. Until someone pays gas to call flush, SICommunityVault.totalIMDHeld undercounts, the creator is unpaid, and the pending IMD sits as claims the hook cannot use for anything else. There is no keeper reward and no on-chain nudge; README.md line 39 assigns this to an off-chain keeper or UI. Reported so the operator provisions that keeper before launch.","line":201,"path":"src/SIFeeHook.sol","reproduction":"State: fee pool seeded; one buy of 1000e18 IMD already flushed so PoolManager holds IMD. Input: trader calls SISwapRouter.swap{gas: 400000}(key, SwapParams(false, -1000e18, MAX_SQRT_PRICE-1), 1000e18, 0, trader, deadline). Expected if payouts were unconditional: vault +16e18 IMD, creator +4e18. Actual: swap succeeds, hook.pending(imd, vault) == 16e18, hook.pending(imd, creator) == 4e18, hook's IMD claim balance == 20e18, vault and creator balances unchanged until flush(imd, vault, 16e18) and flush(imd, creator, 4e18) are called by anyone. Executed in test/scratch/AccessProbe.t.sol test_lowGasSwapDefersButKeepsFee.","severity":"info","snippet":"        if (gasleft() > PAYOUT_GAS + 150_000) {","title":"Automatic payout is skipped whenever a swap arrives with under about 270k gas remaining or the manager holds less of the fee currency than the fee; delivery then depends on an unrewarded flush"}],"hash":"30371f3ea006815a9e1723b5c0bc5a0ec10ef8940320694a83a2d6fe268911cc","nodeId":"38fe557c-8d9f-4c4f-9002-be042bbe0e55","outcome":"completed","summary":"Review complete. The findings file is written at `.imd-findings.json` with all three snippets verified against the tree and 14 coverage rows, one for each of the 10 listed entry points plus the two `beforeInitialize` callbacks, the vault, and the claim-backing invariant.\n\n**Outcome: no access-control bypass, privilege escalation, or asymmetric-accounting defect in the code itself.** Every guard I traced held under adversarial testing against the real vendored PoolManager: pool initialisation is deployer-only, hook claims cannot be moved or burned by outsiders, reentry from an IMD transfer callback is blocked in both flush and afterSwap, flush can only pay the recorded recipient, and every callback rejects direct callers.\n\n**What I reported:**\n\n- **Medium, launch wiring gap.** The entire fee economics live in `SIFeeHook`, but nothing in the tree or the manifest schema tells the factory to attach it. The network's own admission harness initialises the pool with `PoolInitializationGuard`, which charges nothing. A 1000 IMD buy through such a pool leaves the vault, creator and burn at zero. Because `beforeInitialize` is deployer-only, nobody can create the fee pool afterwards. This is a known open item in the README, but it decides whether the commissioned economics exist at all, so the judge needs the evidence request: confirmation the factory can set the hook and that the initialising address equals the hook's CREATE2 deployer.\n- **Low, router asymmetry.** Exact-input swaps that cannot fully fill revert for every router except the trusted `SISwapRouter`. After a single-sided launch that means any sell larger than the pool's IMD reverts through standard routers. Documented and atomic, no loss.\n- **Info, keeper dependency.** A swap sent with a tight gas limit, or any early buy before the manager holds IMD, leaves fees pending until an unrewarded `flush`. Fees stay charged and fully backed.\n\n**Coverage:** all ten listed entry points answered. Seven hold, `afterSwap` carries the low finding, and both `beforeInitialize` variants carry the medium. The scratch suite that produced the reproductions is at `test/scratch/AccessProbe.t.sol` and passes in full. No production file was changed.","treeHash":null,"usage":{"cachedInputTokens":1464689,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":49430,"runtime":"claude","turns":44,"wallClockMs":689360}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2dc755dfe7bd177c","findings":[{"citation":"resolved","description":"Math Precision / zero-rounding. The 2% fee is computed with floor division in both branches: `reserved = gross / 50` for exact input (src/SIFeeHook.sol:111, re-used at :141-142) and `fee = netInput / 49` for exact output and partial fills (src/SIFeeHook.sol:130, :146). The Pashov guide's rule is that fees round UP; here they round DOWN, so the shortfall is always borne by the vault/creator/burn and never by the trader. The effective rate oscillates between 0% and 2%: gross 49 -> 0%, 50 -> 2%, 99 -> 1.01%, 100 -> 2%, 149 -> 1.34%. The split then truncates again (`fee / 5`, `fee / 2`, src/SIFeeHook.sol:187) but the remainder is assigned to the vault so the split always sums to `fee`. With 18-decimal tokens the maximum loss is 49 wei per swap, non-compounding, and splitting a trade into sub-50-wei chunks costs orders of magnitude more gas than the fee avoided, so this is not economically exploitable. It is reported because the brief states '2% fee on every swap' and the README already acknowledges 'Tiny swaps can round to zero'; the author should decide whether `(gross + 49) / 50` rounding-up is wanted. No change to design is required.","line":111,"path":"src/SIFeeHook.sol","reproduction":"Deployed SI/IMD pool, hook at a 0x20cc address, liquidity 1e24 over ticks [-60000, 60000] at price 1.0, TRADER approved to SISwapRouter.\n1) router.swap(key, SwapParams(zeroForOne=IMD->SI, amountSpecified=-49, limit=MIN+1), maxInput=max, minOutput=0, TRADER, now): delta input = 49, output = 48, vault.totalIMDHeld() + imd.balanceOf(creator) = 0. Expected by the brief: 2% of 49 (rounded up, 1 wei). Actual: 0.\n2) Same with amountSpecified=-50: fee = 1 (2%). With -99: reserved = 99/50 = 1, AMM receives 98, fee 1 => 1.01%.\n3) Exact output: router.swap(..., amountSpecified=+48 (SI out), ...): AMM input X=49, fee = 49/49 = 1, gross = 50 => 2%; with X=48 fee would be 0.\n4) Fuzz (256 runs, budget in [1, 1e24], arbitrary price limit): fee == floor(gross/50) on full fills and == floor(ammInput/49) on partial fills; hook ERC6909 claims == pending[vault] + pending[other] after every run. These numbers were produced by test/scratch probes run against this tree; the per-swap shortfall is strictly < 50 wei.","severity":"info","snippet":"        uint256 reserved = params.amountSpecified < 0 ? uint256(-params.amountSpecified) / 50 : 0;","title":"Fee truncates toward the trader: exact-input swaps below 50 wei and exact-output swaps whose AMM input is below 49 wei pay zero fee; every swap under-collects by up to 49 wei"},{"citation":"resolved","description":"Boundary (external-call corner case: partial fill). `beforeSwap` reserves `gross/50` as a specified-currency hook delta before the core swap runs. v4 only lets `afterSwap` return a delta in the *unspecified* currency, so when the pool consumes less than `gross - reserved` (price limit or liquidity edge reached) the hook cannot give the unused reservation back through the swap delta; it instead mints an ERC6909 refund claim to `sender`, and only when `sender == partialFillRouter`. Any other `sender` — a direct PoolManager caller, Uniswap's Universal Router, PositionManager-style routers, and V4Quoter (whose simulation calls `poolManager.swap` with itself as sender) — hits this revert (surfaced by PoolManager as `HookCallFailed()`/`Wrap__FailedHookCall` wrapping `PartialFillRequiresRouter()` 0x72ca16d0). Practical consequence: in the launch pool, which is single-sided SI, the pool's IMD reserve is only what buyers have paid in; a holder who tries to sell more SI than that reserve can absorb through any standard router gets a revert instead of a partial fill, and a frontend using V4Quoter cannot quote that trade at all (the quote itself reverts). Funds are not at risk and state is unchanged on revert, which is why this is low. The README documents the limitation ('Use SISwapRouter for partial exact-input fills'), so this is a design trade-off the author should confirm, not a permission bypass. A minimal alternative that keeps the 2%-of-input rule is to charge the fee entirely in `afterSwap` on the actual `netInput` for all callers (as the exact-output path already does) by returning `netInput/49` as the unspecified delta — but that changes the input/output currency of the fee for exact-input swaps, so it needs a scope decision.","line":145,"path":"src/SIFeeHook.sol","reproduction":"State: SI is currency0, pool initialised at sqrtPrice 2^96 (tick 0), single-sided SI liquidity 1e24 over ticks [0, 60000] (the launch shape), creator = 0xC0FFEE. A DirectTrader contract (unlock -> poolManager.swap -> settle, identical to the protected harness's TraderProbe) holds 1000 IMD and 1,000,000 SI.\n1) DirectTrader.swap(key, SwapParams(zeroForOne=false, -1000e18, MAX_SQRT_PRICE-1)): succeeds, receives 979.040540270534875821 SI; fee 20 IMD distributed 16/4.\n2) DirectTrader.swap(key, SwapParams(zeroForOne=true, -2000e18, MIN_SQRT_PRICE+1)): the pool can only absorb the IMD it holds, price reaches tick 0 where liquidity ends, swap is a partial fill, afterSwap -> _exactInputFee -> `sender != partialFillRouter` -> revert. Observed revert data: Wrap__FailedHookCall(hook, 0x72ca16d0 /* PartialFillRequiresRouter() */) wrapped by HookCallFailed. Expected by a standard-router user: a partial fill returning the available IMD.\n3) Same parameters through SISwapRouter.swap(key, params, maxInput=max, minOutput=0, TRADER, now): succeeds as a partial fill (e.g. in a comparable run: input 999.02 SI consumed, 979.99 IMD out, fee = floor(999.02e18/49) split 50/50 vault/dead).\n4) Selling exactly the 979.04 SI bought in (1) through DirectTrader succeeds (full fill), confirming only the limit-reached case is affected.","severity":"low","snippet":"        if (sender != partialFillRouter) revert PartialFillRequiresRouter();","title":"Exact-input swaps that stop at the price limit revert for every caller except SISwapRouter, so standard routers and V4Quoter cannot execute or quote an over-sized sell or buy into this pool"}],"hash":"3cdf5ce95280910864ecdf10513e1b04ca769276672c5281ab07e5100d3fa573","nodeId":"c4021071-7c3e-4ded-8f95-167d7cfdde70","outcome":"completed","summary":"The review is complete. `.imd-findings.json` is written at the repository root; no source files were changed (scratch tests were removed, and the only other artefacts are the ignored `out/`/`cache/` build dirs).\n\n## Summary\n\n**Area:** Math Precision, Boundary, Numerical Gap (Pashov guides), applied to `SIFeeHook`, `SISwapRouter`, `SwarmInu`, `SICommunityVault`, `LaunchLiquidity`, and the `PrepareLaunch` price planner.\n\n**What I traced and confirmed holds**\n- The custom-accounting delta flow against the vendored v4 `Hooks`/`Pool`/`SwapMath`: exact-input reserves `gross/50` before the core swap, full fills are detected exactly (the pool consumes `amountToSwap` to the wei when it does not hit the limit, including with a protocol fee), partial fills charge `netInput/49` and refund the unused reservation as an ERC6909 claim; exact-output charges `netInput/49` as the unspecified delta. The hook's own delta nets to zero on every path, and `refund` can never underflow (`floor(netInput/49) ≤ floor(gross/50)` for every partial `netInput`).\n- Claim backing (`claims == pending[vault] + pending[other]`), split sums, atomic rollback at the self-call boundary, the 120k payout gas cap (inline delivery still succeeds with a token doing several extra storage writes per transfer), `flush` bounds and flag resets, router refund/settle equality — all confirmed with the existing suite plus 256-run fuzzing of partial fills in scratch tests.\n- `PrepareLaunch._sqrtPrice` recomputed independently in Python for decimals 0/6/18/36 in both currency orders; matches, with no Newton-step overflow.\n\n**Findings (2, neither severe)**\n1. **Info** – fee rounds *down* (guide says fees round up): exact-input < 50 wei and exact-output with AMM input < 49 wei pay zero; max shortfall 49 wei/swap, non-compounding, already acknowledged in the README.\n2. **Low** – exact-input swaps that stop at the price limit revert (`PartialFillRequiresRouter`, surfaced as `HookCallFailed`) for any caller other than `SISwapRouter`, so Universal-Router users and V4Quoter cannot execute or quote an over-sized sell in the single-sided launch pool. Documented design trade-off; no funds at risk.\n\n**Coverage:** all 10 listed entry points have rows (8 `holds`, 2 `finding`), plus 5 invariant/open-item rows. One open item for the judge, not citable as a code defect: the protected harness attaches `PoolInitializationGuard`, which charges no fee — the production launch must attach `SIFeeHook` with `fee=0`, `tickSpacing=60`, and no `launch.json` exists in this tree to verify that.","treeHash":null,"usage":{"cachedInputTokens":2849067,"inputTokens":55,"model":"claude-fable-5-1","outputTokens":60744,"runtime":"claude","turns":29,"wallClockMs":849429}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4dd74fd7c315da80","findings":[{"citation":"resolved","description":"First-principles / execution-trace gap between the requirement and the launch flow. The requester's brief puts every fee rule in the SI/IMD pool hook (2% in the input token, 80/20 to vault and creator on buys, 50/50 burn and vault on sells). SIFeeHook enforces that the only pool it serves is {SI, IMD, fee 0, tickSpacing 60, hooks = itself} (_checkPool, lines 218-226) and that this pool may be initialized only by `initializer`, the address that deployed the hook (line 94). Under the network's custom-token launch, application contracts are deployed through the factory's CREATE2, so `initializer` is the factory, and the factory is also the only party that initializes and seeds the launch pool. The LaunchManifest schema's `pool` object carries only pairedCurrency, fee, tickSpacing and initialPrice; there is no field through which the factory can be told to use SIFeeHook as `PoolKey.hooks`. The supplied protected harness, which 'seeds the pool exactly as the factory will', builds its pool key with its own PoolInitializationGuard as the hook (Token.protected.t.sol lines 165-175 and 345-350). If the production factory behaves the same way, the launch pool has no fee hook, every swap is fee-free, the SI Community Vault and creator receiver never receive anything, nothing is ever burned, and no second party can ever repair this because initializing the hook's pool from any other address reverts with OnlyInitializer. README.md line 98 already lists 'confirm that its launch factory can select this custom fee hook' as an open item, so this is a known scope decision rather than a coding slip, but it is the single largest gap between the brief and what ships and it needs an explicit answer (factory hook selection, or a different mechanism) before admission. Fix options, both requiring a scope decision: (a) the network's factory accepts an application contract address as PoolKey.hooks for this launch, with fee 0 and spacing 60; or (b) the hook drops the OnlyInitializer restriction and pins the opening price so anyone can create the hooked pool, accepting that it would then be a second pool beside the factory's fee-free one and would not satisfy 'fee on every swap'.","line":94,"path":"src/SIFeeHook.sol","reproduction":"State: PrepareLaunch.prepare(factory, manager, imd, creator, 7, 18) and deploy token, vault, router and hook through the factory's CREATE2 (as the harness does), so hook.initializer() == factory. Step 1: from any address other than the factory call manager.initialize(plan.pool, plan.sqrtPriceX96). Expected per brief: the hooked SI/IMD pool exists. Actual: revert, wrapped SIFeeHook.OnlyInitializer. Step 2: the factory initializes the pool key it is able to build without a hook field, i.e. (SI, IMD, 0, 60, PoolInitializationGuard) and seeds 1e18 liquidity single-sided; a trader buys with exact input 100 IMD through a plain unlock-callback trader. Expected per brief: 2 IMD fee, 1.6 IMD to the vault and 0.4 IMD to the creator. Actual: trader receives SI, vault.totalIMDHeld() == 0, hook.pending(imd, vault) == 0, creator receives 0; the hook never executes. Verified locally with a scratch Foundry test against the vendored PoolManager (both assertions hold on the current tree).","severity":"medium","snippet":"        if (sender != initializer) revert OnlyInitializer();","title":"Fee hook can only be bound to a pool the factory initializes, but the launch manifest cannot name a hook: the 2% fee, vault and burn flows are unreachable on the launch pool"},{"citation":"resolved","description":"Execution trace: beforeSwap reserves floor(gross/50) of an exact-input budget as a specified-currency hook delta before the core swap. If the core swap stops early (price limit hit, or the single-sided SI range is exhausted on a large buy), afterSwap computes netInput != gross - reserved and enters _exactInputFee, which can only return the over-reserved input to the trader by minting ERC6909 claims to `sender` and relying on that sender to burn them. For any sender other than the immutable partialFillRouter the hook reverts the whole swap instead (line 145). Consequences: (1) a user of the Universal Router or any other integrator who sends an exact-input buy larger than the remaining SI in range, or any exact-input swap with a tight sqrtPriceLimit, gets a revert rather than the partial fill a hook-less v4 pool would give; (2) once the LP position is ever removed, every exact-input swap from a non-router caller reverts with this error. No funds are lost (the revert is atomic and the existing test test_alternateRouterFullFillWorksButPartialFillRollsBack shows vault and trader balances unchanged) and README.md line 35 documents the restriction, so severity is low. It is reported because the brief says the hook 'must never brick swaps' and because the failure mode is the ordinary large market buy at launch. A minimal fix that keeps the input-currency fee: for non-router senders, keep the full reserved amount as the fee instead of reverting (over-charging by up to 2% of the unfilled remainder, which the trader bounded with amountIn) or document the restriction in the integration notes consumed by the frontend so only SISwapRouter is offered.","line":145,"path":"src/SIFeeHook.sol","reproduction":"State: pool from test/SIFeeHook.t.sol setUp (SI/IMD, fee 0, spacing 60, SIFeeHook, 1e24 liquidity in [-60000, 60000]); TRADER approves a second SISwapRouter instance `alternate` (any contract that is not hook.partialFillRouter()). Call: alternate.swap(key, SwapParams(zeroForOne = IMD is currency0, amountSpecified = -1_000_000e18, sqrtPriceLimitX96 = getSqrtPriceAtTick(-60 or +60)), maxInput 1_000_000e18, minOutput 1, TRADER, block.timestamp). Expected for a 2%-fee pool: partial fill up to the price limit, fee = 2% of the amount actually paid. Actual: revert bubbled from SIFeeHook.afterSwap with PartialFillRequiresRouter; the same call through hook.partialFillRouter() succeeds and charges floor(spent/50). Same outcome for a plain unlock-callback trader (TraderProbe shape) whose exact-input buy exceeds the SI remaining in the seeded range.","severity":"low","snippet":"        if (sender != partialFillRouter) revert PartialFillRequiresRouter();","title":"Exact-input swaps that end as partial fills revert for every caller except SISwapRouter, so market buys that exhaust the single-sided range fail through standard routers"}],"hash":"615e352d79b89c2bd6e09418b7e5fb3839ae6f91b6764668b828af5ebe735cc1","nodeId":"17d1b0b7-0706-44ff-8a95-33accfda9dff","outcome":"completed","summary":"The findings file is in place and the tree is clean apart from it and build caches, which git excludes by design.\n\n**Outcome:** The hook, router and token hold up well under the Execution Trace, Periphery and First Principles passes. I report two defects, neither a loss-of-funds bug, both substantiated against the vendored Uniswap v4 PoolManager. No critical or high finding, so no proof file is attached.\n\n**Findings written to `.imd-findings.json`:**\n\n- **Medium, hook attachment gap.** The fee hook accepts pool initialization only from the address that deployed it, which under the launch flow is the factory. The manifest schema has no hook field, and the protected harness builds the launch pool with its own initialization guard. If the production factory does the same, the launch pool trades with no fee, the vault and creator receive nothing, nothing burns, and nobody else can ever create the hooked pool. A scratch test confirmed both halves: outside initialization reverts with OnlyInitializer, and a guard-keyed pool leaves the vault at zero after a buy. The README already lists this as an open item, so it needs an explicit scope decision rather than a code patch.\n- **Low, partial-fill revert.** Exact-input swaps that stop early revert for every caller except the project's own router. That includes the ordinary large market buy that exhausts the single-sided range through a standard router. The revert is atomic and documented, so severity is low.\n\n**What held:** I traced the delta algebra for all four swap shapes through the v4 Hooks library, the claim backing of pending payouts, the self-call rollback boundary, flush retry and reentry guards, router refund handling with a hostile pool key, and the token's launch flows against the protected harness. All 39 project tests pass, and the protected harness compiles against the vendored helpers.\n\n**Coverage:** All ten listed entry points have rows, plus rows for beforeInitialize, the launch periphery library, the guard, and two invariants. Nothing was left unreached. Scratch files were removed before finishing.","treeHash":null,"usage":{"cachedInputTokens":1411718,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":45156,"runtime":"claude","turns":29,"wallClockMs":606165}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"d6415252dcd668d9","findings":[],"hash":"9a33a9ba8036967b48d1c60885fd9b10bbec119e10bb6d4a22c35df83b73a888","nodeId":"7c3e07ee-fc72-4b49-baf0-af55c2477714","outcome":"no_change","summary":"Reproduced the finding; it remains unresolved. A manifest-only fix cannot satisfy both the hook’s required fee `0` and the permitted fee tiers.\n\nLeft `launch.json` unchanged and recorded the evidence in [.imd-responses.json](.imd-responses.json).\n\n`forge build` succeeded; all 43 tests passed, including four tests confirming the deployment defect. The launch remains blocked.","treeHash":null,"usage":{"cachedInputTokens":362752,"inputTokens":49635,"model":"gpt-6-astra","outputTokens":7959,"runtime":"codex","turns":4,"wallClockMs":261894}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a18a0c6087e1362f","findings":[{"citation":"resolved","description":"All of the brief's economics (2% fee, 80/20 IMD split, 50/50 SI burn/lock, vault accrual) live in SIFeeHook and apply only to a pool whose key is {SI, IMD, fee 0, tickSpacing 60, hooks = SIFeeHook}. beforeInitialize restricts pool creation for that key to `initializer`, which the constructor fixes to msg.sender, i.e. the ProjectFactory that CREATE2-deploys the hook (README deploy step 5, PrepareLaunch plan). The network's launch floor (.imd/reads/protected/custom_token/Token.protected.t.sol, setUp and _key()) initializes the SI pool with a PoolInitializationGuard the factory deploys and with the manifest's pool.fee/pool.tickSpacing, and the LaunchManifest schema has no field to name a hook. If the factory follows that flow, the only pool that receives the 88% single-sided SI liquidity has no fee hook: every swap pays 0 to the SI Community Vault, 0 to the creator receiver and burns nothing, while the project documentation and socials advertise a 2% fee. Because of line 94 no other party (requester, keeper, holder) can later open the correct fee pool either, and even if they could, the liquidity would already sit in the hookless pool. This is a flow gap between execution (factory flow), periphery (PoolManager pool keys) and first principles (the fee guarantee). The code cannot enforce the constraint by itself; the launch needs evidence that the factory initializes the pool with hooks = SIFeeHook, fee = 0, tickSpacing = 60 and seeds into that key. README section 'Before release' lists this as an open item, so this finding records it as a concrete blocking condition rather than a code bug. Minimal code-side mitigation to reduce dependence on the initializer identity: pin the expected sqrtPriceX96 (or a price range) in the hook and allow permissionless initialization once the token exists, so the fee pool can at least be opened by anyone; the liquidity routing still has to be the factory's.","line":94,"path":"src/SIFeeHook.sol","reproduction":"State: SwarmInu, SICommunityVault, SISwapRouter and SIFeeHook deployed through a factory contract F (CREATE2, flags 0x20cc), real v4 PoolManager. (1) From any address A != F call manager.initialize(PoolKey(SI, IMD, 0, 60, IHooks(hook)), sqrtPrice) -> reverts in hook.beforeInitialize with OnlyInitializer (scratch test test_onlyFactoryCanOpenFeePool: prank(TRADER) revert, F succeeds). (2) Reproduce the protected floor's flow: F initializes PoolKey(SI, IMD, manifestFee, manifestTickSpacing, IHooks(guard)) where guard is PoolInitializationGuard(manager) deployed by F, seeds 880,000,000 SI single-sided, and a trader swaps 1000 IMD for SI through that pool (scratch test test_hooklessPoolBypassesFee performs the equivalent swap through a hookless key). Expected per brief: vault.totalIMDHeld() == 16e18 and imd.balanceOf(creator) == 4e18. Actual: 0 and 0; the trader receives SI with no fee charged. The brief's 'immutable 2% fee on every swap' never activates for the launched liquidity.","severity":"medium","snippet":"        if (sender != initializer) revert OnlyInitializer();","title":"Fee economics only exist if the launch factory itself opens the pool with SIFeeHook; the network launch floor opens it with PoolInitializationGuard and nobody else may open the fee pool"},{"citation":"resolved","description":"The brief states the fee is immutable and applies to every swap, but SwarmInu is deliberately a plain ERC20 with no transfer rules, and v4 pool creation is permissionless: PoolManager.initialize accepts any (SI, IMD, fee, tickSpacing, hooks) combination, including hooks = address(0) or any other fee tier. Once SI circulates (swarm distributor claimants hold 10%, remainderTo holds 2%, buyers hold whatever they bought), any holder can open a hookless SI/IMD pool, provide liquidity and capture the spread that the 2% fee creates; aggregators and arbitrageurs will route there. The vault, creator receiver and burn then receive nothing on that volume. Nothing in this repository can prevent it (the design forbids token-level rules), so this is a documented economic limitation rather than a code defect: the fee is a property of the official pool, not of the token. The README already says 'Other pools and ordinary SI transfers do not incur this hook's fee'; the project's public materials should not promise a fee on every swap.","line":222,"path":"src/SIFeeHook.sol","reproduction":"State: SI and IMD deployed, PoolManager live, SIFeeHook deployed and (optionally) its pool open. Any address T calls manager.initialize(PoolKey(SI, IMD, 3000, 60, IHooks(address(0))), sqrtPriceX96) -> succeeds (no hook, no beforeInitialize). An LP with SI and IMD adds liquidity to that key. A trader swaps 1000e18 IMD for SI through SISwapRouter (or any router) with that key. Expected under the brief: 20e18 IMD fee (16e18 to vault, 4e18 to creator). Actual (scratch test test_hooklessPoolBypassesFee): trader receives SI, vault.totalIMDHeld() == 0, imd.balanceOf(creator) == 0, hook.pending unchanged. The same holds for sells: nothing is burned to 0xdEaD.","severity":"low","snippet":"                || key.tickSpacing != TICK_SPACING || address(key.hooks) != address(this)","title":"The 2% fee is scoped to one pool key, so any SI/IMD pool without the hook trades fee-free and routes around vault/creator/burn revenue"},{"citation":"resolved","description":"20% of every IMD buy fee is paid to creatorReceiver, an immutable set once in the constructor. The brief gives only the literal '<YOUR_WALLET>', PrepareLaunch takes the address as an explicit parameter and rejects zero, and the README states the value is unresolved and that remainderTo is not silently reused. The constructor guard is correct, but it means the hook's manifest constructorArgs cannot be completed from the brief as written: with an unresolved or zero value the SIFeeHook deployment reverts InvalidConfiguration and the factory launch transaction fails; with a guessed value 20% of all buy fees go permanently to the wrong party. The requester must supply the receiver address before the manifest is written, and the reviewer of the manifest must check that the fifth constructor argument of SIFeeHook is that address and not remainderTo or the factory.","line":65,"path":"src/SIFeeHook.sol","reproduction":"Deploy SwarmInu si, SICommunityVault vault(si, imd), SISwapRouter router(manager). Call new SIFeeHook{salt}(manager, si, imd, vault, address(0), router) with a salt whose address has flags 0x20cc -> reverts InvalidConfiguration (line 63-67). With creatorReceiver_ = X (any nonzero address, e.g. mistakenly 0x66522f25035C3FAFd2c6D950a506FDa457E06344) deployment succeeds and after a 1000e18 IMD buy imd.balanceOf(X) == 4e18 forever, with no way to change the recipient.","severity":"info","snippet":"                || address(vault_).code.length == 0 || creatorReceiver_ == address(0)","title":"Creator receiver is still the brief's placeholder <YOUR_WALLET>; the hook constructor refuses address(0), so the launch has no deployable fee hook until a real address is supplied"}],"hash":"9e13024659960e331faf63026c45168d4b1da4190c6c846252718557113ecd48","nodeId":"698cd3f5-7eac-48e2-99dd-df15ed7f5a82","outcome":"completed","summary":"The findings file is in place and validated. The working tree is clean apart from the findings file and my scratch test, both of which are ignored paths the task designates, so nothing stray remains.\n\n**Review complete. Findings written to `.imd-findings.json`: one medium, one low, one info, with 16 coverage rows covering all 10 listed entry points plus checked invariants.**\n\n**What I verified holds.** I traced the fee hook's accounting through the vendored PoolManager and Hooks library with concrete values, and it is sound:\n- Exact-input swaps reserve 2% of the gross budget before the core swap and the hook is credited after return. Exact-output swaps charge one forty-ninth of the AMM input, which is 2% of gross. Both split 80/20 on IMD buys and 50/50 burn/lock on SI sells, with rounding dust to the vault.\n- Hook ERC6909 claims always equal the sum of pending payouts. Partial-fill refunds go to the trusted router only, and the hook's deltas net to zero in every path.\n- Failed payouts to the vault, creator, or dead address never revert a swap. They stay claim-backed and anyone can retry them.\n- Enabling the PoolManager protocol fee does not break full-fill detection for third-party routers. I confirmed this in a scratch test.\n- The token is a plain exact-amount ERC20 and the vault has no outflow path.\n\n**Findings.**\n1. **Medium.** The entire fee economy exists only in a pool whose key names SIFeeHook, and only the deploying factory may open it. The network's protected launch floor opens the pool with PoolInitializationGuard, and the manifest schema has no hook field. If the factory follows that flow, the launched liquidity trades with zero fee, zero vault accrual, and zero burn. The code cannot enforce this alone. The launch needs evidence that the factory initializes and seeds the hooked key with fee 0 and tick spacing 60.\n2. **Low.** The fee is pool-scoped, not token-scoped. Anyone can open a hookless SI/IMD pool once SI circulates and route volume around the vault, creator, and burn. This is inherent in the \"no transfer rules\" design, so public materials should not promise a fee on every swap.\n3. **Info.** The creator receiver is still the brief's placeholder. The constructor correctly rejects the zero address, so the hook cannot be deployed until a real address is supplied, and a wrong one would receive 20% of buy fees permanently.\n\nNo finding reached high or critical severity, so no proof test files are attached. The scratch test under `test/scratch/Econ.t.sol` reproduces findings 1 and 2 and the protocol-fee check. It passes as written, documenting the behaviour rather than failing on a defect.","treeHash":null,"usage":{"cachedInputTokens":1407648,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":46519,"runtime":"claude","turns":39,"wallClockMs":654958}},{"artifacts":[],"attempt":1,"bundleHash":"e851919214c76a85baf72fedd227a112529f48484a2fc124b700f6f5f9854f6b","device":"1ab5a860db2abcb2","findings":[],"hash":"9eb588784d4871df6bcfd741af933829b283ed33abce76a26531d1c6b678bcbd","nodeId":"7c3e07ee-fc72-4b49-baf0-af55c2477714","outcome":"completed","summary":"Created [launch.json](launch.json) with exact token metadata, supply, economics, vault constructor arguments, and socials.\n\nValidation passed: supplied schema, ABI checks, `forge build`, and all 39 tests. Only `launch.json` is deliverable.\n\nHook integration remains blocked: accepted code requires fee `0`, which admission forbids. The manifest documents this and omits the hook/router; the requested 2% fee is not enabled.","treeHash":"a2ea14ea059b3fd64e48d363a9f1845d50f526db","usage":{"cachedInputTokens":258944,"inputTokens":39406,"model":"gpt-6-astra","outputTokens":4432,"runtime":"codex","turns":5,"wallClockMs":140540}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2565f234b0a569e9","findings":[{"citation":"resolved","description":"NOT FIXED. Round two settles this finding as still open: the tree I am reading is byte-identical in src/ and launch.json to the one I reviewed before (git: d47c44e contracts, e0d4aa8 manifest; the only new commit adds tests). The author's answer does not claim the behaviour fails to reproduce; it confirms it reproduces and disputes only that a launch.json-only edit can resolve it. I agree with that factual point, and it does not close the finding, because the defect is what the launch would deliver, not which file must change. As submitted, launch.json deploys SwarmInu and SICommunityVault only; neither SIFeeHook nor SISwapRouter is in `contracts`, and pool.fee is 3000 while SIFeeHook._checkPool (src/SIFeeHook.sol:221) reverts InvalidPool for any key.fee != 0. Every requested economic rule (2% input-currency fee, 80/20 IMD to vault/creator on buys, 50/50 SI burn/lock on sells, vault accrual) lives exclusively in SIFeeHook, and the admission harness initialises the pool with PoolInitializationGuard, which has no swap callbacks. A launch from these fields therefore ships a plain token and an empty vault while the project's name, notes and socials describe a fee. The author has documented this honestly in the manifest notes and README, but notes carry no deployment authority. What resolves it is a scope decision outside the author's write budget, and I record it as such rather than restating a manifest demand: (a) the network confirms a supported factory path that deploys the vault, router and a hook mined to low bits 0x20cc, initialises PoolKey{SI, IMD, fee 0, spacing 60, hooks = SIFeeHook} from the same address that ran the hook's CREATE2, and seeds the 88% there; then the manifest lists SISwapRouter and SIFeeHook with a verified PoolManager address and the requester's real creator receiver, and pool.fee becomes 0; or (b) the requester accepts a fee-free launch, which is a change to the commissioned deliverable that only they can make. Until one of these is on record, the implementation does not do what the brief commissions. No code change in src/ can bridge this by itself: making the hook accept fee 3000 or permissionless initialisation would still leave the 88% liquidity in the guard-hooked pool the factory seeds, as the author's own reproduction and mine both show. This merges the flow, economics and permissions specialists' reports and the author's reproduction.","line":11,"path":"launch.json","reproduction":"Re-executed this round in test/scratch/RoundTwoSettle.t.sol against the vendored PoolManager (3 passing assertions-of-defect). State: a factory stand-in shaped like the protected harness's LaunchProbe CREATE2-deploys PoolInitializationGuard (low 14 bits 0x2000), SwarmInu, SICommunityVault(si, imd), SISwapRouter(manager) and SIFeeHook (low 14 bits 0x20cc, creator 0xC0FFEE). Step 1, the manifest's pool: factory initialises PoolKey(SI, IMD, 3000, 60, guard) at 2^96 and seeds 1_000_000e18 single-sided SI over [0,60000] (SI currency0) or [-60000,0]. A plain unlock-callback trader (TraderProbe shape) buys with exact input 1000e18 IMD and a non-binding price limit. Expected per brief: 20e18 IMD fee, 16e18 to vault, 4e18 to creator. Actual: trader receives SI and spends all 1000e18 IMD; vault.totalIMDHeld() == 0, imd.balanceOf(creator) == 0, hook.pending(imd, vault) == 0, hook's ERC6909 IMD claims == 0; the hook's beforeSwap/afterSwap never execute. Step 2: factory initialises PoolKey(SI, IMD, 3000, 60, SIFeeHook) -> reverts (InvalidPool from _checkPool wrapped by the manager). Step 3: address 0xBAD initialises PoolKey(SI, IMD, 0, 60, SIFeeHook) -> reverts (OnlyInitializer wrapped). Step 4: the factory initialises that key successfully, but StateLibrary.getLiquidity for it is 0: the seeded liquidity stays in the guard pool. Author's four tests in test/scratch/ManifestWiringReproduction.t.sol are not in the tree (test/scratch is gitignored) but describe the same four steps and the same outcomes.","severity":"medium","snippet":"  \"contracts\": [","title":"The submitted launch manifest omits the entire required swap-fee system (launch.json line 11)"},{"citation":"resolved","description":"NOT FIXED, unchanged code, advisory severity retained. beforeSwap reserves grossBudget/50 of the specified (input) currency before the core swap. When the AMM stops at a price limit or at the edge of the single-sided range, afterSwap enters _exactInputFee with netInput != gross - reserved and can only return the over-reserved input by minting an ERC6909 refund claim to `sender`; for any sender other than the immutable SISwapRouter it reverts the whole swap instead. Standard v4 callers (a plain unlock-callback trader, Universal Router, V4Quoter) therefore cannot execute or quote an oversized exact-input buy or sell into this pool, which is the ordinary large market order at launch, and once the pool's IMD reserve is thin every non-router exact-input sell larger than that reserve reverts. The revert is atomic, no funds move, and README line 35 documents the restriction, so this stays low. The author did not answer it this round and no code changed. Resolution remains a design choice: keep it as a documented integration constraint (offer only SISwapRouter in the frontend and quote through it), or, for non-router senders, keep the full reserved amount as the fee instead of reverting (over-charging by up to 2% of the unfilled remainder that the trader already bounded). Charging in the output currency would violate the brief. This merges the flow, permissions and math specialists' reports.","line":145,"path":"src/SIFeeHook.sol","reproduction":"Re-executed this round in test/scratch/RoundTwoSettle.t.sol: pool PoolKey(SI, IMD, 0, 60, SIFeeHook) at 2^96, two-sided liquidity 1_000_000e18 over [-60000,60000], hook.partialFillRouter == router. Deploy alternate = new SISwapRouter(manager); trader 0xB0B holds 2_000_000e18 IMD and approves both routers. Call alternate.swap(key, SwapParams(zeroForOne = IMD is currency0, amountSpecified = -1_000_000e18, sqrtPriceLimitX96 = getSqrtPriceAtTick(-60 or +60)), 1_000_000e18, 1, trader, block.timestamp). Expected for a 2%-of-input fee pool: partial fill up to the limit, fee = floor(actualSpend/50). Actual: revert with CustomRevert.WrappedError(hook, afterSwap.selector, PartialFillRequiresRouter(), HookCallFailed()) (matched exactly with expectRevert). Control: router.swap with identical parameters succeeds, spends a positive amount strictly below 1_000_000e18, the returned delta's input component equals the IMD actually taken from the trader, and vault + creator deliveries plus pending equal floor(spent/50).","severity":"low","snippet":"        if (sender != partialFillRouter) revert PartialFillRequiresRouter();","title":"Partial exact-input fills revert through every router except the immutable refund router (src/SIFeeHook.sol line 145)"}],"hash":"ac68fac270f95e3e96ff591d3f5db31b6badb1ee3323bd189ad5c6146f845e99","nodeId":"5b492bd8-b5d0-4ac0-903e-7ac787021a8d","outcome":"completed","summary":"Both earlier findings remain open on this tree, and I reported nothing new.\n\n**What changed since last round:** nothing in `src/` or `launch.json`. The only new commit adds tests. The author's answer does not dispute that the first finding reproduces; it disputes that a manifest-only edit can fix it.\n\n**Finding 1, medium, still open.** The manifest deploys only the token and vault, with pool fee 3000, while every commissioned fee rule lives in SIFeeHook, which rejects any nonzero pool fee and lets only its deployer open its pool. I re-ran the reproduction on the real vendored PoolManager:\n\n- A buy of 1000 IMD through the manifest's guard-hooked pool delivers SI with zero to the vault, zero to the creator, and zero pending or claims.\n- The hook refuses a fee-3000 key, an outsider cannot open the fee-0 key, and the factory opening it leaves that pool with no liquidity.\n\nI agree with the author that no manifest-only or `src/`-only change bridges this. I recorded the resolution as a scope decision: either the network confirms a factory path that deploys router and hook and seeds the fee-0 hooked pool, or the requester accepts a fee-free launch. Until one is on record the launch does not deliver what was commissioned, so the finding stays at medium.\n\n**Finding 2, low, still open.** Partial exact-input fills still revert for any caller other than the immutable SISwapRouter. The scratch test matched the exact wrapped `PartialFillRequiresRouter` error through an alternate router and confirmed the control trade through the configured router charges floor(spent/50). Advisory severity is unchanged.\n\n**Coverage:** all 10 entry points answered, 9 holds and 1 finding, plus one invariant row for the manifest pool. The project's own suite passes 58 tests on this tree. Findings and coverage are in `.imd-findings.json`; the scratch test lives under `test/scratch/` and no tracked file was changed.","treeHash":null,"usage":{"cachedInputTokens":1233802,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":21322,"runtime":"claude","turns":25,"wallClockMs":339619}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b94d8a9fa9123fb1","findings":[],"hash":"bd1727c7e1cf7bc63b3aece485e9671f855fab06f42caf2fad46c6c4954d832d","nodeId":"7c3e07ee-fc72-4b49-baf0-af55c2477714","outcome":"no_change","summary":"The defect reproduces, but cannot be fixed in `launch.json` alone: the hook requires forbidden fee `0`, and the launch path hardwires the guard.\n\nLeft the manifest unchanged and recorded the unresolved scope conflict in [.imd-responses.json](/home/imdc2/.identitymd/work/019d5d85-5f0a-4d6a-aeae-93163ae147fb/7c3e07ee-fc72-4b49-baf0-af55c2477714/.imd-responses.json).\n\nSchema validation, `forge build`, and all 51 tests passed. The required fee integration remains unresolved.","treeHash":null,"usage":{"cachedInputTokens":1177728,"inputTokens":41434,"model":"gpt-6-astra","outputTokens":5550,"runtime":"codex","turns":6,"wallClockMs":330054}},{"artifacts":[],"attempt":1,"bundleHash":"2c4133cd01aad97cd1f3949a5cc46d40084cb51a087bc9214c3f238f8cc7033c","device":"2ad55d105b02faa2","findings":[],"hash":"d13a894d87d06800e5d8d44e6e62326dd7dc62ebfee21bfe7555450a84e35faf","nodeId":"0ec5140b-fc5d-41fc-a218-23dc43be4a15","outcome":"completed","summary":"Added tests only under `test/`, covering failure paths, fee boundaries, reentrancy, settlement rollback, and eight invariant properties.\n\n`forge build` and `forge test` pass: 58 tests, including 49,152 random handler calls.\n\nNo reproducible contract defects found. Live-chain fork validation remains unrun.","treeHash":"d999ddce302a9969483f217788e562950722665d","usage":{"cachedInputTokens":1935616,"inputTokens":135719,"model":"gpt-6-astra","outputTokens":23439,"runtime":"codex","turns":7,"wallClockMs":740035}}],"verification":[{"checks":[{"durationMs":2781,"exitCode":0,"name":"build","output":"Compiling 79 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.59s\nCompiler run successful!\nwarning[reentrancy-no-eth]: external call can be reentered before `activePayer` is updated\n   ╭▸ src/SISwapRouter.sol:70:13\n   │\n70 │             poolManager.unlock(abi.encode(Request(key, params, maxInput, minOutput, recipient))), (BalanceDelta)\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/SISwapRouter.sol:62:13\n   │\n62 │         if (block.timestamp > deadline) revert DeadlineExpired();\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:61:9\n   │\n61 │         address partialFillRouter_\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:57:9\n   │\n57 │         address si_,\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:58:9\n   │\n58 │         address imd_,\n   │         ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:25:33\n   │\n25 │           (BalanceDelta delta,) = manager.modifyLiquidity(\n   │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n26 │ ┃             seed.key,\n27 │ ┃             ModifyLiquidityParams(seed.tickLower, seed.tickUpper, int256(uint256(seed.liquidity)), bytes32(0)),\n28 │ ┃             \"\"\n29 │ ┃         );\n   │ ┗━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/LaunchLiquidity.sol:36:51\n   │\n36 │             manager.take(currency, address(this), uint256(int256(delta)));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/LaunchLiquidity.sol:38:28\n   │\n38 │             uint256 owed = uint256(-int256(delta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:40:17\n   │\n40 │                 manager.settle{value: owed}();\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:44:17\n   │\n44 │                 manager.settle();\n   │                 ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SISwapRouter.sol:112:9\n    │\n112 │         emit SwapExecuted(payer, request.recipient, Currency.unwrap(input), inputAmount, outputAmount, refund);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:89:59\n   │\n89 │         if (inputDelta > 0 || outputDelta < 0 || refund > uint256(-inputDelta)) revert InvalidSwapDelta();\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:94:27\n   │\n94 │             inputDelta += int256(refund);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:96:34\n   │\n96 │                 ? toBalanceDelta(int128(inputDelta), int128(outputDelta))\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:96:54\n   │\n96 │                 ? toBalanceDelta(int128(inputDelta), int128(outputDelta))\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:97:34\n   │\n97 │                 : toBalanceDelta(int128(outputDelta), int128(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:97:55\n   │\n97 │                 : toBalanceDelta(int128(outputDelta), int128(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SISwapRouter.sol:100:31\n    │\n100 │         uint256 inputAmount = uint256(-inputDelta);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SISwapRouter.sol:101:32\n    │\n101 │         uint256 outputAmount = uint256(outputDelta);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:111:57\n    │\n111 │         uint256 reserved = params.amountSpecified < 0 ? uint256(-params.amountSpecified) / 50 : 0;\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:112:63\n    │\n112 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(reserved)), 0), 0);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:112:70\n    │\n112 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(reserved)), 0), 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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `swapping` is updated\n    ╭▸ src/SIFeeHook.sol:149:13\n    │\n149 │             poolManager.mint(sender, input.toId(), refund);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `swapping` is updated\n    ╭▸ src/SIFeeHook.sol:185:9\n    │\n185 │         poolManager.mint(address(this), currency.toId(), fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:192:9\n    │\n192 │         emit FeeAccrued(token, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:208:25\n    │\n208 │         if (!delivered) emit PayoutDeferred(Currency.unwrap(currency), recipient, amount);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:126:28\n    │\n126 │         uint256 netInput = uint256(-int256(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:129:45\n    │\n129 │             ? _exactInputFee(sender, input, uint256(-params.amountSpecified), netInput)\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:131:59\n    │\n131 │         int128 returnedFee = params.amountSpecified > 0 ? int128(int256(fee)) : int128(0);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:131:66\n    │\n131 │         int128 returnedFee = params.amountSpecified > 0 ? int128(int256(fee)) : int128(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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:150:13\n    │\n150 │             emit InputRefund(sender, Currency.unwrap(input), refund);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `flushing` is updated\n    ╭▸ src/SIFeeHook.sol:162:13\n    │\n162 │         try poolManager.unlock(abi.encode(currency, recipient, amount)) returns (bytes memory) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:165:13\n    │\n165 │             emit PayoutDeferred(currency, recipient, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:158:78\n    │\n158 │         if (amount == 0 || amount > pending[currency][recipient] || amount > uint256(uint128(type(int128).max))) {\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:158:86\n    │\n158 │         if (amount == 0 || amount > pending[currency][recipient] || amount > uint256(uint128(type(int128).max))) {\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:215:9\n    │\n215 │         emit PayoutDelivered(Currency.unwrap(currency), recipient, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\n","passed":true},{"durationMs":357,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/TokenVault.t.sol:TokenVaultTest\n[PASS] testFuzz_allowanceConsumptionAndRevocation(uint256,uint256) (runs: 256, μ: 204276, ~: 205608)\nLogs:\n  Bound result 3573\n  Bound result 18\n\n[PASS] testFuzz_transferConservesSupplyAndDeliversExactAmount(uint256) (runs: 256, μ: 156075, ~: 156179)\nLogs:\n  Bound result 1000000000000000000000000000\n\n[PASS] test_infiniteAllowanceStaysInfinite() (gas: 121015)\n[PASS] test_invalidZeroAddresses() (gas: 81637)\n[PASS] test_metadataAndConstructorMint() (gas: 73105)\n[PASS] test_noMintOrHolderControl() (gas: 266485)\n[PASS] test_rejectedTransfersPreserveBalancesAndAllowance() (gas: 221445)\n[PASS] test_vaultDirectDonationsAndBurnViews() (gas: 378807)\n[PASS] test_vaultHasNoExitOrApprovalAndCannotBeDrainedByDeployer() (gas: 341831)\n[PASS] test_vaultRejectsInvalidTokenConfiguration() (gas: 6024)\n[PASS] test_zeroAndSelfTransfers() (gas: 72696)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 12.83ms (21.20ms CPU time)\n\nRan 6 tests for test/LaunchHelpers.t.sol:LaunchHelpersTest\n[PASS] testFuzz_hookFlagsRejectAdditionalPermissions(uint160,uint160) (runs: 256, μ: 3954, ~: 3954)\n[PASS] test_emptySeedRejected() (gas: 46027)\n[PASS] test_guardAllowsOnlyDeployerInitializationThroughManager() (gas: 100695051)\n[PASS] test_nativeSeedAndSwapSettlement() (gas: 548010)\n[PASS] test_seedAndSwapSettleActualManagerBalances() (gas: 545530)\n[PASS] test_seedFailsWithoutFundsAndLeavesPoolUnfunded() (gas: 251047)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 75.41ms (65.44ms CPU time)\n\nRan 19 tests for test/SIFeeHook.t.sol:SIFeeHookTest\n[PASS] testFuzz_feeSplitsAndConservation(uint96,bool) (runs: 256, μ: 432420, ~: 438552)\nLogs:\n  Bound result 5058908553300794729\n\n[PASS] test_alternateRouterFullFillWorksButPartialFillRollsBack() (gas: 619969)\n[PASS] test_callbacksAndDeliveryRejectUnauthorizedCallers() (gas: 182601)\n[PASS] test_emptyLiquidityRefundsEntireReservation() (gas: 744412)\n[PASS] test_exactInputBuysAndSellsChargeInputCurrency() (gas: 755034)\n[PASS] test_exactOutputBuysAndSellsChargeGrossInputFee() (gas: 765715)\n[PASS] test_existingRouterClaimsAreNotSpentByNextTrader() (gas: 400729)\n[PASS] test_failedRecipientsDoNotBrickAndFailedRetryIsAtomic() (gas: 1030723)\n[PASS] test_firstSingleSidedBuyDefersThenAnyoneCanFlush() (gas: 14317433)\n[PASS] test_flushCannotRedirectOrExceedFixedDebt() (gas: 513675)\n[PASS] test_gasGriefDeferredAndNoReturnSupported() (gas: 612690)\n[PASS] test_partialExactInputRefundsUnusedFeeClaims() (gas: 465241)\n[PASS] test_partialExactOutputHasFeeOnActualInputAndHonorsMinimum() (gas: 420300)\n[PASS] test_poolValidationAndInitializationAuthority() (gas: 83007)\n[PASS] test_reentryDuringPayoutCannotFlushOrCorruptAccounting() (gas: 676577)\n[PASS] test_reverseTokenOrdering() (gas: 66879668)\n[PASS] test_routerDeadlineRecipientAndAllowanceFailures() (gas: 535131)\n[PASS] test_routerLimitsRollbackAllFeeTransfers() (gas: 753253)\n[PASS] test_shortReturnAndReturnBombCannotBrickPayouts() (gas: 653304)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 75.41ms (130.91ms CPU time)\n\nRan 3 tests for test/PrepareLaunch.t.sol:PrepareLaunchTest\n[PASS] test_planDeploysPredictedContractsAndPreservesSupply() (gas: 239578501)\n[PASS] test_pricesMatchIndependentIntegerReferenceForBothCurrencyOrders() (gas: 498768962)\n[PASS] test_rejectsMissingAddressesAndUnsupportedDecimals() (gas: 106910)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 214.88ms (304.20ms CPU time)\n\nRan 4 test suites in 215.89ms (378.54ms CPU time): 39 tests passed, 0 failed, 0 skipped (39 total tests)\n","passed":true},{"durationMs":66,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SIFeeHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"SIFeeHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"SIFeeHook.deliver(address,address,uint256)\",\"SIFeeHook.flush(address,address,uint256)\",\"SIFeeHook.unlockCallback(bytes)\",\"SISwapRouter.swap((address,address,uint24,int24,address),(bool,int256,uint160),uint256,uint256,address,uint256)\",\"SISwapRouter.unlockCallback(bytes)\",\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":13,\"README.md\":98,\"VALIDATION.md\":16,\"foundry.toml\":16,\"remappings.txt\":3,\"script/PrepareLaunch.s.sol\":158,\"src/HookFlags.sol\":16,\"src/LaunchLiquidity.sol\":48,\"src/PoolInitializationGuard.sol\":29,\"src/SICommunityVault.sol\":34,\"src/SIFeeHook.sol\":227,\"src/SISwapRouter.sol\":129,\"src/SwarmInu.sol\":64,\"src/interfaces/IERC20.sol\":14,\"test/LaunchHelpers.t.sol\":163,\"test/PrepareLaunch.t.sol\":128,\"test/SIFeeHook.t.sol\":426,\"test/TokenVault.t.sol\":191,\"test/mocks/AdversarialIMD.sol\":80},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1125,"exitCode":0,"name":"slither","output":"[medium/medium] reentrancy-no-eth at src/SISwapRouter.sol:53: Reentrancy in SISwapRouter.swap(PoolKey,SwapParams,uint256,uint256,address,uint256) (src/SISwapRouter.sol#53-73):\n[medium/medium] reentrancy-no-eth at src/SIFeeHook.sol:156: Reentrancy in SIFeeHook.flush(address,address,uint256) (src/SIFeeHook.sol#156-168):\n[medium/medium] reentrancy-no-eth at src/SIFeeHook.sol:115: Reentrancy in SIFeeHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/SIFeeHook.sol#115-135):\n[medium/medium] unused-return at src/SIFeeHook.sol:156: SIFeeHook.flush(address,address,uint256) (src/SIFeeHook.sol#156-168) ignores return value by poolManager.unlock(abi.encode(currency,recipient,amount)) (src/SIFeeHook.sol#162-166)\n[medium/medium] unused-return at src/LaunchLiquidity.sol:34: LaunchLiquidity.settle(IPoolManager,Currency,int128) (src/LaunchLiquidity.sol#34-47) ignores return value by manager.settle{value: owed}() (src/LaunchLiquidity.sol#40)\n[medium/medium] unused-return at src/LaunchLiquidity.sol:22: LaunchLiquidity.settleSeed(IPoolManager,bytes) (src/LaunchLiquidity.sol#22-32) ignores return value by (delta,None) = manager.modifyLiquidity(seed.key,ModifyLiquidityParams(seed.tickLower,seed.tickUpper,int256(uint256(seed.liquidity)),bytes32(0)),) (src/LaunchLiquidity.sol#25-29)\n[medium/medium] unused-return at src/LaunchLiquidity.sol:34: LaunchLiquidity.settle(IPoolManager,Currency,int128) (src/LaunchLiquidity.sol#34-47) ignores return value by manager.settle() (src/LaunchLiquidity.sol#44)\n[low/medium] reentrancy-benign at src/SIFeeHook.sol:183: Reentrancy in SIFeeHook._distribute(Currency,uint256) (src/SIFeeHook.sol#183-195):\n[low/medium] reentrancy-events at src/SIFeeHook.sol:183: Reentrancy in SIFeeHook._distribute(Currency,uint256) (src/SIFeeHook.sol#183-195):\n[low/medium] reentrancy-events at src/SISwapRouter.sol:76: Reentrancy in SISwapRouter.unlockCallback(bytes) (src/SISwapRouter.sol#76-114):\n[low/medium] reentrancy-events at src/SIFeeHook.sol:211: Reentrancy in SIFeeHook._deliver(Currency,address,uint256) (src/SIFeeHook.sol#211-216):\n[low/medium] reentrancy-events at src/SIFeeHook.sol:156: Reentrancy in SIFeeHook.flush(address,address,uint256) (src/SIFeeHook.sol#156-168):\n[low/medium] reentrancy-events at src/SIFeeHook.sol:115: Reentrancy in SIFeeHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/SIFeeHook.sol#115-135):\n[low/medium] reentrancy-events at src/SIFeeHook.sol:137: Reentrancy in SIFeeHook._exactInputFee(address,Currency,uint256,uint256) (src/SIFeeHook.sol#137-152):\n[low/medium] timestamp at src/SISwapRouter.sol:53: SISwapRouter.swap(PoolKey,SwapParams,uint256,uint256,address,uint256) (src/SISwapRouter.sol#53-73) uses timestamp for comparisons","passed":true},{"durationMs":364,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/SIFeeHook.sol:69: Reentrancy: State change after external call (3 places)\n[low] large-numeric-literal at src/SIFeeHook.sol:26: Large Numeric Literal (3 places)\n[low] literal-instead-of-constant at src/SIFeeHook.sol:111: Literal Instead of Constant (4 places)\n[low] missing-inheritance at src/PoolInitializationGuard.sol:10: Missing Inheritance\n[low] state-change-without-event at src/SIFeeHook.sol:98: State Change Without Event (2 places)\n[low] unchecked-return at src/LaunchLiquidity.sol:44: Unchecked Return\n[low] unsafe-erc20-operation at src/LaunchLiquidity.sol:43: Unsafe ERC20 Operation (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0d1b46897950bd873a5a1fb9bfacd06fe37764f1ecf2aa8ba7ba62e15bbb76a1","verifiedTreeHash":"5bb54a1552f46f945c2872c455343efcd4371f8a","verifierVersion":"0.1.0+e6140b7a"},{"checks":[{"durationMs":2563,"exitCode":0,"name":"build","output":"Compiling 79 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.42s\nCompiler run successful!\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:25:33\n   │\n25 │           (BalanceDelta delta,) = manager.modifyLiquidity(\n   │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n26 │ ┃             seed.key,\n27 │ ┃             ModifyLiquidityParams(seed.tickLower, seed.tickUpper, int256(uint256(seed.liquidity)), bytes32(0)),\n28 │ ┃             \"\"\n29 │ ┃         );\n   │ ┗━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/LaunchLiquidity.sol:36:51\n   │\n36 │             manager.take(currency, address(this), uint256(int256(delta)));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/LaunchLiquidity.sol:38:28\n   │\n38 │             uint256 owed = uint256(-int256(delta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:57:9\n   │\n57 │         address si_,\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:40:17\n   │\n40 │                 manager.settle{value: owed}();\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:44:17\n   │\n44 │                 manager.settle();\n   │                 ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:58:9\n   │\n58 │         address imd_,\n   │         ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:61:9\n   │\n61 │         address partialFillRouter_\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activePayer` is updated\n   ╭▸ src/SISwapRouter.sol:70:13\n   │\n70 │             poolManager.unlock(abi.encode(Request(key, params, maxInput, minOutput, recipient))), (BalanceDelta)\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/SISwapRouter.sol:62:13\n   │\n62 │         if (block.timestamp > deadline) revert DeadlineExpired();\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:111:57\n    │\n111 │         uint256 reserved = params.amountSpecified < 0 ? uint256(-params.amountSpecified) / 50 : 0;\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:112:63\n    │\n112 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(reserved)), 0), 0);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:112:70\n    │\n112 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(reserved)), 0), 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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SISwapRouter.sol:112:9\n    │\n112 │         emit SwapExecuted(payer, request.recipient, Currency.unwrap(input), inputAmount, outputAmount, refund);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:89:59\n   │\n89 │         if (inputDelta > 0 || outputDelta < 0 || refund > uint256(-inputDelta)) revert InvalidSwapDelta();\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:94:27\n   │\n94 │             inputDelta += int256(refund);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:96:34\n   │\n96 │                 ? toBalanceDelta(int128(inputDelta), int128(outputDelta))\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:96:54\n   │\n96 │                 ? toBalanceDelta(int128(inputDelta), int128(outputDelta))\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:97:34\n   │\n97 │                 : toBalanceDelta(int128(outputDelta), int128(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:97:55\n   │\n97 │                 : toBalanceDelta(int128(outputDelta), int128(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SISwapRouter.sol:100:31\n    │\n100 │         uint256 inputAmount = uint256(-inputDelta);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SISwapRouter.sol:101:32\n    │\n101 │         uint256 outputAmount = uint256(outputDelta);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `swapping` is updated\n    ╭▸ src/SIFeeHook.sol:149:13\n    │\n149 │             poolManager.mint(sender, input.toId(), refund);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `swapping` is updated\n    ╭▸ src/SIFeeHook.sol:185:9\n    │\n185 │         poolManager.mint(address(this), currency.toId(), fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:192:9\n    │\n192 │         emit FeeAccrued(token, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:208:25\n    │\n208 │         if (!delivered) emit PayoutDeferred(Currency.unwrap(currency), recipient, amount);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:126:28\n    │\n126 │         uint256 netInput = uint256(-int256(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:129:45\n    │\n129 │             ? _exactInputFee(sender, input, uint256(-params.amountSpecified), netInput)\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:131:59\n    │\n131 │         int128 returnedFee = params.amountSpecified > 0 ? int128(int256(fee)) : int128(0);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:131:66\n    │\n131 │         int128 returnedFee = params.amountSpecified > 0 ? int128(int256(fee)) : int128(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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:150:13\n    │\n150 │             emit InputRefund(sender, Currency.unwrap(input), refund);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `flushing` is updated\n    ╭▸ src/SIFeeHook.sol:162:13\n    │\n162 │         try poolManager.unlock(abi.encode(currency, recipient, amount)) returns (bytes memory) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:165:13\n    │\n165 │             emit PayoutDeferred(currency, recipient, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:158:78\n    │\n158 │         if (amount == 0 || amount > pending[currency][recipient] || amount > uint256(uint128(type(int128).max))) {\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:158:86\n    │\n158 │         if (amount == 0 || amount > pending[currency][recipient] || amount > uint256(uint128(type(int128).max))) {\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:215:9\n    │\n215 │         emit PayoutDelivered(Currency.unwrap(currency), recipient, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\n","passed":true},{"durationMs":286,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 19 tests for test/SIFeeHook.t.sol:SIFeeHookTest\n[PASS] testFuzz_feeSplitsAndConservation(uint96,bool) (runs: 256, μ: 431315, ~: 427769)\nLogs:\n  Bound result 3107\n\n[PASS] test_alternateRouterFullFillWorksButPartialFillRollsBack() (gas: 619969)\n[PASS] test_callbacksAndDeliveryRejectUnauthorizedCallers() (gas: 182601)\n[PASS] test_emptyLiquidityRefundsEntireReservation() (gas: 744412)\n[PASS] test_exactInputBuysAndSellsChargeInputCurrency() (gas: 755034)\n[PASS] test_exactOutputBuysAndSellsChargeGrossInputFee() (gas: 765715)\n[PASS] test_existingRouterClaimsAreNotSpentByNextTrader() (gas: 400729)\n[PASS] test_failedRecipientsDoNotBrickAndFailedRetryIsAtomic() (gas: 1030723)\n[PASS] test_firstSingleSidedBuyDefersThenAnyoneCanFlush() (gas: 14317433)\n[PASS] test_flushCannotRedirectOrExceedFixedDebt() (gas: 513675)\n[PASS] test_gasGriefDeferredAndNoReturnSupported() (gas: 612690)\n[PASS] test_partialExactInputRefundsUnusedFeeClaims() (gas: 465241)\n[PASS] test_partialExactOutputHasFeeOnActualInputAndHonorsMinimum() (gas: 420300)\n[PASS] test_poolValidationAndInitializationAuthority() (gas: 83007)\n[PASS] test_reentryDuringPayoutCannotFlushOrCorruptAccounting() (gas: 676577)\n[PASS] test_reverseTokenOrdering() (gas: 66879668)\n[PASS] test_routerDeadlineRecipientAndAllowanceFailures() (gas: 535131)\n[PASS] test_routerLimitsRollbackAllFeeTransfers() (gas: 753253)\n[PASS] test_shortReturnAndReturnBombCannotBrickPayouts() (gas: 653304)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 56.68ms (107.32ms CPU time)\n\nRan 6 tests for test/LaunchHelpers.t.sol:LaunchHelpersTest\n[PASS] testFuzz_hookFlagsRejectAdditionalPermissions(uint160,uint160) (runs: 256, μ: 3954, ~: 3954)\n[PASS] test_emptySeedRejected() (gas: 46027)\n[PASS] test_guardAllowsOnlyDeployerInitializationThroughManager() (gas: 100695051)\n[PASS] test_nativeSeedAndSwapSettlement() (gas: 548010)\n[PASS] test_seedAndSwapSettleActualManagerBalances() (gas: 545530)\n[PASS] test_seedFailsWithoutFundsAndLeavesPoolUnfunded() (gas: 251047)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 68.47ms (71.77ms CPU time)\n\nRan 3 tests for test/PrepareLaunch.t.sol:PrepareLaunchTest\n[PASS] test_planDeploysPredictedContractsAndPreservesSupply() (gas: 239578501)\n[PASS] test_pricesMatchIndependentIntegerReferenceForBothCurrencyOrders() (gas: 498768962)\n[PASS] test_rejectsMissingAddressesAndUnsupportedDecimals() (gas: 106910)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 180.20ms (242.65ms CPU time)\n\nRan 11 tests for test/TokenVault.t.sol:TokenVaultTest\n[PASS] testFuzz_allowanceConsumptionAndRevocation(uint256,uint256) (runs: 256, μ: 203881, ~: 205562)\nLogs:\n  Bound result 860557335634577818584167624\n  Bound result 14225676519824299\n\n[PASS] testFuzz_transferConservesSupplyAndDeliversExactAmount(uint256) (runs: 256, μ: 155259, ~: 156107)\nLogs:\n  Bound result 2326\n\n[PASS] test_infiniteAllowanceStaysInfinite() (gas: 121015)\n[PASS] test_invalidZeroAddresses() (gas: 81637)\n[PASS] test_metadataAndConstructorMint() (gas: 73105)\n[PASS] test_noMintOrHolderControl() (gas: 266485)\n[PASS] test_rejectedTransfersPreserveBalancesAndAllowance() (gas: 221445)\n[PASS] test_vaultDirectDonationsAndBurnViews() (gas: 378807)\n[PASS] test_vaultHasNoExitOrApprovalAndCannotBeDrainedByDeployer() (gas: 341831)\n[PASS] test_vaultRejectsInvalidTokenConfiguration() (gas: 6024)\n[PASS] test_zeroAndSelfTransfers() (gas: 72696)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 180.34ms (25.53ms CPU time)\n\nRan 4 test suites in 181.14ms (485.69ms CPU time): 39 tests passed, 0 failed, 0 skipped (39 total tests)\n","passed":true},{"durationMs":60,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SIFeeHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"SIFeeHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"SIFeeHook.deliver(address,address,uint256)\",\"SIFeeHook.flush(address,address,uint256)\",\"SIFeeHook.unlockCallback(bytes)\",\"SISwapRouter.swap((address,address,uint24,int24,address),(bool,int256,uint160),uint256,uint256,address,uint256)\",\"SISwapRouter.unlockCallback(bytes)\",\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":13,\"README.md\":98,\"VALIDATION.md\":16,\"foundry.toml\":16,\"launch.json\":28,\"remappings.txt\":3,\"script/PrepareLaunch.s.sol\":158,\"src/HookFlags.sol\":16,\"src/LaunchLiquidity.sol\":48,\"src/PoolInitializationGuard.sol\":29,\"src/SICommunityVault.sol\":34,\"src/SIFeeHook.sol\":227,\"src/SISwapRouter.sol\":129,\"src/SwarmInu.sol\":64,\"src/interfaces/IERC20.sol\":14,\"test/LaunchHelpers.t.sol\":163,\"test/PrepareLaunch.t.sol\":128,\"test/SIFeeHook.t.sol\":426,\"test/TokenVault.t.sol\":191,\"test/mocks/AdversarialIMD.sol\":80},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"9eb588784d4871df6bcfd741af933829b283ed33abce76a26531d1c6b678bcbd","verifiedTreeHash":"a2ea14ea059b3fd64e48d363a9f1845d50f526db","verifierVersion":"0.1.0+e6140b7a"},{"checks":[{"durationMs":7104,"exitCode":0,"name":"build","output":"Compiling 84 files with Solc 0.8.26\nSolc 0.8.26 finished in 6.84s\nCompiler run successful!\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:25:33\n   │\n25 │           (BalanceDelta delta,) = manager.modifyLiquidity(\n   │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n26 │ ┃             seed.key,\n27 │ ┃             ModifyLiquidityParams(seed.tickLower, seed.tickUpper, int256(uint256(seed.liquidity)), bytes32(0)),\n28 │ ┃             \"\"\n29 │ ┃         );\n   │ ┗━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activePayer` is updated\n   ╭▸ src/SISwapRouter.sol:70:13\n   │\n70 │             poolManager.unlock(abi.encode(Request(key, params, maxInput, minOutput, recipient))), (BalanceDelta)\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/LaunchLiquidity.sol:36:51\n   │\n36 │             manager.take(currency, address(this), uint256(int256(delta)));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/LaunchLiquidity.sol:38:28\n   │\n38 │             uint256 owed = uint256(-int256(delta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:40:17\n   │\n40 │                 manager.settle{value: owed}();\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/LaunchLiquidity.sol:44:17\n   │\n44 │                 manager.settle();\n   │                 ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/SISwapRouter.sol:62:13\n   │\n62 │         if (block.timestamp > deadline) revert DeadlineExpired();\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:57:9\n   │\n57 │         address si_,\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:61:9\n   │\n61 │         address partialFillRouter_\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SIFeeHook.sol:58:9\n   │\n58 │         address imd_,\n   │         ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SISwapRouter.sol:112:9\n    │\n112 │         emit SwapExecuted(payer, request.recipient, Currency.unwrap(input), inputAmount, outputAmount, refund);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:89:59\n   │\n89 │         if (inputDelta > 0 || outputDelta < 0 || refund > uint256(-inputDelta)) revert InvalidSwapDelta();\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:94:27\n   │\n94 │             inputDelta += int256(refund);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:96:34\n   │\n96 │                 ? toBalanceDelta(int128(inputDelta), int128(outputDelta))\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:96:54\n   │\n96 │                 ? toBalanceDelta(int128(inputDelta), int128(outputDelta))\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:97:34\n   │\n97 │                 : toBalanceDelta(int128(outputDelta), int128(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SISwapRouter.sol:97:55\n   │\n97 │                 : toBalanceDelta(int128(outputDelta), int128(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SISwapRouter.sol:100:31\n    │\n100 │         uint256 inputAmount = uint256(-inputDelta);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SISwapRouter.sol:101:32\n    │\n101 │         uint256 outputAmount = uint256(outputDelta);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:111:57\n    │\n111 │         uint256 reserved = params.amountSpecified < 0 ? uint256(-params.amountSpecified) / 50 : 0;\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:112:63\n    │\n112 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(reserved)), 0), 0);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:112:70\n    │\n112 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(reserved)), 0), 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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `swapping` is updated\n    ╭▸ src/SIFeeHook.sol:149:13\n    │\n149 │             poolManager.mint(sender, input.toId(), refund);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `swapping` is updated\n    ╭▸ src/SIFeeHook.sol:185:9\n    │\n185 │         poolManager.mint(address(this), currency.toId(), fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:192:9\n    │\n192 │         emit FeeAccrued(token, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:208:25\n    │\n208 │         if (!delivered) emit PayoutDeferred(Currency.unwrap(currency), recipient, amount);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:126:28\n    │\n126 │         uint256 netInput = uint256(-int256(inputDelta));\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:129:45\n    │\n129 │             ? _exactInputFee(sender, input, uint256(-params.amountSpecified), netInput)\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:131:59\n    │\n131 │         int128 returnedFee = params.amountSpecified > 0 ? int128(int256(fee)) : int128(0);\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:131:66\n    │\n131 │         int128 returnedFee = params.amountSpecified > 0 ? int128(int256(fee)) : int128(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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:150:13\n    │\n150 │             emit InputRefund(sender, Currency.unwrap(input), refund);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `flushing` is updated\n    ╭▸ src/SIFeeHook.sol:162:13\n    │\n162 │         try poolManager.unlock(abi.encode(currency, recipient, amount)) returns (bytes memory) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:165:13\n    │\n165 │             emit PayoutDeferred(currency, recipient, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:158:78\n    │\n158 │         if (amount == 0 || amount > pending[currency][recipient] || amount > uint256(uint128(type(int128).max))) {\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SIFeeHook.sol:158:86\n    │\n158 │         if (amount == 0 || amount > pending[currency][recipient] || amount > uint256(uint128(type(int128).max))) {\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://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SIFeeHook.sol:215:9\n    │\n215 │         emit PayoutDelivered(Currency.unwrap(currency), recipient, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\n","passed":true},{"durationMs":19773,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/LaunchHelpers.t.sol:LaunchHelpersTest\n[PASS] testFuzz_hookFlagsRejectAdditionalPermissions(uint160,uint160) (runs: 256, μ: 3954, ~: 3954)\n[PASS] test_emptySeedRejected() (gas: 46027)\n[PASS] test_guardAllowsOnlyDeployerInitializationThroughManager() (gas: 100695051)\n[PASS] test_nativeSeedAndSwapSettlement() (gas: 548010)\n[PASS] test_seedAndSwapSettleActualManagerBalances() (gas: 545530)\n[PASS] test_seedFailsWithoutFundsAndLeavesPoolUnfunded() (gas: 251047)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 127.43ms (160.95ms CPU time)\n\nRan 19 tests for test/SIFeeHook.t.sol:SIFeeHookTest\n[PASS] testFuzz_feeSplitsAndConservation(uint96,bool) (runs: 256, μ: 430297, ~: 427785)\nLogs:\n  Bound result 1125899906842624\n\n[PASS] test_alternateRouterFullFillWorksButPartialFillRollsBack() (gas: 619969)\n[PASS] test_callbacksAndDeliveryRejectUnauthorizedCallers() (gas: 182601)\n[PASS] test_emptyLiquidityRefundsEntireReservation() (gas: 744412)\n[PASS] test_exactInputBuysAndSellsChargeInputCurrency() (gas: 755034)\n[PASS] test_exactOutputBuysAndSellsChargeGrossInputFee() (gas: 765715)\n[PASS] test_existingRouterClaimsAreNotSpentByNextTrader() (gas: 400729)\n[PASS] test_failedRecipientsDoNotBrickAndFailedRetryIsAtomic() (gas: 1030723)\n[PASS] test_firstSingleSidedBuyDefersThenAnyoneCanFlush() (gas: 14317433)\n[PASS] test_flushCannotRedirectOrExceedFixedDebt() (gas: 513675)\n[PASS] test_gasGriefDeferredAndNoReturnSupported() (gas: 612690)\n[PASS] test_partialExactInputRefundsUnusedFeeClaims() (gas: 465241)\n[PASS] test_partialExactOutputHasFeeOnActualInputAndHonorsMinimum() (gas: 420300)\n[PASS] test_poolValidationAndInitializationAuthority() (gas: 83007)\n[PASS] test_reentryDuringPayoutCannotFlushOrCorruptAccounting() (gas: 676577)\n[PASS] test_reverseTokenOrdering() (gas: 66879668)\n[PASS] test_routerDeadlineRecipientAndAllowanceFailures() (gas: 535131)\n[PASS] test_routerLimitsRollbackAllFeeTransfers() (gas: 753253)\n[PASS] test_shortReturnAndReturnBombCannotBrickPayouts() (gas: 653304)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 137.75ms (259.83ms CPU time)\n\nRan 11 tests for test/TokenVault.t.sol:TokenVaultTest\n[PASS] testFuzz_allowanceConsumptionAndRevocation(uint256,uint256) (runs: 256, μ: 204249, ~: 205556)\nLogs:\n  Bound result 17813\n  Bound result 10930\n\n[PASS] testFuzz_transferConservesSupplyAndDeliversExactAmount(uint256) (runs: 256, μ: 155351, ~: 156239)\nLogs:\n  Bound result 500000000000000000000000\n\n[PASS] test_infiniteAllowanceStaysInfinite() (gas: 121015)\n[PASS] test_invalidZeroAddresses() (gas: 81637)\n[PASS] test_metadataAndConstructorMint() (gas: 73105)\n[PASS] test_noMintOrHolderControl() (gas: 266485)\n[PASS] test_rejectedTransfersPreserveBalancesAndAllowance() (gas: 221445)\n[PASS] test_vaultDirectDonationsAndBurnViews() (gas: 378807)\n[PASS] test_vaultHasNoExitOrApprovalAndCannotBeDrainedByDeployer() (gas: 341831)\n[PASS] test_vaultRejectsInvalidTokenConfiguration() (gas: 6024)\n[PASS] test_zeroAndSelfTransfers() (gas: 72696)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 139.17ms (237.38ms CPU time)\n\nRan 13 tests for test/SIAdversarialBoundaries.t.sol:SIAdversarialBoundariesTest\n[PASS] testFuzz_exactOutputChargesOnlyInputCurrencyAndExactWalletSpend(uint256,bool) (runs: 1000, μ: 399281, ~: 409008)\nLogs:\n  Bound result 3717209482441875011981\n\n[PASS] testFuzz_transferFromSelfConsumesOnlyFiniteAllowance(uint256,uint256) (runs: 1000, μ: 137783, ~: 138070)\nLogs:\n  Bound result 143238499692185822174492\n  Bound result 115792089237316195423570985008687907853269984665640563896219101367011913677869\n\n[PASS] test_callbackStateMachineRejectsRepetitionAndRecovers() (gas: 627508)\n[PASS] test_everyPoolKeyComponentIsBoundToTheIntendedPool() (gas: 581865)\n[PASS] test_feeAndSplitRoundingAtOneWeiAndEachThreshold() (gas: 13701535)\n[PASS] test_hookConstructorRejectsMismatchedDependenciesAndMissingCode() (gas: 12640)\n[PASS] test_hookRejectsZeroAndOutOfInt128DomainBeforeAnyReservation() (gas: 606551)\n[PASS] test_maximumSupportedBudgetReservationDoesNotOverflow() (gas: 70114)\n[PASS] test_maximumTransferAndFailedDelegatedTransferPreserveState() (gas: 118958)\n[PASS] test_noReturnTransferFromWorksAndOutputGoesToChosenRecipient() (gas: 973036)\n[PASS] test_routerRejectsSelfAndManagerAsRecipientAndUnauthenticatedCallback() (gas: 106805)\n[PASS] test_settlementFailuresRollBackMutationsPayoutsAndFiniteAllowance() (gas: 4531649)\n[PASS] test_transferFromCallbackCannotStartNestedSwap() (gas: 1867198)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 139.26ms (252.01ms CPU time)\n\nRan 3 tests for test/PrepareLaunch.t.sol:PrepareLaunchTest\n[PASS] test_planDeploysPredictedContractsAndPreservesSupply() (gas: 239578501)\n[PASS] test_pricesMatchIndependentIntegerReferenceForBothCurrencyOrders() (gas: 498768962)\n[PASS] test_rejectsMissingAddressesAndUnsupportedDecimals() (gas: 106910)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 323.17ms (417.56ms CPU time)\n\nRan 2 tests for test/invariant/SIFeeAccountingInvariant.t.sol:SIAsCurrencyOneInvariantTest\n[PASS]\nSIAsCurrencyOneInvariantTest invariants:\n[PASS] invariant_allTokensAreConservedAcrossTradersPoolAndSinks\n[PASS] invariant_deferredFeesAreFullyBackedAndRouterRetainsNoFunds\n[PASS] invariant_feesArePaidOrRemainOwedToExactlyTheIntendedRecipient\n SIAsCurrencyOneInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| SIFeeSequenceHandler | donateSI          | 2652  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | flush             | 2763  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | rejectedSwap      | 2731  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | roundTrip         | 2738  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | setPayoutBehavior | 2815  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | swap              | 2685  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 9866\n  Bound result 9800276528634195435\n  Bound result 17409\n  Bound result 939095471976916506400\n  Bound result 53261\n  Bound result 4594\n  Bound result 1045\n  Bound result 14641\n  Bound result 330027593299108325658\n  Bound result 10\n  Bound result 10049\n  Bound result 16150\n  Bound result 13314\n  Bound result 934\n  Bound result 296\n  Bound result 115788162\n  Bound result 2626\n  Bound result 6347\n  Bound result 7525\n  Bound result 1663\n  Bound result 5\n  Bound result 2175\n  Bound result 9\n  Bound result 1187668587\n  Bound result 3000\n  Bound result 5635\n  Bound result 2888\n  Bound result 4097\n  Bound result 1051\n  Bound result 5305\n  Bound result 69136721345997384490\n  Bound result 16170\n  Bound result 63349718259392808727\n  Bound result 6999999999999999999\n  Bound result 500000000000000000000\n  Bound result 100000\n  Bound result 13805\n  Bound result 1628\n  Bound result 25019331111857830687\n  Bound result 48266761126677\n  Bound result 53261\n  Bound result 1170413884\n  Bound result 255\n  Bound result 28\n  Bound result 499963056897212663632\n  Bound result 12523\n  Bound result 11277\n  Bound result 74752035793766770263\n  Bound result 15999999999999986098\n  Bound result 40816695540734374\n\n[PASS] test_sequenceWitnessIncludesFailurePartialFillRecoveryAndRoundTrip() (gas: 2971373)\nLogs:\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 100000000000000000000\n  Bound result 16163266782143934272\n  Bound result 300000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 11.15s (11.14s CPU time)\n\nRan 2 tests for test/invariant/SIFeeAccountingInvariant.t.sol:SIAsCurrencyZeroInvariantTest\n[PASS]\nSIAsCurrencyZeroInvariantTest invariants:\n[PASS] invariant_allTokensAreConservedAcrossTradersPoolAndSinks\n[PASS] invariant_deferredFeesAreFullyBackedAndRouterRetainsNoFunds\n[PASS] invariant_feesArePaidOrRemainOwedToExactlyTheIntendedRecipient\n SIAsCurrencyZeroInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭----------------------+-------------------+-------+---------+----------╮\n| Contract             | Selector          | Calls | Reverts | Discards |\n+=======================================================================+\n| SIFeeSequenceHandler | donateSI          | 2652  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | flush             | 2763  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | rejectedSwap      | 2731  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | roundTrip         | 2738  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | setPayoutBehavior | 2815  | 0       | 0        |\n|----------------------+-------------------+-------+---------+----------|\n| SIFeeSequenceHandler | swap              | 2685  | 0       | 0        |\n╰----------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 15803\n  Bound result 9800276528634195435\n  Bound result 4000000000000000000\n  Bound result 17359\n  Bound result 2599\n  Bound result 53261\n  Bound result 1036\n  Bound result 15210\n  Bound result 330027593299108325658\n  Bound result 17\n  Bound result 16226\n  Bound result 15943\n  Bound result 43685020\n  Bound result 8710\n  Bound result 599290590\n  Bound result 3688\n  Bound result 2624\n  Bound result 6347\n  Bound result 7342\n  Bound result 1661\n  Bound result 5\n  Bound result 2173\n  Bound result 9\n  Bound result 119\n  Bound result 3000\n  Bound result 345\n  Bound result 3232\n  Bound result 4097\n  Bound result 1026\n  Bound result 5069\n  Bound result 69136721345997384490\n  Bound result 409922888120531943422\n  Bound result 63349718259392808727\n  Bound result 6999999999999999999\n  Bound result 500000000000000000000\n  Bound result 100000\n  Bound result 13455\n  Bound result 1629\n  Bound result 25019331111857830687\n  Bound result 48266761126677\n  Bound result 53261\n  Bound result 11373\n  Bound result 255\n  Bound result 28\n  Bound result 499963056897212663632\n  Bound result 12414\n  Bound result 11247\n  Bound result 74752035793766770263\n  Bound result 15999999999999985957\n  Bound result 40799897069345305\n\n[PASS] test_sequenceWitnessIncludesFailurePartialFillRecoveryAndRoundTrip() (gas: 2972358)\nLogs:\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 100000000000000000000\n  Bound result 16163265149476112832\n  Bound result 300000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 11.40s (11.36s CPU time)\n\nRan 2 tests for test/invariant/TokenVaultInvariant.t.sol:TokenVaultInvariantTest\n[PASS]\nTokenVaultInvariantTest invariants:\n[PASS] invariant_balancesAndAllowancesMatchIndependentLedger\n[PASS] invariant_vaultViewsIncludeAllDonationsAndBurnsForever\n TokenVaultInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭-------------------+-----------------------+-------+---------+----------╮\n| Contract          | Selector              | Calls | Reverts | Discards |\n+========================================================================+\n| TokenVaultHandler | approve               | 2708  | 0       | 0        |\n|-------------------+-----------------------+-------+---------+----------|\n| TokenVaultHandler | attemptEscape         | 2730  | 0       | 0        |\n|-------------------+-----------------------+-------+---------+----------|\n| TokenVaultHandler | invalidTransfer       | 2761  | 0       | 0        |\n|-------------------+-----------------------+-------+---------+----------|\n| TokenVaultHandler | revokeAndAttemptSpend | 2753  | 0       | 0        |\n|-------------------+-----------------------+-------+---------+----------|\n| TokenVaultHandler | transfer              | 2721  | 0       | 0        |\n|-------------------+-----------------------+-------+---------+----------|\n| TokenVaultHandler | transferFrom          | 2711  | 0       | 0        |\n╰-------------------+-----------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 4295128740\n  Bound result 57849828\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 6659\n  Bound result 0\n  Bound result 107000000000000000000\n  Bound result 0\n  Bound result 274\n  Bound result 51966\n  Bound result 87088830\n  Bound result 258834908\n  Bound result 251553709\n  Bound result 9174\n  Bound result 0\n  Bound result 107742814\n  Bound result 0\n  Bound result 888\n  Bound result 5246\n  Bound result 0\n  Bound result 0\n  Bound result 1365\n  Bound result 88982648684142701601680982\n  Bound result 0\n  Bound result 0\n  Bound result 163276254814114198318013706\n  Bound result 7682\n  Bound result 0\n  Bound result 0\n  Bound result 121226850\n  Bound result 0\n\n[PASS] test_handlerExercisesFullBalanceInfiniteApprovalAndRejection() (gas: 2365175)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 249999999000000000000000000\n  Bound result 249999999000000000000000000\n  Bound result 315360000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 19.59s (19.56s CPU time)\n\nRan 8 test suites in 19.60s (43.00s CPU time): 58 tests passed, 0 failed, 0 skipped (58 total tests)\n","passed":true},{"durationMs":96,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SIFeeHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"SIFeeHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"SIFeeHook.deliver(address,address,uint256)\",\"SIFeeHook.flush(address,address,uint256)\",\"SIFeeHook.unlockCallback(bytes)\",\"SISwapRouter.swap((address,address,uint24,int24,address),(bool,int256,uint160),uint256,uint256,address,uint256)\",\"SISwapRouter.unlockCallback(bytes)\",\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":13,\"README.md\":98,\"VALIDATION.md\":16,\"foundry.toml\":16,\"remappings.txt\":3,\"script/PrepareLaunch.s.sol\":158,\"src/HookFlags.sol\":16,\"src/LaunchLiquidity.sol\":48,\"src/PoolInitializationGuard.sol\":29,\"src/SICommunityVault.sol\":34,\"src/SIFeeHook.sol\":227,\"src/SISwapRouter.sol\":129,\"src/SwarmInu.sol\":64,\"src/interfaces/IERC20.sol\":14,\"test/LaunchHelpers.t.sol\":163,\"test/PrepareLaunch.t.sol\":128,\"test/SIAdversarialBoundaries.t.sol\":299,\"test/SIFeeHook.t.sol\":426,\"test/TESTING.md\":24,\"test/TokenVault.t.sol\":191,\"test/helpers/SIIntegrationFixture.sol\":81,\"test/invariant/SIFeeAccountingInvariant.t.sol\":381,\"test/invariant/TokenVaultInvariant.t.sol\":208,\"test/mocks/AdversarialIMD.sol\":80,\"test/mocks/SettlementIMD.sol\":65},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d13a894d87d06800e5d8d44e6e62326dd7dc62ebfee21bfe7555450a84e35faf","verifiedTreeHash":"d999ddce302a9969483f217788e562950722665d","verifierVersion":"0.1.0+94826a22"}]}