{"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":"6e0f859e-9d6f-4384-8457-0c4e0cf85f93","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"fc3704f45a23ce150a281cd4f5b62253cf082a7417acd0a38703ba3c142fb789","dependsOn":["manifest"],"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":"171c54ad96829e70bb64860415a7e0bc0bd83ff20c57d01a6f0798dc93c47b7e","dependsOn":["manifest"],"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":"f15326ca81b6d3f8183819d427bfdcfae784fcc73adfe870c8100f829ef1049e","dependsOn":[],"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":"2e3748352f634935161da4a1bc27a35deaa0309b125357878a38ff7d3f5a89f8","dependsOn":["manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"f40e7925358480f519ba85feef376a3e8d75c0bf842e5bce42db033bf3efcb5a","dependsOn":["manifest"],"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":"eaceaa26c60ae08a18e03469c63d4dc1fe1be6cb35b7d33e4ef2e1ce80806a19","dependsOn":["manifest"],"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":"b43d1bf1348c5dc3930e78dd2bcdbfeec3601b7a4c6b0a2038b980520da7461b","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"}],"objective":"Token name: Pupate\nToken symbol: PUPATE\n\nTotal supply 1,000,000,000 with 18 decimals, minted once to its deployer. Ethereum mainnet (chain id 1), a Uniswap v4 hook launch paired with native ETH; 85% of supply to the pool.\n\nLAUNCH THIS REPOSITORY AS IT IS. The workspace is a finished, tested and reviewed project at the given base commit. The deliverable is the launch of this exact code: do not rewrite, refactor or reformat it, and do not modify src/, test/, script/, lib/ or foundry.toml. PupateHook is bound by its constructor to two contracts already deployed on Ethereum mainnet from this source: the vault Cocoon at 0x54993066369e57a49215f6fc2d9911a8e5a57a79 (its sink) and an OpenZeppelin TimelockController with a 48-hour delay at 0x8be826082c0fbaec485048aa26ef42ac147898ec (its owner).\n\nWHAT TO DO. (1) Verify that launch.json is a valid manifest: hook PupateHook with constructor ($poolManager, the Cocoon address, the timelock address); permissions afterInitialize, beforeAddLiquidity, beforeSwap, afterSwap, beforeSwapReturnDelta, afterSwapReturnDelta (flags 0x18CC, validated by the constructor against the hook's own address, so it needs a mined CREATE2 salt); token PupateToken with a zero-argument constructor; pool fee 12500, tick spacing 60, native ETH. Keep pool.initialPrice as it is (792281625142643375935439503360000, the policy's 10 ETH valuation, tick 184216): it is not a reference value to replace. (2) Run the existing suite (forge test; test/fork runs only with MAINNET_RPC_URL set) and report the result. (3) Review the code as it is; report a defect with a reproducing test instead of changing the source.\n\nKEEP THESE FACTS UNCHANGED. PupateToken is a plain ERC-20: no owner, mint, pause, fee, transfer limit or blacklist; burn and burnFrom only reduce supply. PupateHook taxes the ETH side of every swap in its launch pool, the first native-ETH pool initialised on it; swaps whose sender is the sink are not taxed. Sells pay the standing tax of 6%. Buys pay 99% when the pool opens, falling one percentage point a minute to the standing tax about 93 minutes later. The tax is collected inside the swap as ERC-6909 claims on the PoolManager; swap callbacks call only the PoolManager and move no ETH. A taxed swap that names its ETH amount and cannot fill in full reverts (PartialFill). flush() is permissionless and hands the hook's whole ETH balance to Cocoon.depositTax. The owner can only lower the standing tax and transfer ownership.\n\nLIQUIDITY. beforeAddLiquidity admits liquidity only into the launch pool and only in the transaction that initialises it (an EIP-1153 mark set in afterInitialize): the factory's deploy, initialise and seed transaction passes, and every later transaction is refused, in the same block as well. Removing liquidity and collecting fees are never gated. Known residual, kept on purpose and pinned by a test: the mark names no account, so code that gets control later inside the opening transaction could add too; the launch factory calls only the PoolManager, the token and its own registry there. test/fork/LaunchFactory.fork.t.sol rehearses this launch through the real factory.\n\nCONTEXT. Cocoon, FloorFeed and PupateVesting are in src/ for review and are not deployed by this launch. After it, script/PostLaunch.s.sol wires the vault to the new pool, vests the launch wallet's 5% over 12 months, pins the oracle question, and transfers Cocoon and FloorFeed to the timelock. Do not claim the code is audited or secure.\n\nPREVIOUS ATTEMPTS. #1400 and #1412 passed every admission check but findings; PupateHook and PupateToken drew none and are byte-identical. The vault findings, all fixed in this commit and recorded with their tests in docs/REVIEW.md: skim() reachable from inside takeAuction's lot transfer (skim and depositTax now hold the reentrancy lock, the excess is refunded before the lot token is called); an auction reopened from inside a taker's refund (startAuction and startImdAuction hold the lock; invariant: no auction claims more than the vault holds); buySeat accepting an order whose offerer was Cocoon itself (_checkOrder refuses an order from Cocoon and any order for a seat the vault already holds; the mock Seaport skips validation for a self-fulfilled order as the real one does). Before this attempt an independent audit of the whole vault found one more, medium, fixed: the lower bound on a purchase price now binds what the vault actually paid (Seaport charges a listing's current amount, not its ceiling); the burn's price limit also rounds in the vault's favour. Accepted and documented: a dust lot parking a harvest auction for 48 hours, burn buying nothing while the price is parked above the range, FloorFeed's slow recovery after a low report. The Cocoon above is a new deployment of this source; the two earlier vaults were never wired and hold nothing.","parentJobId":null,"planHash":"ccfc08938cce86f0bed3cebdaed92b5719e930567c667826d3979a6c7a011037","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"6e0f859e-9d6f-4384-8457-0c4e0cf85f93","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1434-pupate"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52159","feedbackHash":"3953c0f60aa7871ca6ca218f95224521e3f461ca1d0a2d690d59e648a2d8507b","nodeKey":"audit_economics","submissionHash":"fc3704f45a23ce150a281cd4f5b62253cf082a7417acd0a38703ba3c142fb789","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51234","feedbackHash":"83d543e53c3173f335d2a66118932ead9e1ef348f166d9deaf0bf68d967258c6","nodeKey":"audit_flow","submissionHash":"171c54ad96829e70bb64860415a7e0bc0bd83ff20c57d01a6f0798dc93c47b7e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51250","feedbackHash":"7444bc55690ee99c98517903a8d2a01902d2bebba1ff12ebc7794221102da3ce","nodeKey":"audit_imported_code","submissionHash":"f15326ca81b6d3f8183819d427bfdcfae784fcc73adfe870c8100f829ef1049e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52179","feedbackHash":"3ba0a6caab01d77f7dd6b013900f25b5945238e343cf7bd5a8066a674ec5c291","nodeKey":"audit_judge","submissionHash":"2e3748352f634935161da4a1bc27a35deaa0309b125357878a38ff7d3f5a89f8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51742","feedbackHash":"5fef1e13405cf9e6fe9e1ac503a256b29342907d408658ff9fe10a779453bcaa","nodeKey":"audit_math","submissionHash":"f40e7925358480f519ba85feef376a3e8d75c0bf842e5bce42db033bf3efcb5a","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51540","feedbackHash":"b893d76a81d22462a92263fba2159386ad15f709311fed9b55eb4b5c52e4df36","nodeKey":"audit_permissions","submissionHash":"eaceaa26c60ae08a18e03469c63d4dc1fe1be6cb35b7d33e4ef2e1ce80806a19","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52154","feedbackHash":"69ea9d0ad3a1ee3c8bb847bc78882ad937be45348db5621644b38d5708c72054","nodeKey":"manifest","submissionHash":"b43d1bf1348c5dc3930e78dd2bcdbfeec3601b7a4c6b0a2038b980520da7461b","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"6c19bef4a547777da6d97e026c6970b43d41937e0b627959eed3c9848c17f702","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"d00f790fc692b1a4","findings":[{"citation":"resolved","description":"startAuction fixes the lot at the vault's balance of `token` when the auction opens (line 546) and takeAuction always transfers exactly that lot (line 569). Nothing lets a taker take a smaller lot, and nothing closes or reopens an auction whose lot can no longer be transferred: startAuction refuses while `auctions[token].lot != 0` (line 543). So for any harvest token whose balance can fall after the auction opened without the vault transferring it (a down-rebasing token, a token with an admin clawback or burn-from, or one that deducts a fee from the sender), every take reverts TransferFailed at any price, the auction cannot be restarted for the balance actually held, and the price keeps decaying. After 48 hours the price is zero and whoever donates the missing dust takes the whole lot for free; in a shrinking token the shortfall only grows, so the vault receives nothing for that harvest. The ETH books stay whole (the taker's value is refunded before the lot transfer reverts the call), so this is a loss of a harvest's auction value under a specific token behaviour, not of ETH. The IMD token and PUPATE are plain ERC-20s, so the mainnet harvests expected today are not affected; this applies only if the vault ever holds a token of that kind. Minimal fix that keeps the design: let takeAuction transfer `min(a.lot, balanceOf(this))` (or let anyone close an auction whose lot exceeds the balance so startAuction can reopen it on the real balance). Demonstrated by test/scratch/StuckHarvestAuction.scratch.t.sol, which passes on this code as a reproduction of the behaviour.","line":569,"path":"src/Cocoon.sol","reproduction":"State: Cocoon wired; the vault holds 1000e18 of token T whose balance of the vault can fall (test: ShrinkingToken with shrink()). 1) anyone: cocoon.startAuction(T) -> auctions[T].lot = 1000e18, start 100 ETH. 2) T's balance of the vault drops by 1 wei (rebase down / clawback). 3) taker: cocoon.takeAuction{value: 100 ether}(T) -> expected: the lot (or what the vault holds of it) is sold for 100 ETH; actual: revert TransferFailed, the value is returned, seatPot unchanged. 4) anyone: cocoon.startAuction(T) -> revert AuctionRunning, so the 999.999…e18 the vault still holds cannot be auctioned. 5) warp 48h: auctionPrice(T) == 0; anyone mints/donates 1 wei of T to the vault and calls takeAuction(T) with no value -> takes 1000e18 of T, seatPot += 0.","severity":"low","snippet":"        _safeTransfer(token, msg.sender, a.lot);","title":"A harvest auction whose lot the vault no longer holds in full can neither be taken nor restarted; the token's harvest then goes for nothing"}],"hash":"171c54ad96829e70bb64860415a7e0bc0bd83ff20c57d01a6f0798dc93c47b7e","nodeId":"89d7da40-b09f-4f94-9367-15d1c1b9fc4c","outcome":"completed","summary":"The review is complete. The findings file is written and valid, the working tree is clean, and the only new files are the ones the task allows.\n\n**Outcome.** The code holds up under the Execution Trace, Periphery and First Principles passes. I found one low-severity defect in the vault and nothing in the hook or token. `.imd-findings.json` holds that finding plus a coverage row for all 38 listed entry points, the manifest and the test run.\n\n**What I verified**\n\n- **Manifest.** The schema keys, the hook constructor order (pool manager placeholder, sink, timelock), the six permissions encoding flags 0x18CC, fee 12500, tick spacing 60, native ETH and the kept initial price (tick 184216) are all correct. The notes are under the limit.\n- **Mainnet state of the bound addresses.** The sink address holds code identical to this tree's Cocoon once the five immutables are masked, bound to the mainnet v4 PoolManager and Seaport 1.6, still unwired and owned by the deployer as the docs say. The owner address is a TimelockController with a 48-hour delay where the developer proposes and anyone executes.\n- **Test suite.** On forge 1.8.3 the run shows 227 passed, 0 failed, 10 fork tests skipped because the mainnet RPC variable is unset. I did not run the real-factory fork rehearsal.\n- **Hook delta accounting.** I re-derived all four swap modes against the vendored `Hooks.afterSwap` and `PoolManager.swap`. The named-ETH tax returned in beforeSwap, the partial-fill check on the raw pool delta, the unspecified-delta return for token-named swaps and the claim mint all net the hook's delta to zero, and flush is backed by settled swapper input.\n\n**The finding (low).** A harvest auction fixes its lot at the opening balance and takeAuction always transfers exactly that lot. If the token's balance of the vault later falls on its own (a down-rebasing or clawback token), every take reverts and startAuction refuses to reopen, so after 48 hours whoever donates the shortfall takes the whole harvest for nothing. The IMD and PUPATE tokens are plain ERC-20s, so today's expected harvests are not affected. A demonstration test lives in `test/scratch/StuckHarvestAuction.scratch.t.sol`.\n\n**Not reached.** The live Seaport and IMD token behaviour were not exercised here, only the fork tests cover them and they skipped without an RPC.","treeHash":null,"usage":{"cachedInputTokens":2889928,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":56146,"runtime":"claude","turns":50,"wallClockMs":825297}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"02f22d6f13810ca8","findings":[{"citation":"resolved","description":"startAuction fixes the lot at the vault's balance when it opens (line 546) and takeAuction always transfers exactly that lot. Nothing lets a taker take less, nothing closes an auction, and startAuction refuses while auctions[token].lot != 0 (line 543, AuctionRunning). If the vault's balance of a harvest token falls after the auction opened without the vault transferring it (a down-rebasing token, an admin clawback or burn-from, a fee deducted from the sender, or a token that is paused while the price decays), every take reverts TransferFailed at any price while the curve keeps falling. After 48 hours the price is zero, and whoever donates the missing dust (or waits for the pause to lift) takes the whole lot for free; the seat pot gets nothing for that harvest. ETH books stay whole (the taker's value is refunded before the lot call). PUPATE and the IMD token are plain ERC-20s, so this needs a harvest token of that kind. Confirms the flow specialist's finding; same root cause as the accepted 'dust lot parks the auction' note but with a loss of the harvest's value rather than a delay. Minimal fix keeping the design: transfer min(a.lot, balanceOf(this)), or let anyone close an auction whose lot exceeds the balance so startAuction can reopen it on the real balance.","line":569,"path":"src/Cocoon.sol","reproduction":"test/scratch/Judge.scratch.t.sol:StuckHarvestAuctionScratch (passes on this code as a reproduction). State: CocoonFixture, vault holds 1000e18 of ShrinkingToken T. 1) startAuction(T): lot 1000e18, start 100 ETH. 2) T.shrink(cocoon, 1). 3) keeper: takeAuction{value: 100 ether}(T) -> expected the lot sold for 100 ETH (or what the vault holds of it); actual revert TransferFailed. 4) startAuction(T) -> revert AuctionRunning. 5) warp 48h: auctionPrice(T) == 0; mint 1 wei of T to the vault; takeAuction(T) with no value from a fresh account -> taker holds 1000e18, seatPot unchanged.","severity":"low","snippet":"        _safeTransfer(token, msg.sender, a.lot);","title":"A harvest auction whose lot can no longer be transferred in full is stuck: it cannot be taken, closed or restarted, and after 48 hours the whole lot goes for nothing"},{"citation":"resolved","description":"report() has one replay guard, `if (a.issuedAt <= previousIssuedAt) revert NotNewer();` (line 87), reading stored issuedAt. setQuestion deletes issuedAt with the price (lines 130-132); its comment names setting the same hash again as the way to clear a bad value. After the reset the guard reads zero, the first report is exempt from the rise limit (line 95), and report() is permissionless, so the exact attestation that was cleared (same bytes, same attester signature) is accepted again by any caller as long as block.timestamp <= issuedAt + maxAge (line 85). The owner's remedy only works once the bad attestation is older than maxAge (6 h default, 24 h max). Reachable while the deployer EOA owns FloorFeed (before PostLaunch); after the handover the 48 h timelock delay exceeds MAX_MAX_AGE, so a consumed attestation has expired by execution. Impact while reachable: Cocoon.buySeat and adopt price seats from FLOOR.latest(), so a cleared too-high floor comes straight back, purchases up to floor x 1.05 resume, and mode() flips with it. Confirms the permissions specialist. Minimal fix: keep a monotone high-water mark of issuedAt that setQuestion does not delete, or clear only floorWei and expiresAt.","line":131,"path":"src/FloorFeed.sol","reproduction":"test/scratch/Judge.scratch.t.sol:FloorFeedReplayScratch (passes on this code as a reproduction). State: FloorFeed(owner, attester, 1), question Q set, maxAge 6 h. 1) report A1 {Q, answer 2 ether, issuedAt T0, expiresAt T0+24h}. 2) at T0+1h report A2 {answer 2.08 ether, issuedAt T0+1h}, latest() = 2.08 ether. 3) owner setQuestion(Q): latest() = (0,false), issuedAt() = 0. 4) at T0+2h a third party calls report(A2, sigA2) with the identical bytes. Expected: revert NotNewer. Actual: accepted; latest() = (2.08 ether, true).","severity":"low","snippet":"        delete issuedAt;","title":"FloorFeed.setQuestion clears the replay guard, so an attestation the owner just cleared can be re-reported by anyone while it is still within maxAge"},{"citation":"resolved","description":"Cocoon.burn() buys PUPATE at spot up to a price move of burnImpactBps and anyone may call it. Its only protection against a front-run buy / back-run sell is that the sandwicher pays the hook's standing tax twice plus the LP fee twice. _checkParams admits burnImpactBps up to 1000 and PupateHook.lowerTax (src/PupateHook.sol:237-242) admits a standing tax of 0; neither contract reads the other. With tax 0 and impact 10% a round trip costs about 2 x 1.25% LP fee against a guaranteed lift of up to 10%, so a searcher takes a large share of every burn's spend instead of holders. Both levers are the timelock's, docs/REVIEW.md already records the rule of thumb (keep twice the standing tax above burnImpactBps), and the defaults (600 / 500) are safe, so this is a documented trust assumption on the owner rather than an exploit of the launch state; kept at low because the bound is enforced only by convention. Confirms the economics specialist. Minimal fix keeping the design: have _checkParams bound burnImpactBps by the hook's current taxBps (e.g. burnImpactBps <= 2 * taxBps - LP fee allowance), or have burn() read hook.taxBps() and refuse when the sandwich is profitable.","line":693,"path":"src/Cocoon.sol","reproduction":"test/scratch/Judge.scratch.t.sol:BurnSandwichScratch (both tests pass on this code). State: CocoonFixture after the launch window, pool holding 5 ETH, depositTax 40 ETH (burnPot 17 ETH). Defaults (tax 600, impact 500): attacker buys 5 ETH exact-in, keeper burn() spends 0.467971848358831849 ETH, attacker sells everything exact-in: attacker net -0.405072741171615316 ETH (loses). Then owner: hook.lowerTax(0) and cocoon.setParams with burnImpactBps = 1000, both accepted. Same sandwich: burn spends 0.991200093389357418 ETH, attacker net +0.446068864882843161 ETH, i.e. 45% of the burn's spend leaves to the sandwicher. Expected: no admissible parameter set makes the sandwich profitable. Actual: the bounds are independent.","severity":"low","snippet":"        if (p.burnImpactBps < 100 || p.burnImpactBps > 1000) revert OutOfBounds();","title":"Admissible owner settings (hook tax 0, burnImpactBps 10%) make the permissionless burn sandwichable: nothing couples the two bounds"}],"hash":"2e3748352f634935161da4a1bc27a35deaa0309b125357878a38ff7d3f5a89f8","nodeId":"170c3af9-ffca-4d97-86f0-76bb61e41ad0","outcome":"completed","summary":"The review is complete. The report is in `.imd-findings.json` at the repository root, and only that file plus my scratch test under `test/scratch/` were created. Nothing in `src/`, `test/`, `script/`, `lib/` or the configuration was touched.\n\n**Verdict: nothing blocks this launch.** All three findings I kept are low. PupateHook and PupateToken drew none.\n\n**Manifest.** launch.json is valid for this hook launch. The hook's three constructor arguments match the implementation in declaration order, the two literal addresses are lowercase and real, the six permissions equal getHookPermissions and encode to 0x18CC, the token has a zero-argument constructor and 18 decimals, and the pool is native ETH at fee 12500, spacing 60. The initial price was left as the 10 ETH valuation (sqrt ratio 10,000, tick 184216). Notes are 3,619 characters. The hook's runtime is 6,075 bytes, Cocoon's 24,490, both under the limits.\n\n**Tests.** The existing suite passed. Fork tests skipped because no mainnet RPC URL is set.\n\n| Suite | Result |\n|---|---|\n| forge test | 227 passed, 0 failed, 10 skipped |\n| my scratch reproductions | 4 passed |\n\n**Mainnet inputs (read only).** The sink at 0x5499…5a79 holds code of exactly the local Cocoon runtime size, points at the v4 PoolManager and Seaport 1.6, is unwired and holds no ETH. The timelock at 0x8be8…98ec reports a 172,800 second delay.\n\n**Findings kept, each reproduced by a test I wrote and ran:**\n- **Stuck harvest auction (low, Cocoon.takeAuction).** If a harvest token's balance falls after an auction opens, every take reverts, the auction cannot be restarted, and after 48 hours the lot goes for nothing. Needs a rebasing, clawback or pausable harvest token.\n- **FloorFeed replay after setQuestion (low).** Clearing a bad report deletes the replay guard, so anyone can re-submit the same signed attestation within maxAge. Only reachable before the timelock handover.\n- **Burn sandwich under admissible settings (low, Cocoon.setParams).** Tax 0 and impact 10% are both allowed and together make the buyback sandwichable. Reproduced with the specialist's exact numbers. A trust assumption on the timelock, documented already.\n\n**Dropped:** the three info items (hookless pool, tax rounding, FloorFeed's linear rise allowance) are accepted or documented behaviour, not defects. No duplicates existed across specialists.\n\n**My own pass** re-derived the hook's delta accounting in all four swap modes, the opening-transaction liquidity gate, the sink exemption, flush, Cocoon's lock and balance identity, Seaport order checks, and the vesting contract. It found nothing beyond the above. Coverage answers all 39 listed entry points plus five extra rows.","treeHash":null,"usage":{"cachedInputTokens":1336863,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":37289,"runtime":"claude","turns":23,"wallClockMs":545654}},{"artifacts":[],"attempt":1,"bundleHash":"55535003f1e20e0077953d88a12abddc4c76b4d2ab9408229e838eae4dca987f","device":"24282732aac890f7","findings":[],"hash":"b43d1bf1348c5dc3930e78dd2bcdbfeec3601b7a4c6b0a2038b980520da7461b","nodeId":"cc640181-c5e9-442e-a4ae-4510ab65f7fa","outcome":"completed","summary":"Updated [launch.json](/home/imd/.identitymd/work/6e0f859e-9d6f-4384-8457-0c4e0cf85f93/cc640181-c5e9-442e-a4ae-4510ab65f7fa/launch.json) notes; deployment fields and source remain unchanged.\n\n- Manifest checks passed; notes: 3,619/4,000 characters.\n- `forge build --offline` passed with warnings.\n- `forge test --offline`: **229 passed, 0 failed, 10 skipped** because `MAINNET_RPC_URL` is unset.\n- Both imported limitations reproduced in scratch tests: untaxed hookless pools and temporary price parking that blocks burns.\n- No additional defect identified. Only `launch.json` changed outside scratch.","treeHash":"2fa2492cf355a4623c9a6ce63f9c049b32bac9ee","usage":{"cachedInputTokens":1013504,"inputTokens":89543,"model":"gpt-6-astra","outputTokens":8885,"runtime":"codex","turns":6,"wallClockMs":220231}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"589ef002581a5371","findings":[{"citation":"resolved","description":"Asymmetry between report() and setQuestion(). report() has exactly one replay guard: `if (a.issuedAt <= previousIssuedAt) revert NotNewer();` (src/FloorFeed.sol:87), which reads the stored `issuedAt`. setQuestion() deletes `issuedAt` together with the price (lines 130-132) and its comment says that \"Setting the same hash again is the way to clear a bad value\". After that reset the guard reads zero, the first report is by design not rate-limited (line 95: `previousIssuedAt != 0`), and report() is permissionless. So the exact attestation the owner just cleared (same bytes, same attester signature) passes every check again as long as `block.timestamp <= a.issuedAt + maxAge` (line 85), and any address can re-submit it; no new signature from the attester is needed. The owner's remedy therefore only works if the bad attestation is older than maxAge (6 h by default, up to 24 h) at the time of the reset. Preconditions and reach: before PostLaunch the deployer EOA owns FloorFeed and can reset at once, so the window is real; after the handover the 48-hour TimelockController delay exceeds MAX_MAX_AGE (24 h), so an attestation consumed before the proposal is expired by execution and the path closes, unless the attester issues the same bad value again, which is attester trust rather than this defect. Impact while reachable: Cocoon.buySeat and adopt price seats off `FLOOR.latest()`, so a cleared too-high floor comes straight back and purchases up to floor x 1.05 resume at the bad value; mode() also flips with it. Minimal fix that keeps the design: keep a monotone high-water mark for issuedAt that setQuestion does not delete (or clear only floorWei and expiresAt), so a cleared attestation stays consumed. The existing tests cover a reset to a different hash (WrongQuestion) but not a reset to the same hash followed by the old attestation.","line":131,"path":"src/FloorFeed.sol","reproduction":"State: FloorFeed(owner, attester, 1) with question Q set; maxAge 6 h. (1) Anyone reports attestation A1 = {questionHash Q, answer 2 ether, issuedAt T0, expiresAt T0+24h}, signed by the attester. (2) At T0+1h anyone reports A2 = {answer 2.08 ether, issuedAt T0+1h} (inside the rise cap). (3) Owner calls setQuestion(Q) at T0+1h: latest() = (0, false). (4) At T0+2h anyone calls report(A2, sigA2) with the identical bytes from step 2. Expected: revert NotNewer (A2 was already consumed). Actual: accepted; latest() = (2.08 ether, true) and the rise limit was not applied. Scratch test test/scratch/Permissions.scratch.t.sol:FloorFeedReplayScratch.test_aClearedBadReportCanBeReplayedByAnyoneAfterTheReset passes on this code, i.e. the replay succeeds.","severity":"low","snippet":"        delete floorWei;\n        delete issuedAt;\n        delete expiresAt;","title":"FloorFeed.setQuestion clears the replay guard, so a cleared attestation can be re-reported by anyone while it is still within maxAge"}],"hash":"eaceaa26c60ae08a18e03469c63d4dc1fe1be6cb35b7d33e4ef2e1ce80806a19","nodeId":"1937e37b-38c7-4d37-b0d0-c5fe18146218","outcome":"completed","summary":"The findings file is valid, the snippet matches the tree at the cited line, and the working tree holds only my findings file and the scratch tests (both ignored by git, as expected). The review is complete.\n\n**Outcome**\n\nThe permission model of the launched code holds under the Access Control, Trust Gap and Asymmetry guides. I found one low-severity defect, in FloorFeed, which is reviewed source and not deployed by this launch. Nothing blocks the launch of PupateHook and PupateToken as they are.\n\n**What I verified**\n\n- **Manifest.** Schema keys only, constructor arguments in declaration order with both addresses lowercase, permissions equal to the implementation and encoding to flags 0x18CC, zero-argument token, native pair at fee 12500 and spacing 60, initial price kept at the 10 ETH valuation, notes under the limit.\n- **Suite.** The existing tests pass on forge 1.8.3. Fork tests skipped because no mainnet RPC was set.\n\n| Result | Count |\n|---|---|\n| passed | 227 |\n| failed | 0 |\n| skipped (fork) | 10 |\n\n- **Hook.** Every callback and the unlock callback refuse any caller but the PoolManager. Scratch tests confirm an outsider who unlocks the manager in its own name cannot reach the hook's callback or burn its claims. The sink exemption reaches only Cocoon's own fixed buyback. Lowering the tax is owner-only, strictly downward, and every swap mode still settles at zero tax.\n- **Vault.** Each role's power is bounded, every value-moving entry point holds the lock, parameter changes do not alter in-flight value, and the paired functions mirror each other's state writes.\n\n**The finding**\n\nFloorFeed's reset path deletes the stored issue time, which is the only replay guard in `report`. After the owner resets the same question to clear a bad value, anyone can re-submit the identical consumed attestation while it is within `maxAge`, and the rise limit does not apply. This is reachable while the deployer EOA still owns the feed. After the handover, the 48-hour timelock delay exceeds the 24-hour maximum age, so the path closes. A reproducing test is described step by step in the findings file.\n\n**Coverage**\n\nAll 38 listed entry points have a row, plus rows for the manifest, the suite run, and the liquidity-gate invariant. Every row is `holds` except the two FloorFeed functions tied to the finding. Nothing was left unreached.","treeHash":null,"usage":{"cachedInputTokens":1696269,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":45684,"runtime":"claude","turns":27,"wallClockMs":697662}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0cf632e317dfab7a","findings":[{"citation":"resolved","description":"Design limit, already stated by the authors (docs/REVIEW.md, audit of #1412, note 4) and recorded here so the adapter and the audit panel do not treat it as a defect. _taxed() restricts the tax to the launch pool id, and beforeAddLiquidity gates only pools on this hook. The PoolManager accepts a second ETH/PUPATE pool with hooks = address(0) from anyone holding PUPATE (the requester's 5% before PostLaunch moves it to vesting, the distributor's contributors, any buyer). That pool pays no hook tax and admits liquidity in every block. Nothing in the hook or the token can prevent it, and nothing is lost from the vault; the effect is that volume routed through such a pool funds no seat purchases or burns. Not a code defect; no change proposed.","line":255,"path":"src/PupateHook.sol","reproduction":"Fresh PoolManager; deploy PupateHook at a 0x18CC address and initialise the launch pool (ETH/PUPATE, fee 12500, spacing 60). In a later block initialise PoolKey(ETH, PUPATE, fee 3000, spacing 60, hooks = address(0)) at the same price, add full-range liquidity 1e21 with 10 ETH, then swap exact-input 1 ETH zeroForOne. Expected if the tax were universal: 0.06 to 0.99 ETH of ERC-6909 claims minted to the hook. Actual: the swap fills, manager.balanceOf(hook, 0) == 0 and hook.totalTax() == 0, and the add in a later block was admitted. Scratch test test/scratch/HooklessPool.scratch.t.sol::test_hooklessPoolTradesUntaxedAndTakesLiquidityAnyTime passes on this tree.","severity":"info","snippet":"        return sender != sink && PoolId.unwrap(key.toId()) == PoolId.unwrap(launchPool);","title":"Tax and liquidity gate bind only the launch pool; a hookless ETH/PUPATE pool trades untaxed and takes liquidity at any time"},{"citation":"resolved","description":"Accepted by the authors (docs/REVIEW.md, audit of #1400, finding 4) and recorded with a concrete reproduction at the launch's real parameters. The factory's position [-887220, 184200] sits entirely below the opening tick 184216, so before the first buy, and again whenever sells have taken the pool's last ETH, there is no liquidity above the price. An exact-input sell of 1 wei of PUPATE (oneForZero, limit MAX_SQRT_PRICE - 1) then walks the price to the limit with a (0, 0) delta: the seller pays nothing and no tax is due. burn() derives its price limit from that parked spot price (sqrtPrice * 9747 / 10000), which is still far above the seeded range, so the buyback buys nothing and reverts NothingBought. Self-healing: any buy, however small, moves the price back into the range (shown in the same test). The keeper does not send such a buy itself. Not a loss; no change proposed.","line":488,"path":"src/Cocoon.sol","reproduction":"Open the launch pool at sqrtPriceX96 792281625142643375935439503360000 with fee 12500, spacing 60 and the factory's token-only position of 850,000,000 PUPATE in [-887220, 184200]; wire Cocoon. From an account holding 1 wei of PUPATE, swap SwapParams(zeroForOne=false, amountSpecified=-1, sqrtPriceLimitX96=MAX_SQRT_PRICE-1). Expected for a priced sell: a non-zero delta or a revert. Actual: delta (0, 0) and slot0.sqrtPriceX96 == MAX_SQRT_PRICE - 1. A following buy of 1 ETH still fills from the seeded range (tick < 184200 afterwards). Scratch test test/scratch/LaunchParams.scratch.t.sol::test_launchParameters_freePricePark_thenAnyBuyRestores passes on this tree.","severity":"info","snippet":"        (uint160 sqrtPrice,,,) = POOL_MANAGER.getSlot0(launchKey.toId());","title":"While the launch pool holds no ETH, a 1-wei sell parks the price at MAX for free and Cocoon.burn() reverts NothingBought until any buy lands"}],"hash":"f15326ca81b6d3f8183819d427bfdcfae784fcc73adfe870c8100f829ef1049e","nodeId":"46ad847f-3a6d-4399-991f-579ea226f69d","outcome":"completed","summary":"No tracked file changed. The review is complete.\n\n## Result\n\nNo defect found that opens a revision. The findings file holds two info-level entries, both design limits the authors already document, each with a reproducing scratch test that passes on this tree. No critical, high, medium or low finding.\n\n**Manifest.** launch.json is valid against every point in the task: only schema keys, hook PupateHook with constructorArgs `$poolManager`, the Cocoon address, the timelock address in declaration order and lowercase, the six permissions matching getHookPermissions and summing to flags 0x18CC, PupateToken with no constructor arguments and 18 decimals, pool fee 12500, tick spacing 60, native ETH, initialPrice kept at 792281625142643375935439503360000 which equals 10^4 times 2^96 (tick 184216). Notes are 3,889 characters. The hook has no beforeInitialize, so it accepts the listed fee.\n\n**Tests.** `forge build` succeeds. `forge test` on forge 1.8.3:\n\n| Result | Count |\n|---|---|\n| Passed | 227 |\n| Failed | 0 |\n| Skipped (fork tests, MAINNET_RPC_URL unset) | 10 |\n\nThe fork rehearsal through the real factory did not run here. Not executed: `--isolate` mode, fuzz above the configured 256 runs.\n\n**On-chain checks (Ethereum mainnet, block 26177300, public RPC).** The sink at the manifest's Cocoon address has runtime code identical to this tree's Cocoon build outside immutables. Its PoolManager is the canonical v4 manager, Seaport is 1.6, FloorFeed is the documented feed, and it is unwired and empty. The timelock's minimum delay is 172,800 seconds. FloorFeed's question is not yet pinned, as expected before PostLaunch.\n\n**Read in full.** PupateHook, PupateToken, Cocoon, FloorFeed, PupateVesting, SeatListing, Decay, WorkerAuthorization, OracleAttestation, the four interfaces, the three scripts, the hook and fork tests, the fixtures and docs/REVIEW.md. Checked against the Pashov guide: caller checks on every callback, the four tax modes against v4's delta accounting, the hook's net-zero delta per swap, claims backing at flush, the transient liquidity gate including the zero-delta path the factory uses for fees, sink exemption reachability, Cocoon's lock coverage and balance identity, the burn's price limit, casts and rounding. Not reached: the real Seaport and IMD token behaviour (fork tests skipped), the keeper and site code.\n\n**Analysers.** Slither on the hook reports four items, all benign (immutable sink, intentional zero sentinel, empty unused return). Slither on the token reports nothing. Aderyn's five highs are generic pattern hits with no exploit path. The opcode scan of all five contracts finds no DELEGATECALL, CALLCODE or SELFDESTRUCT.\n\n**Scratch verification at the launch's real parameters** (fee 12500, the factory's range, a real Cocoon as sink): a 1 ETH buy at the open yields 0.99 ETH of claims, flush reaches Cocoon with the 10/5/85 split, Cocoon's own burn is untaxed, the gate refuses an add in the next transaction and admits removals.\n\nNothing here is a claim that the code is audited or secure. The scratch tests under test/scratch/ are disposable.","treeHash":null,"usage":{"cachedInputTokens":2852709,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":57453,"runtime":"claude","turns":48,"wallClockMs":837416}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ce319efac2b76da0","findings":[{"citation":"resolved","description":"Math Precision guide, 'fees round UP': all four tax formulas (lines 198, 272, 273) truncate. The leak is bounded by one wei per swap and the guide's compounding condition does not apply: every swap costs more than 100k gas, so splitting a trade into sub-17-wei legs to avoid the 6% tax is not economic. Pinned by the author's own test_dustSwapWhoseTaxRoundsToZeroStillGoesThrough. Recorded for coverage only; no change needed.","line":272,"path":"src/PupateHook.sol","reproduction":"After the launch window (standing rate 600 bps): exact-input buy of 16 wei -> tax = 16*600/10000 = 0, claims unchanged; buy of 17 wei -> tax 1 (1/17 = 5.88%, under 6%). Exact-output sell naming 15 wei of ETH: tax = 15*600/9400 = 0. At the opening rate (9900 bps) an exact-input buy of 1 wei pays 0 tax. Expected under strict 'round fees up': 1 wei in each case. Actual: 0. Verified by `_buyExactIn(10)` in test/PupateHook.t.sol returning claims 0.","severity":"info","snippet":"        if (params.zeroForOne) return uint256(-params.amountSpecified) * rate / BPS;\n        return uint256(params.amountSpecified) * rate / (BPS - rate);","title":"Hook tax rounds down in every mode, so the ETH leg of a dust swap is untaxed (trader-favouring by under one wei per swap)"},{"citation":"resolved","description":"Boundary x invariant seam. The documented property is 'the stored price may rise by at most 25% per 6 hours between two reports'. The allowance is proportional to gap with no upper bound, so the invariant that bounds a single report's rise only holds while reports are frequent. The same formula truncates to zero for a tiny stored floor (prev = 1 wei cannot rise for any gap under 86,400 s), which an earlier review already recorded. Only the trusted attester can supply the report, so per the validation gates this is a trust assumption to document, not a defect; the vault's purchase tolerance (floor * 1.05) then binds what Cocoon.buySeat will pay. Falls are unlimited by design.","line":97,"path":"src/FloorFeed.sol","reproduction":"State: floorWei = 2.68e18 (the first attested floor), issuedAt = T. Input: a valid attestation with issuedAt = T + 30 days and answer = 806e18. gap = 2,592,000; allowedRise = 2.68e18 * 2500 * 2,592,000 / (21,600 * 10,000) = 2.68e18 * 300 = 804e18; next - prev = 803.32e18 <= 804e18, so report() accepts a 301x rise in one step. Expected from the documented 25%-per-6h guarantee read as a per-report bound: MoveTooLarge. Actual: accepted, floorWei = 806e18, and Cocoon.buySeat will pay up to 846.3 ETH for a seat while that report is fresh. Reverse input: prev = 1 wei, gap = 86,399 s, next = 2 -> allowedRise = 0, MoveTooLarge.","severity":"info","snippet":"            uint256 allowedRise = FullMath.mulDiv(prev, MAX_RISE_BPS * gap, RISE_WINDOW * BPS);","title":"FloorFeed's rise allowance grows linearly with the gap between reports and has no cap, so one report after a long silence may lift the floor by hundreds of times (trusted attester only)"}],"hash":"f40e7925358480f519ba85feef376a3e8d75c0bf842e5bce42db033bf3efcb5a","nodeId":"5d23f294-451f-412d-8d53-9996441db6ad","outcome":"completed","summary":"The review is complete. The findings file holds two info-level notes and a coverage row for every one of the 38 entry points, and the working tree is clean apart from that file.\n\n**Outcome: no defect in the math.** Nothing I traced in the Math Precision, Boundary or Numerical Gap guides breaks the hook, the token, the vesting contract or the vault. The two recorded items are information for the author, not defects that need a fix.\n\n**What was checked**\n\n- **The manifest is valid.** Constructor arguments follow the hook's declaration order, the six permissions sum to flags 0x18CC, the addresses are lowercase, and the initial price is exactly 10,000 times 2^96, which is tick 184216. The notes are under the 4,000-character limit.\n- **The existing suite passes.** 227 tests passed, none failed, and the 10 fork tests skipped because no mainnet RPC was set. I did not run the real-factory fork rehearsal.\n- **Hook tax arithmetic.** The partial-fill equality is checked against the raw pool delta, which the vendored v4 library does pass before applying the hook's own delta. Each of the four swap modes taxes the gross ETH leg at rate/10,000 within one wei, at both the standing and opening rates. No divisor can reach zero because the rate never exceeds 9,900.\n- **Vault arithmetic.** The deposit split conserves every wei including dust. The burn's price limit held at every allowed impact setting on the opened pool, and the limit clamp stays valid near the minimum price. The decay curve is continuous and monotone at all 24 half-life boundaries. The uint128 casts in the auctions are unreachable with any plausible ETH amount.\n- **Predeployed contracts.** Read from mainnet through a public node: the sink's pool manager, floor feed and 24,490-byte runtime match this source, it is not yet wired, and the timelock delay is 48 hours.\n\n**The two info notes**\n\n- Hook tax truncates in every mode, so swaps whose ETH leg is under 17 wei pay no tax. The leak is under one wei per swap and gas makes it uneconomic. The author's own test already pins this.\n- FloorFeed's rise allowance grows linearly with the gap between reports with no cap. After 30 days of silence one report could lift a 2.68 ETH floor to 806 ETH. Only the trusted attester can do this, so it is a trust assumption to document rather than a defect.\n\n**Not reached.** The live Seaport and the real IMD oracle attestation record could not be fetched during this run, so the attestation's actual validity window was checked only against what the keeper requests, which is 24 hours.","treeHash":null,"usage":{"cachedInputTokens":1656665,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":46578,"runtime":"claude","turns":46,"wallClockMs":732111}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"6b37e4ab65246705","findings":[{"citation":"resolved","description":"Cocoon.burn() is permissionless and buys PUPATE at the current spot price up to a price move of burnImpactBps. Its only protection against a front-run buy / back-run sell around it is that the sandwicher pays the hook's standing tax twice plus the LP fee twice. The vault's own bounds allow burnImpactBps up to 1000 (10%), and PupateHook.lowerTax (src/PupateHook.sol:239) lets the same owner (the timelock) take the standing tax to 0. Neither contract checks the other, so a configuration every bound admits (tax 0, impact 10%) makes the burn pot extractable by any searcher: the round-trip then costs only 2 x 1.25% LP fee against a guaranteed 10% price lift. docs/REVIEW.md already records this as a note ('the timelock should keep twice the standing tax above burnImpactBps'), so it is a trust assumption on the timelock rather than an exploit of the launch state, but it is enforced only by convention.","line":693,"path":"src/Cocoon.sol","reproduction":"CocoonFixture, after the launch window, pool holding 5 ETH, burnPot 17 ETH (depositTax 40 ETH). Default parameters (tax 600, impact 500): attacker buys 5 ETH exact-in, keeper calls burn() (spends 0.467971848358831849 ETH), attacker sells all tokens exact-in: attacker net -0.405072741171615316 ETH (loses). Owner then calls hook.lowerTax(0) and cocoon.setParams with burnImpactBps=1000, both accepted: same sandwich with a 5 ETH front: burn spends 0.991200093389357418 ETH, attacker net +0.446068864882843161 ETH, i.e. 45% of the burn's spend leaves to the sandwicher instead of lifting the price for holders. Expected: no admissible parameter set makes a sandwich on the buyback profitable (e.g. _checkParams bounding burnImpactBps below twice the hook's current taxBps, or burn() reading hook.taxBps()). Actual: the bounds are independent. Scratch test: test/scratch/BurnSandwich.scratch.t.sol (both cases pass as stated).","severity":"low","snippet":"        if (p.burnImpactBps < 100 || p.burnImpactBps > 1000) revert OutOfBounds();","title":"Owner-settable envelope lets a sandwich capture most of a burn: burnImpactBps may reach 10% while the hook's standing tax may reach 0, and nothing couples the two"},{"citation":"resolved","description":"PupateToken has no transfer hook, so anyone may initialise a second ETH/PUPATE pool on the PoolManager with hooks = address(0), seed it, and route buys and sells there. No tax is collected on that pool, so the whole Cocoon economy (seat purchases, burns, developer share) depends on the launch pool keeping the liquidity. The liquidity gate on the launch pool stops untaxed resting orders inside it but cannot stop a parallel pool. The manifest notes and the review log record this as accepted (3df3451d); it is listed here so the judge sees the economics specialist considered it and found nothing new.","line":255,"path":"src/PupateHook.sol","reproduction":"Any account: PoolManager.initialize(PoolKey(ETH, PUPATE, 3000, 60, IHooks(address(0))), sqrtPrice), modifyLiquidity with ETH and PUPATE, then swap 1 ETH exact-in zeroForOne. Expected under the brief's economics: every PUPATE buy pays the tax. Actual: hook.totalTax and the hook's ERC-6909 claims stay at 0; the swap fills with no tax. No source change requested: accepted by the requester.","severity":"info","snippet":"        return sender != sink && PoolId.unwrap(key.toId()) == PoolId.unwrap(launchPool);","title":"Only the launch pool is taxed: a hookless ETH/PUPATE pool accepts liquidity and untaxed trades (accepted design limitation, restated with concrete inputs)"}],"hash":"fc3704f45a23ce150a281cd4f5b62253cf082a7417acd0a38703ba3c142fb789","nodeId":"3366ec81-7a36-468c-b68c-59027fcfa5f1","outcome":"completed","summary":"The findings file is complete with 2 findings and 43 coverage rows, all 38 entry points answered. Final check that the JSON parses and the scratch test still runs clean has already passed above, so here is the recap.\n\n**Outcome: no new blocking defect in the economics area. One low finding, one info note, full coverage recorded in `.imd-findings.json`.**\n\n**Manifest.** launch.json is valid for this launch. Constructor args are `$poolManager`, the Cocoon vault and the timelock, in declaration order and lowercase. The six permissions match getHookPermissions and encode to flags 0x18CC. Pool is native ETH, fee 12500, spacing 60, and initialPrice is unchanged at 10000 × 2^96 (the 10 ETH valuation). Notes are 3,619 characters.\n\n**Test suite.**\n\n| Result | Count |\n|---|---|\n| passed | 227 |\n| failed | 0 |\n| skipped (fork, no MAINNET_RPC_URL) | 10 |\n\n**Findings.**\n- **Low, Cocoon.sol line 693.** The vault's parameter bounds allow burnImpactBps up to 10% and the hook lets the same owner lower the standing tax to 0. Nothing couples them, so an admissible configuration makes the permissionless buyback sandwichable. Measured in test/scratch/BurnSandwich.scratch.t.sol: under default parameters a 5 ETH front-run loses 0.405 ETH; with tax 0 and impact 10% it captures 0.446 ETH of a 0.991 ETH burn. The review log already carries this as a convention for the timelock, so it is a trust assumption, not a launch-state exploit.\n- **Info, PupateHook.sol line 255.** A hookless ETH/PUPATE pool trades untaxed. Accepted by the requester and documented; restated with concrete inputs so the judge sees it was weighed.\n\n**Coverage.** Every entry point has a row. Both Cocoon.burn and Cocoon.setParams point to finding 1. Everything else holds: the four swap tax modes re-derived against v4 delta accounting, the balance identity across every pot-changing path, the Seaport purchase refund logic, the auctions, FloorFeed's rise cap, the token and vesting.\n\n**Not verified here.** Mainnet state of the deployed Cocoon and timelock (that Cocoon's PoolManager is the launch chain's, and the fork rehearsal) needs an RPC and was skipped.","treeHash":null,"usage":{"cachedInputTokens":1175037,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":39969,"runtime":"claude","turns":21,"wallClockMs":612820}}],"verification":[{"checks":[{"durationMs":9343,"exitCode":0,"name":"build","output":"Compiling 138 files with Solc 0.8.26\nSolc 0.8.26 finished in 9.14s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n  --> test/FloorFeed.t.sol:49:5:\n   |\n49 |     function _signFor(OracleAttestation.Attestation memory a, uint256 key, uint256 chainId, address consumer)\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/PupateVesting.sol:38:13\n   │\n38 │         if (block.timestamp < START) return 0;\n   │             ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/FloorFeed.sol:140:9\n    │\n140 │         owner = to;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/PupateVesting.sol:39:13\n   │\n39 │         if (block.timestamp >= uint256(START) + DURATION) return total;\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/PupateVesting.sol:54:9\n   │\n54 │         emit Released(amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/FloorFeed.sol:85:13\n   │\n85 │         if (a.issuedAt > block.timestamp || block.timestamp > uint256(a.issuedAt) + age) revert Expired();\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/FloorFeed.sol:85:45\n   │\n85 │         if (a.issuedAt > block.timestamp || block.timestamp > uint256(a.issuedAt) + age) revert Expired();\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/FloorFeed.sol:104:9\n    │\n104 │         emit Reported(next, a.issuedAt, _freshUntil());\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/FloorFeed.sol:149:33\n    │\n149 │         return issuedAt != 0 && block.timestamp <= _freshUntil();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/PupateHook.sol:248:9\n    │\n248 │         owner = to;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PupateHook.sol:111:13\n    │\n111 │         if (fallen >= LAUNCH_TAX_BPS - standing) return standing;\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/PupateHook.sol:134:13\n    │\n134 │             emit LaunchPoolSet(id, block.timestamp);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PupateHook.sol:126:24\n    │\n126 │             openedAt = uint40(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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/PupateHook.sol:127:29\n    │\n127 │             openedAtBlock = uint40(block.number);\n    │                             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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/PupateHook.sol:209:44\n    │\n209 │         return (IHooks.afterSwap.selector, unspecified);\n    │                                            ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PupateHook.sol:193:69\n    │\n193 │             if (int256(delta.amount0()) != params.amountSpecified + int256(tax)) revert PartialFill();\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/PupateHook.sol:198:25\n    │\n198 │             tax = buy ? uint256(uint128(-eth)) * rate / (BPS - rate) : uint256(uint128(eth)) * rate / BPS;\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/PupateHook.sol:198:33\n    │\n198 │             tax = buy ? uint256(uint128(-eth)) * rate / (BPS - rate) : uint256(uint128(eth)) * rate / BPS;\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/PupateHook.sol:198:72\n    │\n198 │             tax = buy ? uint256(uint128(-eth)) * rate / (BPS - rate) : uint256(uint128(eth)) * rate / BPS;\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/PupateHook.sol:198:80\n    │\n198 │             tax = buy ? uint256(uint128(-eth)) * rate / (BPS - rate) : uint256(uint128(eth)) * rate / BPS;\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/PupateHook.sol:220:9\n    │\n220 │         emit Flushed(amount);\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/PupateHook.sol:218:9\n    │\n218 │         poolManager.unlock(abi.encode(claims));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/Cocoon.sol:662:9\n    │\n662 │         owner = to;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PupateHook.sol:272:39\n    │\n272 │         if (params.zeroForOne) return uint256(-params.amountSpecified) * rate / BPS;\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/PupateHook.sol:273:16\n    │\n273 │         return uint256(params.amountSpecified) * rate / (BPS - rate);\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[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/oracle/OracleAttestation.sol:63:31\n   │\n63 │         if (sig.length != 65) revert BadSignatureLength();\n   │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/oracle/OracleAttestation.sol:72:34\n   │\n72 │         if (uint256(s) > HALF_N) revert BadSignatureS();\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/Cocoon.sol:260:9\n    │\n260 │         emit OwnershipTransferred(address(0), owner_);\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/Cocoon.sol:261:9\n    │\n261 │         emit DeveloperSet(developer_);\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/Cocoon.sol:262:9\n    │\n262 │         emit OperatorSet(operator_);\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/Cocoon.sol:274:9\n    │\n274 │         emit ProceedsReceived(msg.sender, msg.value);\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/Cocoon.sol:293:9\n    │\n293 │         emit TaxDeposited(amount, toSeat, toBurn, dev, toImd, m);\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/Cocoon.sol:304:9\n    │\n304 │         emit ProceedsReceived(address(0), surplus);\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/Cocoon.sol:446:9\n    │\n446 │ ┏         emit SeatListed(\n447 │ ┃             tokenId,\n448 │ ┃             SeatListing.startPrice(t),\n449 │ ┃             SeatListing.endPrice(t),\n450 │ ┃             block.timestamp,\n451 │ ┃             block.timestamp + p.listDecay\n452 │ ┃         );\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/Cocoon.sol:351:9\n    │\n351 │         emit SeatBought(tokenId, spent, msg.sender, reward);\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/Cocoon.sol:362:9\n    │\n362 │         emit SeatAdopted(tokenId, floor);\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/Cocoon.sol:378:9\n    │\n378 │         emit SeatSold(tokenId, s.cost);\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/Cocoon.sol:377:9\n    │\n377 │         SEAPORT.cancel(orders);\n    │         ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Cocoon.sol:415:80\n    │\n415 │             if (c.itemType != ItemType.NATIVE || c.recipient == address(this)) revert BadOrder();\n    │                                                                                ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Cocoon.sol:416:57\n    │\n416 │             if (c.startAmount == 0 || c.endAmount == 0) revert BadOrder();\n    │                                                         ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Cocoon.sol:433:19\n    │\n433 │             cost: uint128(cost),\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/Cocoon.sol:434:23\n    │\n434 │             boughtAt: uint40(block.timestamp),\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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/Cocoon.sol:445:9\n    │\n445 │         SEAPORT.validate(SeatListing.orders(address(this), address(COLLECTION), tokenId, t));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/Cocoon.sol:469:64\n    │\n469 │             (,, uint256 totalFilled,) = SEAPORT.getOrderStatus(SEAPORT.getOrderHash(orders[i]));\n    │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/Cocoon.sol:469:41\n    │\n469 │             (,, uint256 totalFilled,) = SEAPORT.getOrderStatus(SEAPORT.getOrderHash(orders[i]));\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/Cocoon.sol:469:41\n    │\n469 │             (,, uint256 totalFilled,) = SEAPORT.getOrderStatus(SEAPORT.getOrderHash(orders[i]));\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `burnPot` is updated\n    ╭▸ src/Cocoon.sol:494:31\n    │\n494 │         bytes memory result = POOL_MANAGER.unlock(abi.encode(swapBudget, uint160(limit)));\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/Cocoon.sol:502:9\n    │\n502 │         emit Burned(spent, bought, msg.sender, reward);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Cocoon.sol:494:74\n    │\n494 │         bytes memory result = POOL_MANAGER.unlock(abi.encode(swapBudget, uint160(limit)));\n    │                                                                          ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' 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/Cocoon.sol:513:9\n    │\n513 │         emit Burned(0, amount, msg.sender, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Cocoon.sol:523:77\n    │\n523 │         BalanceDelta delta = POOL_MANAGER.swap(launchKey, SwapParams(true, -int256(budget), limit), \"\");\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/Cocoon.sol:524:25\n    │\n524 │         uint256 spent = uint256(uint128(-delta.amount0()));\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/Cocoon.sol:524:33\n    │\n524 │         uint256 spent = uint256(uint128(-delta.amount0()));\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/Cocoon.sol:525:26\n    │\n525 │         uint256 bought = uint256(uint128(delta.amount1()));\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/Cocoon.sol:525:34\n    │\n525 │         uint256 bought = uint256(uint128(delta.amount1()));\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[unused-return]: return value of an external call is not used\n    ╭▸ src/Cocoon.sol:526:25\n    │\n526 │         if (spent != 0) POOL_MANAGER.settle{value: spent}();\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/Cocoon.sol:548:9\n    │\n548 │         emit AuctionStarted(token, lot, params.harvestStartWei);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Cocoon.sol:546:73\n    │\n546 │         uint128 lot = balance > type(uint128).max ? type(uint128).max : uint128(balance);\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/Cocoon.sol:547:64\n    │\n547 │         auctions[token] = Auction(lot, params.harvestStartWei, uint40(block.timestamp));\n    │                                                                ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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/Cocoon.sol:565:9\n    │\n565 │         emit AuctionTaken(token, msg.sender, a.lot, price);\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/Cocoon.sol:582:9\n    │\n582 │         emit ImdAuctionStarted(lot, demand);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Cocoon.sol:581:30\n    │\n581 │         imdAuction = Auction(uint128(lot), uint128(demand), uint40(block.timestamp));\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/Cocoon.sol:581:44\n    │\n581 │         imdAuction = Auction(uint128(lot), uint128(demand), uint40(block.timestamp));\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/Cocoon.sol:581:61\n    │\n581 │         imdAuction = Auction(uint128(lot), uint128(demand), uint40(block.timestamp));\n    │                                                             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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/Cocoon.sol:598:9\n    │\n598 │         emit ImdBurned(msg.sender, demand, a.lot);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Cocoon.sol:610:13\n    │\n610 │         if (a.expiresAt <= block.timestamp) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Cocoon.sol:615:51\n    │\n615 │         _workerApprovals[digest] = WorkerApproval(uint232(a.tokenId), s.round, true);\n    │                                                   ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint232' 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/Cocoon.sol:642:9\n    │\n642 │         emit DeveloperPaid(amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/Cocoon.sol:702:22\n    │\n702 │         (bool ok,) = to.call{value: amount}(\"\");\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/utils/CocoonFixture.sol:75:13\n   │\n75 │         if (block.timestamp <= lastIssuedAt) vm.warp(lastIssuedAt + 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/utils/CocoonHandler.sol:121:13\n    │\n121 │         if (block.timestamp <= lastIssuedAt) vm.warp(lastIssuedAt + 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/cocoon/CocoonAuctions.t.sol:27:17\n   │\n27 │         vm.warp(block.timestamp + 2 hours);\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.number` may be reused across `vm.roll`\n   ╭▸ test/cocoon/CocoonBurn.t.sol:20:17\n   │\n20 │         vm.roll(block.number + 5);\n   │         ────────━━━━━━━━━━━━───── `vm.roll` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockNumber()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/cocoon/CocoonBurn.t.sol:74:17\n   │\n74 │         vm.roll(block.number + 4);\n   │         ────────━━━━━━━━━━━━───── `vm.roll` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockNumber()` 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/utils/CocoonFixture.sol:76:34\n   │\n76 │         uint64 issuedAt = uint64(block.timestamp);\n   │                                  ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/cocoon/CocoonCore.t.sol:96:9\n   │\n96 │         vm.warp(block.timestamp + 4 hours);\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/utils/CocoonFixture.sol:75:13\n   │\n75 │         if (block.timestamp <= lastIssuedAt) vm.warp(lastIssuedAt + 1);\n   │             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/cocoon/CocoonCore.t.sol:96:9\n   │\n96 │         vm.warp(block.timestamp + 4 hours);\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/cocoon/CocoonCore.t.sol:96:17\n   │\n96 │         vm.warp(block.timestamp + 4 hours);\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/utils/CocoonFixture.sol:76:34\n   │\n75 │         if (block.timestamp <= lastIssuedAt) vm.warp(lastIssuedAt + 1);\n   │                                              ───────────────────────── `vm.warp` changes this environment here\n76 │         uint64 issuedAt = uint64(block.timestamp);\n   │                                  ━━━━━━━━━━━━━━━\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/cocoon/CocoonMarket.t.sol:41:48\n    │\n 41 │             price, startX, endX, decay, uint40(block.timestamp), uint16(block.number)\n    │                                                ━━━━━━━━━━━━━━━\n    ‡\n109 │         vm.warp(block.timestamp + 3.5 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/cocoon/CocoonMarket.t.sol:109:17\n    │\n109 │         vm.warp(block.timestamp + 3.5 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/cocoon/CocoonMarket.t.sol:41:48\n   │\n41 │             price, startX, endX, decay, uint40(block.timestamp), uint16(block.number)\n   │                                                ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/utils/CocoonFixture.sol:95:9\n   │\n95 │         vm.warp(block.timestamp + 6 hours + 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/utils/CocoonFixture.sol:95:17\n   │\n95 │         vm.warp(block.timestamp + 6 hours + 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/cocoon/CocoonMarket.t.sol:41:48\n    │\n 41 │             price, startX, endX, decay, uint40(block.timestamp), uint16(block.number)\n    │                                                ━━━━━━━━━━━━━━━\n    ‡\n278 │         vm.warp(block.timestamp + 20 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/cocoon/CocoonMarket.t.sol:278:17\n    │\n278 │         vm.warp(block.timestamp + 20 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/cocoon/CocoonReentrancy.t.sol:39:17\n   │\n39 │         vm.warp(block.timestamp + 48 hours);\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/cocoon/CocoonReview.t.sol:193:73\n    │\n193 │             SeatListing.Terms(2.4 ether, 12_000, 10_000, 7 days, uint40(block.timestamp), 1),\n    │                                                                         ━━━━━━━━━━━━━━━\n    ‡\n197 │         vm.warp(block.timestamp + 3.5 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/cocoon/CocoonReview.t.sol:197:17\n    │\n197 │         vm.warp(block.timestamp + 3.5 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/cocoon/CocoonReview.t.sol:73:69\n    │\n 73 │             SeatListing.Terms(price, 10_000, 10_000, 7 days, uint40(block.timestamp), uint16(block.number)),\n    │                                                                     ━━━━━━━━━━━━━━━\n    ‡\n256 │         vm.warp(block.timestamp + 1 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/cocoon/CocoonReview.t.sol:248:30\n    │\n248 │         a.expiresAt = uint64(block.timestamp + 30 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n256 │         vm.warp(block.timestamp + 1 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/cocoon/CocoonReview.t.sol:256:17\n    │\n256 │         vm.warp(block.timestamp + 1 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/cocoon/CocoonReview.t.sol:73:69\n    │\n 73 │             SeatListing.Terms(price, 10_000, 10_000, 7 days, uint40(block.timestamp), uint16(block.number)),\n    │                                                                     ━━━━━━━━━━━━━━━\n    ‡\n327 │         vm.warp(block.timestamp + 1 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/cocoon/CocoonReview.t.sol:327:17\n    │\n327 │         vm.warp(block.timestamp + 1 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/cocoon/CocoonReview.t.sol:73:69\n   │\n73 │             SeatListing.Terms(price, 10_000, 10_000, 7 days, uint40(block.timestamp), uint16(block.number)),\n   │                                                                     ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/utils/CocoonFixture.sol:75:46\n   │\n75 │         if (block.timestamp <= lastIssuedAt) vm.warp(lastIssuedAt + 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.chainid` may be reused across `vm.chainId`\n   ╭▸ src/cocoon/WorkerAuthorization.sol:26:79\n   │\n26 │         return keccak256(abi.encode(DOMAIN_TYPEHASH, NAME_HASH, VERSION_HASH, block.chainid, collection));\n   │                                                                               ━━━━━━━━━━━━━\n   │\n   ⸬  test/cocoon/WorkerAuthorization.t.sol:62:9\n   │\n62 │         vm.chainId(1);\n   │         ───────────── `vm.chainId` changes this environment here\n   │\n   ├ help: capture it with `vm.getChainId()` 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/fork/CocoonSeaport.fork.t.sol:141:81\n    │\n141 │             holder, SeatListing.Terms(2.4 ether, 12_000, 10_000, 7 days, uint40(block.timestamp), 0)\n    │                                                                                 ━━━━━━━━━━━━━━━\n    ‡\n145 │         vm.warp(block.timestamp + 3.5 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/fork/CocoonSeaport.fork.t.sol:145:17\n    │\n145 │         vm.warp(block.timestamp + 3.5 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/fork/CocoonSeaport.fork.t.sol:272:81\n    │\n272 │             holder, SeatListing.Terms(2.8 ether, 10_000, 10_000, 7 days, uint40(block.timestamp), 0)\n    │                                                                                 ━━━━━━━━━━━━━━━\n    ‡\n282 │         vm.warp(block.timestamp + 7 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/fork/CocoonSeaport.fork.t.sol:451:31\n    │\n282 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    ‡\n451 │         a.requestId = bytes32(block.timestamp);\n    │                               ━━━━━━━━━━━━━━━\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/fork/CocoonSeaport.fork.t.sol:459:29\n    │\n282 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    ‡\n459 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\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/fork/CocoonSeaport.fork.t.sol:460:30\n    │\n282 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    ‡\n460 │         a.expiresAt = uint64(block.timestamp + 24 hours);\n    │                              ━━━━━━━━━━━━━━━\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/fork/CocoonSeaport.fork.t.sol:380:69\n    │\n282 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    ‡\n380 │             SeatListing.Terms(price, 10_000, 10_000, 7 days, uint40(block.timestamp), 0),\n    │                                                                     ━━━━━━━━━━━━━━━\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/fork/CocoonSeaport.fork.t.sol:282:17\n    │\n282 │         vm.warp(block.timestamp + 7 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\n","passed":true},{"durationMs":714,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Scaffold.t.sol:ScaffoldTest\n[PASS] test_toolchainIsCancun() (gas: 3313)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 200.17µs (61.20µs CPU time)\n\nRan 3 tests for test/cocoon/WorkerAuthorization.t.sol:WorkerAuthorizationTest\n[PASS] test_digestIsBoundToTheCollectionAndTheChain() (gas: 10299)\n[PASS] test_digestMatchesTheSpelledOutEncoding() (gas: 5552)\n[PASS] test_everyFieldChangesTheDigest() (gas: 13981)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 368.50µs (317.08µs CPU time)\n\nRan 5 tests for test/cocoon/SeatListing.t.sol:SeatListingTest\n[PASS] test_componentsMatchTheOrdersFieldForField() (gas: 31891)\n[PASS] test_differentPurchasesOfTheSameSeatGetDifferentSalts() (gas: 16894)\n[PASS] test_prices() (gas: 4305)\n[PASS] test_theDescendingOrder() (gas: 20052)\n[PASS] test_theFlatTailOrder() (gas: 13034)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 476.33µs (558.99µs CPU time)\n\nRan 3 tests for test/OracleAttestation.t.sol:OracleAttestationTest\n[PASS] test_differentConsumerDoesNotRecoverRealSigner() (gas: 9220)\n[PASS] test_discoverAnswerType() (gas: 27095)\nLogs:\n  answerType for uint256 = 3\n\n[PASS] test_realAttestationRecoversRealSigner() (gas: 9213)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 619.78µs (870.24µs CPU time)\n\nRan 7 tests for test/fork/CocoonSeaport.fork.t.sol:CocoonSeaportForkTest\n[SKIP] test_adoptTakesADirectTransferAndRefusesAnUnsolicitedSafeTransfer() (gas: 0)\n[SKIP] test_buysARealListingPublishesItsOrdersAndSellsThroughOne() (gas: 0)\n[SKIP] test_fulfillerTipIsRefused() (gas: 0)\n[SKIP] test_fullRestrictedOrderIsAccepted() (gas: 0)\n[SKIP] test_refundFromAFallingOrderStaysInTheSeatPot() (gas: 0)\n[SKIP] test_repurchaseIncrementsTheRoundWithoutColliding() (gas: 0)\n[SKIP] test_twoItemConsiderationIsAcceptedAndCostIsTheSum() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 7 skipped; finished in 844.32µs (131.64µs CPU time)\n\nRan 5 tests for test/PoolSetup.t.sol:PoolSetupTest\n[PASS] test_buyPaysExactlyTheNamedEthAndReceivesTokens() (gas: 191316)\n[PASS] test_seedingTakesTokensAndNoEth() (gas: 18284)\n[PASS] test_sellPaysOutEth() (gas: 289808)\n[PASS] test_sinkRouterCanBeToldToReject() (gas: 1125337)\n[PASS] test_sinkRouterKeepsItsDepositsWhenItSwaps() (gas: 1324664)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.48ms (693.72µs CPU time)\n\nRan 3 tests for test/fork/LaunchFactory.fork.t.sol:LaunchFactoryForkTest\n[SKIP] test_afterTheFactorysTransactionTheLaunchPoolIsClosedToLiquidity() (gas: 0)\n[SKIP] test_swapsAreTaxedAndTheFactoryStillCollectsItsPoolFees() (gas: 0)\n[SKIP] test_theRealFactoryOpensAndSeedsTheLaunchPoolInOneTransaction() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 2.28ms (172.97µs CPU time)\n\nRan 9 tests for test/PupateVesting.t.sol:PupateVestingTest\n[PASS] testFuzz_vestedNeverExceedsTheBalanceAndNeverFalls(uint256,uint256) (runs: 256, μ: 44097, ~: 44192)\nLogs:\n  Bound result 7914\n  Bound result 11408\n\n[PASS] test_anyoneMayRelease() (gas: 113322)\n[PASS] test_constructorRejectsBadArguments() (gas: 6339)\n[PASS] test_everythingVestsAtTheEnd() (gas: 188052)\n[PASS] test_halfVestsHalfway() (gas: 127783)\n[PASS] test_nothingVestsBeforeTheStart() (gas: 88727)\n[PASS] test_onlyTheBeneficiaryChangesTheBeneficiary() (gas: 184996)\n[PASS] test_releaseIsIdempotent() (gas: 143708)\n[PASS] test_tokensAddedLaterVestOnTheSameCurve() (gas: 154694)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 7.36ms (7.73ms CPU time)\n\nRan 9 tests for test/cocoon/CocoonAuctions.t.sol:CocoonAuctionsTest\n[PASS] test_afterTheCutoffTheLotIsFree() (gas: 174295)\n[PASS] test_harvestAuctionFallsAndTheTakerGetsTheLot() (gas: 393885)\n[PASS] test_imdAuctionBurnsTheDemandedImdAndPaysTheLot() (gas: 585220)\n[PASS] test_imdAuctionTakerWithoutImdFails() (gas: 255477)\n[PASS] test_imdThatArrivesDuringTheAuctionWaitsForTheNext() (gas: 517436)\n[PASS] test_openingAndTakingAtOnceCostsTheWholeStartPrice() (gas: 270053)\n[PASS] test_theStartPriceIsFixedWhenTheAuctionStarts() (gas: 161225)\n[PASS] test_whatArrivesDuringAnAuctionGoesToTheNextLot() (gas: 361337)\n[PASS] test_whatCannotBeAuctioned() (gas: 590998)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 11.22ms (2.98ms CPU time)\n\nRan 6 tests for test/cocoon/CocoonPairing.t.sol:CocoonPairingTest\n[PASS] test_isValidSignatureNeverReverts() (gas: 117756)\n[PASS] test_onlyTheOperator() (gas: 60532)\n[PASS] test_operatorApprovesAPairingForAHeldSeat() (gas: 122127)\n[PASS] test_pairingApprovalDiesWithTheSeat() (gas: 162017)\n[PASS] test_rejectsTheWrongWalletAnExpiredMessageAndAnUnheldSeat() (gas: 188889)\n[PASS] test_revokeTurnsAnApprovalInvalid() (gas: 106083)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 12.58ms (947.41µs CPU time)\n\nRan 13 tests for test/PupateToken.t.sol:PupateTokenTest\n[PASS] testFuzz_transferNeverChangesTheSupply(address,uint256) (runs: 256, μ: 86998, ~: 87015)\nLogs:\n  Bound result 501415215872419712611187801\n\n[PASS] test_burnFromSpendsTheAllowance() (gas: 115277)\n[PASS] test_burnFromWithoutAllowanceReverts() (gas: 34995)\n[PASS] test_burnOfMoreThanTheBalanceReverts() (gas: 34339)\n[PASS] test_burnReducesBalanceAndSupply() (gas: 55217)\n[PASS] test_metadata() (gas: 26725)\n[PASS] test_transferFromBeyondTheAllowanceReverts() (gas: 84572)\n[PASS] test_transferFromSpendsTheAllowance() (gas: 135818)\n[PASS] test_transferMovesBalance() (gas: 88632)\n[PASS] test_transferOfMoreThanTheBalanceReverts() (gas: 37201)\n[PASS] test_transferToTheZeroAddressReverts() (gas: 30093)\n[PASS] test_unlimitedAllowanceIsNotSpent() (gas: 120054)\n[PASS] test_wholeSupplyIsMintedToTheDeployer() (gas: 20961)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 12.49ms (12.20ms CPU time)\n\nRan 17 tests for test/cocoon/CocoonReview.t.sol:CocoonReviewTest\n[PASS] test_aFloorTooLargeForTheBooksCannotBeAdopted() (gas: 275779)\n[PASS] test_aLegitimateSplitPaymentIsAccepted() (gas: 456327)\n[PASS] test_aPurchaseThatDeliversNoSeatIsRefused() (gas: 343280)\n[PASS] test_aSeatFarUnderTheFloorIsNotBought() (gas: 637884)\n[PASS] test_aSeatSentBackBeforeSettleCanBeSettledAndAdopted() (gas: 1053709)\n[PASS] test_aSeatTheVaultAlreadyHoldsCannotBeBoughtFromAnyone() (gas: 185371)\n[PASS] test_auctionsRejectTheCollectionAndNeedTheWire() (gas: 87830)\n[PASS] test_cocoonCannotBeSoldASeatItAlreadyHolds() (gas: 437911)\n[PASS] test_costIsWhatSeaportPaidOutAndTheRewardIsOnIt() (gas: 566456)\n[PASS] test_ethFromAnyoneButSeaportDuringAPurchaseRevertsThePurchase() (gas: 1258417)\n[PASS] test_pairingApprovalDoesNotReviveWhenTheSeatComesBack() (gas: 1106041)\n[PASS] test_rejectsConsiderationThatIsNotTheOriginal() (gas: 90574)\n[PASS] test_rejectsOrdersThatPayCocoon() (gas: 133168)\n[PASS] test_rejectsZeroAmountItems() (gas: 127644)\n[PASS] test_skimBooksForcedEthAsProceeds() (gas: 126139)\n[PASS] test_theLargestCostTheBooksHoldIsRecordedWhole() (gas: 425211)\n[PASS] test_theOperatorCannotMoveValueSeatsOrParameters() (gas: 747119)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 12.92ms (9.02ms CPU time)\n\nRan 9 tests for test/cocoon/CocoonBurn.t.sol:CocoonBurnTest\n[PASS] test_aBurnNeverMovesThePricePastTheLimit() (gas: 541413)\n[PASS] test_aLargeBurnStopsAtTheImpactLimitAndKeepsTheRest() (gas: 603751)\n[PASS] test_aSmallBurnSpendsTheWholeBudgetAndPaysTheCaller() (gas: 640597)\n[PASS] test_burnNeedsAPot() (gas: 39265)\n[PASS] test_burnPupateBurnsWhatCocoonHolds() (gas: 157725)\n[PASS] test_burnWithTheSpotAboveLiquidityBuysNothingAndReverts() (gas: 1297135)\n[PASS] test_burnsAreSpacedOut() (gas: 799722)\n[PASS] test_theOwnerCanTightenOrLoosenTheLimitWithinBounds() (gas: 602128)\n[PASS] test_unlockCallbackIsOnlyForThePoolManagerDuringABurn() (gas: 60417)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 21.16ms (10.21ms CPU time)\n\nRan 6 tests for test/cocoon/Decay.t.sol:DecayTest\n[PASS] testFuzz_neverRises(uint256,uint256,uint256) (runs: 256, μ: 16008, ~: 16067)\nLogs:\n  Bound result 172801\n  Bound result 1597\n  Bound result 4801\n\n[PASS] test_constants() (gas: 3487)\n[PASS] test_fallsLinearlyInsideAHalfLife() (gas: 6141)\n[PASS] test_halvesEveryHalfLife() (gas: 5813)\n[PASS] test_isZeroFromTheCutoff() (gas: 4666)\n[PASS] test_startsAtTheStartPrice() (gas: 3644)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 25.97ms (26.02ms CPU time)\n\nRan 5 tests for test/cocoon/CocoonPriceBound.t.sol:CocoonPriceBoundTest\n[PASS] test_ascendingListingInItsFirstSecondIsRefused() (gas: 251873)\n[PASS] test_descendingListingNearItsEndIsRefused() (gas: 346779)\n[PASS] test_descendingListingStillAboveHalfTheFloorIsBought() (gas: 413902)\n[PASS] test_flatListingAtHalfTheFloorIsBought() (gas: 404684)\n[PASS] test_flatListingJustUnderHalfTheFloorIsRefused() (gas: 248335)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 32.17ms (1.68ms CPU time)\n\nRan 45 tests for test/FloorFeed.t.sol:FloorFeedTest\n[PASS] testFuzz_aReportWithinTheAllowanceIsStored(uint256,uint256) (runs: 256, μ: 209326, ~: 208962)\nLogs:\n  Bound result 21970567\n  Bound result 65900166862443172080\n\n[PASS] testFuzz_aRiseAboveTheAllowanceNeverChangesTheStoredPrice(uint256,uint256) (runs: 256, μ: 211746, ~: 211535)\nLogs:\n  Bound result 21970567\n  Bound result 340282366920938463018696834479396568721\n\n[PASS] test_aRejectedReportNeverChangesTheStoredValue() (gas: 391528)\n[PASS] test_aRiseAboveTheAllowanceIsRejected() (gas: 167884)\n[PASS] test_aRiseOfAQuarterOverSixHoursIsAccepted() (gas: 176219)\n[PASS] test_acceptsValidReport() (gas: 116282)\n[PASS] test_constructorRejectsAZeroEvidenceChain() (gas: 8258)\n[PASS] test_fallsAreNotLimited() (gas: 175483)\n[PASS] test_freshnessIsBoundedByTheAttestationsOwnExpiry() (gas: 147350)\n[PASS] test_holdingAnAttestationBackGainsNothing() (gas: 211160)\n[PASS] test_maxAgeShortensFreshness() (gas: 146965)\n[PASS] test_onlyOwnerCanAdminister() (gas: 106198)\n[PASS] test_ownerCanRotateAttester() (gas: 176382)\n[PASS] test_ownershipCanBeHandedOver() (gas: 114533)\n[PASS] test_questionCannotBeSetToZero() (gas: 34308)\n[PASS] test_raisingMaxAgeRevivesAnOlderReport() (gas: 161923)\n[PASS] test_rejectsAReportOlderThanMaxAge() (gas: 151709)\n[PASS] test_rejectsAShortLivedAttestation() (gas: 196089)\n[PASS] test_rejectsAgreementBelowQuorum() (gas: 51225)\n[PASS] test_rejectsAnswerOfWrongLength() (gas: 57946)\n[PASS] test_rejectsAttestationForAnotherConsumer() (gas: 47831)\n[PASS] test_rejectsAttestationSignedForAnotherChainsDomain() (gas: 47965)\n[PASS] test_rejectsEveryReportBeforeAQuestionIsSet() (gas: 50224)\n[PASS] test_rejectsEvidenceFromAnotherChain() (gas: 50203)\n[PASS] test_rejectsHighS() (gas: 44631)\n[PASS] test_rejectsIssuedInTheFuture() (gas: 54890)\n[PASS] test_rejectsMoreAgreementThanPanel() (gas: 51581)\n[PASS] test_rejectsQuorumBelowTheMinimum() (gas: 50482)\n[PASS] test_rejectsQuorumThatIsNotAMajority() (gas: 188740)\n[PASS] test_rejectsReplayAndOlderReports() (gas: 203174)\n[PASS] test_rejectsShortSignature() (gas: 40581)\n[PASS] test_rejectsWrongAnswerType() (gas: 57758)\n[PASS] test_rejectsWrongQuestion() (gas: 50195)\n[PASS] test_rejectsWrongSigner() (gas: 48015)\n[PASS] test_rejectsZeroAnswer() (gas: 58035)\n[PASS] test_reportGoesStaleAfterMaxAge() (gas: 130651)\n[PASS] test_reportsInQuickSuccessionCannotCompound() (gas: 550627)\n[PASS] test_setMaxAgeIsBounded() (gas: 59578)\n[PASS] test_settingTheQuestionClearsTheStoredReport() (gas: 306240)\n[PASS] test_settingTheSameQuestionAgainClearsTheStoredReport() (gas: 144986)\n[PASS] test_startsEmptyAndNotFresh() (gas: 13193)\n[PASS] test_theAllowanceGrowsWithTheGapBetweenReports() (gas: 292964)\n[PASS] test_theAllowanceStillAppliesAfterTheReportHasGoneStale() (gas: 245258)\n[PASS] test_theFirstReportIsNotRateLimited() (gas: 113462)\n[PASS] test_zeroAddressesAreRejected() (gas: 6145)\nSuite result: ok. 45 passed; 0 failed; 0 skipped; finished in 35.66ms (86.12ms CPU time)\n\nRan 49 tests for test/PupateHook.t.sol:PupateHookTest\n[PASS] testFuzz_buyExactIn_traderPaysWhatTheyNamedAtAnyPointOfTheSchedule(uint256,uint256) (runs: 256, μ: 292119, ~: 296635)\nLogs:\n  Bound result 65900166862443172080\n  Bound result 1809\n\n[PASS] test_aLowerStandingTaxExtendsTheLaunchScheduleDownToIt() (gas: 56037)\n[PASS] test_aPoolWithoutNativeEthDoesNotBecomeTheLaunchPool() (gas: 2085185)\n[PASS] test_aSecondNativePoolIsNotTheLaunchPoolAndTakesNoLiquidity() (gas: 193231)\n[PASS] test_addressEncodesExactlyTheDeclaredPermissions() (gas: 15833)\n[PASS] test_buyAtTheOpenPaysTheLaunchTax() (gas: 251871)\n[PASS] test_buyExactIn_taxIsSixPercentOfTheEthPaid() (gas: 266521)\n[PASS] test_buyExactOutAtTheOpenPaysNinetyNineTimesThePoolLeg() (gas: 246538)\n[PASS] test_buyExactOut_taxIsSixPercentOfTheGrossEthPaid() (gas: 252092)\n[PASS] test_buyTaxFallsOnePointAMinute() (gas: 36383)\n[PASS] test_buyTaxMeetsTheStandingTaxAfterNinetyThreeMinutes() (gas: 36246)\n[PASS] test_buyTaxStartsAtNinetyNinePercent() (gas: 10960)\n[PASS] test_callbacksRejectCallersOtherThanThePoolManager() (gas: 127534)\n[PASS] test_constructorRejectsAnAddressThatDoesNotEncodeItsPermissions() (gas: 11545)\n[PASS] test_constructorRejectsZeroAddresses() (gas: 8291)\n[PASS] test_dustSwapWhoseTaxRoundsToZeroStillGoesThrough() (gas: 199390)\n[PASS] test_exactEthSwapThatCannotFillReverts() (gas: 169975)\n[PASS] test_exactOutSellDuringTheLaunchPaysTheStandingRate() (gas: 398665)\n[PASS] test_exactOutSellThatCannotFillReverts() (gas: 781762)\n[PASS] test_exactTokenSwapMayFillPartlyAndIsTaxedOnWhatMoved() (gas: 269431)\n[PASS] test_firstBuyWorksWhileThePoolHoldsNoEth() (gas: 247268)\n[PASS] test_firstNativePoolBecomesTheLaunchPool() (gas: 37793)\n[PASS] test_flushAlsoDeliversEthForcedIntoTheHook() (gas: 341668)\n[PASS] test_flushHandsTheCollectedTaxToTheSink() (gas: 370899)\n[PASS] test_flushLeavesTheTaxInPlaceWhenTheSinkRejects() (gas: 494053)\n[PASS] test_flushWithNothingCollectedReverts() (gas: 35051)\n[PASS] test_hookRefusesEthFromAnyoneButThePoolManager() (gas: 35873)\n[PASS] test_inTheOpeningTransactionOnlyTheLaunchPoolTakesLiquidity() (gas: 2754754)\n[PASS] test_laterPoolsOnTheHookDoNotReopenTheLaunchPool() (gas: 628340)\n[PASS] test_launchPoolSetEventNamesThePoolAndTheTime() (gas: 1981699)\n[PASS] test_liquidityCanStillBeRemovedAfterTheOpeningBlock() (gas: 131532)\n[PASS] test_liquidityIsClosedOnceTheOpeningTransactionEnds() (gas: 69922)\n[PASS] test_liquidityStaysClosedInLaterBlocks() (gas: 62550)\n[PASS] test_noPoolOnTheHookTakesLiquidityBeforeTheLaunchPoolOpens() (gas: 2096454)\n[PASS] test_onlyTheOwnerCanLowerTheTaxOrHandOverOwnership() (gas: 56839)\n[PASS] test_ownerCanLowerTheStandingTax() (gas: 294664)\n[PASS] test_ownershipCanBeHandedOver() (gas: 112688)\n[PASS] test_ownershipCannotGoToTheZeroAddress() (gas: 34510)\n[PASS] test_sellAtTheOpenPaysOnlyTheStandingTax() (gas: 420153)\n[PASS] test_sellExactIn_taxIsSixPercentOfTheEthPaidOut() (gas: 423350)\n[PASS] test_sellExactOut_taxIsSixPercentOfTheGrossEthPaidOut() (gas: 426905)\n[PASS] test_standingTaxCannotBeRaisedOrRestated() (gas: 65556)\n[PASS] test_taxCanBeLoweredToZero() (gas: 612428)\n[PASS] test_taxedEventReportsSells() (gas: 397201)\n[PASS] test_theOpeningTransactionIsTheGateNotTheAccountThatOpens() (gas: 3765738)\n[PASS] test_theOpeningTransactionSeedsTheLaunchPool() (gas: 2258118)\n[PASS] test_theSinkIsExemptInEveryMode() (gas: 545664)\n[PASS] test_theSinksOwnSwapMayFillPartly() (gas: 206190)\n[PASS] test_theSinksOwnSwapsAreNotTaxed() (gas: 205669)\nSuite result: ok. 49 passed; 0 failed; 0 skipped; finished in 36.19ms (64.21ms CPU time)\n\nRan 9 tests for test/cocoon/CocoonReentrancy.t.sol:CocoonReentrancyTest\n[PASS] test_aTakerCannotReopenTheHarvestAuctionFromItsRefund() (gas: 1461959)\n[PASS] test_aTakerCannotReopenTheImdAuctionFromItsPayout() (gas: 1067729)\n[PASS] test_noGuardedEntryPointRunsFromInsideTheLotTransfer() (gas: 3180187)\n[PASS] test_plainEthSentFromInsideTheLotTransferIsBookedOnce() (gas: 386900)\n[PASS] test_skimCannotBookATakersExcessFromInsideTheLotTransfer() (gas: 424191)\n[PASS] test_skimCannotBookTheImdLotFromInsideTheImdTransfer() (gas: 499690)\n[PASS] test_skimStillBooksEthThatWasForcedIn() (gas: 148312)\n[PASS] test_taxCannotBeDepositedFromInsideTheLotTransfer() (gas: 460920)\n[PASS] test_theExcessIsRefundedBeforeTheLotTokenIsCalled() (gas: 269492)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 39.02ms (4.76ms CPU time)\n\nRan 16 tests for test/cocoon/CocoonCore.t.sol:CocoonCoreTest\n[PASS] testFuzz_noWeiIsLostInTheSplit(uint96) (runs: 256, μ: 199779, ~: 204005)\n[PASS] testFuzz_theBalanceIdentityHoldsThroughDepositsClaimsAndProceeds(uint96[6],uint8) (runs: 256, μ: 720968, ~: 731104)\n[PASS] test_aStaleFloorMeansNeutralEvenWithSeats() (gas: 387782)\n[PASS] test_burnAndAdoptNeedTheWire() (gas: 45510)\n[PASS] test_constructorRejectsZeroAddresses() (gas: 19182)\n[PASS] test_defaults() (gas: 81947)\n[PASS] test_depositAccumulatesWhileNoSeatIsHeld() (gas: 297673)\n[PASS] test_depositSplitsEvenlyWhileTheFloorIsUnknown() (gas: 220196)\n[PASS] test_developerClaimsOnlyTheDeveloperBalance() (gas: 274653)\n[PASS] test_modeFollowsTheFloorAgainstTheAveragePurchasePrice() (gas: 1011762)\n[PASS] test_onlyTheDeveloperRotatesTheDeveloper() (gas: 289717)\n[PASS] test_onlyTheOwnerAdministers() (gas: 127060)\n[PASS] test_ownershipAndOperatorCanBeHandedOver() (gas: 169120)\n[PASS] test_plainEthIsSaleProceedsAndGoesToTheBurnPot() (gas: 105157)\n[PASS] test_setParamsChecksEveryBound() (gas: 778111)\n[PASS] test_wireHappensOnceAndOnlyToTheHooksLaunchPool() (gas: 147014)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 39.10ms (52.34ms CPU time)\n\nRan 13 tests for test/cocoon/CocoonMarket.t.sol:CocoonMarketTest\n[PASS] test_aThirdPartyBuysOurListingAndSettleFixesTheBooks() (gas: 959414)\n[PASS] test_adoptNeedsAHeldUnrecordedSeatAndAFreshFloor() (gas: 433690)\n[PASS] test_buySeatRefundStaysInTheSeatPot() (gas: 565134)\n[PASS] test_buysAListingAtTheFloorListsItAndPaysTheCaller() (gas: 574739)\n[PASS] test_buysRightAtTheTolerance() (gas: 408678)\n[PASS] test_reentryDuringThePurchaseIsRejected() (gas: 978744)\n[PASS] test_rejectsAPurchaseThePotCannotCover() (gas: 997736)\n[PASS] test_rejectsOrdersThatAreNotOneSeatForEth() (gas: 1251069)\n[PASS] test_rejectsPricesAboveTheToleranceAndStaleFloors() (gas: 260948)\n[PASS] test_settleAlsoWorksWhenTheSeatWasBurned() (gas: 541884)\n[PASS] test_settleCancelsTheOldListingsSoARepurchaseCannotBeSoldAtTheOldPrice() (gas: 1341532)\n[PASS] test_settleSeatIsPermissionlessAndFixesTheAverage() (gas: 1123985)\n[PASS] test_unsolicitedSafeTransfersAreRejected() (gas: 84668)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 39.77ms (8.98ms CPU time)\n\nRan 2 tests for test/PupateHook.invariant.t.sol:PupateHookInvariantTest\n[PASS]\nPupateHookInvariantTest invariants:\n[PASS] invariant_everyWeiOfTaxIsHeldAsClaimsOrDeliveredToTheSink\n[PASS] invariant_theHookHoldsNoEth\n[PASS] invariant_theStandingTaxNeverRises\n PupateHookInvariantTest invariants (runs: 48, calls: 2304, reverts: 0)\n\n╭----------+--------------+-------+---------+----------╮\n| Contract | Selector     | Calls | Reverts | Discards |\n+======================================================+\n| Trader   | buyExactIn   | 340   | 0       | 0        |\n|----------+--------------+-------+---------+----------|\n| Trader   | buyExactOut  | 356   | 0       | 0        |\n|----------+--------------+-------+---------+----------|\n| Trader   | flush        | 315   | 0       | 0        |\n|----------+--------------+-------+---------+----------|\n| Trader   | lowerTax     | 343   | 0       | 0        |\n|----------+--------------+-------+---------+----------|\n| Trader   | sellExactIn  | 318   | 0       | 0        |\n|----------+--------------+-------+---------+----------|\n| Trader   | sellExactOut | 308   | 0       | 0        |\n|----------+--------------+-------+---------+----------|\n| Trader   | wait         | 324   | 0       | 0        |\n╰----------+--------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1324\n  Bound result 4999999000000000000009501\n  Bound result 964161355445744900\n  Bound result 4999999000000000000010498\n  Bound result 999999999000011232\n  Bound result 4999999000000000000002217\n  Bound result 401\n  Bound result 49999999999000000594\n  Bound result 1746\n  Bound result 938359925360006447\n  Bound result 1600\n  Bound result 1097\n  Bound result 5400000000000000000\n  Bound result 55\n  Bound result 999999999023817983\n  Bound result 3494573994736678107061609\n  Bound result 78\n  Bound result 400\n  Bound result 49999999999000002294\n  Bound result 999999999000000433\n  Bound result 49999999999000072001\n  Bound result 19999999980\n  Bound result 172417487857090870\n  Bound result 49999999999000009747\n  Bound result 835687916371119730\n  Bound result 4999999000000000000000121\n  Bound result 1688\n  Bound result 4999999000000000000000028\n  Bound result 7\n  Bound result 4999999000000000000001012\n  Bound result 1500\n  Bound result 27681357873075798876\n  Bound result 567983601334969171\n  Bound result 32\n  Bound result 9000000001\n  Bound result 1\n  Bound result 49999999999000009601\n  Bound result 20\n  Bound result 27665624086522703363\n  Bound result 5\n  Bound result 49999999999000012949\n\n[PASS] test_theHandlerActuallyTrades() (gas: 870740)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000000000\n  Bound result 1000000000000000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 432.82ms (420.29ms CPU time)\n\nRan 2 tests for test/cocoon/Cocoon.invariant.t.sol:CocoonInvariantTest\n[PASS]\nCocoonInvariantTest invariants:\n[PASS] invariant_aSeatLeavesCocoonOnlyThroughAFilledListing\n[PASS] invariant_cocoonNeverKeepsPupate\n[PASS] invariant_ethLeavesCocoonOnlyThroughSanctionedPaths\n[PASS] invariant_everyWeiOfTaxIsClaimsOrDelivered\n[PASS] invariant_noAuctionClaimsMoreThanCocoonHolds\n[PASS] invariant_theBalanceIsExactlyTheFourPots\n[PASS] invariant_theBooksMatchTheSeatsHeld\n CocoonInvariantTest invariants (runs: 48, calls: 2304, reverts: 0)\n\n╭---------------+----------------------+-------+---------+----------╮\n| Contract      | Selector             | Calls | Reverts | Discards |\n+===================================================================+\n| CocoonHandler | burn                 | 142   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | claimDeveloper       | 158   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | deposit              | 163   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | donate               | 146   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | flush                | 144   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | harvest              | 152   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | hostileHarvest       | 148   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | imdCycle             | 152   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | listAndBuy           | 160   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | reopeningHarvestTake | 146   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | reopeningImdTake     | 156   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | reportFloor          | 162   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | sellOurs             | 158   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | trade                | 168   | 0       | 0        |\n|---------------+----------------------+-------+---------+----------|\n| CocoonHandler | warp                 | 149   | 0       | 0        |\n╰---------------+----------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 331441903543837\n  Bound result 1960000000000000011\n  Bound result 0\n  Bound result 65537\n  Bound result 2800000000000000000\n  Bound result 100000000000000018288\n  Bound result 2559\n  Bound result 2329596499\n  Bound result 100000000000000012216\n  Bound result 5317173412216980425\n  Bound result 2800000000000000000\n  Bound result 4882\n  Bound result 100000000000000003202\n  Bound result 19999999999404098525\n  Bound result 2800000000000000000\n  Bound result 3015925047\n  Bound result 2800000000000000000\n  Bound result 100000000000000000972\n  Bound result 1960000000000000483\n  Bound result 1960000000000012401\n  Bound result 1726\n  Bound result 147511\n  Bound result 55\n  Bound result 21\n  Bound result 2800000000000000000\n  Bound result 2800000002329599059\n  Bound result 2800000000000000000\n  Bound result 2800000000000000000\n  Bound result 100000000000000012748\n  Bound result 14125\n  Bound result 100000000000000000972\n  Bound result 245\n  Bound result 9500000000000002753\n  Bound result 1\n  Bound result 2800000000000000000\n  Bound result 2800000000000000000\n  Bound result 30074898028889\n  Bound result 301\n  Bound result 99\n  Bound result 1611753842227764066\n  Bound result 2800000000000000000\n  Bound result 100000000000000002192\n  Bound result 172800\n  Bound result 24\n  Bound result 543912398467143\n\n[PASS] test_theHandlerActuallyActs() (gas: 2475345)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 2800000000000000000\n  Bound result 86400\n  Bound result 45\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 10000000000000000000\n  Bound result 100000000000000000990\n  Bound result 5000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 595.07ms (589.39ms CPU time)\n\nRan 22 test suites in 597.69ms (1.36s CPU time): 227 tests passed, 0 failed, 10 skipped (237 total tests)\n","passed":true},{"durationMs":152,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Cocoon.adopt(uint256)\",\"Cocoon.authorizeWorker((bytes32,address,uint256,bytes32,uint64,string))\",\"Cocoon.burn()\",\"Cocoon.burnPupate()\",\"Cocoon.claimDeveloper()\",\"Cocoon.depositTax()\",\"Cocoon.receive()\",\"Cocoon.revokeWorker(bytes32)\",\"Cocoon.setDeveloper(address)\",\"Cocoon.setOperator(address)\",\"Cocoon.setParams((uint16,uint16,uint16,uint32,uint16,uint16,uint16,uint16,uint128,uint128))\",\"Cocoon.settleSeat(uint256)\",\"Cocoon.skim()\",\"Cocoon.startAuction(address)\",\"Cocoon.startImdAuction()\",\"Cocoon.takeAuction(address)\",\"Cocoon.takeImdAuction()\",\"Cocoon.transferOwnership(address)\",\"Cocoon.unlockCallback(bytes)\",\"Cocoon.wire((address,address,uint24,int24,address))\",\"FloorFeed.report((bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"FloorFeed.setAttester(address)\",\"FloorFeed.setMaxAge(uint64)\",\"FloorFeed.setQuestion(bytes32)\",\"FloorFeed.transferOwnership(address)\",\"PupateHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"PupateHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PupateHook.flush()\",\"PupateHook.lowerTax(uint16)\",\"PupateHook.receive()\",\"PupateHook.transferOwnership(address)\",\"PupateHook.unlockCallback(bytes)\",\"PupateToken.approve(address,uint256)\",\"PupateToken.burn(uint256)\",\"PupateToken.burnFrom(address,uint256)\",\"PupateToken.transfer(address,uint256)\",\"PupateToken.transferFrom(address,address,uint256)\",\"PupateVesting.release()\",\"PupateVesting.setBeneficiary(address)\"],\"files\":{\".gitattributes\":1,\".gitignore\":6,\"LICENSE\":21,\"README.md\":111,\"brand/README.md\":20,\"brand/assets.html\":120,\"brand/banner.png\":1192,\"brand/favicon-32.png\":8,\"brand/favicon.png\":948,\"brand/key.mjs\":62,\"brand/logo.png\":2127,\"brand/mark-source.png\":3156,\"brand/mark.png\":568,\"brand/og.png\":1791,\"brand/render.mjs\":35,\"deploy/README.md\":76,\"deploy/keeper.env.example\":37,\"deploy/nginx-locations.conf\":40,\"deploy/nginx-site.conf\":10,\"deploy/setup.sh\":91,\"deploy/update.sh\":65,\"docs/REVIEW.md\":179,\"docs/dependencies.md\":20,\"docs/deployment.md\":187,\"docs/phase0-findings.md\":125,\"docs/superpowers/plans/2026-10-06-pupate-plan-1-foundation.md\":782,\"docs/superpowers/plans/2026-10-06-pupate-plan-2-token-and-hook.md\":2040,\"docs/superpowers/plans/2026-10-06-pupate-plan-3-cocoon.md\":154,\"docs/superpowers/specs/2026-10-06-pupate-design.md\":332,\"docs/superpowers/specs/2026-10-10-site-two-layers-design.md\":55,\"docs/v2-mining-proof-of-work.md\":139,\"foundry.toml\":33,\"keeper/.gitignore\":4,\"keeper/README.md\":235,\"keeper/addresses.sepolia.json\":22,\"keeper/bin/imd.mjs\":161,\"keeper/bin/keeper.mjs\":205,\"keeper/lib/abi.mjs\":221,\"keeper/lib/actions.mjs\":351,\"keeper/lib/chain.mjs\":161,\"keeper/lib/config.mjs\":211,\"keeper/lib/imd.mjs\":248,\"keeper/lib/listings.mjs\":222,\"keeper/lib/log.mjs\":60,\"keeper/lib/oracle.mjs\":334,\"keeper/lib/state.mjs\":282,\"keeper/lib/status.mjs\":253,\"keeper/lib/work.mjs\":117,\"keeper/package-lock.json\":258,\"keeper/package.json\":26,\"keeper/questions/floor.check.json\":11,\"keeper/questions/floor.question.txt\":1,\"keeper/questions/floor.quote.json\":30,\"keeper/questions/launch.check.json\":29,\"keeper/questions/launch.sepolia.check.json\":29,\"keeper/test/fork.mjs\":366,\"launch.json\":32,\"script/DeployPreLaunch.s.sol\":68,\"script/PostLaunch.s.sol\":68,\"script/RedeployCocoon.s.sol\":58,\"script/local/LaunchLocal.s.sol\":149,\"script/local/LocalLaunchFactory.sol\":87,\"script/local/README.md\":160,\"script/local/ReportLocal.s.sol\":57,\"script/local/common.mjs\":271,\"script/local/smoke.mjs\":281,\"script/local/up.mjs\":392,\"script/mainnet/README.md\":58,\"script/mainnet/launch.mjs\":843,\"script/sepolia/Mocks.s.sol\":28,\"script/sepolia/README.md\":35,\"script/sepolia/up.mjs\":407,\"site/.env.example\":8,\"site/.gitignore\":15,\"site/.vercelignore\":13,\"site/README.md\":40,\"site/app/apple-icon.png\":123,\"site/app/buy/page.tsx\":13,\"site/app/cocoon/page.tsx\":14,\"site/app/docs/control/page.tsx\":113,\"site/app/docs/launch/page.tsx\":92,\"site/app/docs/layout.tsx\":24,\"site/app/docs/mechanism/page.tsx\":143,\"site/app/docs/oracle/page.tsx\":102,\"site/app/docs/page.tsx\":112,\"site/app/docs/parameters/page.tsx\":97,\"site/app/docs/seats/page.tsx\":116,\"site/app/docs/steps/page.tsx\":124,\"site/app/emerge/page.tsx\":14,\"site/app/feed/page.tsx\":16,\"site/app/flow/page.tsx\":14,\"site/app/globals.css\":628,\"site/app/how/page.tsx\":13,\"site/app/icon.png\":948,\"site/app/inside/page.tsx\":13,\"site/app/layout.tsx\":66,\"site/app/mine/page.tsx\":13,\"site/app/not-found.tsx\":28,\"site/app/page.tsx\":10,\"site/app/record/page.tsx\":14,\"site/app/seat/page.tsx\":17,\"site/app/steps/page.tsx\":14,\"site/app/work/page.tsx\":14,\"site/components/Buy.tsx\":113,\"site/components/BuyPanel.tsx\":123,\"site/components/Chrysalis.tsx\":28,\"site/components/Cocoon.tsx\":80,\"site/components/ConnectWallet.tsx\":45,\"site/components/Contracts.tsx\":78,\"site/components/Emerge.tsx\":98,\"site/components/EmergenceCard.tsx\":197,\"site/components/Feed.tsx\":176,\"site/components/FieldLog.tsx\":33,\"site/components/Flash.tsx\":17,\"site/components/Flow.tsx\":94,\"site/components/Hero.tsx\":53,\"site/components/Home.tsx\":128,\"site/components/How.tsx\":149,\"site/components/Inside.tsx\":30,\"site/components/InsideBar.tsx\":66,\"site/components/KeeperStatus.tsx\":156,\"site/components/Launch.tsx\":57,\"site/components/LineChart.tsx\":160,\"site/components/Mine.tsx\":119,\"site/components/OracleProof.tsx\":163,\"site/components/Providers.tsx\":28,\"site/components/Record.tsx\":85,\"site/components/SeatSheet.tsx\":252,\"site/components/SeatWork.tsx\":94,\"site/components/Shell.tsx\":35,\"site/components/SimContext.tsx\":271,\"site/components/Stages.tsx\":42,\"site/components/Steps.tsx\":147,\"site/components/TopBar.tsx\":92,\"site/components/TryControls.tsx\":70,\"site/components/Web3Provider.tsx\":46,\"site/components/Work.tsx\":111,\"site/components/docs/Doc.tsx\":46,\"site/components/docs/DocsNav.tsx\":33,\"site/lib/abi.ts\":96,\"site/lib/addresses.ts\":90,\"site/lib/attestation.ts\":234,\"site/lib/docs.ts\":24,\"site/lib/live.ts\":289,\"site/lib/rainbowTheme.ts\":46,\"site/lib/seat.ts\":91,\"site/lib/sim.ts\":516,\"site/lib/swap.ts\":101,\"site/lib/work.ts\":85,\"site/next.config.ts\":37,\"site/package-lock.json\":7904,\"site/package.json\":27,\"site/public/cards/prototype-1376.svg\":34,\"site/public/og.png\":1791,\"site/public/skill.md\":184,\"site/scripts/dev.mjs\":15,\"site/scripts/fork-e2e.ts\":109,\"site/scripts/verify-attestation.ts\":32,\"site/tsconfig.json\":21,\"site/vercel.json\":37,\"src/Cocoon.sol\":741,\"src/FloorFeed.sol\":151,\"src/PupateHook.sol\":275,\"src/PupateToken.sol\":86,\"src/PupateVesting.sol\":63,\"src/cocoon/Decay.sol\":16,\"src/cocoon/SeatListing.sol\":122,\"src/cocoon/WorkerAuthorization.sol\":44,\"src/interfaces/IERC20Minimal.sol\":11,\"src/interfaces/IERC721Minimal.sol\":12,\"src/interfaces/ILaunchHook.sol\":11,\"src/interfaces/ITaxSink.sol\":8,\"src/oracle/OracleAttestation.sol\":75,\"test/FloorFeed.t.sol\":548,\"test/OracleAttestation.t.sol\":54,\"test/PoolSetup.t.sol\":67,\"test/PupateHook.invariant.t.sol\":44,\"test/PupateHook.t.sol\":678,\"test/PupateToken.t.sol\":102,\"test/PupateVesting.t.sol\":118,\"test/Scaffold.t.sol\":17,\"test/cocoon/Cocoon.invariant.t.sol\":134,\"test/cocoon/CocoonAuctions.t.sol\":174,\"test/cocoon/CocoonBurn.t.sol\":153,\"test/cocoon/CocoonCore.t.sol\":350,\"test/cocoon/CocoonMarket.t.sol\":336,\"test/cocoon/CocoonPairing.t.sol\":100,\"test/cocoon/CocoonPriceBound.t.sol\":124,\"test/cocoon/CocoonReentrancy.t.sol\":250,\"test/cocoon/CocoonReview.t.sol\":444,\"test/cocoon/Decay.t.sol\":44,\"test/cocoon/SeatListing.t.sol\":104,\"test/cocoon/WorkerAuthorization.t.sol\":90,\"test/fork/CocoonSeaport.fork.t.sol\":465,\"test/fork/LaunchFactory.fork.t.sol\":239,\"test/mocks/MockERC20.sol\":53,\"test/mocks/MockERC721.sol\":82,\"test/mocks/MockSeaport.sol\":164,\"test/mocks/ReenteringToken.sol\":55,\"test/mocks/ReopeningTaker.sol\":61,\"test/utils/CocoonFixture.sol\":118,\"test/utils/CocoonHandler.sol\":340,\"test/utils/HookFixture.sol\":95,\"test/utils/PoolRouter.sol\":104,\"test/utils/PoolSetup.sol\":95,\"test/utils/SinkRouter.sol\":23,\"test/utils/Trader.sol\":84},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b43d1bf1348c5dc3930e78dd2bcdbfeec3601b7a4c6b0a2038b980520da7461b","verifiedTreeHash":"2fa2492cf355a4623c9a6ce63f9c049b32bac9ee","verifierVersion":"0.1.0+fb8278c5"}]}