{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"f7d306f0-2f43-4c58-a466-23ab573b494a","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"11583851dd73523c2f241b405dbdd22d206faac3888b6c8f465b07ba99e2d547","dependsOn":["manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"e5af34906c0960e4adae230ca52b8d304ba0f241ee57abd70647925764c9c2f9","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"}],"objective":"Begin with an audit-imported-code step: audit both contracts, the library and the deploy script exactly as they arrived in this repository, before anything is adapted, and report findings rather than fixing them. Only then deploy the Ponzinomics ($PIMD) contracts to Robinhood Chain (4663) and open the pool, exactly as they are. Two contracts to deploy. PimdToken is an ERC-20 named Ponzinomics, symbol PIMD, with a fixed total supply of exactly 1,000,000,000 at 18 decimals, minted once in a constructor that takes no arguments, to whoever deploys it; there is no owner, no mint, no burn and no pause, and burning is a plain transfer to 0xdEaD so totalSupply never moves. PimdHook is a Uniswap V4 hook whose constructor takes the pool manager, the token address and the launch factory, so its constructorArgs are $poolManager, $token and $factory; everything else is a source constant. It does not gate the opening price: it accepts the pool the factory opens and reads the tick only for its Launched event. It taxes every trade in IMD, 2.4% on buys and 5.6% on sells, split 75% to holders and 25% to the team, taking its fees as ERC-6909 claims on the quote currency. The pool's own 1.25% fee sits on top of that tax and the hook never touches it. A third contract, PimdEngine, is already deployed at 0xFFDB5Dd341F692a29b5a0d3D1577DF683C1bACa4 and its address is baked into PimdHook as a constant: audit it as imported code, but do not deploy or redeploy it. Do not change the economics, the tax rates, the split, the tier ladder or the opening tick: they are settled, and the opening tick follows the chain policy's 2500 IMD initial market cap. If you find a defect, report it rather than redesigning around it. Three things deserve the most attention. First, the hook accepts the token against IMD in EITHER currency order, because V4 orders currencies by address and the factory decides where the token lands; it records which side IMD is on at initialization and every direction test and IMD amount goes through _isBuy, _imdIsSpecified and _imdAmount, so a buy is always IMD in and the token out whichever way the pool sorts. beforeInitialize still refuses a second pool, a caller that is not the factory, a pairing that is not this token and IMD, and a fee tier outside the permitted set, and it does not gate the opening price. Second, beforeAddLiquidity must let the factory's seed through exactly once and refuse every add after it, because 'third-party liquidity is blocked' is an advertised property; and beforeRemoveLiquidity must refuse every negative liquidity delta for ever while still allowing the zero delta that collects the pool's own fee. Third, the engine must never read holder weights while the PoolManager is unlocked, which is where a flash borrower would stand.","parentJobId":null,"planHash":"539c9fd4a79968020e7cacd40fcc4da9e8d6a84c308727174bdf89ca33a1edd2","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"f7d306f0-2f43-4c58-a466-23ab573b494a","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1439-src-pimd-pimdtoken-sol-src-pimd-pimdhook"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51419","feedbackHash":"3ad89dfffd14e9b3b0b620485211b924bfb684465c58bb1348af05015d997bc9","nodeKey":"audit_imported_code","submissionHash":"11583851dd73523c2f241b405dbdd22d206faac3888b6c8f465b07ba99e2d547","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51447","feedbackHash":"0203684160d34d3bf6023b0e2ade22bb74518a86702c770f03412118ceb14e0d","nodeKey":"manifest","submissionHash":"e5af34906c0960e4adae230ca52b8d304ba0f241ee57abd70647925764c9c2f9","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"702b9fb3ac3d7a03cc55b0cfd5388013d650194c01176e5130788407170bea56","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fea57d3e9d0ca7bf","findings":[{"citation":"resolved","description":"pool.initialPrice is 2^96, i.e. sqrtPrice 1.0, tick 0: one IMD buys one PIMD, so the billion-token supply opens at a 1,000,000,000 IMD market cap. The task states the opening tick follows the chain policy's 2,500 IMD initial market cap, which the hook itself records as LAUNCH_TICK = 129_000 (2.5e-6 IMD per PIMD with PIMD as currency1; the mirror pool needs tick -129_000). Since commit 63d1f82 beforeInitialize no longer gates the price, so whatever sqrtPriceX96 the deployer passes is accepted and latched as the one pool this hook will ever serve (launched = true). If the deployer honours the manifest's initialPrice the pool opens 400,000x above the intended price; if the factory overrides it from chain policy the manifest field is simply wrong documentation. Either way the field cannot be right for both currency orderings, because the correct tick is +129000 when IMD is currency0 and -129000 when it is currency1, and the token's address is not known until the factory deploys it. The adapter must resolve which party sets the price and make the manifest agree with it.","line":31,"path":"launch.json","reproduction":"State: fresh PimdHook, pool not yet opened. Input: factory calls PoolManager.initialize(key{token, IMD, fee 12500, spacing 60, hook}, sqrtPriceX96 = 79228162514264337593543950336). Actual: beforeInitialize accepts, launched = true, Launched(id, tick = 0) is emitted, no second pool can ever be opened (test/scratch/Review.t.sol test_manifest_price_opens_at_tick_zero passes on the current code). Expected per the task and LAUNCH_TICK: Launched tick within LAUNCH_TICK_TOLERANCE of 129000 (IMD currency0) or -129000 (IMD currency1), i.e. sqrtPriceX96 = TickMath.getSqrtPriceAtTick(129000) = 50111677533496076234078224273595 or getSqrtPriceAtTick(-129000) = 125262255113908064987203232 (both computed with v4-core TickMath; getTickAtSqrtPrice(79228162514264337593543950336) = 0). A buyer who spends 1 IMD at tick 0 would receive about 0.976 PIMD after the 2.4% tax instead of about 390,000 PIMD.","severity":"medium","snippet":"    \"initialPrice\": \"79228162514264337593543950336\"","title":"launch.json opens the pool at tick 0 (1 IMD per PIMD, 1e9 IMD market cap), not at the settled 2,500 IMD opening cap"},{"citation":"resolved","description":"beforeAddLiquidity admits only sender == LAUNCH_FACTORY and only once (seeded latch), and beforeInitialize admits only sender == LAUNCH_FACTORY. V4 passes msg.sender of PoolManager.initialize / PoolManager.modifyLiquidity as sender, so both calls must be made by the factory contract itself from inside its own unlock callback, and the whole seed must be one modifyLiquidity. The rehearsal (script/RehearsalSeeder.sol) and tests (MockLaunchFactory) assume exactly that; the real factory is resolved from $factory at deploy time and its code was not available to this review. If it instead routes the seed through PositionManager or any router (sender = that router), or splits the seed into two ranges, the pool is already initialised and launched = true, so the hook can never accept liquidity for the only pool it will ever serve, and no second pool can be opened: the launch is paid for and dead. The hook has no owner and no escape path. This is a precondition the adapter must verify against the factory's code rather than a code bug in the hook, and it is the reason this is medium rather than info.","line":391,"path":"src/pimd/PimdHook.sol","reproduction":"State: pool opened by the factory (launched = true, seeded = false). Input A: factory seeds via a periphery contract P, so PoolManager.modifyLiquidity is called by P with liquidityDelta > 0. Actual: beforeAddLiquidity(sender = P) reverts NotLaunchFactory; the seed never lands; no later call from any address can add liquidity because the pool stays initialised and launched is latched. Input B: factory seeds in two modifyLiquidity calls (two ranges). Actual: first call sets seeded = true, second reverts LiquidityIsLocked (existing test test_even_the_factory_gets_only_one_add shows the latch). Expected: whatever the real factory does, the seed lands once. Verification needed: the factory's bytecode or source showing it calls PoolManager.initialize and a single PoolManager.modifyLiquidity directly.","severity":"medium","snippet":"        if (sender != launchFactory()) revert NotLaunchFactory();","title":"The launch is unrecoverable if the factory does not seed with exactly one direct PoolManager.modifyLiquidity call; the factory could not be read to confirm it does"},{"citation":"resolved","description":"On this line imd0_ is always false (the branch is only reached when both imd0_ and imd1_ are false), so the error always carries c0. When the pairing contains this token but the other side is not IMD, the offending currency is c1 whenever the token sorts below it, and the hook then reports its own token's address as the wrong quote. The revert itself is correct, so no funds are at risk; the diagnostic is wrong in the ordering that commit 71db64e added support for. The intended expression is `c0 == address(token) ? c1 : c0`.","line":272,"path":"src/pimd/PimdHook.sol","reproduction":"State: fresh hook, token address sorting below some ERC-20 X that is not IMD. Input: PoolManager.initialize(key{currency0 = token, currency1 = X, fee 12500, spacing 60, hook}, any price). Actual: revert WrongQuoteCurrency(token). Expected: revert WrongQuoteCurrency(X). test/scratch/Review.t.sol test_wrong_quote_error_names_the_token_not_the_quote fails on the current code with exactly this mismatch (WrappedError(..., WrongQuoteCurrency(0x2e23...470b = token)) != expected WrongQuoteCurrency(0x3bd5...ca7b = X)).","severity":"low","snippet":"            revert WrongQuoteCurrency(imd0_ ? c1 : c0);","title":"WrongQuoteCurrency reports the launch token instead of the offending quote when the token is currency0"},{"citation":"resolved","description":"Trust assumption, reported as the Pashov adapter requires rather than as a code bug. The hook pushes the holders' slice to ENGINE_ADDRESS on every flush/flushHolders regardless of the engine's state, and on chain the engine is unbound (bound() = false). bind is callable only by binder = 0x0960E8Bd80462e3842Bb6620c7C5289A44c4559B (also the team wallet), exactly once, and only after the pool exists (it requires hook.quote() == IMD). fire reverts NotBound until then, and nothing in the engine can move IMD except the drip, so every IMD flushed before bind, or forever if the binder's key is lost or bind is never called, sits in the engine with no sweep. tally is further restricted to two keeper EOAs fixed at construction with no way to add one; if both are lost the drip stops permanently (documented in the engine's keeper NatSpec). Holders are therefore exposed to the team's operational liveness for the entire advertised 75%.","line":278,"path":"src/pimd/PimdEngine.sol","reproduction":"State: on-chain engine 0xFFDB5Dd341F692a29b5a0d3D1577DF683C1bACa4 with bound() = false (current state). Sequence after launch: trades accrue holdersOwed; anyone calls PimdHook.flush() -> engine IMD balance rises; anyone calls PimdEngine.fire() -> reverts NotBound; PimdEngine.seed/pay/tally/prune cannot move it either. Expected: holders paid by the drip. Actual: IMD stranded until 0x0960...559B calls bind(token, hook, [distributor]) with the exact token and hook; if that address never does, permanently. Also the binder must include the airdrop distributor in alsoExclude or it is paid drips it cannot forward (DeployPimd.s.sol:116).","severity":"low","snippet":"    function bind(address token_, address hook_, address[] calldata alsoExclude) external {","title":"Holders' 75% can only ever flow if one EOA calls bind once and two keeper EOAs keep tallying; IMD pushed to the engine before then has no way back"},{"citation":"resolved","description":"Since commit 71db64e the hook accepts IMD as either currency and routes every amount through _isBuy/_imdIsSpecified/_imdAmount; beforeInitialize no longer enforces IMD as currency0. The @dev block still says the opposite. Likewise getHookPermissions (line 224, 'the pool must pair PIMD with IMD, at the briefed price') says beforeInitialize checks the price, which commit 63d1f82 removed. An adapter or auditor reading the header is told the wrong invariants to protect.","line":50,"path":"src/pimd/PimdHook.sol","reproduction":"Read-only. Compare PimdHook.sol:50 and :224 with beforeInitialize (lines 259-277, 287): the pool with currency0 = token, currency1 = IMD is accepted (test_the_tax_is_read_the_right_way_round_when_the_token_is_currency0 passes) and the price argument is only used for the Launched event.","severity":"info","snippet":"/// `take`-ing; every fee calculation assumes **IMD is currency0**, which `beforeInitialize` enforces rather","title":"Hook NatSpec contradicts the code on currency ordering and on price gating"},{"citation":"resolved","description":"The deploy script's header says the factory constructs the hook with just the pool manager and the token; the constructor has taken a third argument, $factory, since commit 63d1f82 and launch.json lists three constructorArgs. script/RehearsePimd.s.sol builds the rehearsal PoolKey with fee: 0 (line 36) and speaks of 'the 7% side' (line 72) although the pool fee is 12500 and the sell tax 5.6%, and it reads deployments.pimd.4663.json, which is not in the repository. The script deploys only the engine, which is already live, so none of this affects the launch, but the rehearsal as written cannot find the pool it means to trade against (fee 0 is part of the PoolId).","line":10,"path":"script/DeployPimd.s.sol","reproduction":"Run forge script script/RehearsePimd.s.sol against a fork with the launched pool: vm.readFile('deployments.pimd.4663.json') reverts because the file does not exist; with a hand-made file, router.swap on a key with fee 0 reverts PoolNotInitialized because the launched pool's key has fee 12500. Expected: the rehearsal trades against the launched pool.","severity":"info","snippet":"/// The hook and the token are deployed by the IMD launch factory, which constructs the hook with just the","title":"DeployPimd and RehearsePimd describe a hook and pool that no longer exist"},{"citation":"resolved","description":"The cap is tracked per tx.origin for the first 600 seconds / 6000 L2 blocks. One actor with N funded EOAs can spend 25*N IMD in the window, and a contract wallet (ERC-4337 account) shares its bundler's tx.origin with every other user of that bundler, so unrelated users can exhaust each other's cap. Documented in launch.json notes as a known limit; recorded here so nobody relies on it as a hard per-person cap. No funds at risk.","line":373,"path":"src/pimd/PimdHook.sol","reproduction":"State: inside the launch window. Input: EOA A buys exact-in 25e18 IMD (passes, launchBuys[A] = 25e18), EOA B controlled by the same person buys 25e18 (passes). Actual: 50 IMD spent by one actor. Expected by a reader of 'launchBuyCap': 25. Conversely, bundler EOA R submits a UserOp for account X buying 25 IMD then one for account Y buying 1 IMD in the window: the second reverts LaunchBuyCap although Y never bought.","severity":"info","snippet":"                uint256 total = launchBuys[tx.origin] + spent;","title":"The 25 IMD launch buy cap is keyed on tx.origin and is a soft limit only"}],"hash":"11583851dd73523c2f241b405dbdd22d206faac3888b6c8f465b07ba99e2d547","nodeId":"6a05f439-e5f1-4bac-beee-aa05ddcadf10","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the report. No tracked file was changed.\n\n**What was read.** All of PimdToken, PimdHook, PimdEngine, L2Block and DeployPimd, plus the rehearsal scripts, launch.json, and the relevant v4-core routing and lock code. The build passes and all 94 existing tests pass, including the fork suite. On Robinhood Chain I read the deployed engine's configuration and fetched its runtime bytecode. It matches the local build of the engine source byte for byte once immutables are masked, and it is unbound with production parameters.\n\n**What could not be reached.** The launch factory, whose address is only resolved from `$factory` at deploy time, and the IMD token's source and owner powers.\n\n**Findings, most severe first.**\n\n- **Medium, manifest price.** launch.json's initialPrice is 2^96, which is tick 0 and a one billion IMD market cap. The task settles the opening tick at the chain policy's 2,500 IMD cap, which the hook records as tick 129000 or minus 129000 depending on currency order. The hook no longer gates price, so it accepts either. The adapter must settle who sets the price and make the manifest agree.\n- **Medium, factory seeding assumption.** The hook admits initialize and the one liquidity add only from the factory as direct caller, and only one add. If the real factory seeds through a periphery contract or in two ranges, the pool is latched open with no liquidity and no recovery. I could not read the factory to confirm.\n- **Low, wrong revert argument.** When the token is currency0 and the other side is not IMD, the revert names the token rather than the offending currency. Reproduced by a scratch test.\n- **Low, trust assumption.** Holders' 75% depends on the team wallet calling bind once and on two fixed keeper addresses. IMD flushed to the engine before bind has no sweep.\n- **Three info items.** Stale NatSpec in the hook that still claims IMD must be currency0 and that the price is checked. The deploy and rehearsal scripts describe a two-argument hook, a fee-0 pool and a missing deployments file. The launch buy cap is per tx.origin and so a soft limit only.\n\n**The three focus areas hold.** Either currency order is handled consistently through the three direction helpers. The seed is admitted exactly once from the factory, every negative liquidity delta is refused forever, and the zero delta for fee collection passes. Every engine function that reads balances first checks the PoolManager's unlocked slot, whose constant I verified against v4-core.\n\nThe coverage record answers all 20 listed entry points plus five invariants. No finding reached critical or high, so no proof files are attached. The scratch test under test/scratch/ is disposable.","treeHash":null,"usage":{"cachedInputTokens":1594408,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":46555,"runtime":"claude","turns":33,"wallClockMs":923638}},{"artifacts":[],"attempt":1,"bundleHash":"663e053c45d540e8cb979fb45651887042fe55820974b0a66eb128b040545a99","device":"e0f64c10e30e33e2","findings":[],"hash":"e5af34906c0960e4adae230ca52b8d304ba0f241ee57abd70647925764c9c2f9","nodeId":"172dc002-42d0-4133-9fa2-3b74278685a0","outcome":"completed","summary":"I've written `launch.json` and changed no other file. It parses as JSON, `kind` is the first field, and the notes are 2,370 characters, under the 4,000 cap. `forge build` succeeds and all 94 `forge test` tests pass. Nothing ran the actual schema validator, so schema validity is checked only by reading the file against the brief's rules.\n\n**What the manifest says:**\n- **Hook:** `PimdHook`, with constructor arguments `[\"$poolManager\", \"$token\", \"$factory\"]`.\n- **Permissions:** exactly what `getHookPermissions` returns: `beforeInitialize`, `afterInitialize`, `beforeAddLiquidity`, `beforeRemoveLiquidity`, `beforeSwap`, `afterSwap`, `beforeSwapReturnDelta`, `afterSwapReturnDelta`.\n- **Token:** `PimdToken`, named Ponzinomics, symbol PIMD, 18 decimals.\n- **Pool:** paired with IMD (`0x5f7b…7127`), fee 12500, tickSpacing 60, initialPrice `79228162514264337593543950336`. The hook accepts fee 12500.\n\n**Audit of the code as it arrived (reported in notes, nothing fixed):**\n1. **Currency order:** the hook accepts the token and IMD in either order and records which side IMD is on. Every direction test and IMD amount goes through `_isBuy`, `_imdIsSpecified` and `_imdAmount`, and I checked those for all four swap types (buy or sell, exact-in or exact-out). `beforeInitialize` refuses a second pool, any caller other than the factory, any other pairing, and fees outside {500, 3000, 10000, 12500}, including the dynamic-fee flag. It does not gate the opening price. One small gap: it doesn't check tickSpacing.\n2. **Liquidity:** the factory can add liquidity once and every later add is refused. Every withdrawal is refused forever, while the zero-size removal that collects the pool's fee still works.\n   - **Risk:** the hook only accepts the seed if the factory calls the PoolManager's `modifyLiquidity` itself. The rehearsal script does this. If the real factory seeds through PositionManager or a router, the seed reverts.\n3. **Engine:** every function that changes state refuses to run while the PoolManager is unlocked. The slot it reads matches Uniswap V4's unlock flag, so holder weights are never read where a flash borrower could stand. I read the deployed engine on Robinhood Chain: it has code, it is not yet bound, and its settings are the production values (drip 150, minimum interval 900 seconds). I did not compare its bytecode to the source. Once the pool launches, the binder still has to call `bind(token, hook, [distributor])`, or no payouts reach holders.\n4. **Smaller points:**\n   - A swap that fixes the IMD amount and only partly fills reverts with `PartialFill`. This is intended.\n   - Several wallets can get round the launch buy cap of 25 IMD per wallet.\n   - `LAUNCH_TICK` is for information only.\n   - Some comments contradict the code. The hook's comments say the fee maths assumes IMD is currency0 and that `beforeInitialize` checks the price. `DeployPimd`'s comments say the hook takes only the pool manager and the token.\n\nI haven't committed `launch.json`; it's an untracked file in the working tree.","treeHash":"9f05a4b76000ecf1227a60df56936890ff282242","usage":{"cachedInputTokens":466660,"inputTokens":22,"model":"claude-opus-5-5","outputTokens":7412,"runtime":"claude","turns":11,"wallClockMs":247362}}],"verification":[{"checks":[{"durationMs":78437,"exitCode":0,"name":"build","output":"Compiling 90 files with Solc 0.8.26\nSolc 0.8.26 finished in 78.25s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/pimd/PimdFixes.t.sol:684:5:\n    |\n684 |     function _maxHolders() internal view override returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/pimd/PimdFixes.t.sol:939:5:\n    |\n939 |     function _maxHolders() internal view override returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n   ╭▸ src/libraries/L2Block.sol:17:39\n   │\n17 │         (bool ok, bytes memory ret) = ARBSYS.staticcall{gas: ARBSYS_GAS}(abi.encodeWithSignature(\"arbBlockNumber()\"));\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[missing-events-arithmetic]: `totalWeight` is changed without an event but is used in arithmetic\n    ╭▸ src/pimd/PimdEngine.sol:541:9\n    │\n541 │         totalWeight = tw;\n    │         ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-arithmetic]: `cursor` is changed without an event but is used in arithmetic\n    ╭▸ src/pimd/PimdEngine.sol:542:9\n    │\n542 │         cursor = end;\n    │         ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-arithmetic]: `tipBudget` is changed without an event but is used in arithmetic\n    ╭▸ src/pimd/PimdEngine.sol:767:9\n    │\n767 │         tipBudget = budget - amt;\n    │         ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-arithmetic]: `pot` is changed without an event but is used in arithmetic\n    ╭▸ src/pimd/PimdEngine.sol:768:9\n    │\n768 │         pot -= amt;\n    │         ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/pimd/PimdEngine.sol:264:45\n    │\n264 │             if (c.keepers[i] == address(0)) revert BadConfig();\n    │                                             ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/pimd/PimdHook.sol:295:9\n    │\n295 │         emit Launched(key.toId(), tick);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:293:21\n    │\n293 │         initBlock = uint64(L2Block.number());\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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/pimd/PimdHook.sol:294:23\n    │\n294 │         launchStart = uint64(block.timestamp);\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/pimd/PimdHook.sol:323:28\n    │\n323 │         _tstore(_FEE_SLOT, fee);\n    │                            ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:315:46\n    │\n315 │                 params.amountSpecified < 0 ? uint256(-params.amountSpecified) : uint256(params.amountSpecified);\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/pimd/PimdHook.sol:315:81\n    │\n315 │                 params.amountSpecified < 0 ? uint256(-params.amountSpecified) : uint256(params.amountSpecified);\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/pimd/PimdHook.sol:324:63\n    │\n324 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(uint128(fee)), 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/pimd/PimdHook.sol:324:70\n    │\n324 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(uint128(fee)), 0), 0);\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-no-eth]: external call can be reentered before `locked` is updated\n    ╭▸ src/pimd/PimdEngine.sol:329:17\n    │\n329 │         require(imd.transferFrom(msg.sender, address(this), amount));\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/pimd/PimdEngine.sol:332:9\n    │\n332 │         emit Seeded(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/pimd/PimdHook.sol:380:44\n    │\n380 │         return (IHooks.afterSwap.selector, hookDeltaUnspecified);\n    │                                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/pimd/PimdHook.sol:369:24\n    │\n369 │                     && block.timestamp < uint256(launchStart) + launchCapSeconds\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/pimd/PimdHook.sol:370:24\n    │\n370 │                     && block.timestamp < uint256(launchStart) + LAUNCH_CAP_MAX_SECONDS\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/pimd/PimdHook.sol:572:9\n    │\n572 │         emit FeeTaken(isBuy, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:345:43\n    │\n345 │             uint256 movedQuote = aq < 0 ? uint256(uint128(-aq)) : uint256(uint128(aq));\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/pimd/PimdHook.sol:345:51\n    │\n345 │             uint256 movedQuote = aq < 0 ? uint256(uint128(-aq)) : uint256(uint128(aq));\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:345:67\n    │\n345 │             uint256 movedQuote = aq < 0 ? uint256(uint128(-aq)) : uint256(uint128(aq));\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/pimd/PimdHook.sol:345:75\n    │\n345 │             uint256 movedQuote = aq < 0 ? uint256(uint128(-aq)) : uint256(uint128(aq));\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:353:40\n    │\n353 │             uint256 quoteAmt = a < 0 ? uint256(uint128(-a)) : uint256(uint128(a));\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/pimd/PimdHook.sol:353:48\n    │\n353 │             uint256 quoteAmt = a < 0 ? uint256(uint128(-a)) : uint256(uint128(a));\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:353:63\n    │\n353 │             uint256 quoteAmt = a < 0 ? uint256(uint128(-a)) : uint256(uint128(a));\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/pimd/PimdHook.sol:353:71\n    │\n353 │             uint256 quoteAmt = a < 0 ? uint256(uint128(-a)) : uint256(uint128(a));\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:360:36\n    │\n360 │             hookDeltaUnspecified = int128(uint128(fee));\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/pimd/PimdHook.sol:360:43\n    │\n360 │             hookDeltaUnspecified = int128(uint128(fee));\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdHook.sol:372:33\n    │\n372 │                 uint256 spent = uint256(uint128(-_imdAmount(delta))) + fee;\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/pimd/PimdHook.sol:372:41\n    │\n372 │                 uint256 spent = uint256(uint128(-_imdAmount(delta))) + fee;\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[calls-loop]: external call inside a loop\n    ╭▸ src/pimd/PimdEngine.sol:350:27\n    │\n350 │             uint256 bal = IERC20Min(token).balanceOf(a);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/pimd/PimdEngine.sol:807:17\n    │\n807 │             if (IERC20Min(token).balanceOf(a) < minBalance || _shapeChanged(a, _holder[a])) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/pimd/PimdEngine.sol:792:9\n    │\n792 │         emit Pruned(a);\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/pimd/PimdEngine.sol:367:17\n    │\n367 │                 emit RegistrationDeferred(a, reclaimCursor);\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/pimd/PimdEngine.sol:378:13\n    │\n378 │             emit Registered(a);\n    │             ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdEngine.sol:372:24\n    │\n372 │             h.index1 = uint32(holders.length);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' 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/pimd/PimdEngine.sol:376:25\n    │\n376 │             h.lastBal = uint128(bal);\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdEngine.sol:377:29\n    │\n377 │             h.streakStart = uint64(block.timestamp); // the clock starts at registration, never earlier\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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[calls-loop]: external call inside a loop\n    ╭▸ src/pimd/PimdEngine.sol:403:17\n    │\n403 │             if (IERC20Min(token).balanceOf(a) >= minBalance && !_shapeChanged(a, _holder[a]) && !_isPool(a)) continue;\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-no-eth]: external call can be reentered before `phase` is updated\n    ╭▸ src/pimd/PimdEngine.sol:423:17\n    │\n423 │             try hook.flush() {}\n    │                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `phase` is updated\n    ╭▸ src/pimd/PimdEngine.sol:428:21\n    │\n428 │                 try hook.flushHolders() {} catch {}\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/pimd/PimdEngine.sol:415:13\n    │\n415 │         if (block.timestamp < lastFire + minInterval) revert TooSoon();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_lock` is updated\n    ╭▸ src/pimd/PimdHook.sol:453:9\n    │\n453 │         poolManager.unlock(abi.encode(ACTION_HOLDERS, toHolders));\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/pimd/PimdEngine.sol:719:9\n    │\n719 │         emit Income(income);\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/pimd/PimdEngine.sol:443:9\n    │\n443 │         emit Fired(epoch + 1, drip, n);\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/pimd/PimdHook.sol:457:9\n    │\n457 │         emit Flushed(msg.sender, toHolders, 0, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/pimd/PimdHook.sol:453:9\n    │\n453 │         poolManager.unlock(abi.encode(ACTION_HOLDERS, toHolders));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_lock` is updated\n    ╭▸ src/pimd/PimdHook.sol:483:9\n    │\n483 │         poolManager.unlock(abi.encode(ACTION_FLUSH, toHolders, toTeam - tip, msg.sender, tip));\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/pimd/PimdHook.sol:491:9\n    │\n491 │         emit Flushed(msg.sender, toHolders, toTeam, tip);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/pimd/PimdHook.sol:483:9\n    │\n483 │         poolManager.unlock(abi.encode(ACTION_FLUSH, toHolders, toTeam - tip, msg.sender, tip));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pot` is updated\n    ╭▸ src/pimd/PimdEngine.sol:751:13\n    │\n751 │             address(imd).call{gas: SEND_GAS}(abi.encodeCall(IERC20Min.transfer, (to, amount)));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/pimd/PimdEngine.sol:538:32\n    │\n538 │             h.weight = uint128(w);\n    │                                ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/pimd/PimdEngine.sol:523:27\n    │\n523 │             uint256 bal = IERC20Min(token).balanceOf(a);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdEngine.sol:526:33\n    │\n526 │                 h.streakStart = uint64(nowTs); // sold or sent out: the clock restarts\n    │                                 ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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/pimd/PimdEngine.sol:529:33\n    │\n529 │                 h.streakStart = uint64((last * h.streakStart + (bal - last) * nowTs) / bal);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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/pimd/PimdEngine.sol:535:25\n    │\n535 │             h.lastBal = uint128(bal);\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdEngine.sol:538:24\n    │\n538 │             h.weight = uint128(w);\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-no-eth]: external call can be reentered before `cursor` is updated\n    ╭▸ src/pimd/PimdEngine.sol:751:13\n    │\n751 │             address(imd).call{gas: SEND_GAS}(abi.encodeCall(IERC20Min.transfer, (to, amount)));\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/pimd/PimdHook.sol:538:16\n    │\n538 │             && block.timestamp < uint256(launchStart) + launchCapSeconds\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/pimd/PimdHook.sol:539:16\n    │\n539 │             && block.timestamp < uint256(launchStart) + LAUNCH_CAP_MAX_SECONDS;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/pimd/PimdEngine.sol:592:17\n    │\n592 │                 paid += amt;\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/pimd/PimdEngine.sol:593:19\n    │\n593 │                 ++paidHolders;\n    │                   ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/pimd/PimdEngine.sol:751:13\n    │\n751 │             address(imd).call{gas: SEND_GAS}(abi.encodeCall(IERC20Min.transfer, (to, amount)));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/pimd/PimdEngine.sol:596:17\n    │\n596 │                 emit PayoutFailed(a, amt);\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/pimd/PimdEngine.sol:612:13\n    │\n612 │             emit EpochPaid(epoch, epochPaidHolders == 0 ? 0 : total - leftover, epochPaidHolders);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdEngine.sol:591:31\n    │\n591 │                 h.received += uint128(amt);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/pimd/PimdEngine.sol:646:13\n    │\n646 │         if (block.timestamp < lastFire + ABORT_DELAY) revert TooSoon();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/pimd/PimdEngine.sol:751:13\n    │\n751 │             address(imd).call{gas: SEND_GAS}(abi.encodeCall(IERC20Min.transfer, (to, amount)));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/pimd/PimdEngine.sol:789:32\n    │\n789 │         _holder[last].index1 = uint32(idx0 + 1);\n    │                                ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' 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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/pimd/PimdBase.t.sol:290:17\n    │\n290 │         vm.warp(block.timestamp + hook.launchCapSeconds() + 1);\n    │         ────────━━━━━━━━━━━━━━━─────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/pimd/Pimd.t.sol:195:17\n    │\n195 │         vm.warp(block.timestamp + 15 days); // alice reaches 3x\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/pimd/Pimd.t.sol:237:17\n    │\n237 │         vm.warp(block.timestamp + 2 days); // alice is past the first hour, and this epoch clears the backlog\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/pimd/PimdAttacks.t.sol:352:17\n    │\n352 │         vm.warp(block.timestamp + 2 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/pimd/PimdFork.t.sol:236:17\n    │\n236 │         vm.warp(block.timestamp + 601);\n    │         ────────━━━━━━━━━━━━━━━─────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":1420,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/pimd/PimdFixes.t.sol:PimdReclaimCursorTest\n[PASS] test_a_dead_slot_behind_eight_live_ones_is_still_reclaimed() (gas: 2400267)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 226.26ms (876.00µs CPU time)\n\nRan 1 test for test/pimd/Gas.t.sol:GasTest\n[PASS] test_epoch_gas_for_100_holders() (gas: 45451999)\nLogs:\n  fire             408683\n  tally(100)       3489228\n  pay(100)         3562883\n  epoch total      7460794\n  per holder       70521\n  hook.flush       130330\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 227.50ms (23.77ms CPU time)\n\nRan 32 tests for test/pimd/PimdFixes.t.sol:PimdFixesTest\n[PASS] test_a_7702_delegated_wallet_keeps_earning_and_its_streak() (gas: 1973335)\n[PASS] test_a_bag_that_arrives_just_before_the_tally_carries_no_weight() (gas: 2318838)\n[PASS] test_a_deferred_registration_says_so() (gas: 1910436)\n[PASS] test_a_fire_that_opens_no_epoch_emits_nothing() (gas: 843220)\n[PASS] test_a_fresh_buy_earns_from_the_next_epoch() (gas: 2470174)\n[PASS] test_a_null_epoch_pays_no_per_holder_tip() (gas: 1998529)\n[PASS] test_a_null_epoch_pays_the_firer_nothing() (gas: 1682025)\n[PASS] test_a_pay_page_cannot_take_more_than_its_share_of_the_tips() (gas: 3481094)\n[PASS] test_a_refused_team_transfer_does_not_stop_the_drip() (gas: 1463494)\n[PASS] test_a_stuck_epoch_can_be_abandoned_and_the_imd_comes_back() (gas: 1665312)\n[PASS] test_a_walked_bag_cannot_lock_the_holder_set_for_ever() (gas: 1170111)\n[PASS] test_abort_is_refused_when_no_epoch_is_open() (gas: 97384)\n[PASS] test_an_engine_with_no_keeper_cannot_be_deployed() (gas: 13974)\n[PASS] test_an_unbounded_holder_set_cannot_be_configured() (gas: 13371)\n[PASS] test_bind_refuses_a_token_the_hook_does_not_tax() (gas: 57148)\n[PASS] test_everything_except_tally_stays_permissionless() (gas: 1547108)\n[PASS] test_fire_does_not_tip_the_engine_out_of_the_team_slice() (gas: 1407802)\n[PASS] test_firing_into_an_empty_holder_set_pays_no_tip() (gas: 883642)\n[PASS] test_only_a_keeper_can_tally() (gas: 1288292)\n[PASS] test_pay_is_funded_even_when_the_firer_could_take_the_lot() (gas: 2845528)\n[PASS] test_prune_cannot_brick_a_running_epoch() (gas: 2385187)\n[PASS] test_prune_is_refused_during_pay_too() (gas: 1234545)\n[PASS] test_prune_refuses_while_the_pool_is_unlocked() (gas: 1149501)\n[PASS] test_prune_still_works_between_epochs() (gas: 1168503)\n[PASS] test_real_code_still_voids_the_vetted_shape() (gas: 913392)\n[PASS] test_register_refuses_while_the_pool_is_unlocked() (gas: 1040933)\n[PASS] test_the_firer_is_paid_not_the_tallier() (gas: 1257370)\n[PASS] test_the_holder_bound_fits_the_chains_per_transaction_budget() (gas: 14237)\n[PASS] test_the_holder_set_is_bounded() (gas: 1917946)\n[PASS] test_the_keeper_tip_cannot_take_the_whole_team_slice() (gas: 750382)\n[PASS] test_the_launch_factory_and_precompiles_can_never_register() (gas: 749630)\n[PASS] test_total_to_team_matches_what_the_team_received() (gas: 763789)\nSuite result: ok. 32 passed; 0 failed; 0 skipped; finished in 240.14ms (41.35ms CPU time)\n\nRan 14 tests for test/pimd/PimdAttacks.t.sol:PimdAttacksTest\n[PASS] test_a_holder_that_turns_pool_shaped_earns_nothing_at_once() (gas: 2105137)\n[PASS] test_a_holder_that_turns_pool_shaped_is_prunable() (gas: 1812722)\n[PASS] test_a_long_gap_still_releases_only_a_slice() (gas: 1473836)\n[PASS] test_a_pool_like_contract_is_not_paid() (gas: 1434447)\n[PASS] test_a_stranger_can_deploy_it_and_hold_nothing() (gas: 91094)\n[PASS] test_a_wallet_that_grows_code_is_not_stuck_at_zero() (gas: 2751948)\n[PASS] test_dust_holder_is_skipped_and_prunable() (gas: 745766)\n[PASS] test_fire_refuses_while_the_pool_is_unlocked() (gas: 1100067)\n[PASS] test_many_holders_weigh_whole_and_pay_across_pages() (gas: 54705957)\n[PASS] test_one_bag_cannot_be_weighed_twice_across_wallets() (gas: 1839118)\n[PASS] test_one_refused_holder_does_not_stop_the_others() (gas: 2408335)\n[PASS] test_pay_refuses_while_the_pool_is_unlocked() (gas: 1833483)\n[PASS] test_tally_refuses_while_the_pool_is_unlocked() (gas: 1659010)\n[PASS] test_team_is_excluded_from_drips() (gas: 26127)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 392.86ms (41.48ms CPU time)\n\nRan 40 tests for test/pimd/Pimd.t.sol:PimdTest\n[PASS] test_a_partially_filled_buy_is_refused_rather_than_overtaxed() (gas: 787539)\n[PASS] test_a_second_liquidity_add_is_refused() (gas: 448517)\n[PASS] test_a_second_pool_on_this_hook_is_refused() (gas: 47685)\n[PASS] test_a_stranger_cannot_squat_the_seed() (gas: 7291795)\n[PASS] test_a_token_below_imd_opens_the_pool_too() (gas: 27519816)\n[PASS] test_an_excluded_holder_is_never_registered_or_paid() (gas: 642020)\n[PASS] test_bind_is_one_shot() (gas: 38639)\n[PASS] test_buy_pays_the_buy_tax_in_imd() (gas: 561004)\n[PASS] test_drip_releases_about_four_percent_per_fifteen_minutes() (gas: 2337347)\n[PASS] test_even_the_factory_gets_only_one_add() (gas: 64069)\n[PASS] test_exact_out_buy_is_taxed_too() (gas: 859925)\n[PASS] test_exact_out_sell_is_taxed_too() (gas: 826264)\n[PASS] test_fee_collection_is_still_allowed() (gas: 693430)\n[PASS] test_first_hour_pays_nobody() (gas: 1155130)\n[PASS] test_flush_payouts_moves_real_imd() (gas: 775386)\n[PASS] test_holder_is_paid_in_imd_after_a_day() (gas: 1450517)\n[PASS] test_hook_refuses_raw_eth() (gas: 36967)\n[PASS] test_initialize_accepts_the_briefed_price() (gas: 6856563)\n[PASS] test_initialize_does_not_gate_the_opening_price() (gas: 6861373)\n[PASS] test_initialize_refuses_a_pool_that_is_not_our_token() (gas: 7559348)\n[PASS] test_initialize_refuses_a_quote_that_is_not_imd() (gas: 7559391)\n[PASS] test_initialize_refuses_an_unsupported_fee_tier() (gas: 6661890)\n[PASS] test_keeper_tip_comes_out_of_the_team_slice() (gas: 767794)\n[PASS] test_launch_cap_expires() (gas: 886154)\n[PASS] test_launch_cap_limits_one_buyer() (gas: 754873)\n[PASS] test_launch_puts_the_seed_in_one_range() (gas: 35531)\n[PASS] test_launch_sets_imd_as_currency0() (gas: 9871)\n[PASS] test_liquidity_can_never_be_removed_even_by_its_owner() (gas: 137735)\n[PASS] test_longer_holder_gets_a_bigger_share() (gas: 1937341)\n[PASS] test_only_the_launch_factory_may_open_the_pool() (gas: 6662701)\n[PASS] test_pool_starts_with_no_imd() (gas: 10222)\n[PASS] test_sell_pays_the_sell_tax_in_imd() (gas: 837648)\n[PASS] test_selling_restarts_the_streak() (gas: 1454559)\n[PASS] test_tax_splits_seventy_five_twenty_five() (gas: 565218)\n[PASS] test_the_direction_helpers_hold_for_both_orderings() (gas: 189002)\n[PASS] test_the_imd_address_is_never_registered() (gas: 647316)\n[PASS] test_the_tax_is_only_holders_and_team() (gas: 548430)\n[PASS] test_the_tax_is_read_the_right_way_round_when_the_token_is_currency0() (gas: 27508124)\n[PASS] test_the_token_address_is_never_registered_or_paid() (gas: 1873200)\n[PASS] test_third_party_liquidity_is_blocked() (gas: 1605850)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 453.27ms (732.50ms CPU time)\n\nRan 6 tests for test/pimd/PimdFork.t.sol:PimdForkTest\n[PASS] test_fork_buy_takes_tax_in_real_imd() (gas: 668257)\n[PASS] test_fork_engine_drips_real_imd_to_a_holder() (gas: 1545504)\nLogs:\n  IMD paid to one holder (wei) 5621280779456078301\n\n[PASS] test_fork_flush_moves_real_imd() (gas: 895264)\n[PASS] test_fork_imd_is_a_plain_erc20_with_no_transfer_fee() (gas: 286859)\n[PASS] test_fork_launch_against_real_state() (gas: 41137)\n[PASS] test_fork_sell_takes_tax_in_real_imd() (gas: 951336)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.29s (990.36ms CPU time)\n\nRan 6 test suites in 1.30s (2.83s CPU time): 94 tests passed, 0 failed, 0 skipped (94 total tests)\n","passed":true},{"durationMs":80,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PimdEngine.abortEpoch()\",\"PimdEngine.bind(address,address,address[])\",\"PimdEngine.fire()\",\"PimdEngine.pay(uint256)\",\"PimdEngine.prune(address[])\",\"PimdEngine.register(address[])\",\"PimdEngine.seed(uint256)\",\"PimdEngine.tally(uint256)\",\"PimdHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PimdHook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"PimdHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"PimdHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PimdHook.flush()\",\"PimdHook.flushHolders()\",\"PimdHook.receive()\",\"PimdHook.unlockCallback(bytes)\",\"PimdToken.approve(address,uint256)\",\"PimdToken.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"PimdToken.transfer(address,uint256)\",\"PimdToken.transferFrom(address,address,uint256)\"],\"files\":{\".audit/HOT_SPOTS.md\":65,\".audit/REVIEW.md\":218,\".audit/context/01-access-control.md\":612,\".audit/context/02-swap-accounting.md\":568,\".audit/context/03-engine-lifecycle.md\":559,\".audit/context/04-arithmetic.md\":585,\".audit/context/05-reentrancy-external.md\":605,\".audit/context/06-tests-and-deploy.md\":829,\".audit/poc/ZZArith.t.sol\":188,\".audit/poc/ZZArith2.t.sol\":78,\".gitignore\":5,\"LICENSE\":21,\"README.md\":160,\"foundry.toml\":35,\"launch.json\":34,\"script/DeployPimd.s.sol\":118,\"script/PimdRehearsal.sol\":185,\"script/RehearsalSeeder.sol\":71,\"script/RehearsePimd.s.sol\":93,\"src/libraries/L2Block.sol\":21,\"src/pimd/PimdEngine.sol\":880,\"src/pimd/PimdHook.sol\":597,\"src/pimd/PimdToken.sol\":49,\"test/pimd/Gas.t.sol\":46,\"test/pimd/Pimd.t.sol\":691,\"test/pimd/PimdAttacks.t.sol\":420,\"test/pimd/PimdBase.t.sol\":424,\"test/pimd/PimdFixes.t.sol\":1003,\"test/pimd/PimdFork.t.sol\":265},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e5af34906c0960e4adae230ca52b8d304ba0f241ee57abd70647925764c9c2f9","verifiedTreeHash":"9f05a4b76000ecf1227a60df56936890ff282242","verifierVersion":"0.1.0+fb8278c5"}]}