{"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":"9060a248-29ce-4683-b5d1-54fbc83cd49d","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"30550e36665b697d8ef4edf5261e2779cc997e6b8a957180ddfb72978df7fe3f","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"d4a6e8090f495ee90705027f642b04d95fefa80f0b5b4b9f55adec6b5e122a99","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"b5d03915ec250e356cd99ba9f08fdf90fb2d419885e57479abc58432fa03be87","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"40b79676379435101388a79e2e21afe0d7e915364126a9dbb116bb964d9abff2","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":"137ea4163a7b216f3ccceec8618997a2f75a7a4dc10b707f2220bfe6c91cb151","dependsOn":["adapt_contract_project","write_foundry_tests","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":"bbed721b16b38f277ff8f6acb5cd142d1f643f3d62daff8eea35e7d2a5a37b79","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"e00feb914d29fdfd72ebb90bca0b72112e64397b272e1a9804ac2921e28d0911","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"5ffee37d4b50c826eae12edbfd4accdfd0cfc52c9fecedce0eea4fe190faba46","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"0a5d14ae71e03fd5bf1dcdd59f842ed95321186b8af8081ddcc55ea4af59e97b","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Marginalia (x.com/marginalia_md): notes in the margin of every trade. Token name \"Marginalia\", symbol \"MARG\", 18 decimals, fixed supply. Callbacks: beforeInitialize, beforeSwap with beforeSwapReturnDelta, afterSwap with afterSwapReturnDelta (flags 0x20cc). Fee rule: no hook fee on buys; MARG sells pay 1% plus a 0.1 IMD stamp with a note in hookData, 3% without; exact-output quiet sells are refused (exact-input only). Where fees go: kept as IMD claims in the hook, split at accrual 70% to the week's thesis prize and 30% to the day's writer refund; never sold for ETH. Who can change it: nobody; no owner, admin, pause, upgrade or setter anywhere. Launch kind univ4_hook on Ethereum mainnet paired with IMD 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7, LP fee 12500, tick spacing 60. MarginaliaHook(IPoolManager, token, factory): validates its permissions, binds the first pool initialized through it (requires the supplied factory and fee 12500, never blocks the factory's seeding, liquidity or fee claims, refuses later pools). Its constructor clones (EIP-1167) three companions from the LIVE implementations of launch #1240 and initialises each once: MarginaliaRouter 0x365CcB3cfBC430600485234F56FD5ECb23fd70D1, MarginaliaJudge 0xC93460730a79a22282f063A0c6BA5E340Ac372b4, MarginaliaTreasury 0xe2086012f5F9CC7cAECDBC70dE392e263aAe8481; it calls the stateless MarginaliaPricer 0xEaff9B262341A0cB05579227e662BFE768A71cfb by staticcall. These addresses are compile-time constants in src/MarginaliaImpls.sol, verified by the mainnet-fork rehearsal in test/fork; the constructor reads no chain state (it must pass an empty-EVM rehearsal), and a codeless companion would revert on first use. Do not redeploy the companions. NOTES. Buying MARG through the router with a note in hookData posts a falsifiable call on any ERC-20 X priced on a canonical Uniswap v4, v3 or v2 venue: side BUY or SELL, target at least 10% away, horizon 1-90 days, text up to 280 chars in the event. Cost: a flat 0.1 IMD stamp (to the pools), a fixed 0.25 IMD spent on MARG through the pool, and an IMD bond the author sizes between 0.25 and 10 IMD by how much IMD they send, held as IMD claims for the horizon; a noted sell bonds the minimum off its IMD output. The router may trade X in the same transaction (class Traded); contract authors are class Agent. A THESIS (target 0, up to 8 KB) bonds the same way and needs a child call of the author within 7 days or forfeits. SEALED NOTES. seal(x, venue, hash) commits to a note before posting: it pays one stamp now (non-refundable), prices the venue's BUY and SELL baselines now and snapshots the author's X balance now; the note is then posted through the router no sooner than 30 minutes and no later than 6 hours after the seal, settles against the sealed baseline, and a sealed BUY call is refused if the author's X balance fell since the seal. Between seal and reveal only the author, X and venue are public. A lapsed seal keeps its stamp in the pools. COUNTERS. A thesis whose parentId is another author's open thesis is a rebuttal and competes in the same judged set; a call whose parentId is another author's open call on the same X from the opposite side is a counter-call. No deposit moves between them; each settles on its own price. PRICES. Posting needs a router-held checkpoint of the venue at least one hour old (checkpointVenue; windows expire after six hours): v3/v2 baselines are accumulator TWAPs since the checkpoint, v4 and ETH/IMD-hub baselines the window extreme adverse to the call. RESOLUTION. Permissionless observe(noteId) in a 6-hour window after the horizon records the venue accumulator or spot, the hub leg and the author's balance (bounded-gas read; a failed read counts as not held); at least 3 observations 20 blocks apart spanning at least one hour; a slot is replaced by a more adverse reading. Settle price: TWAP first-to-last on v3/v2, the observation least favourable to the call on v4 and the hub leg; fewer observations or an unpriceable series is VoidNoData (deposit back, scored as wrong). BUY calls must keep their post balance (else VoidSold); SELL calls settle on price alone. RIGHT returns exactly the bonded IMD; WRONG, VoidSold and retractions forfeit it to the pools at once. The hook never holds MARG claims and sells no pot (the deployed judge's convertForfeits finds potMarg() == 0). settle is permissionless and pays the keeper 10% of a forfeited bond. SCORE. score += difficulty x outcome (+1 right, -1 wrong, broken or unproven, -0.5 retracted), difficulty = log2(multiple) x sqrt(30/horizon) x market-cap tier, on every venue. The score is reputation only: no pool pays for it, so a self-provisioned venue (an author as its only LP and trader) can inflate a number but never draw money; every call keeps its right/wrong/broken tallies and the writer refund. PAYOUTS. Thesis prize: once a week, when the pool holds at least 2 IMD, the judge clone buys the panel's ranking of the week's theses through the IMD Intake 0x1397434cd35e8a9C8aC312A61D3A285EB31dea56 (0.5 IMD, head 3, evidence panel) and the hook pays 50/30/20; an empty eligible head rolls the pool forward. Writer refund: every non-retracted note of a day claims an equal split capped at one stamp. Unclaimed pools sweep forward after 28 days. The treasury drips 2% of its IMD into the pools daily. Build from this repository as it is: audit, adapt only what deployment strictly requires, keep all numbers and rules, deploy. Tests: forge test --no-match-path 'test/fork/*' (179 tests); the fork suite needs MAINNET_RPC_URL.","parentJobId":null,"planHash":"839628b73554feebfaa082ba006ff16a6b7263c2831eb056d220b7ed31cc139b","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"9060a248-29ce-4683-b5d1-54fbc83cd49d","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1283-marginalia-x-com-marginalia-md-notes-mar"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51730","feedbackHash":"fe519acffff52c58e537c066fd0591424a41e8f3256743bcb8c23c0f680ec21f","nodeKey":"adapt_contract_project","submissionHash":"30550e36665b697d8ef4edf5261e2779cc997e6b8a957180ddfb72978df7fe3f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52200","feedbackHash":"6cb004ef97bd0ba6faa9ea1a6e5f8c19a5c334497c8aab9b080531f78898260e","nodeKey":"adapt_contract_project","submissionHash":"f3c85d37898ef0c69cdba6c9a1b260b1c581d99f0185bf9eeed5b08a96004eef","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52173","feedbackHash":"dbada6d5f2834639f2a69e6ffab0cbc5fb04f9da263cf0c525751553c12789b7","nodeKey":"audit_economics","submissionHash":"d4a6e8090f495ee90705027f642b04d95fefa80f0b5b4b9f55adec6b5e122a99","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52145","feedbackHash":"e863b60c6cbd980079c43c0a478552f03c294a2764efe7b65ab64cc0eb81ba23","nodeKey":"audit_flow","submissionHash":"b5d03915ec250e356cd99ba9f08fdf90fb2d419885e57479abc58432fa03be87","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51023","feedbackHash":"6ef7507b24b123b7c61397519f21832be31d9a59d49e0fb126dfa20d9985b624","nodeKey":"audit_imported_code","submissionHash":"40b79676379435101388a79e2e21afe0d7e915364126a9dbb116bb964d9abff2","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52011","feedbackHash":"31b3c7951e27ecbb9c2ecba8850a2b63939c3b7253e6e7c4a6a516a06834440c","nodeKey":"audit_judge","submissionHash":"66b2402ac275390abee80bf2977038ee9028f5b7f22755830943a6ef5a6135fa","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51347","feedbackHash":"c102c09bae4945e23c72c71f95c709fe70d143630504c954c52169b69f849e62","nodeKey":"audit_judge","submissionHash":"137ea4163a7b216f3ccceec8618997a2f75a7a4dc10b707f2220bfe6c91cb151","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52174","feedbackHash":"fa942ed01e3f7bd2742c9934fda5bb8ad9ad8faba7573ead323fb125ac38e7b6","nodeKey":"audit_math","submissionHash":"bbed721b16b38f277ff8f6acb5cd142d1f643f3d62daff8eea35e7d2a5a37b79","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51488","feedbackHash":"7c32924b78c5d0a97f0a4269f9cf03f1218289293b6fb25e62dd1f0d79197d44","nodeKey":"audit_permissions","submissionHash":"e00feb914d29fdfd72ebb90bca0b72112e64397b272e1a9804ac2921e28d0911","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51495","feedbackHash":"cb9da236ba4a52658919aa8b6bb27126cde5c1a89f0a2069ac47c083e42c8f61","nodeKey":"manifest","submissionHash":"d294b0095b9919d7e0fdcd5f9d968d1e2f548ab5686db9f5e61607dfab6b96a6","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51727","feedbackHash":"34146c0f28eaf4eea5823b1bb31a6351d7168515b27461662cc8b100c017b39c","nodeKey":"manifest","submissionHash":"5ffee37d4b50c826eae12edbfd4accdfd0cfc52c9fecedce0eea4fe190faba46","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51536","feedbackHash":"6986378133e1f4cea033604d2afb681098cab6723de0f7f78b21d91a4dbd97d2","nodeKey":"write_foundry_tests","submissionHash":"0a5d14ae71e03fd5bf1dcdd59f842ed95321186b8af8081ddcc55ea4af59e97b","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52206","feedbackHash":"248b70f1a281b482a23da4481dba4be2270f612c5ec0c1cc86ba3b5f2bf394ec","nodeKey":"write_foundry_tests","submissionHash":"d3db90f9129d27ad728f2ad5d3d456bba17375dd56bcdffc2b5371349ff4891c","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"2edab5c20aa402be6eb6b09655984db3c874aa4ab599e76b55822661afb072ed","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"657c4c178d56f7385751e6bf408b5f5c26f4b0f38c245d2ce45224d9cbf305b5","device":"78f562a53c16db4c","findings":[],"hash":"0a5d14ae71e03fd5bf1dcdd59f842ed95321186b8af8081ddcc55ea4af59e97b","nodeId":"5714e926-571a-405a-a438-efd62b19f8b6","outcome":"completed","summary":"Updated accounting invariants and added three regression tests for thesis caps, late children, and judging deadlines. Changes are confined to `test/`.\n\nValidation: `forge build` passed; 249 tests passed, zero failed. The accounting invariant exercised 10,240 calls. Mainnet fork checks skipped because `MAINNET_RPC_URL` was unavailable.","treeHash":"e179ef751c500f274c6a388fe6189bd16e9667b6","usage":{"cachedInputTokens":6145408,"inputTokens":195438,"model":"gpt-6-astra","outputTokens":23675,"runtime":"codex","turns":11,"wallClockMs":945411}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"af9a875696459139","findings":[],"hash":"137ea4163a7b216f3ccceec8618997a2f75a7a4dc10b707f2220bfe6c91cb151","nodeId":"d81387de-e8f7-4979-a40d-e2a2634ee6f2","outcome":"completed","summary":"All checks are done. Summary of this round:\n\n**All six blocking findings are fixed; I report no new defects.** The findings file at the repository root holds an empty findings list and a coverage row for every one of the 33 listed entry points, all `holds`.\n\nHow each earlier finding was settled against the revised hook:\n\n- **Call on IMD unwinnable (high):** `_checkCallVenue` now refuses X equal to IMD or to the venue's quote in both posting and sealing. The author's regression shows the hub baseline still prices at exactly 1 IMD and the note is refused atomically with no stamp or bond taken. Confirmed by reading the router's venue derivation: the quote is always the pool's other token, so no legitimate X can trip the check.\n- **Late thesis child (medium):** the child branch now requires `block.timestamp <= postedAt + THESIS_GRACE`, consistent with settleThesis's strict inequality. My fix-agnostic proof passes; the specialist's original proof fails only because the late child is now refused with InvalidNote.\n- **Observation monopoly (medium):** replacements keep the slot's opening block. I re-ran my round-one scenario in a scratch copy: against 94 dust-sell-and-observe replacements every 19 blocks, the honest observer appended 15 slots and the wrong call settled Wrong with the keeper paid 10%. The new reserved 16th slot also behaves as described: refused before the hour, accepted after.\n- **One wallet fills the week (medium):** a 3-per-author weekly cap, counting rebuttals. This was one of the options I left to the requester. It limits one wallet, not forty, and the README says so. I treat it as settled.\n- **Early judging (medium):** the first draw is gated to week end plus the 7-day grace. Verified at week end plus one second, at the gate minus one second, and at the gate.\n- **Mixed-observation settlement (medium):** v4 observations are priced one at a time through the live pricer, taking the adverse per-observation product. The posting baseline in the immutable router remains a conservative component-wise bound, which is now documented.\n\nThe four advisories are settled as documented limits or corrected text.\n\nVerification on the revised tree: the full non-fork suite passes, 246 tests plus 3 invariant suites, with no failures. The protected hook and token floors pass 11 of 11 against the rebuilt creation code, including the empty-companion constructor rehearsal and factory initialisation at fee 12500. Hook runtime is 23,916 bytes, 660 under the EIP-170 limit. No file in the tree was changed other than the findings file.","treeHash":null,"usage":{"cachedInputTokens":5394404,"inputTokens":964,"model":"claude-fable-5-1","outputTokens":55279,"runtime":"claude","turns":54,"wallClockMs":2626504}},{"artifacts":[],"attempt":2,"bundleHash":"9e73b257bd3d565e4f0bf1c293d9ce52b67da700c6f8843e6e9347df03b75253","device":"1ab5a860db2abcb2","findings":[],"hash":"30550e36665b697d8ef4edf5261e2779cc997e6b8a957180ddfb72978df7fe3f","nodeId":"b37a4aed-d9ff-46ff-9ae3-e0e5be58442f","outcome":"completed","summary":"Fixed all six blocking findings, plus checkpoint aliases and misleading documentation. Recorded all 22 verdicts in `.imd-responses.json` and changes in `ADAPTATION.md`.\n\nValidation passed: build, 205 local tests, 5 mainnet-fork tests, and 11 protected checks.\n\nLive companions and protected configuration remain unchanged. No transaction was broadcast.","treeHash":"798b7243c8d52583d4fcfd37ca62f45c1e859de8","usage":{"cachedInputTokens":7215744,"inputTokens":232113,"model":"gpt-6-astra","outputTokens":43804,"runtime":"codex","turns":9,"wallClockMs":1663033}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ca080fd306399669","findings":[{"citation":"resolved","description":"seal(x, venue, hash) prices baseBuy/baseSell on the caller-supplied `venue` and snapshots the caller's balance of the caller-supplied `x`, but stores none of (msg.sender, x, venue) and `hash` is an opaque commitment the hook cannot open. At reveal, _postNote (lines 449-458) looks up seals[sealHash(author, p)] and, if the seal is 30 min to 6 h old, uses its baseBuy/baseSell as n.postPrice for the venue the note actually carries (p.venue), from whoever sealed it. Consequences: (a) GRIEF/THEFT: anyone watching the mempool for router.note(p, ...) computes sealHash(payer, p with validateVenue-derived venue) (both are public views) and front-runs seal(anyToken, venueB, thatHash) for one stamp (0.1 IMD). The victim's transaction reverts TooEarly (line 451) for 30 minutes; the identical note re-sent between 30 min and 6 h later is posted with venue B's baseline. With venue B a hookless v4 pool the attacker provisioned at 1e6 IMD per unit (checkpointed an hour earlier), a BUY call on MARG priced at 1 IMD is settled WRONG whatever MARG does and the bond (0.25-10 IMD) is forfeited to the pools with 10% to the settler, who can be the attacker. The same front-run also sets s.balance from the attacker's balance of an arbitrary token, so the sealed-BUY hold check (line 455) is meaningless. (b) SELF-DEALING: an author seals a MARG note with venue B's baseline and reveals it on the MARG pool: a SELL -10% call with postPrice 1e6 IMD is RIGHT whatever happens, booking full difficulty (log2 of a 1e6 multiple, tier 3 via the inflated mcap) on the reputation score the product exists to produce; the author's own balance check is bypassed by naming an x they hold none of. The spec (SPEC.md line 57) says the seal prices 'the venue's' baselines and snapshots 'the author's X balance'; the code enforces neither. Fix: store sealer, x and venue (kind, ref, quote, xIsToken0) in Seal and at reveal treat a seal whose sealer != author or whose x/venue differ from the note as absent (so a stranger's seal cannot block or price a note), or revert the reveal; also bind them into the hash.","line":757,"path":"src/MarginaliaHook.sol","reproduction":"State: launch pool MARG/IMD at 1 MARG = 1 IMD with a mature router checkpoint; a hookless v4 pool Y/IMD at 1 Y = 1e6 IMD, also checkpointed an hour earlier. (a) attacker: hook.seal(Y, venueB, hook.sealHash(author, p)) where p = BUY MARG +10% 7d (venue derived by router.validateVenue(p, keyA)). author: router.note(p, keyA, 1 ether, 1, deadline) within 30 min -> reverts TooEarly; 31 min later the same call succeeds and hook.noteOf(id).postPrice == 1e24 instead of router.postPrice(venueA, true) == 1e18 (the proof shows exactly '1000000000000000000000000 != 1000000000000000000'). After the horizon, MARG unchanged or up 20%: settle -> Wrong, bond forfeited, 10% to msg.sender. (b) author: hook.seal(MARG, venueB, sealHash(author, pSell)) with pSell = SELL MARG -10%; 31 min later router.note(pSell, keyA, ...) -> postPrice 1e24; at settlement 1e18*10000 <= 1e24*9000 -> Right. Expected in both cases: the note is priced on its own venue (postPrice 1e18) or refused.","severity":"high","snippet":"        seals[hash] = Seal(uint64(block.timestamp), baseBuy, baseSell, _balanceOf(x, msg.sender));","title":"seal() binds neither the sealer, X nor the venue to the hash: a stranger pins a victim's baseline to another venue (bond forfeited), an author self-selects any baseline"},{"citation":"resolved","description":"_difficulty is called on every settle outcome (Right, Wrong, VoidSold, VoidNoData; lines 611-622) and in retract (line 638). It calls IERC20(n.x).totalSupply() with the full remaining gas and no try/catch, and then FullMath.mulDiv(postPrice, totalSupply, 1e18), which reverts when postPrice * totalSupply >= 2^256. X is any contract with code chosen by the author (line 419), so X's totalSupply() may revert (pausable or upgradeable token, a token the author controls, a view that burns all gas) or return a value whose product with postPrice overflows (e.g. totalSupply 2^200 at postPrice 1e18). When it does, settle(id) reverts for everyone and forever: the note stays Open, the IMD bond stays as hook claims (claimDeposit needs Right/VoidNoData/ThesisClosed), the keeper never earns the 10% bounty, the pools never receive the forfeit, the author's right/wrong tallies and a parent thesis's release (_resolveChild) never happen. An author posting calls on their own token can brick totalSupply only for calls the observations show WRONG, and let RIGHT ones settle: the reputation score only ever goes up, at the price of a 0.25 IMD bond per suppressed loss. The brief's rule for X reads is that a failed read counts against the call (balance: bounded staticcall, sentinel = not held) and SPEC.md line 276 says 'unreadable = 1' for the mcap tier; the supply read follows neither. Fix: read totalSupply by bounded-gas staticcall like _balanceOf, treat failure as tier 1, and compute mcap with an overflow-safe path (e.g. cap totalSupply or use a non-reverting mulDiv).","line":698,"path":"src/MarginaliaHook.sol","reproduction":"State: hookless v4 pool X/IMD at 1:1, checkpointed; X is an ERC-20 whose totalSupply() reverts once its deployer flips a flag (balanceOf unaffected). author: router.note(BUY X +10% 1d, keyX, 1 ether, 1, deadline). Warp to horizonEnd(id); observe(id) three times 25 blocks and 1 h apart; warp past horizonEnd + 6 h. X.setBrick(true). Anyone: hook.settle(id) -> reverts 'supply unavailable' (proof: both tests fail with that reason); hook.retract(id, ..) by the author reverts the same way. Expected: settle records Wrong (price unchanged), forfeits the bond with the keeper bounty, or at worst books tier 1; retract succeeds. Same effect with totalSupply() returning 2^200 (mulDiv overflow).","severity":"medium","snippet":"        uint256 mcap = FullMath.mulDiv(n.postPrice, IERC20(n.x).totalSupply(), 1e18);","title":"settle()/retract() make an unbounded, unguarded totalSupply() call on the arbitrary note token: a reverting or huge-supply X strands the bond forever and lets an author suppress WRONG outcomes"},{"citation":"resolved","description":"onOracleResult verifies the signature, chainId, quorum and panel size, and keys replay on requestId, but ignores a.questionHash. questionBody(week) is deterministic and pins the allow-list of eligible thesis ids, yet nothing checks that the attestation answers that question. The consumer therefore relies entirely on the Intake routing the right answer to the right requestId: any attestation the oracle signer produced for this consumer (another week's question, a mistakenly routed or re-used panel result) is accepted and marks the week judged. The supplied oracle-consumer reference documents questionHash as the field a consumer that pins its question compares. Since judgedOf later filters to the week's eligible theses, a wrong-question answer most often yields an empty head and rolls the pool forward, but it still consumes the one ranking the week gets (judgedSet[week] = true, no retry) so the week's theses are never judged.","line":243,"path":"src/MarginaliaJudge.sol","reproduction":"State: requestJudging(w) made, pendingDay[reqId] set. vm.prank(INTAKE); judge.onOracleResult(reqId, a, sig) with a valid signature over an attestation whose questionHash = keccak256('unrelated') and whose answer ranks ids from another week. Actual: accepted, judgedSet[w] = true, judgedOf(w) empty -> payJudged rolls w's pool forward and the week can never be re-requested. Expected: revert BadAnswer unless a.questionHash == keccak256(bytes(questionBody(w))).","severity":"low","snippet":"            a.chainId != block.chainid || a.agreed < a.quorum || a.quorum < QUORUM || a.panelSize < PANEL_SIZE","title":"Judge accepts a signed answer to any question: a.questionHash is never compared with keccak256(questionBody(week))"},{"citation":"resolved","description":"claimRefund refuses a retracted note (line 809) but notesPerDay[n.day] still counts it (incremented at post, decremented only on a successful claim). Every honest claimant of that day therefore receives pool / (honest + retracted) instead of pool / honest, and the retracted notes' shares sit in refundPool until sweep() moves them to a later thesis pool 28 days on. SPEC.md line 90: 'every non-retracted note of that day may claim an equal split of the day's refund pool, capped at one stamp'. Fix: decrement notesPerDay[n.day] in retract (status Retracted is final), or count retractions separately.","line":811,"path":"src/MarginaliaHook.sol","reproduction":"Day d: alice posts note 1 and bob posts note 2 (refundPool[d] = 2 * 0.03 = 0.06 IMD from the stamps' 30%); bob retracts note 2 the same day (forfeit 0.25 IMD -> +0.075 to refundPool[d], total 0.135). Day d+1: alice.claimRefund(1) pays 0.135 / 2 = 0.0675 IMD. Expected under the spec: min(0.135 / 1, STAMP) = 0.1 IMD; 0.0675 remains unclaimable until sweep.","severity":"low","snippet":"        uint256 amount = refundPool[n.day] / count;","title":"Writer refund divides the day's pool by all notes including retracted ones, which can never claim; the spec's equal split among non-retracted notes is under-paid"},{"citation":"resolved","description":"seal() refuses any hash with seals[hash].at != 0. _postNote deletes the seal only on a timely reveal (line 458); when the seal has lapsed (age > SEAL_MAX) the note is posted as an ordinary one and the Seal struct stays forever. The author can never seal that exact note (same x, venue, side, target, horizon, parentId, text) again, and anyone who front-ran a hash (finding 1) blocks it permanently for one stamp. Fix: allow re-sealing when the stored seal is older than SEAL_MAX (overwrite), or delete it on the lapsed-reveal path.","line":752,"path":"src/MarginaliaHook.sol","reproduction":"author: hook.seal(x, venue, h) at t0 (stamp paid). Nothing posted. At t0 + 7 h: hook.seal(x, venue, h) -> reverts InvalidNote although the seal lapsed an hour ago. Expected: a fresh seal replaces the lapsed one.","severity":"low","snippet":"        if (seals[hash].at != 0 || x == address(0) || hash == bytes32(0)) revert InvalidNote();","title":"A lapsed seal is never cleared, so the same note can never be sealed again and a lapsed seal stays readable as a live commitment"},{"citation":"resolved","description":"The manifest rules require addresses in lowercase and pool.initialPrice as a decimal sqrtPriceX96 string. The committed manifest writes the IMD address in checksum case and has no initialPrice; the fork rehearsal derives the opening price from the policy cap instead. The later manifest step rewrites this file, so this is for the adapter: hook constructorArgs, permissions (0x20cc), token fields, fee 12500 and tickSpacing 60 otherwise match the code.","line":25,"path":"launch.json","reproduction":"Validate launch.json against the schema: pool.pairedCurrency '0xD34a99Bc...' is not lowercase; pool.initialPrice is absent. Expected: '0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7' and an initialPrice string.","severity":"low","snippet":"    \"pairedCurrency\": \"0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7\",","title":"launch.json as committed: pairedCurrency is mixed-case and pool.initialPrice is missing"},{"citation":"resolved","description":"forge test --no-match-path 'test/fork/*' on the tree as delivered: 177 passed, 1 failed (178 total). testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried asserts that a 120-id oracle answer does NOT fit a 200k-gas callback; on this forge/solc 0.8.26 via-IR build it does fit, so the assertion fails. Not a contract defect (the judge stores only the head of three either way), but the suite is not green as the brief states and the assertion encodes a toolchain-dependent measurement rather than a property.","line":114,"path":"test/AuditFindings.t.sol","reproduction":"forge test --no-match-path 'test/fork/*' -> '[FAIL: a full ranking does not fit the stipend] testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried() (gas: 2197717)'. Expected per README/brief: 179 passing.","severity":"info","snippet":"        assertFalse(ok, \"a full ranking does not fit the stipend\");","title":"Local suite: 178 tests (brief says 179), one fails on this toolchain because it asserts a gas limit that no longer binds"},{"citation":"resolved","description":"The launch reference lists DELEGATECALL, proxies and initialisers as forbidden; the brief explicitly requires the hook to clone the three live implementations and init() each once in the constructor, and the brief wins. Recorded so the adapter and the panel do not re-open it: the clones' 45-byte runtime delegatecalls fixed, codeless-safe implementations; init() is callable only by msg.sender == hook_ and only while hook == address(0) (implementations lock hook = address(1) in their constructors, verified against the live bytecode); the hook runtime contains no DELEGATECALL/CALLCODE/SELFDESTRUCT (Clones.clone runs only in the constructor). Verified against mainnet: Router, Treasury and Pricer runtime bytecode at the pinned addresses are byte-identical to this tree's compile; Judge differs only in its EIP-712 immutables. The constructor passes the empty-EVM rehearsal: a clone of a codeless implementation accepts init() silently (delegatecall to no code returns success).","line":217,"path":"src/MarginaliaHook.sol","reproduction":"cast code 0x365CcB3c..., 0xe2086012..., 0xEaff9B26... == out/*.json deployedBytecode.object; cast code 0xC9346073... differs from out/MarginaliaJudge.sol only inside immutableReferences. hook.router().init(manager, x) -> AlreadyInitialised.","severity":"info","snippet":"        MarginaliaTreasury t = MarginaliaTreasury(payable(Clones.clone(MarginaliaImpls.TREASURY_IMPL)));","title":"Companions are EIP-1167 proxies with post-deployment initialisers (DELEGATECALL in their runtime), as the brief mandates; the hook's own runtime has none"},{"citation":"resolved","description":"The brief fixes tick spacing 60 and the pair IMD 0xD34a...; the hook accepts any spacing and any paired contract with code. The factory supplies both from the manifest, so this is only a missing belt: a manifest typo (another tickSpacing or pair) would launch and bind the hook to it permanently. The pricer's HUB_POOL_ID and WETH constants assume mainnet IMD; the judge's Intake address does too.","line":248,"path":"src/MarginaliaHook.sol","reproduction":"vm.prank(factory); manager.initialize(PoolKey(MARG, anyERC20WithCode, 12500, 10, hook), price) -> succeeds and binds the pool. Expected by the brief: spacing 60 with IMD.","severity":"info","snippet":"        if (sender != factory || initialized || key.fee != LP_FEE || address(key.hooks) != address(this)) {","title":"beforeInitialize pins factory, fee and hook but not tickSpacing 60 or the IMD address; any ERC-20 the factory pairs is bound"},{"citation":"resolved","description":"_dataKind decodes every non-empty hookData as a uint8 and reverts unless it is DATA_NOTE from the router or DATA_EXEMPT from the hook (never sent now: the hook no longer swaps, so lines 279 and 346 are dead code). A router or aggregator that forwards arbitrary hookData (even 1 byte) cannot trade MARG; exact-output sells are also refused. Documented behaviour, listed so the README states it for integrators.","line":277,"path":"src/MarginaliaHook.sol","reproduction":"Any router: manager.swap(key, SwapParams(..., -1 ether, limit), hex\"01\") -> abi.decode of 1 byte reverts; with 32 bytes of 0x05 -> BadHookData. Expected (documented): only empty hookData trades.","severity":"info","snippet":"        kind = abi.decode(data, (uint8));","title":"Any non-empty hookData from a third-party router reverts the swap (BadHookData); only empty hookData trades quietly"},{"citation":"resolved","description":"Read in full: src/MarginaliaHook.sol, MarginaliaRouter.sol, MarginaliaJudge.sol, MarginaliaTreasury.sol, MarginaliaPricer.sol, MarginaliaTypes.sol, MarginaliaImpls.sol, Marginalia.sol, HookFlags.sol, OracleAttestation.sol, interfaces/IIntake.sol and ILaunchFactory.sol; test/helpers/Fixture.sol, test/fork/MainnetLaunch.t.sol, the protected hook/token floors, launch.json, ADAPTATION.md and the relevant SPEC.md sections. Every external/public state-changing function of the hook, router, judge and treasury was walked for caller, funds moved and trust. Verified over a public mainnet RPC (block 26167090): the four pinned implementations have code; Router/Treasury/Pricer runtime is byte-identical to this tree's compile and the Judge differs only in EIP-712 immutables, so the local suite (which etches this tree's code at those addresses) exercises the live companions; companion sources are unchanged since the pin commit 10fa150 (only Hook and Types changed). IMD at 0xD34a... is a live 18-decimal token with symbol IMD. The fork suite test/fork/MainnetLaunch.t.sol was run over the same public RPC: 5 passed (launch through the real LaunchFactory 0x12C6... with the live companions, 7.63M gas; notes on the hub, v3 LINK/WETH and v2 UNI/WETH venues; a v3 TWAP settlement). Not reached: the Intake's and IMD's internals (bytecode only, no verified source consulted), the oracle signer, and the behaviour of the live companions under the sealed-note and counter paths beyond what the local suite etches (identical bytecode, so equivalent). Delta accounting of beforeSwap/afterSwap was checked by hand against v4-core Hooks.afterSwap: noted buys take STAMP+bond off the specified IMD and swap exactly MARG_BUY; noted sells take 1%+stamp+BOND_MIN and quiet sells 3% off the IMD output; each is minted as claims, so hook deltas net to zero and no fee is ever taken from the manager's balance during a swap.","line":10,"path":"src/MarginaliaImpls.sol","reproduction":"Coverage statement; no defect.","severity":"info","snippet":"    address internal constant ROUTER_IMPL = 0x365CcB3cfBC430600485234F56FD5ECb23fd70D1;","title":"Coverage: what was read, what was verified against mainnet, what could not be reached"}],"hash":"40b79676379435101388a79e2e21afe0d7e915364126a9dbb116bb964d9abff2","nodeId":"e47fbd83-01c6-4002-8d16-b0c9935c3063","outcome":"completed","summary":"The tree is clean apart from the findings file and my scratch directory, both excluded by the repository's own git exclude list. The review is complete.\n\n## Review of Marginalia (MARG) as delivered\n\n**Findings file:** `.imd-findings.json` holds 11 findings, 2 with Foundry proofs that fail on the current tree. All snippets were verified against their lines.\n\n**High: `seal()` binds neither sealer, X nor venue to the hash** (`src/MarginaliaHook.sol:757`). The seal prices baselines on whatever venue the caller names, and the reveal applies them to whatever venue the note carries, from whoever sealed. A stranger can front-run a pending `router.note` with a one-stamp seal priced on a pool they provisioned at 1e6 IMD: the victim's note is refused for 30 minutes, and the identical note re-sent inside 6 hours is posted at that baseline, settles WRONG, and forfeits the bond with 10% to the settler. An author can likewise seal on one venue and reveal on another for a guaranteed RIGHT at full difficulty. Proof shows postPrice 1e24 where the venue's own baseline is 1e18.\n\n**Medium: unguarded `totalSupply()` at settlement** (`src/MarginaliaHook.sol:698`). `_difficulty` reads the note token's supply with full gas and no try/catch, then multiplies it. A reverting or overflow-sized supply makes `settle` and `retract` revert forever: bond stranded, no keeper bounty, no forfeit to the pools, and an author controlling X can suppress every WRONG outcome. The spec itself says \"unreadable = 1\" for the tier. Proof fails with \"supply unavailable\" on both paths.\n\n**Low:** the judge never compares `questionHash` with its own question body; the writer refund divides by all notes including retracted ones, under-paying honest writers; a lapsed seal is never cleared so the same note can never be re-sealed; `launch.json` has a mixed-case pair address and no `initialPrice`.\n\n**Info:** the local suite is 178 tests with 1 failing on this toolchain (a gas-bound assertion that no longer binds); the companions are EIP-1167 proxies with initialisers as the brief mandates; `beforeInitialize` does not pin tick spacing or the IMD address; any non-empty third-party hookData reverts.\n\n**Coverage.** Every `src` contract, both interfaces, the fixture, fork test, protected floors and manifest were read. Over a public mainnet RPC I confirmed the four pinned implementations have code, that Router, Treasury and Pricer runtime bytecode is byte-identical to this tree's compile and the Judge differs only in EIP-712 immutables, and that companion sources are unchanged since the pin commit. The fork suite ran against the live LaunchFactory and companions: 5 passed. Not reached: the Intake's and IMD's internals beyond bytecode, and the oracle signer.","treeHash":null,"usage":{"cachedInputTokens":3303735,"inputTokens":548,"model":"claude-fable-5-1","outputTokens":58644,"runtime":"claude","turns":43,"wallClockMs":1404535}},{"artifacts":[],"attempt":1,"bundleHash":"d18ba42cabdf85ed16a120af59c72dad1d43e00baf5328963d58911932b7c3ce","device":"6e1819675bb7567a","findings":[],"hash":"5ffee37d4b50c826eae12edbfd4accdfd0cfc52c9fecedce0eea4fe190faba46","nodeId":"18a490e9-f355-4087-b272-2a9616ead464","outcome":"completed","summary":"Updated only [launch.json](/root/nft4/.identitymd/work/9060a248-29ce-4683-b5d1-54fbc83cd49d/18a490e9-f355-4087-b272-2a9616ead464/launch.json), aligning its notes with the accepted implementation.\n\nValidated fields, constructor ABI, permissions, pool values, and the 3,811-character notes limit.\n\n`forge build` passed. `forge test`: **204 passed, 0 failed**; fork suite skipped because `MAINNET_RPC_URL` is unavailable.","treeHash":"2cf2d7c24c542cdc8557d826032ee34d8fe643b5","usage":{"cachedInputTokens":905600,"inputTokens":170196,"model":"gpt-6-astra","outputTokens":6476,"runtime":"codex","turns":5,"wallClockMs":352471}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a406deaac63a93b0","findings":[{"citation":"resolved","description":"_postNote accepts any ERC-20 with code as X, including IMD, the asset every price is denominated in. For X == IMD the only canonical venue is the hookless ETH/IMD hub pool (native token0, IMD token1), which MarginaliaRouter.validateVenue admits (quote = address(0)). The baseline (MarginaliaPricer.postPrice, line 152) and the settlement (settlePrice, line 198) both compute x * q / 1e18 where x = _spotInQuote = fromSqrt(hubSqrtP, xIsToken0 = false) = ETH per IMD and q = _quoteSpot(address(0)) = fromSqrt(hubSqrtP, true) = IMD per ETH, both from the same hub slot0. The product is 1e18 (minus 1 wei of rounding) whatever IMD does against ETH, so settle() at MarginaliaHook.sol:600 compares 1e18 * 10_000 with 1e18 * targetBps (>= 1.1e22 for a BUY, and a SELL fails the mirror test), books Wrong and _forfeit() sends the author's 0.25 to 10 IMD bond to the pools with 10% to the keeper. The project advertises exactly this note (test/fork/MainnetLaunch.t.sol:343 testNoteAboutImdOnTheHubPool, SPEC row 0b), so authors are invited into a bond they cannot keep. Merged from audit_math (52ef1863). The pricer and router are live and cannot change; the hook can refuse p.x == imd (and any X equal to its venue's quote) in _postNote, or price such a note on a real leg. Reproduced locally with test/scratch/NoteOnImdUnwinnable.t.sol: postPrice = 999999999999999999, status after a ~60% rise = Wrong (2).","line":422,"path":"src/MarginaliaHook.sol","reproduction":"Local PoolManager, vm.chainId(1), an 18-decimal ERC-20 etched at 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7, the hookless ETH/IMD pool (fee 10000, spacing 200) whose id equals MarginaliaPricer.HUB_POOL_ID at 1 ETH = 2000 IMD with 1e24 liquidity, the MARG/IMD launch pool bound to the hook. (1) router.checkpointVenue({x: IMD, venue: {UniV4, HUB_POOL_ID}}, hubKey); wait 1 h / 300 blocks. (2) alice: router.note(side Buy, targetBps 11000, horizonDays 1, imdIn 1 ether) -> accepted, noteOf(id).postPrice == 999999999999999999, deposit 0.65 IMD. (3) swap 6000 ETH into the hub for IMD: IMD per ETH falls from 2000e18 to below 1800e18 (IMD rose > 10% against ETH). (4) at horizonEnd observe() three times 155 blocks and 31 minutes apart; settle() after end + 6 h + 1. Expected: Right (deposit 0.65 claimable) or the post refused. Actual: status Wrong (2), 0.65 IMD forfeited to the pools. Any target and any hub move give the same result; a SELL call on IMD is equally unwinnable.","severity":"high","snippet":"            if (p.x == address(0) || p.x.code.length == 0) revert InvalidNote();","title":"A call on IMD itself priced through the ETH/IMD hub settles at the identity product (ETH per IMD) x (IMD per ETH) = 1e18 and can never be RIGHT; its bond is always forfeited"},{"citation":"resolved","description":"The child branch of _postNote checks only that the parent thesis is ThesisOpen; it never checks block.timestamp <= parent.postedAt + THESIS_GRACE. settleThesis (line 652) refuses to forfeit once children > 0. So an author whose thesis sat childless for 8, 30 or 300 days posts a child at any moment before (or by front-running) a keeper's settleThesis: children becomes 1, settleThesis reverts NotOpen forever, the child is retracted or voids with no observations, _resolveChild sets the thesis ThesisClosed and claimDeposit returns the thesis bond (up to 10 IMD) in full. The pools lose the forfeit and the keeper the 10% bounty; the thesis also becomes judge-eligible (hasChild) late. The only keeper incentive is 10% of a bond as small as 0.25 IMD, so in practice no one races. Merged from audit_economics (9cfba9ec), audit_permissions (dcf654e0, proof) and write_foundry_tests (7d5ab0f7): one root cause. Fix: in the child branch also require block.timestamp <= uint256(parent.postedAt) + THESIS_GRACE.","line":475,"path":"src/MarginaliaHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {Marginalia} from \"src/Marginalia.sol\";\nimport {MarginaliaHook} from \"src/MarginaliaHook.sol\";\nimport {MarginaliaRouter} from \"src/MarginaliaRouter.sol\";\nimport {MarginaliaJudge} from \"src/MarginaliaJudge.sol\";\nimport {MarginaliaTreasury} from \"src/MarginaliaTreasury.sol\";\nimport {MarginaliaPricer} from \"src/MarginaliaPricer.sol\";\nimport {MarginaliaImpls} from \"src/MarginaliaImpls.sol\";\nimport {HookFlags} from \"src/HookFlags.sol\";\nimport {MarginaliaTypes as T} from \"src/MarginaliaTypes.sol\";\n\ncontract ScratchToken is ERC20 {\n    constructor(string memory n, string memory s, uint256 supply) ERC20(n, s) {\n        _mint(msg.sender, supply);\n    }\n}\n\ncontract ScratchLiquidity is IUnlockCallback {\n    IPoolManager public immutable manager;\n\n    constructor(IPoolManager m) {\n        manager = m;\n    }\n\n    function add(PoolKey memory key, int24 lower, int24 upper, int256 amount) external {\n        manager.unlock(abi.encode(key, ModifyLiquidityParams(lower, upper, amount, bytes32(0))));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager));\n        (PoolKey memory key, ModifyLiquidityParams memory p) = abi.decode(data, (PoolKey, ModifyLiquidityParams));\n        (BalanceDelta delta,) = manager.modifyLiquidity(key, p, \"\");\n        _settle(key.currency0, delta.amount0());\n        _settle(key.currency1, delta.amount1());\n        return \"\";\n    }\n\n    function _settle(Currency c, int128 d) private {\n        if (d < 0) {\n            manager.sync(c);\n            IERC20(Currency.unwrap(c)).transfer(address(manager), uint256(-int256(d)));\n            require(manager.settle() == uint256(-int256(d)));\n        } else if (d > 0) {\n            manager.take(c, address(this), uint256(uint128(d)));\n        }\n    }\n}\n\n/// @notice A thesis must have a child call within THESIS_GRACE (7 days) or forfeit its bond. The hook only\n/// checks `children == 0` inside settleThesis and accepts a child at any time while the thesis is ThesisOpen,\n/// so the author posts the child on day 8+ (front-running or simply preceding any settleThesis call), the\n/// forfeit is blocked, and the child's retraction releases the thesis bond.\ncontract LateThesisChildTest is Test {\n    using PoolIdLibrary for PoolKey;\n\n    IPoolManager manager;\n    Marginalia token;\n    ScratchToken imd;\n    MarginaliaHook hook;\n    MarginaliaRouter router;\n    PoolKey key;\n    address alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.roll(20_000_000);\n        manager = IPoolManager(address(new PoolManager(address(this))));\n        token = new Marginalia();\n        imd = new ScratchToken(\"IMD\", \"IMD\", 1_000_000_000 ether);\n        vm.etch(MarginaliaImpls.ROUTER_IMPL, address(new MarginaliaRouter()).code);\n        vm.etch(MarginaliaImpls.JUDGE_IMPL, address(new MarginaliaJudge()).code);\n        vm.etch(MarginaliaImpls.TREASURY_IMPL, address(new MarginaliaTreasury()).code);\n        vm.etch(MarginaliaImpls.PRICER, address(new MarginaliaPricer()).code);\n        bytes memory code = abi.encodePacked(type(MarginaliaHook).creationCode, abi.encode(manager, token, address(this)));\n        bytes32 h = keccak256(code);\n        for (uint256 i = 0; i < 300_000; ++i) {\n            address predicted = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(i), h)))));\n            if (!HookFlags.matches(predicted, HookFlags.MARGINALIA)) continue;\n            bytes32 salt = bytes32(i);\n            address deployed;\n            assembly (\"memory-safe\") {\n                deployed := create2(0, add(code, 32), mload(code), salt)\n            }\n            hook = MarginaliaHook(deployed);\n            break;\n        }\n        require(address(hook) != address(0), \"mining\");\n        router = hook.router();\n        (address c0, address c1) = address(token) < address(imd) ? (address(token), address(imd)) : (address(imd), address(token));\n        key = PoolKey(Currency.wrap(c0), Currency.wrap(c1), 12500, 60, IHooks(address(hook)));\n        manager.initialize(key, uint160(1 << 96));\n        ScratchLiquidity lp = new ScratchLiquidity(manager);\n        token.transfer(address(lp), 50_000_000 ether);\n        imd.transfer(address(lp), 50_000_000 ether);\n        lp.add(key, -6000, 6000, 10_000_000 ether);\n        imd.transfer(alice, 1_000 ether);\n        vm.prank(alice);\n        imd.approve(address(router), type(uint256).max);\n    }\n\n    function _p(T.Side side, uint32 target, uint16 horizon, string memory text) internal view returns (T.NoteParams memory p) {\n        p.x = address(token);\n        p.venue = T.Venue(T.VenueKind.UniV4, PoolId.unwrap(key.toId()), address(0), false);\n        p.side = side;\n        p.targetBps = target;\n        p.horizonDays = horizon;\n        p.class = uint8(T.Class.Declared);\n        p.text = text;\n    }\n\n    function testAChildPostedAfterTheGraceStillRescuesTheThesisBond() public {\n        // Day 0: a thesis with a 2 IMD bond (2.35 sent: 0.1 stamp, 0.25 MARG buy, 2 bond).\n        vm.prank(alice);\n        router.note(_p(T.Side.Buy, 0, 0, \"thesis\"), key, 2.35 ether, 1, vm.getBlockTimestamp() + 1);\n        bytes32 tid = bytes32(hook.noteCount());\n        assertEq(hook.noteOf(tid).deposit, 2 ether);\n\n        // Day 8: no child was posted inside THESIS_GRACE. The spec says the thesis forfeits now.\n        vm.warp(vm.getBlockTimestamp() + hook.THESIS_GRACE() + 1 days);\n        vm.roll(vm.getBlockNumber() + 50_000);\n\n        // The author posts the child anyway (a fresh checkpoint is all a priced post needs).\n        router.checkpointVenue(_p(T.Side.Buy, 11_000, 1, \"cp\"), key);\n        vm.warp(vm.getBlockTimestamp() + 1 hours);\n        vm.roll(vm.getBlockNumber() + 300);\n        T.NoteParams memory child = _p(T.Side.Buy, 11_000, 1, \"late child\");\n        child.parentId = tid;\n        vm.prank(alice);\n        // A fixed hook either refuses the late child here, or accepts it and still lets the thesis forfeit.\n        try router.note(child, key, 0.6 ether, 1, vm.getBlockTimestamp() + 1) {} catch {}\n\n        // Expected: a thesis with no child inside the grace forfeits. Actual: the late child blocks the forfeit\n        // (settleThesis reverts NotOpen) and the author later releases the bond through the child.\n        hook.settleThesis(tid);\n        assertEq(uint8(hook.noteOf(tid).status), uint8(T.Status.ThesisForfeited), \"thesis should have forfeited\");\n        assertEq(hook.noteOf(tid).deposit, 0, \"the thesis bond must have gone to the pools\");\n    }\n}","reproduction":"Fixture at 1 MARG = 1 IMD. Day 0: alice router.note({targetBps: 0, text: 'thesis'}, key, 2.35 ether, 1, deadline) -> thesis tid with deposit 2 IMD, status ThesisOpen. Warp +8 days (THESIS_GRACE + 1 day), nobody has called settleThesis. router.checkpointVenue(...); warp +1 h, roll +300. alice router.note({side Buy, targetBps 11000, horizonDays 1, parentId: tid}, key, 0.6 ether, ...) -> succeeds, noteOf(tid).children == 1. hook.settleThesis(tid) -> reverts NotOpen (expected: ThesisForfeited, 1.8 IMD to the pools, 0.2 IMD to the keeper). alice then hook.retract(child, '') and hook.claimDeposit(tid) -> receives the 2 IMD bond. The attached proof (the permissions specialist's, made fix-agnostic: the late child is posted inside try/catch so the test passes whether the fix refuses the child or lets settleThesis forfeit anyway) fails on this tree with NotOpen().","severity":"medium","snippet":"                    if (parent.status != T.Status.ThesisOpen) revert InvalidNote();","title":"A thesis accepts its first child call after the 7-day grace, so the 'child within 7 days or forfeit' rule holds only if a keeper calls settleThesis first"},{"citation":"resolved","description":"A reading inside OBS_GAP_BLOCKS of the last slot may replace that slot when it is more adverse, and the replacement is stored with the current block number, so the gap that gates a push is measured from the latest replacement rather than the latest push. On a v4 venue (or any ETH-quoted venue through the hub leg) a strictly more adverse reading costs one dust swap (a 1e9 wei MARG sell lowers sqrtPrice by at least one unit). Whoever lands dust-swap + observe every <= 19 blocks keeps the series at one entry for the whole 6-hour window: every honest observe() reverts ObservationTooSoon because block.number < lastReplacement + 20 and an honest reading is not more adverse. settle() then sees count < OBS_MIN and books VoidNoData, which returns the bond and pays no keeper. The author of a call going WRONG (or an accomplice) escapes forfeiture of up to 10 IMD for about 95 cheap transactions; the pools lose the forfeit the brief promises. Reported by audit_flow (452f572d); reproduced with test/scratch/ObsMonopoly.t.sol (status 4 = VoidNoData, deposit 9.65 IMD still held; carol never adds a second slot). Fix (hook only): measure the push gap from the block of the last push (keep obs[len-1].blockNumber on replace, or store a separate lastPushBlock) so an honest observer can always append after 20 blocks while adverse overwrites still work.","line":526,"path":"src/MarginaliaHook.sol","reproduction":"Fixture (1 MARG = 1 IMD, 1e25 liquidity). alice router.note(BUY +50%, 1 day, on MARG / launch pool, 10 IMD in) -> bond 9.65 IMD; the market stays flat so the call is WRONG. At horizonEnd: hook.observe(id) (1 slot). Then 95 times: roll +19 blocks, warp +228 s; carol hook.observe(id) -> reverts ObservationTooSoon; bob sells 1e9 wei MARG on the pool and calls hook.observe(id) -> replaces slot 0 with blockNumber = now. Warp to end + 6 h + 1; hook.settle(id). Expected: status Wrong, deposit 0 (forfeited, keeper paid 10%). Actual: status VoidNoData (4), deposit 9.65 IMD claimable by alice through claimDeposit.","severity":"medium","snippet":"        if (len > 0 && (len >= OBS_MAX || block.number < obs[len - 1].blockNumber + OBS_GAP_BLOCKS)) {\n            if (!_moreAdverse(n, o, obs[len - 1])) revert ObservationTooSoon();\n            obs[len - 1] = o;","title":"A sub-gap slot replacement restarts the 20-block gap, so one party can hold a series at a single slot for the whole window and turn a WRONG call into VoidNoData (bond returned)"},{"citation":"resolved","description":"Posting a thesis is permissionless and the only limit is a global per-week cap MAX_WEEK_THESES = 120, consumed in posting order with no per-author limit and no rising cost. The week's thesis prize (70% of every stamp, fee, forfeit and drip of the week, paid 50/30/20 by payJudged) is ranked by the panel only among judge.eligibleTheses(week), i.e. among the theses that got into weekTheses. One wallet posting 120 theses early in the week (0.6 IMD each at the minimum: 0.1 stamp sunk, 0.25 spent on MARG it keeps, 0.25 bond returned once a child resolves) makes every later thesis of every other author revert InvalidNote for the rest of the week; with one child call per thesis the panel can only rank that wallet's entries, so the pool funded by everyone else is paid to it or rolls forward. Net cash cost on the order of 24 IMD of stamps (16.8 of which land in the pool the attacker alone competes for) plus LP fees and gas; the repository's own testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment (test/RevisionFindings.t.sol:216) shows bob taking all 120 slots and alice refused. Merged from audit_economics (1c5d24c6) and audit_permissions (9310a91b). MAX_JUDGED is fixed in the deployed judge, so the fix is hook-side: a per-author (or per-author-per-day) cap on the week's eligible theses, or a rising per-slot thesis price, as the requester chooses.","line":446,"path":"src/MarginaliaHook.sol","reproduction":"Week W. bob calls router.note(p, key, 0.6 ether, 1, deadline) 120 times with p.targetBps = 0 and distinct text; hook.thesesOfWeek(W).length == 120. alice router.note({targetBps: 0, text: 'a real thesis'}, key, 10 ether, 1, deadline) -> reverts InvalidNote at line 446 (wrapped by the PoolManager). bob posts one child call per thesis (parentId = thesis id, targetBps 11000, horizonDays 1); judge.eligibleTheses(W) lists only bob's ids. After the week, judge.requestJudging(W) puts only bob's ids in the allow list, and judge.payJudged(W) pays 50/30/20 of thesisPool[W] to bob. Expected: other authors can enter the week's judged set; actual: locked out for a flat cost.","severity":"medium","snippet":"            if (weekTheses[_week()].length >= MAX_WEEK_THESES) revert InvalidNote();","title":"One wallet can fill a week's 120 thesis slots first-come and exclude every other author from the week's judged prize"},{"citation":"resolved","description":"A thesis posted in week w has 7 days to receive a child call and only theses with a child are eligible (MarginaliaJudge.eligibleTheses filters on hasChild). MarginaliaJudge.requestJudging(w) is permissionless and requires only w < hook.week() (src/MarginaliaJudge.sol:204), so it can run at the first second of week w+1. The question body's guards.allow is built from the eligible set at that moment and the week is then locked (AlreadyRequested, then judgedSet). A thesis posted late in week w whose child is posted a day later, inside the grace the brief guarantees, is absent from the only ranking the week will ever have, although it is eligible at pay time (judgedOf would accept it) and stays in thesesOfWeek. The trigger is unprivileged and profitable: a rival with an early thesis + child calls requestJudging(w) at the week boundary to shrink the field, and ordinary keepers do it routinely. The judge is live, but the hook's drawForJudging is the gate that releases the draw and checks only the pool size. Reported by audit_flow (a64b4285); reproduced by code reading of the two lines above and judge.eligibleTheses. Fix (hook only): for the first draw of week w require block.timestamp >= (uint256(w) + 1) * 7 days + THESIS_GRACE.","line":787,"path":"src/MarginaliaHook.sol","reproduction":"Fixture, week w. bob posts a thesis and its child early in the week; alice hook.fundPot(20 IMD). At weekEnd - 1 h alice posts a thesis (no child yet). At weekEnd + 1 s bob calls judge.requestJudging(w): succeeds (hook.drawForJudging passes: pool >= 2 IMD) and the Intake body's allow list holds only bob's id (eligibleTheses(w).length == 1). At weekEnd + 2 days alice posts her child (parentId = her thesis, inside THESIS_GRACE): eligibleTheses(w).length == 2 but judge.requestJudging(w) reverts AlreadyRequested. The panel answers with bob's id only; judge.payJudged(w) pays bob 50% and rolls the rest; judge.paid(w) == true. Expected: every thesis of week w that gets its child inside the grace is in the judged set; actual: alice's is never judged and never can be.","severity":"medium","snippet":"        uint256 need = retry ? amount : JUDGE_THRESHOLD;","title":"Weekly judging can be requested in the first second of the next week, freezing the allow-list before late theses can post their child inside THESIS_GRACE; those theses can never be judged"},{"citation":"resolved","description":"SPEC.md, README.md and the pricer's own NatSpec (lines 35-36) say v4 venues and the hub leg settle on 'the observation least favourable to the call'. settlePrice instead takes the extreme of xRead over all observations (lines 184-188) and, independently, the extreme of quoteRead (lines 194-197), then multiplies. When the venue leg and the hub leg move in opposite directions between observations, min(x) * min(q) is strictly below the minimum per-observation product (and max * max strictly above the maximum), so a RIGHT call on an ETH/WETH-quoted v4 venue is settled WRONG and forfeits its bond with no attacker, only ordinary uncorrelated moves. The hook's own slot-replacement rule _moreAdverse (MarginaliaHook.sol:567-569) ranks observations by the per-observation product, so the two rules disagree about which reading is adverse. postPrice (lines 146-152) has the same shape for the baseline (w.xMax with w.quoteMax for a BUY), squeezing a BUY call from both ends. IMD-quoted venues are unaffected (q is constant 1e18). Reported by audit_math (1e3db928); reproduced with test/scratch/Componentwise.t.sol (settlePrice returned 2000e18 for observations whose per-observation prices were 2400e18, 2500e18, 2400e18). The pricer is live; the hook can compute the per-observation extreme itself in settle() from its stored observations for v4 and ETH-quoted venues and keep the pricer for v3/v2 TWAPs.","line":194,"path":"src/MarginaliaPricer.sol","reproduction":"MarginaliaPricer.settlePrice(venue {UniV4, xIsToken0 true}, buy = true, obs = [(xRead 1.0e18, quoteRead 2400e18), (1.25e18, 2000e18), (1.0e18, 2400e18)]) returns 2000e18 (= min(x) 1.0e18 * min(q) 2000e18 / 1e18). Per-observation prices are 2400e18, 2500e18, 2400e18, so the observation least favourable to a BUY is 2400e18. With postPrice 2000e18 and targetBps 12000 (target 2400e18) every observation met the target, yet settle() at MarginaliaHook.sol:600 computes 2000e18 * 10000 < 2000e18 * 12000 and books Wrong, forfeiting the bond. Expected: 2400e18 -> Right.","severity":"medium","snippet":"        uint256 q = obs[0].quoteRead;\n        for (uint256 i = 1; i < n; ++i) {\n            q = _adverse(q, obs[i].quoteRead, buy);\n        }\n        uint256 p = FullMath.mulDiv(x, q, 1e18);","title":"v4 and hub-leg settlement multiplies the venue extreme and the quote-leg extreme taken from different observations, settling on a price no observation showed"},{"citation":"resolved","description":"A bond is forfeited only on WRONG or VoidSold, and either outcome needs at least 3 observe() transactions spread over an hour inside the 6-hour window plus settle(). The only payment is KEEPER_BPS (10%) of the bond on settle: 0.025 IMD for the minimum bond, 1 IMD for the maximum, against four mainnet transactions. The author of a wrong call is better off never observing (VoidNoData returns the bond and books the same -difficulty as WRONG), and no third party is paid to observe. The brief's 'WRONG ... forfeit it to the pools at once' therefore holds only when someone pays to hurt the author. An incentive gap, not a code bug; the fix is a design choice (e.g. a slice of the stamp or of a non-RIGHT bond pays the observers of a complete series). Reported by audit_economics (62707ceb); reproduced by the repository's own testNoDataRefunds (test/Lifecycle.t.sol:217), which settles a never-observed call VoidNoData and returns the bond.","line":582,"path":"src/MarginaliaHook.sol","reproduction":"Fixture. alice posts a BUY call on MARG +10% in 1 day with 0.6 IMD (bond 0.25). bob sells 1,500,000 MARG so the price falls far below the target. Nobody calls observe. After horizonEnd + 6 h + 1 anyone calls hook.settle(id): status VoidNoData, score -difficulty, deposit still 0.25; alice.claimDeposit(id) returns 0.25 IMD. Expected per the brief: WRONG forfeits the bond to the pools; actual: the pools receive nothing.","severity":"low","snippet":"        if (count < OBS_MIN || obs[count - 1].timestamp - obs[0].timestamp < OBS_MIN_SPAN) {","title":"Forfeiture of a WRONG call is economically unenforced: the only keeper reward is 10% of the bond at settle, and the three observations it needs pay nothing, so wrong calls resolve VoidNoData and get t"},{"citation":"resolved","description":"Only a reading MORE adverse to the call may replace the latest slot (line 527); a less adverse honest reading inside the 20-block gap reverts ObservationTooSoon, and after the gap it is appended without removing the hostile slot. MarginaliaPricer.settlePrice then takes the extreme across all slots for v4 venues and the hub leg, so one hostile reading decides the outcome. The comment at lines 511-513 and SPEC.md's 'A two-block pump-observe-unwind moves neither rule' are wrong for the adverse direction; README's known-limits section states it correctly. The requester previously accepted this as design (ec6beba1), so this is recorded as a documentation defect with its amplifier: the attacker needs no capital held across blocks (dump, observe, buy back in one transaction) and settle() pays msg.sender 10% of the forfeited bond, so on a thin venue the round-trip fee can be below the bounty. Reported by audit_permissions (abe520eb); reproduced by reading lines 526-531 against settlePrice lines 184-188: no path removes a slot except replacement by a more adverse reading.","line":512,"path":"src/MarginaliaHook.sol","reproduction":"Fixture. alice router.note(BUY, 11000 bps, 1 day) on the launch pool; bob buys 1.3M IMD of MARG and holds, price > 1.1x baseline. At horizonEnd anyone observes (honest). Next block carol in one transaction: plain.swap sells 3M MARG (price < 1.1x baseline), hook.observe(id) (more adverse, replaces slot 0), plain.swap buys the IMD back. One block later an honest hook.observe(id) reverts ObservationTooSoon (not more adverse). Two more honest observations at +31 and +62 minutes are appended. hook.settle(id) after the window: status Wrong, alice's bond forfeited, 10% to the settler. Expected per the comment and SPEC: Right. Actual: Wrong.","severity":"low","snippet":"    /// latest one replaces it. So a pump-observe-unwind in one block is overwritten by any honest reading in\n    /// the next, and the series must span OBS_MIN_SPAN: a pump has to be held for the whole span.","title":"observe()'s comment and SPEC claim an honest reading overwrites a one-block pump; in fact one hostile reading inside the window decides a v4 settlement and cannot be overwritten by a less adverse hone"},{"citation":"resolved","description":"validateVenue reads the v3 pool / v2 pair as address(uint160(uint256(v.ref))) (lines 213 and 221) and never requires the high 12 bytes of ref to be zero, but the price window is stored under keccak256(abi.encode(v)) with the full ref, and the hook stores n.venue with the full ref (the pricer masks it, so settlement works). Every distinct high-byte pattern is an independent PriceWindow on the same canonical pool with its own startedAt, TWAP start and hub-leg extremes. A poster opens as many windows as they like at times of their choosing and picks, at post time, the one whose TWAP start and quote extremes give the least adverse baseline; the documented 'a live checkpoint cannot be replaced or have its start reset' holds only per alias. v4 venues are unaffected (ref must equal key.toId()). Reported by audit_flow (1714ef27); reproduced by reading validateVenue and checkpointVenue: no check on uint256(v.ref) >> 160. The router is live; the hook can refuse in _postNote and seal() a UniV3/UniV2 venue whose ref has nonzero high bytes.","line":146,"path":"src/MarginaliaRouter.sol","reproduction":"A canonical-looking v3 pool mock behind a factory mock etched at UNIV3_FACTORY. refA = bytes32(uint256(uint160(pool))); refB = refA | (1 << 200). checkpointVenue(venue refA) at T; at T + 2 h checkpointVenue(refA) keeps startedAt = T; checkpointVenue(refB) at T + 2 h creates a second window with startedAt = T + 2 h on the same pool (priceWindows keys differ). One hour later router.note(p with refB) is accepted by the hook (status Open) and hook.observe(id) works at the horizon. Expected: one window per canonical pool, or the aliased ref refused.","severity":"low","snippet":"        bytes32 id = keccak256(abi.encode(v));","title":"v3/v2 venue ref is keyed by all 32 bytes but the pool is the low 20, so every high-byte pattern is a separate price window on the same pool and a poster picks the window start of their choosing"},{"citation":"resolved","description":"claimRefund needs only n.day < today and status != Retracted; retract needs only block.timestamp < horizonEnd. For any call with horizonDays >= 1 there is a window from 00:00 UTC of the next day until the horizon in which the author first claims the refund and then retracts. retract's accounting skips the notesPerDay decrement when the refund was already claimed, so the day's split stays consistent, but the refund (up to one stamp) stays with a note the rule excludes. No profit: the retraction forfeits at least the 0.25 IMD bond. Reported by audit_permissions (d99cf9e0); reproduced by reading lines 630-637 and 826-838.","line":830,"path":"src/MarginaliaHook.sol","reproduction":"Day d 23:00: alice router.note(BUY, 11000, horizonDays 2, 1 IMD). Day d+1 00:01: hook.claimRefund(id) pays min(refundPool[d] / notesPerDay[d], 0.1 IMD). Day d+1 12:00: hook.retract(id, 'changed my mind') succeeds; status Retracted, refund kept. Expected per retract's own comment: a retracted note takes no refund.","severity":"info","snippet":"        if (refundClaimed[id] || n.status == T.Status.Retracted) revert NothingToClaim();","title":"A note can claim its writer refund on the next day and then retract before its horizon, keeping a refund the retract rule says it never gets"},{"citation":"resolved","description":"The hook taxes MARG sells only inside beforeSwap/afterSwap and has no liquidity permissions (the brief fixes the flags at 0x20cc), so a holder adds a MARG-only position just above the current price and removes it once buyers have swapped through the range: the position is then IMD, the holder sold MARG at the range's price, and the hook saw only untaxed buys. Inherent to the chosen callbacks and the brief's own fee rule (a fee on swaps, not on exits); recorded as a known limit, not a defect to repair. Reported by audit_economics (0ef703de); reproduced by reading getHookPermissions and the absence of any liquidity callback.","line":236,"path":"src/MarginaliaHook.sol","reproduction":"Fixture (1 MARG = 1 IMD). bob holds 100,000 MARG. Instead of plain.swap (3% minted to the hook), bob calls manager.modifyLiquidity on the launch key with tickLower 60, tickUpper 120 and a MARG-only amount; afterSwap is not invoked. alice buys enough MARG to move the tick past 120. bob removes the position: the delta is all IMD plus LP fees; the hook's IMD claims, thesisPool and refundPool are unchanged by bob's exit.","severity":"info","snippet":"    function getHookPermissions() public pure returns (Hooks.Permissions memory p) {\n        p.beforeInitialize = true;\n        p.beforeSwap = true;\n        p.afterSwap = true;","title":"The 3%/1% sell fee is avoidable by exiting MARG through a single-sided liquidity position, since flags 0x20cc carry no liquidity callbacks"}],"hash":"66b2402ac275390abee80bf2977038ee9028f5b7f22755830943a6ef5a6135fa","nodeId":"d81387de-e8f7-4979-a40d-e2a2634ee6f2","outcome":"completed","summary":"Review complete. The findings file is written and validated.\n\n**Outcome:** `.imd-findings.json` holds 11 findings and a 34-row coverage record answering all 32 listed entry points. Two findings carry proofs that fail on this tree and pass once fixed. No source, config or test file outside `test/scratch/` was changed.\n\n**What I kept, by severity**\n\n- **High (proof):** A call on IMD itself priced through the ETH/IMD hub can never be RIGHT. The pricer multiplies ETH-per-IMD by IMD-per-ETH from the same hub slot, which is always 1e18, so every such bond is forfeited. Reproduced locally with a hub pool at the pricer's hub id: postPrice 999999999999999999, status Wrong after a 60% rise. The project's own fork test advertises this note.\n- **Medium (proof):** A thesis accepts its first child after the 7-day grace, so forfeiture only happens if a keeper races the author. Three specialists reported this; merged into one. I made the supplied proof fix-agnostic so it passes whether the author refuses late children or lets settleThesis forfeit anyway.\n- **Medium:** Sub-gap slot replacements restart the 20-block gap, letting one party hold the series at one slot and turn a WRONG call into VoidNoData. Reproduced: status 4, 9.65 IMD bond retained.\n- **Medium:** One wallet can fill a week's 120 thesis slots and exclude every other author (two specialists, merged).\n- **Medium:** requestJudging in the first second after a week freezes the allow-list before late theses get their grace.\n- **Medium:** The pricer settles v4 and hub-leg calls on min(x)·min(q) from different observations. Reproduced in a unit test: 2000e18 where every observation showed at least 2400e18.\n- **Low:** keeper economics for WRONG calls, the wrong observe() comment about hostile slots, v3/v2 ref high-byte aliasing.\n- **Info:** refund-then-retract, and fee avoidance via single-sided liquidity (inherent to the mandated flags).\n\n**Dropped or demoted:** nothing was dropped outright; all specialist findings reproduced. I did not promote the thesis-cap finding to high because the panel can still return an empty head, so capture is not guaranteed.\n\n**Verified clean:** manifest schema and constructor args, hook runtime 22,770 bytes and creation 24,308 bytes under the limits, beforeInitialize gating, swap delta accounting, unlock plumbing, and the clone-only initialisers. Baseline suite: 228 tests pass. The fork suite was not run (no RPC available).","treeHash":null,"usage":{"cachedInputTokens":2184242,"inputTokens":420,"model":"claude-fable-5-1","outputTokens":50569,"runtime":"claude","turns":26,"wallClockMs":1520444}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e02bec63aa9dcaa5","findings":[{"citation":"resolved","description":"A reading inside OBS_GAP_BLOCKS of the last slot may replace that slot when it is more adverse to the call, and the replacement is written with the current block number (T.Observation(..., uint64(block.number), ...)). The 20-block gap that gates a push is therefore measured from the latest replacement, not from the latest push. On a v4 venue (or an ETH-quoted venue through the hub leg) a strictly more adverse reading costs one dust swap: a dust sell of X lowers sqrtPrice by at least one unit, so fromSqrt() is strictly lower for a BUY call (strictly higher after a dust buy for a SELL call). Whoever lands dust-swap+observe every <=19 blocks keeps the series at one entry for the entire 6-hour window; every honest observe() is refused with ObservationTooSoon because block.number < lastReplacement + 20 and the honest reading is not more adverse than the attacker's. settle() then sees count < OBS_MIN and books VoidNoData, which returns the bond and pays no keeper. The author of a call that is going WRONG (or an accomplice, or any griefer against a RIGHT call) escapes forfeiture of a 0.25-10 IMD bond at the cost of about 95 cheap transactions over six hours. The pools lose the forfeit the brief promises them ('WRONG, VoidSold and retractions forfeit it to the pools at once') and the keeper bounty is never earned. The replacement rule was added so a pump-observe-unwind can be overwritten; as written it also gives the overwriter control of the gap. Fix (hook only): measure the push gap from the block of the last push, not the last replacement (keep obs[len-1].blockNumber on replace, or store a separate lastPushBlock), so an honest observer can always append after 20 blocks while the adverse-overwrite still works.","line":526,"path":"src/MarginaliaHook.sol","reproduction":"Fixture: launch pool at 1 MARG = 1 IMD with 1e25 liquidity; alice posts a BUY call +50%, 1 day, on MARG priced on the launch pool (router.note, 10 IMD in). The market stays flat, so the call should settle WRONG. At horizonEnd: hook.observe(id) once (1 slot). Then for i = 1..95: roll +19 blocks, warp +228 s; carol calls hook.observe(id) -> reverts ObservationTooSoon; bob sells 1e9 wei of MARG on the pool (price strictly lower) and calls hook.observe(id) -> replaces slot 0 with blockNumber = now. After end + 6 h + 1: hook.settle(id). Expected: status Wrong, deposit 0 (forfeited to the pools, keeper paid 10%). Actual: status VoidNoData (4), deposit untouched and claimable by alice through claimDeposit; carol never managed to add a second slot. Proof test: test/scratch/ObsMonopoly.t.sol (fails on this tree with 'a wrong call must settle wrong: 4 != 2').","severity":"medium","snippet":"        if (len > 0 && (len >= OBS_MAX || block.number < obs[len - 1].blockNumber + OBS_GAP_BLOCKS)) {\n            if (!_moreAdverse(n, o, obs[len - 1])) revert ObservationTooSoon();\n            obs[len - 1] = o;","title":"observe(): a sub-gap replacement restarts the gap timer, so one party can hold a series at a single slot for the whole window and turn a WRONG call into VoidNoData (bond returned)"},{"citation":"resolved","description":"A thesis posted in week w has THESIS_GRACE (7 days) to get a child call; only theses with a child are eligible (MarginaliaJudge.eligibleTheses filters on hasChild). MarginaliaJudge.requestJudging(w) is permissionless and only requires w < hook.week(), so it can be called at the first second of week w+1 (src/MarginaliaJudge.sol:204 `if (day >= hook.week()) revert DayNotOver();`). The question body (guards.allow) is built at request time from the eligible set at that moment, the week is then locked (AlreadyRequested; judgedSet after the answer). The Intake's guards.allow restricts the panel's answer to the ids in that body, so a thesis absent from it cannot be ranked; judgedOf() filters only on week/thesis/hasChild and would accept the id if it ever came back, but it never can. A thesis posted late in the week whose author posts the child a day or two later, well inside the 7-day grace the brief guarantees, is excluded from the only ranking the week will ever have, although it becomes eligible and stays in thesesOfWeek. The trigger is unprivileged and profitable: a rival with an early thesis+child calls requestJudging(w) at the week boundary to shrink the field. The judge is a live implementation that cannot be redeployed, but the hook is the gate that releases the draw: drawForJudging(w, amount, retry) checks only the pool size. Fix (hook only): in drawForJudging require block.timestamp >= (uint256(w) + 1) * 7 days + THESIS_GRACE for the first draw, so a request can only be made once every thesis of the week has had its full grace period.","line":787,"path":"src/MarginaliaHook.sol","reproduction":"Fixture (test/scratch/EarlyJudging.t.sol, passes = reproduces): week w. bob posts a thesis and its child early in the week; alice funds the thesis pool (hook.fundPot(20 IMD)). At weekEnd - 1 h alice posts a thesis (no child yet). At weekEnd + 1 s bob calls judge.requestJudging(w): succeeds; MockIntake.lastBody() == judge.questionBody(w), and that body does not contain alice's id (eligibleTheses(w).length == 1). At weekEnd + 2 days alice posts her child call (parentId = her thesis, inside THESIS_GRACE): judge.eligibleTheses(w).length is now 2, but judge.requestJudging(w) reverts AlreadyRequested. The Intake answers with bob's id only; judge.payJudged(w) pays bob 50% of the pool and rolls the rest; judge.paid(w) is true. alice's thesis, eligible under the brief's rule, is never judged and never can be.","severity":"medium","snippet":"        uint256 need = retry ? amount : JUDGE_THRESHOLD;\n        if (thesisPool[w] < need || amount > thesisPool[w]) revert PotTooSmall();","title":"Weekly judging can be requested in the first second of the next week, before late theses can post their child call inside THESIS_GRACE: the allow-list is frozen and those theses can never be judged"},{"citation":"resolved","description":"validateVenue() reads the v3 pool / v2 pair as address(uint160(uint256(v.ref))) (src/MarginaliaRouter.sol:213 and :221) and never requires the high 12 bytes of ref to be zero, but the price window is stored under keccak256(abi.encode(v)) with the full ref, and the hook stores n.venue with the full ref (observe() also masks to the low 20 bytes, so settlement works). Every distinct high-byte pattern is therefore a separate PriceWindow on the same canonical pool, each with its own startedAt, TWAP start (xStart) and hub-leg extremes. A poster can open as many windows as they like at times of their choosing and pick, at post time, the one whose TWAP start and whose quoteMin/quoteMax (for WETH/ETH-quoted venues) give the least adverse baseline, and nobody else's checkpoint extends 'their' window. ADAPTATION.md states 'A live checkpoint cannot be replaced or have its start reset' and 'preserving live extrema prevents an attacker from erasing an honest checkpoint immediately before posting'; for v3/v2 venues both are bypassable. v4 venues are not affected (ref must equal key.toId()). The router is a live implementation; a hook-side fix is to refuse, in _postNote and seal(), a UniV3/UniV2 venue whose ref has any nonzero high bytes (uint256(p.venue.ref) >> 160 != 0 -> InvalidNote).","line":146,"path":"src/MarginaliaRouter.sol","reproduction":"Fixture + a canonical-looking v3 pool mock behind a factory mock etched at UNIV3_FACTORY (test/scratch/RefAlias.t.sol, passes = reproduces): refA = bytes32(uint256(uint160(pool))); refB = refA | (1 << 200). checkpointVenue(venue refA) at T; at T + 2 h checkpointVenue(refA) again keeps startedAt = T (live window, not reset); checkpointVenue(refB) at T + 2 h creates a second window with startedAt = T + 2 h on the same pool (priceWindows keys differ). One hour later router.note(p with refB) is accepted by the hook (status Open) and hook.observe(id) works at the horizon. Expected: one window per canonical pool, so the second checkpoint extends the existing window instead of starting a new one, or the hook refuses the aliased ref.","severity":"low","snippet":"        bytes32 id = keccak256(abi.encode(v));","title":"v3/v2 venue ref: the window is keyed by all 32 bytes but the pool is the low 20, so any value of the high 12 bytes is a fresh, independent price window on the same pool (the 'live window cannot be res"}],"hash":"b5d03915ec250e356cd99ba9f08fdf90fb2d419885e57479abc58432fa03be87","nodeId":"8d68d6f9-968c-4725-bf57-1e3088215719","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds three substantiated findings and a coverage row for every listed entry point. No source file was changed; only the findings file and my scratch tests under `test/scratch/` exist outside the tree (git shows a clean tracked state).\n\n**Findings**\n\n1. **Medium, `src/MarginaliaHook.sol:526` (observe).** A reading inside the 20-block gap may replace the last slot when it is more adverse, and the replacement carries the current block number, so the push gap restarts from every replacement. One party doing a dust swap plus `observe` every 19 blocks keeps the series at one slot for the whole 6-hour window. Honest observers are refused every time, and `settle` books VoidNoData, returning the bond of a call that was WRONG. The author or an accomplice escapes forfeiture; a griefer can void a correct call. The proof `test/scratch/ObsMonopoly.t.sol` fails on this tree with `a wrong call must settle wrong: 4 != 2`. Hook-only fix: measure the push gap from the last push, not the last replacement.\n\n2. **Medium, `src/MarginaliaHook.sol:787` (drawForJudging, with `MarginaliaJudge.requestJudging`).** Judging can be requested at the first second of the next week, which freezes the question's allow-list before theses posted late in the week can get their child call inside the 7-day grace. A rival with an early thesis profits by shrinking the field. Reproduced with `test/scratch/EarlyJudging.t.sol`. The judge is live, but the hook can gate the first draw until the grace has elapsed.\n\n3. **Low, `src/MarginaliaRouter.sol:146` (checkpointVenue).** v3/v2 refs are masked to the low 20 bytes but windows are keyed by the full 32 bytes, so any high-byte pattern is a separate window on the same pool. The \"live window cannot be reset\" guarantee does not hold for v3/v2 venues. Reproduced with `test/scratch/RefAlias.t.sol`. A hook-side fix can refuse non-zero high bytes in `_postNote` and `seal`.\n\n**Coverage.** All 33 listed entry points have a row (29 holds, 5 findings including the extra `tradeAndNote` and a claims-conservation invariant row). The swap callbacks, unlock plumbing, seal and counter flows, pool accounting, judge request and payment, treasury drip and router legs were traced in full. The fork suite was not run because no `MAINNET_RPC_URL` is available; the known missing `questionHash` check in the judge is already recorded in the adaptation notes and was left outside this area.","treeHash":null,"usage":{"cachedInputTokens":4369428,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":89357,"runtime":"claude","turns":51,"wallClockMs":1673188}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b4f6137e7c93a2b3","findings":[{"citation":"resolved","description":"Seam: boundary x invariant (Numerical Gap). The hook accepts any ERC-20 with code as X, including IMD, the quote asset every price is denominated in. For X == IMD the only canonical venue is the ETH/IMD hub pool (quote = native ETH), which the router's validateVenue admits. Settlement and the baseline then multiply MarginaliaPricer._spotInQuote (fromSqrt(hubSqrtP, xIsToken0=false) = ETH per 1e18 IMD) by MarginaliaPricer._quoteSpot (fromSqrt(hubSqrtP, true) = IMD per 1e18 ETH), both read from the same hub slot0: x * q / 1e18 == 1e18 up to one wei of rounding, whatever IMD does against ETH. settle() at MarginaliaHook.sol:600 then compares settlePrice*10_000 (= 1e22) with postPrice*targetBps (>= 1.1e22 for any accepted BUY target, <= 0.9e22 for any SELL target), so every call on IMD is WRONG and _forfeit() sends the author's bond (0.25 to 10 IMD) to the pools, 10% to the keeper. The project's own fork rehearsal (test/fork/MainnetLaunch.t.sol:343 testNoteAboutImdOnTheHubPool, 'IMD 1.5x in 30d', 10 IMD in => 9.65 IMD bond) and SPEC.md row 0b advertise exactly this note as the flagship use, so authors are invited into a bond they cannot keep. Concrete arithmetic: hub at 1 ETH = 2000 IMD: x = 1e36/2000e18 = 5e14 (ETH per IMD), q = 2000e18; x*q/1e18 = 1e18. After IMD rises 50% (1 ETH = 1333 IMD): x = 7.5e14, q = 1333e18; product = 1e18 again. Fix in the hook (the pricer and router are live and unchangeable): in _postNote refuse p.x == imd (and, for the same reason, any X equal to the venue's quote), e.g. `if (p.x == address(0) || p.x == imd || p.x.code.length == 0) revert InvalidNote();`, or price IMD on a real leg (quote the hub in ETH with q = 1e18).","line":422,"path":"src/MarginaliaHook.sol","reproduction":"Local, no fork (test/scratch/NoteOnImdIsUnwinnable.t.sol): chainId 1; an 18-decimal token etched at 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7; a hookless ETH/IMD pool (fee 10000, spacing 200) whose id equals MarginaliaPricer.HUB_POOL_ID, 1 ETH = 2000 IMD, 1e24 liquidity; the MARG/IMD launch pool bound to the hook. 1) router.checkpointVenue(x=IMD, venue={UniV4, HUB_POOL_ID}), wait 1 h / 300 blocks. 2) router.note(side=Buy, targetBps=11000, horizonDays=1, imdIn=1 ether) -> accepted, postPrice = 1e18 (+/-1 wei), deposit 0.65 IMD. 3) Buy IMD with 230,000 ETH on the hub: IMD per ETH falls below 1400e18, i.e. IMD rose > 40% against ETH. 4) After the horizon, observe() three times 150+ blocks and 30+31 minutes apart; settle() 6 h later. Expected: a BUY call for +10% on an asset that rose ~50% is RIGHT (or the post is refused). Actual: status == Wrong, settlePrice 1e18, 0.65 IMD forfeited. The same holds for any target and any hub move; a SELL call on IMD is equally unwinnable.","severity":"high","snippet":"            if (p.x == address(0) || p.x.code.length == 0) revert InvalidNote();","title":"A call on IMD itself priced through the ETH/IMD hub settles at the identity product (ETH per IMD) x (IMD per ETH) = 1, so it can never be RIGHT and its bond is always forfeited"},{"citation":"resolved","description":"Seam: precision x invariant (Numerical Gap). SPEC.md:78, README.md:136 and the contract's own NatSpec (MarginaliaPricer.sol:35-36) say v4 venues and the hub leg settle on 'the observation least favourable to the call'. settlePrice instead takes the extreme of xRead over all observations (lines 184-188) and, independently, the extreme of quoteRead over all observations (lines 194-197), then multiplies. When the venue leg and the hub leg move in opposite directions between observations, min(x)*min(q) is strictly below min over observations of x*q (and max(x)*max(q) strictly above the max): the settlement price is one that never existed. The hook's own slot-replacement rule _moreAdverse (MarginaliaHook.sol:567-569) compares the per-observation product, so the two rules disagree about which reading is 'adverse'. The posting baseline has the same shape: postPrice (lines 146-152) combines w.xMax with w.quoteMax for a BUY, so the baseline can be above every price the window actually showed, and a BUY call is squeezed from both ends. Affects every v4 venue quoted in ETH/WETH (q is constant 1e18 for IMD-quoted venues). A RIGHT call is settled WRONG and forfeits its bond; no attacker needed, ordinary uncorrelated moves suffice. Fix: compute the extreme over the per-observation product x_i*q_i/1e18 (and for the baseline, over per-checkpoint products); since the pricer is live, the hook can do this itself in settle() from its stored observations and keep the pricer only for v3/v2.","line":194,"path":"src/MarginaliaPricer.sol","reproduction":"test/scratch/ComponentwiseExtreme.t.sol (pricer unit): venue {UniV4, xIsToken0=true}, buy=true, observations (xRead, quoteRead): (1.0e18, 2400e18), (1.25e18, 2000e18), (1.0e18, 2400e18). Per-observation prices are 2400e18, 2500e18, 2400e18 IMD per X. settlePrice returns min(x)=1.0e18 * min(q)=2000e18 / 1e18 = 2000e18. With postPrice 2000e18 and targetBps 12000 the target is 2400e18: every observation met it, settle() at MarginaliaHook.sol:600 computes 2000e18*10000 < 2000e18*12000 and books Wrong, forfeiting the bond. Expected (spec: the observation least favourable to the call) 2400e18 -> Right. The hook's _moreAdverse would have ranked obs[1] (2500) as less adverse than obs[0] (2400) by the product, the opposite of what settlePrice then uses.","severity":"medium","snippet":"        uint256 q = obs[0].quoteRead;\n        for (uint256 i = 1; i < n; ++i) {\n            q = _adverse(q, obs[i].quoteRead, buy);\n        }\n        uint256 p = FullMath.mulDiv(x, q, 1e18);","title":"v4 and hub-leg settlement combines the venue minimum and the quote-leg minimum from different observations, settling on a price no observation ever showed"}],"hash":"bbed721b16b38f277ff8f6acb5cd142d1f643f3d62daff8eea35e7d2a5a37b79","nodeId":"416e86e8-fd8b-4338-87fe-105808f4f3b3","outcome":"completed","summary":"The review is complete. Findings are in `.imd-findings.json` (2 findings, 34 coverage rows covering all 31 listed entry points plus two invariants), and both reproductions were run against the tree as it stands.\n\n**Finding 1, high: a call on IMD itself can never be RIGHT.** The hook accepts any ERC-20 with code as X, including IMD, and the router admits the ETH/IMD hub as its venue. The pricer then multiplies ETH-per-IMD by IMD-per-ETH, both read from the same hub slot, so the price is identically 1.0 whatever IMD does. Every accepted target is at least 10% away, so the call always settles WRONG and the bond (0.25 to 10 IMD) is forfeited. The project's own fork rehearsal posts exactly this note (\"IMD 1.5x in 30d\", 9.65 IMD bond). The proof at `test/scratch/NoteOnImdIsUnwinnable.t.sol` runs locally with no fork: it recreates the hub pool at the pinned pool id, posts a +10% BUY call on IMD, moves the hub so IMD rises about 50% against ETH, observes three times across an hour, and settles. Result today: status Wrong, 0.65 IMD lost. The suggested fix is one line in the hook, since the pricer and router are live: refuse X equal to the quote asset.\n\n**Finding 2, medium: v4 and hub-leg settlement can land on a price no observation showed.** The pricer takes the venue extreme and the hub-leg extreme separately across observations and multiplies them, while the spec, README and the pricer's own comment promise \"the observation least favourable to the call\". With observed prices 2400, 2500, 2400 the settlement is 2000, so a BUY call whose target of 2400 was met by every observation books WRONG. The hook's own replacement rule ranks readings by the per-observation product, so the two rules disagree. The posting baseline has the same shape in the other direction. This affects only ETH-quoted v4 venues.\n\n**What was covered.** All hook arithmetic (bond band, stamp and fee splits, the 70/30 accrual, refund split and cap, 50/30/20 prize split, keeper share, sweep timing, observation gap and span boundaries, score and difficulty math), the pricer (fromSqrt in both orientations, v3 tick TWAP flooring, v2 wrapped cumulatives, log2 and sqrt domains, the decimals question for the market-cap tier), and the router's delta and slippage checks. Static-analysis leads were read and none promoted on their own; the weak-PRNG and strict-equality lines are false positives in this code.\n\n**Not reached in depth.** The attestation verification path in the judge and the exact Intake interaction are outside the math area and only had their integer comparisons traced.","treeHash":null,"usage":{"cachedInputTokens":2524504,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":55704,"runtime":"claude","turns":41,"wallClockMs":942085}},{"artifacts":[],"attempt":1,"bundleHash":"fcaeb7ca2662397199f7f452d144f7f296eb72081202749f3cf56316c9386a8b","device":"3311c48cd0280ed4","findings":[],"hash":"d294b0095b9919d7e0fdcd5f9d968d1e2f548ab5686db9f5e61607dfab6b96a6","nodeId":"18a490e9-f355-4087-b272-2a9616ead464","outcome":"completed","summary":"Created [launch.json](/home/imd1/.identitymd/work/9060a248-29ce-4683-b5d1-54fbc83cd49d/18a490e9-f355-4087-b272-2a9616ead464/launch.json) with matching constructor arguments, permissions `0x20cc`, and required IMD pool settings.\n\n- `forge build` passed.\n- 197 tests passed, including 11 protected checks.\n- Fork suite skipped: `MAINNET_RPC_URL` unavailable.\n\nOnly `launch.json` is changed for submission.","treeHash":"ccd01a420af02076d538410bbd5d25378b19306b","usage":{"cachedInputTokens":1473280,"inputTokens":92110,"model":"gpt-6-astra","outputTokens":11066,"runtime":"codex","turns":7,"wallClockMs":428823}},{"artifacts":[],"attempt":1,"bundleHash":"410940326e0096a4b3e38e44c6308b6fb4f5164453642c316c3dfd482f7c1289","device":"cf3b0a0c089b1430","findings":[{"description":"The assignment requires a thesis to receive a child call from its author within seven days or forfeit its bond. _postNote checks only that the parent is ThesisOpen before incrementing children; it never checks parent.postedAt + THESIS_GRACE. Consequently, an overdue thesis stays rescuable until a keeper settles it. A late child makes settleThesis revert because children > 0, and resolving or retracting that child closes the thesis and enables return of its bond. It also makes the otherwise ineligible thesis enter the judged set. This changes a deadline into a transaction-order race with the keeper.","line":475,"path":"src/MarginaliaHook.sol","reproduction":"Run the embedded proof as test/scratch/LateThesisChildProof.t.sol with forge test --match-path test/scratch/LateThesisChildProof.t.sol. On a real local PoolManager seeded at 1:1, Alice posts a thesis with 10.35 IMD (10 IMD bond). Advance eight days, renew the venue checkpoint, advance another hour, and have Alice post a 11000-bps BUY call with a one-day horizon, 0.6 IMD input, and parentId equal to that thesis. Expected: reject the late child so the overdue thesis can forfeit. Actual: the child posts successfully and increments the thesis children count; Foundry fails with \"next call did not revert as expected\". The proof was run locally and failed for this reason. No production files were changed.","severity":"medium","title":"A thesis can acquire its first child after the seven-day deadline and evade forfeiture"}],"hash":"d3db90f9129d27ad728f2ad5d3d456bba17375dd56bcdffc2b5371349ff4891c","nodeId":"5714e926-571a-405a-a438-efd62b19f8b6","outcome":"completed","summary":"Added 42 tests, including randomized accounting invariants.\n\n- `forge build` passes.\n- `forge test`: 228 passed, 0 failed; mainnet fork suite skipped without RPC configuration.\n- Reported one medium defect: late thesis children bypass seven-day forfeiture. `.imd-findings.json` includes the reproduced failing proof.\n\nImplementation and configuration files remain unchanged.","treeHash":"c0d385542d6da783d3ce0e81f33cf0b9017fd8ab","usage":{"cachedInputTokens":4872576,"inputTokens":203904,"model":"gpt-6-astra","outputTokens":38290,"runtime":"codex","turns":8,"wallClockMs":1167854}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c2e167266d13dcf4","findings":[{"citation":"resolved","description":"The week's judged set is capped at MAX_WEEK_THESES = 120 by posting order with no per-author limit, no rising cost, and no relation to the pool it competes for. The thesis pool receives 70% of EVERY accrual (all stamps, all 3% quiet-sell fees, all forfeits, the treasury's daily 2% drip, gifts) and is paid 50/30/20 to whichever three theses the panel ranks among the eligible set. A single wallet can post 120 theses early in the week (each 0.1 IMD stamp + 0.25 IMD MARG buy it keeps + 0.25 IMD bond it gets back) and give each a child call (same cost, bond back after the child voids with no observations). From then on every other author's thesis reverts InvalidNote for the rest of the week, so judge.eligibleTheses(week) contains only the attacker's ids, the panel can only rank the attacker, and hook.payJudged pays the attacker 100% of the pool (50+30+20). The 120 cap was introduced in revision round 2 (7539406d) to replace a silent cut, but a global first-come cap turns the judged set into a capacity one actor can exhaust (Pashov Economic Security: 'starve shared capacity' / 'legitimate features turned against the protocol'). Economics: the attacker's sunk cost is 240 stamps = 24 IMD plus ~1.25% LP fee on 60 IMD of MARG buys (~0.75 IMD); the 60 IMD of bonds return via VoidNoData and the 60 IMD of MARG is kept. Any week whose pool exceeds ~25 IMD (one 2% drip of a 1,800 IMD treasury, or ~1,200 IMD of quiet MARG sells) is profitable, and the attacker also collects writer refunds on 240 notes. Honest thesis writers of that week are refused and the pool their stamps funded pays the attacker.","line":446,"path":"src/MarginaliaHook.sol","reproduction":"Fixture: MARG/IMD pool at 1:1, bob funded. Week w. (1) 120 times: bob calls router.note({x: MARG, venue: launch pool, targetBps: 0, text: '...'}, key, 0.6e18, 1, deadline) then router.note({..., targetBps: 11000, horizonDays: 1, parentId: <that thesis>}, key, 0.6e18, ...). bob's IMD drops by 144 IMD (60 of it bonds that come back, 60 of it MARG he keeps, 24 of it stamps). (2) alice calls router.note({targetBps: 0, text: 'a real thesis'}, key, 1e18, 1, deadline) -> reverts (hook InvalidNote at line 446, wrapped by the PoolManager). (3) imd.transfer(treasury, 10_000e18); treasury.drip(); alice sells 50,000 MARG through any router (3% quiet fee). hook.thesisPool(w) == 1188.59 IMD. judge.eligibleTheses(w).length == 120 and every id's author is bob. (4) warp past the week; judge.requestJudging(w); deliver an attestation ranking any three of bob's theses; judge.payJudged(w): bob receives 1188.09 IMD (50%+30%+20% of the pool after the 0.5 IMD draw). Expected: a week's prize cannot be monopolised for a flat 24 IMD; actual: alice is locked out and bob is paid 100%. Verified by test/scratch/EconReview.t.sol testOneWalletFillsTheJudgedSetAndTakesTheWeeksPool (bob spent 144.0 IMD gross, was paid 1188.09 IMD). Suggested direction (requester's decision; preserves the 120 panel cap): cap eligible theses per author per week (e.g. 3, the size of the paid head) or make the cap apply per author rather than per week, so a flood cannot exclude other writers.","severity":"medium","snippet":"            if (weekTheses[_week()].length >= MAX_WEEK_THESES) revert InvalidNote();","title":"One wallet can fill a week's 120 judged thesis slots and take the whole week's thesis pool, excluding every other author"},{"citation":"resolved","description":"_postNote accepts a child call under the author's own thesis whenever parent.status == ThesisOpen, with no check that block.timestamp <= parent.postedAt + THESIS_GRACE. settleThesis only forfeits a thesis while children == 0, and nothing but a third party's settleThesis call changes a childless thesis's status after day 7. So an author whose thesis has sat childless for 8, 30 or 300 days can post a child the moment they like; the child increments children, settleThesis then reverts NotOpen forever, the child voids with no observations, _resolveChild closes the thesis and claimDeposit returns the thesis bond in full. The brief's rule 'needs a child call of the author within 7 days or forfeits' is therefore enforced only when a keeper happens to call settleThesis first. The keeper's incentive is KEEPER_BPS of a bond that is 0.25 IMD at minimum (0.025 IMD, about $0.20) against one mainnet transaction, so in practice no keeper races. The same gap lets a thesis become judge-eligible (hasChild) at any time after its week, though eligibleTheses is only read when the week is requested.","line":475,"path":"src/MarginaliaHook.sol","reproduction":"Fixture. (1) alice: router.note({x: MARG, venue: launch pool, targetBps: 0, text: 'essay'}, key, 1e18, 1, deadline) -> thesis tid, bond 0.65 IMD, status ThesisOpen. (2) vm.warp(+8 days); refresh the router checkpoint and wait 1 hour. (3) alice: router.note({targetBps: 11000, horizonDays: 1, parentId: tid, text: 'late child'}, key, 1e18, ...) -> succeeds, noteOf(tid).children == 1. Expected per spec/brief: refused (grace over) or the thesis already forfeited. (4) hook.settleThesis(tid) -> reverts NotOpen. (5) warp past the child's horizon + 6h; hook.settle(child) -> VoidNoData; noteOf(tid).status == ThesisClosed; alice.claimDeposit(tid) returns 0.65 IMD. Verified by test/scratch/EconReview.t.sol testChildAfterGraceRescuesTheThesis. Fix: in the child branch require block.timestamp <= uint256(parent.postedAt) + THESIS_GRACE (one comparison; preserves every rule).","severity":"low","snippet":"                    if (parent.status != T.Status.ThesisOpen) revert InvalidNote();","title":"A thesis can receive its child after the 7-day grace, so the 'no child within 7 days forfeits' rule is only enforced if a keeper races the author"},{"citation":"resolved","description":"A bond is forfeited only on WRONG or VoidSold, and either outcome needs at least 3 observe() transactions spread over 1 hour inside the 6-hour window plus a settle() transaction afterwards. The only payment for that work is KEEPER_BPS (10%) of the bond, paid on settle: 0.025 IMD for the minimum 0.25 IMD bond and 1 IMD for the maximum 10 IMD bond, i.e. roughly $0.20 to $9 at IMD = $9, against four mainnet transactions (~150k gas each; ~$30-60 at 30 gwei). The author of a wrong call is better off never observing (VoidNoData returns the bond and books the same -difficulty as WRONG), and no rational keeper closes it. The brief's rule 'WRONG ... forfeit it to the pools at once' and the pools' forfeit revenue therefore hold only when a third party pays to hurt the author. This is an incentive gap in my area (Economic Security: misaligned incentives), not a code bug; the hook cannot pay observers from a bond it must return on RIGHT, so the fix is a design choice (e.g. the author's stamp, or a slice of the bond on every non-RIGHT outcome, pays the observers of a complete series).","line":582,"path":"src/MarginaliaHook.sol","reproduction":"Fixture. alice posts a BUY call on MARG, +10% in 1 day, imdIn 0.6 IMD (bond 0.25). bob then sells 1,500,000 MARG so the price falls far below the target: the call is plainly wrong. Nobody calls observe (the reward for doing so would be 0.025 IMD). After horizonEnd + 6h + 1, anyone calls hook.settle(id): status VoidNoData, score -difficulty, deposit still 0.25. alice.claimDeposit(id) returns 0.25 IMD. Expected by the brief: WRONG forfeits the bond to the pools at once; actual: the pools receive nothing and the wrong author keeps the bond. The repository's own testNoDataRefunds (test/Lifecycle.t.sol) exercises exactly this path.","severity":"low","snippet":"        if (count < OBS_MIN || obs[count - 1].timestamp - obs[0].timestamp < OBS_MIN_SPAN) {\n            outcome = T.Status.VoidNoData;","title":"Forfeiture of a WRONG call is economically unenforced: the keeper reward never covers the three observations plus settle it needs, so wrong calls resolve VoidNoData and get the bond back"},{"citation":"resolved","description":"The hook taxes MARG sells only inside beforeSwap/afterSwap. It has no beforeAddLiquidity, beforeRemoveLiquidity or afterRemoveLiquidity permission (the brief fixes the flags at 0x20cc), so a holder who wants to exit without paying 3% (or 1% plus a stamp and a bond) adds a MARG-only position just above the current price and removes it once buyers have swapped through the range: the position is then IMD, the holder has sold MARG at the range's price, and the hook saw only buys, which it does not tax. The buyers paid the 1.25% LP fee to the seller instead of a sell fee to the pools. Cost to the seller: waiting for price to cross the range and the gas of two liquidity transactions. This is inherent to the chosen callbacks and cannot be fixed without changing the manifest's permissions, so it is recorded as a trust assumption / known limit rather than a defect to repair: the fee rule in the brief is a fee on swaps, not on exits.","line":236,"path":"src/MarginaliaHook.sol","reproduction":"Fixture (pool 1 MARG = 1 IMD). (1) bob holds 100,000 MARG. Instead of plain.swap (which pays 3%: on the fixture a 100,000 MARG sell yields ~96k IMD gross and 3% is minted to the hook), bob calls manager.modifyLiquidity on the launch pool key with tickLower = 60, tickUpper = 120 (just above the current tick 0) and a liquidity amount funded entirely in MARG; afterSwap is not invoked. (2) alice buys enough MARG (any router, no fee on buys) to move the tick past 120. (3) bob removes the position: the delta is all IMD plus his share of the 1.25% LP fee. hook claim balance of IMD is unchanged by bob's exit; thesisPool/refundPool received nothing. Expected by the brief's wording 'MARG sells pay 1%/3%'; actual: an exit via liquidity pays no hook fee.","severity":"info","snippet":"    function getHookPermissions() public pure returns (Hooks.Permissions memory p) {","title":"The 3%/1% sell fee is avoidable by selling MARG as a single-sided liquidity position, since flags 0x20cc carry no liquidity callbacks"}],"hash":"d4a6e8090f495ee90705027f642b04d95fefa80f0b5b4b9f55adec6b5e122a99","nodeId":"0151c4ed-b363-46ad-9492-4fa3c30cb427","outcome":"completed","summary":"Review complete. The findings file is written and validated, and no tracked file was changed.\n\n**What I did.** I read the Senior Auditor's Mindset and the Economic Security, Invariant and Flow Gap guides, then traced every value flow in the hook against them: the stamp, the 0.25 IMD MARG buy, the IMD bond band, the 70/30 accrual split, the writer refund, the weekly thesis prize, the keeper reward, seals, sweeps and the treasury drip. The repository's 186 local tests pass. I confirmed two findings with scratch tests under test/scratch/EconReview.t.sol, both passing on this tree.\n\n**Findings written to .imd-findings.json**\n\n- **Medium: one wallet can fill a week's 120 judged thesis slots and take the whole pool.** The cap at line 446 is global and first-come with no per-author limit. In the test, bob posted 120 theses plus 120 children for a net 24 IMD in stamps. Alice's thesis then reverted for the rest of the week. The panel could only rank bob, and he was paid the full 1188 IMD pool, funded by a drip and other sellers' fees.\n- **Low: a thesis child is accepted after the 7-day grace.** The child branch at line 475 checks only that the parent is still open. An author posts a child on day 8, settleThesis reverts forever, and the thesis bond comes back. The rule holds only if a keeper races for a 0.025 IMD reward.\n- **Low: forfeiture of a wrong call is economically unenforced.** Reaching WRONG needs three observations and a settle. The keeper's 10% of a bond pays at most 1 IMD against four mainnet transactions. Wrong calls resolve VoidNoData and return the bond.\n- **Info: the sell fee is avoidable via a single-sided liquidity exit** because the fixed flags carry no liquidity callbacks. Recorded as a known limit, not a repair item.\n\n**Coverage.** All 32 listed entry points have a row, plus three invariant rows. The hook's claim accounting, bond return and forfeit splits, pool movements and the no-MARG-claims rule all hold. I did not re-report the v4 single-block adverse observation or checkpoint poisoning, both documented in the README and ADAPTATION as accepted limits. No finding reached critical or high, so none carries a proof file.","treeHash":null,"usage":{"cachedInputTokens":2398643,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":63403,"runtime":"claude","turns":32,"wallClockMs":1080211}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"5835e48821d8827d","findings":[{"citation":"resolved","description":"Access x economics (Trust Gap seam 1). Posting a thesis is permissionless and the only limit is a global per-week cap of MAX_WEEK_THESES = 120 (mirroring the deployed judge's MAX_JUDGED). The cap is not per author and is consumed first-come. The week's thesis prize (70% of every stamp, fee, forfeit and drip of the week, paid 50/30/20 by payJudged) is ranked by the panel only among eligibleTheses(week), i.e. among the theses that got into weekTheses. An author (or one wallet, no Sybil needed) who posts 120 theses early in the week makes every later thesis of every other author revert InvalidNote for the rest of the week, so the panel can only rank that author's entries and the whole pool goes to that author (or rolls forward if the panel returns an empty head). Cost per thesis at the minimum: 0.6 IMD sent (0.1 stamp, 0.25 spent on MARG which the author keeps, 0.25 bond) plus one child call to become eligible (another 0.6 IMD; the child's 0.25 bond returns if RIGHT/VoidNoData or is forfeited on retract). For 120 pairs: 24 IMD of stamps of which 16.8 IMD lands in the very thesis pool the attacker now alone competes for, 60 IMD parked in MARG (recoverable minus the 3% quiet sell fee and 1.25% LP fee), and 30 IMD of thesis bonds that return once each child resolves. Net cash cost to lock out the week is roughly 7 to 12 IMD plus gas, against a prize of the week's entire thesis pool funded by everyone else. The repository's own test testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment (test/RevisionFindings.t.sol:216) already shows bob taking all 120 slots and alice being refused. A per-author cap alone is Sybil-able; the economic fix is a rising per-slot thesis price or a per-author/per-day limit combined with a higher thesis stamp, which is the requester's call since MAX_JUDGED is fixed in the deployed judge.","line":446,"path":"src/MarginaliaHook.sol","reproduction":"Week W, any day. Attacker bob calls router.note(p, key, 0.6 ether, 1, deadline) 120 times with p.targetBps = 0 (thesis) and distinct text; hook.thesesOfWeek(W).length == 120. Honest alice then calls router.note(thesis, key, 10 ether, 1, deadline): reverts InvalidNote at src/MarginaliaHook.sol:446. Bob posts one child call per thesis (parentId = thesis id, targetBps 11000, horizonDays 1) and retracts or lets them settle; judge.eligibleTheses(W) now lists only bob's theses. After the week, judge.requestJudging(W) and the panel's answer can only rank bob's ids; hook.payJudged pays 50/30/20 of thesisPool[W] to bob. Expected: other authors can enter the week's judged set; actual: they are locked out for about 10 IMD of net cost.","severity":"medium","snippet":"            if (weekTheses[_week()].length >= MAX_WEEK_THESES) revert InvalidNote();","title":"A week's 120 thesis slots are a shared first-come cap: one author can fill them all and exclude every other author from the week's judged prize"},{"citation":"resolved","description":"Asymmetry between the two writers of the thesis lifecycle. settleThesis (src/MarginaliaHook.sol:652) refuses to forfeit once n.children > 0 and only then checks THESIS_GRACE, while the child-post path (line 475) accepts a child whenever the parent is still ThesisOpen, with no check that block.timestamp <= postedAt + THESIS_GRACE. The spec says a thesis with no child within 7 days forfeits its bond (SPEC.md:52, the brief's 'needs a child call of the author within 7 days or forfeits'). Because settleThesis is a separate permissionless call, the author can post the child at any time before a keeper calls settleThesis, including by front-running that call, and the forfeit is blocked. Retracting the child then sets the thesis ThesisClosed through _resolveChild and claimDeposit returns the full thesis bond (up to 10 IMD). The pools lose the forfeit and the keeper the 10% bounty. Fix: in the child-post branch, require block.timestamp <= uint256(parent.postedAt) + THESIS_GRACE (or let settleThesis forfeit when the first child was posted after the grace).","line":475,"path":"src/MarginaliaHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {Marginalia} from \"src/Marginalia.sol\";\nimport {MarginaliaHook} from \"src/MarginaliaHook.sol\";\nimport {MarginaliaRouter} from \"src/MarginaliaRouter.sol\";\nimport {MarginaliaJudge} from \"src/MarginaliaJudge.sol\";\nimport {MarginaliaTreasury} from \"src/MarginaliaTreasury.sol\";\nimport {MarginaliaPricer} from \"src/MarginaliaPricer.sol\";\nimport {MarginaliaImpls} from \"src/MarginaliaImpls.sol\";\nimport {HookFlags} from \"src/HookFlags.sol\";\nimport {MarginaliaTypes as T} from \"src/MarginaliaTypes.sol\";\n\ncontract ScratchToken is ERC20 {\n    constructor(string memory n, string memory s, uint256 supply) ERC20(n, s) {\n        _mint(msg.sender, supply);\n    }\n}\n\ncontract ScratchLiquidity is IUnlockCallback {\n    IPoolManager public immutable manager;\n\n    constructor(IPoolManager m) {\n        manager = m;\n    }\n\n    function add(PoolKey memory key, int24 lower, int24 upper, int256 amount) external {\n        manager.unlock(abi.encode(key, ModifyLiquidityParams(lower, upper, amount, bytes32(0))));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager));\n        (PoolKey memory key, ModifyLiquidityParams memory p) = abi.decode(data, (PoolKey, ModifyLiquidityParams));\n        (BalanceDelta delta,) = manager.modifyLiquidity(key, p, \"\");\n        _settle(key.currency0, delta.amount0());\n        _settle(key.currency1, delta.amount1());\n        return \"\";\n    }\n\n    function _settle(Currency c, int128 d) private {\n        if (d < 0) {\n            manager.sync(c);\n            IERC20(Currency.unwrap(c)).transfer(address(manager), uint256(-int256(d)));\n            require(manager.settle() == uint256(-int256(d)));\n        } else if (d > 0) {\n            manager.take(c, address(this), uint256(uint128(d)));\n        }\n    }\n}\n\n/// @notice A thesis must have a child call within THESIS_GRACE (7 days) or forfeit its bond. The hook only\n/// checks `children == 0` inside settleThesis and accepts a child at any time while the thesis is ThesisOpen,\n/// so the author posts the child on day 8+ (front-running or simply preceding any settleThesis call), the\n/// forfeit is blocked, and the child's retraction releases the thesis bond.\ncontract ThesisGraceTest is Test {\n    using PoolIdLibrary for PoolKey;\n\n    IPoolManager manager;\n    Marginalia token;\n    ScratchToken imd;\n    MarginaliaHook hook;\n    MarginaliaRouter router;\n    PoolKey key;\n    address alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.roll(20_000_000);\n        manager = IPoolManager(address(new PoolManager(address(this))));\n        token = new Marginalia();\n        imd = new ScratchToken(\"IMD\", \"IMD\", 1_000_000_000 ether);\n        vm.etch(MarginaliaImpls.ROUTER_IMPL, address(new MarginaliaRouter()).code);\n        vm.etch(MarginaliaImpls.JUDGE_IMPL, address(new MarginaliaJudge()).code);\n        vm.etch(MarginaliaImpls.TREASURY_IMPL, address(new MarginaliaTreasury()).code);\n        vm.etch(MarginaliaImpls.PRICER, address(new MarginaliaPricer()).code);\n        bytes memory code = abi.encodePacked(type(MarginaliaHook).creationCode, abi.encode(manager, token, address(this)));\n        bytes32 h = keccak256(code);\n        for (uint256 i = 0; i < 300_000; ++i) {\n            address predicted = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(i), h)))));\n            if (!HookFlags.matches(predicted, HookFlags.MARGINALIA)) continue;\n            bytes32 salt = bytes32(i);\n            address deployed;\n            assembly (\"memory-safe\") {\n                deployed := create2(0, add(code, 32), mload(code), salt)\n            }\n            hook = MarginaliaHook(deployed);\n            break;\n        }\n        require(address(hook) != address(0), \"mining\");\n        router = hook.router();\n        (address c0, address c1) = address(token) < address(imd) ? (address(token), address(imd)) : (address(imd), address(token));\n        key = PoolKey(Currency.wrap(c0), Currency.wrap(c1), 12500, 60, IHooks(address(hook)));\n        manager.initialize(key, uint160(1 << 96));\n        ScratchLiquidity lp = new ScratchLiquidity(manager);\n        token.transfer(address(lp), 50_000_000 ether);\n        imd.transfer(address(lp), 50_000_000 ether);\n        lp.add(key, -6000, 6000, 10_000_000 ether);\n        imd.transfer(alice, 1_000 ether);\n        vm.prank(alice);\n        imd.approve(address(router), type(uint256).max);\n    }\n\n    function _p(T.Side side, uint32 target, uint16 horizon, string memory text) internal view returns (T.NoteParams memory p) {\n        p.x = address(token);\n        p.venue = T.Venue(T.VenueKind.UniV4, PoolId.unwrap(key.toId()), address(0), false);\n        p.side = side;\n        p.targetBps = target;\n        p.horizonDays = horizon;\n        p.class = uint8(T.Class.Declared);\n        p.text = text;\n    }\n\n    function testAChildPostedAfterTheGraceStillRescuesTheThesisBond() public {\n        // Day 0: a thesis with a 2 IMD bond (2.35 sent: 0.1 stamp, 0.25 MARG buy, 2 bond).\n        vm.prank(alice);\n        router.note(_p(T.Side.Buy, 0, 0, \"thesis\"), key, 2.35 ether, 1, vm.getBlockTimestamp() + 1);\n        bytes32 tid = bytes32(hook.noteCount());\n        assertEq(hook.noteOf(tid).deposit, 2 ether);\n\n        // Day 8: no child was posted inside THESIS_GRACE. The spec says the thesis forfeits now.\n        vm.warp(vm.getBlockTimestamp() + hook.THESIS_GRACE() + 1 days);\n        vm.roll(vm.getBlockNumber() + 50_000);\n\n        // The author posts the child anyway (a fresh checkpoint is all a priced post needs).\n        router.checkpointVenue(_p(T.Side.Buy, 11_000, 1, \"cp\"), key);\n        vm.warp(vm.getBlockTimestamp() + 1 hours);\n        vm.roll(vm.getBlockNumber() + 300);\n        T.NoteParams memory child = _p(T.Side.Buy, 11_000, 1, \"late child\");\n        child.parentId = tid;\n        vm.prank(alice);\n        router.note(child, key, 0.6 ether, 1, vm.getBlockTimestamp() + 1);\n        bytes32 cid = bytes32(hook.noteCount());\n\n        // Expected: a thesis with no child inside the grace forfeits. Actual: the late child blocks the forfeit.\n        hook.settleThesis(tid);\n        assertEq(uint8(hook.noteOf(tid).status), uint8(T.Status.ThesisForfeited), \"thesis should have forfeited\");\n        cid; // the author would now retract the child to release the thesis and claim its bond\n    }\n}","reproduction":"Day 0: alice posts a thesis with router.note(targetBps 0, imdIn 2.35 IMD) -> deposit 2 IMD. Day 8 (THESIS_GRACE + 1 day): nobody has called settleThesis yet. alice checkpoints the venue, waits one hour, and posts a child call with parentId = thesis id (router.note(..., 0.6 IMD)). Then anyone calls hook.settleThesis(thesisId): reverts NotOpen because children == 1. alice calls hook.retract(childId, \"\") and then hook.claimDeposit(thesisId): receives the 2 IMD bond. Expected: the thesis forfeits (ThesisForfeited, 1.8 IMD to the pools, 0.2 IMD to the keeper). Actual: the bond is recoverable in full. The proof test posts the late child and asserts settleThesis forfeits; it fails with NotOpen on the current code.","severity":"low","snippet":"                    if (parent.status != T.Status.ThesisOpen) revert InvalidNote();\n                    parent.children += 1;","title":"The 7-day thesis grace is not enforced when the child is posted: a child on day 8 or later blocks the forfeit and releases the thesis bond"},{"citation":"resolved","description":"Asymmetry in the slot rule: only a reading MORE adverse to the call may replace the latest slot; a less adverse (honest) reading inside the 20-block gap reverts ObservationTooSoon, and after the gap it is appended as a new slot without removing the hostile one. MarginaliaPricer.settlePrice then takes the extreme across ALL slots for v4 venues and the hub leg, so one hostile reading decides the outcome. The comment at lines 511-513 ('a pump-observe-unwind in one block is overwritten by any honest reading in the next ... a pump has to be held for the whole span') and SPEC.md:78 ('A two-block pump-observe-unwind ... moves neither rule') are therefore wrong for the adverse direction; README 'known limits' states it correctly ('A single hostile observation can push a genuine call to WRONG'). The requester previously disputed this as design (ec6beba1), so this is recorded as a documentation defect plus the trust-gap amplifier the dispute did not weigh: the attacker needs no capital at risk across blocks (dump, observe and buy back are one transaction, so no arbitrage exposure), and settle() pays msg.sender 10% of the forfeited bond (KEEPER_BPS), so on a thin hookless v4 venue the attacker's round-trip fee can be below 10% of a 10 IMD bond. Verified locally with test/scratch/AdverseSlot.t.sol (not a proof file): alice's +10% BUY call with the price held +25% by bob settles Wrong after carol's one-transaction sell, observe, buy-back; carol's honest-direction re-observe one block later reverts ObservationTooSoon, and the two later honest slots do not rescue it.","line":527,"path":"src/MarginaliaHook.sol","reproduction":"On the Fixture: alice router.note(BUY, 11000 bps, 1 day) on the launch pool; bob buys 1.3M IMD of MARG and holds, price > 1.1x baseline. At horizonEnd: anyone observes (honest). Next block, carol in one transaction: plain.swap sells 3M MARG (price < 1.1x baseline), hook.observe(id) (more adverse, replaces slot 0), plain.swap buys the IMD back (price restored). One block later an honest hook.observe(id) reverts ObservationTooSoon. Two more honest observations at +31 and +62 minutes (25 blocks apart) are appended. After the window hook.settle(id): status Wrong, alice's bond forfeited, 10% to the settler. Expected per the code comment and SPEC: Right, because the honest readings overwrite a one-block pump. Actual: Wrong.","severity":"low","snippet":"            if (!_moreAdverse(n, o, obs[len - 1])) revert ObservationTooSoon();\n            obs[len - 1] = o;","title":"One single-transaction dump, observe, buy-back by any third party settles a genuinely RIGHT v4 call as WRONG; the comment on observe() and SPEC 4.3 claim the opposite"},{"citation":"resolved","description":"Asymmetry between claimRefund and retract. claimRefund only needs n.day < today and status != Retracted; retract only needs block.timestamp < horizonEnd. For any call with horizonDays >= 1 posted before the day's end there is a window (from 00:00 UTC of the next day until the horizon) in which the author first claims the refund and then retracts. retract's accounting (line 637, 'A retracted note never claims its writer refund') skips the notesPerDay decrement when the refund was already claimed, so the day's split stays consistent, but the refund (up to one stamp, 0.1 IMD, from a pool funded by other writers, quiet-sell fees, forfeits and drips) stays with a note the spec excludes from the split. No profit: the retraction forfeits at least the 0.25 IMD bond. Recorded for completeness of the paired-function check.","line":830,"path":"src/MarginaliaHook.sol","reproduction":"Day d at 23:00: alice router.note(BUY, 11000, horizonDays 2, 1 IMD). Day d+1 at 00:01: hook.claimRefund(id) pays min(refundPool[d]/notesPerDay[d], 0.1 IMD) to alice. Day d+1 at 12:00 (before horizonEnd = d+2 23:00): hook.retract(id, \"changed my mind\") succeeds; status Retracted, refund kept. Expected per the rule in retract: a retracted note takes no refund. Actual: it already did.","severity":"info","snippet":"        if (refundClaimed[id] || n.status == T.Status.Retracted) revert NothingToClaim();","title":"A note can claim its writer refund on the next day and then retract before its horizon, keeping the refund the retract rule says it never gets"}],"hash":"e00feb914d29fdfd72ebb90bca0b72112e64397b272e1a9804ac2921e28d0911","nodeId":"5adc9209-8a46-44f1-8179-108dde60d164","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds 4 findings and a coverage row for all 32 listed entry points plus two invariants. Nothing outside `test/scratch/` and the findings file was touched.\n\n**What I audited.** The Access Control, Asymmetry and Trust Gap passes over the hook, the router, judge and treasury clones, and the pricer. I mapped every guard (`onlyManager`, router-only `DATA_NOTE`, judge-only draw and pay, author-only retract, claim and refund, hook-only `init` on the clones), traced the claim accounting through every accrual and payout path, and diffed the paired functions (note vs sellWithNote, claimRefund vs retract, child-post vs settleThesis, observe vs settle). The local suite passes (186 tests). The fork suite was not run because no `MAINNET_RPC_URL` is available.\n\n**Findings, most severe first:**\n\n- **Medium, weekly thesis slots can be bought out.** The 120-thesis cap in `_postNote` is global and first-come. One wallet posting 120 theses locks every other author out of the week's judged prize for about 7 to 12 IMD net, since most of its own stamps land in the pool it then alone competes for. The repo's own 121st-thesis test already demonstrates the lockout.\n- **Low, thesis grace not enforced at child-post time.** A child posted on day 8 or later still blocks `settleThesis`, and retracting that child releases the thesis bond in full. Proof test written under `test/scratch/ThesisGrace.t.sol`, which fails with `NotOpen` on the current code.\n- **Low, single-transaction hostile observation decides a v4 settlement.** A third party's dump, observe, buy-back in one transaction settles a genuinely right call as wrong. An honest reading in the next block reverts with `ObservationTooSoon`. The requester disputed this as design earlier, but the comment on `observe` and SPEC §4.3 state the opposite protection, and the 10% keeper bounty gives the attacker a payout the dispute did not weigh. Verified locally.\n- **Info, refund then retract.** A note can claim its writer refund on the next UTC day and retract before its horizon, keeping the refund the retract rule says it never gets. No profit, since the retraction forfeits at least the bond.\n\n**What held.** No owner, admin, pause, upgrade or setter exists anywhere. Clone initialisers are locked on the implementations and callable once by the hook. The hook's claim balance is conserved across every accrual and payout. The `beforeInitialize` binding, the hookData sender checks, the unlock callbacks and the oracle callback's signer, chain and quorum checks all behave as specified. The judge's missing `questionHash` and `requestId` binding remains the known, documented limitation of the deployed companion.","treeHash":null,"usage":{"cachedInputTokens":4189744,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":72587,"runtime":"claude","turns":48,"wallClockMs":1426998}},{"artifacts":[],"attempt":2,"bundleHash":"65a9f7e7da5b2b0cbc91e2ad8a84dc4e12db7deb8b344eff3bf34df7666b5abb","device":"fdbedee33322a6ef","findings":[],"hash":"f3c85d37898ef0c69cdba6c9a1b260b1c581d99f0185bf9eeed5b08a96004eef","nodeId":"b37a4aed-d9ff-46ff-9ae3-e0e5be58442f","outcome":"completed","summary":"The hook launch is ready to hand over. `forge build` passes, and `forge test --no-match-path 'test/fork/*'` passes 186 of 186: the 178 tests the project shipped with, plus 8 new ones. The mainnet fork suite did not run because there is no `MAINNET_RPC_URL` on this machine, so the live companions were not re-checked this round. Nothing is committed.\n\nThe launch setup itself needed no changes. The token's and hook's constructors were already in the shape the factory needs. The hook has no owner, pause, upgrade or setter, and its deployed code is 22,770 bytes, under the 24,576 limit. I ran the two supplied launch checks (hook and token) unchanged from `test/scratch/`, with the launch's own values; all 11 passed, including building the hook on a chain where the companion addresses have no code.\n\n**Audit findings I reproduced and fixed** (one test each in `test/LaunchAuditFindings.t.sol`; only `src/MarginaliaHook.sol` changed):\n- **Seal hijack (high):** a stranger could seal someone else's note to delay it and price it off another market, and an author could seal one market's price and post on another. Seals are now stored per sealer and record which token and market they priced. A note uses only its author's own seal of that same token and market; any other seal is ignored.\n- **Stuck settlement (medium):** a note token whose `totalSupply()` reverts or is absurdly large could block `settle` and `retract` forever. The supply is now read with a gas cap; a failed read or an overflow counts as the lowest market-cap tier.\n- **Writer refund (low):** retracted notes no longer count when a day's refund is split, so each remaining note gets its full share.\n- **Expired seals (low):** a seal past 6 hours can now be replaced, and posting the note clears the seal.\n- **Failing test (info):** one existing test asserted a gas measurement that no longer holds on this toolchain. It now checks the actual rule (the judge keeps only the top three) whichever way the gas falls.\n- **`launch.json` (low):** it was incomplete (no opening price, mixed-case IMD address), so I deleted it rather than write it; the manifest step writes it after this one.\n\n**Left alone, with reasons in ADAPTATION.md:**\n- **Judge ignores `questionHash` (low):** this reproduces, but the check belongs in the judge, and the hook clones the live judge you told me not to redeploy. Fixing it needs a new judge implementation, which is your call.\n- **The four informational findings:** these are behaviour the brief asks for or already documented, so nothing changed.\n\nADAPTATION.md now opens with this launch's changes and results. The README's sealed-notes section describes the new seal rules.","treeHash":"99a27c9909c8e187114a77dabae62d95e42ce95d","usage":{"cachedInputTokens":2889732,"inputTokens":56,"model":"claude-opus-5-5","outputTokens":29948,"runtime":"claude","turns":29,"wallClockMs":1369859}}],"verification":[{"checks":[{"durationMs":238966,"exitCode":0,"name":"build","output":"Compiling 118 files with Solc 0.8.26\nSolc 0.8.26 finished in 238.74s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n   --> src/MarginaliaHook.sol:859:9:\n    |\n859 |         uint256 pool = thesisPool[w];\n    |         ^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> src/MarginaliaHook.sol:99:5:\n   |\n99 |     PoolKey private pool;\n   |     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n   --> src/MarginaliaHook.sol:299:5:\n    |\n299 |     function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata data)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/helpers/Fixture.sol:114:5:\n    |\n114 |     function priceOf(bytes32, address) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  --> test/fork/MainnetLaunch.t.sol:78:5:\n   |\n78 |     function _mine(bytes memory hookCode) internal view returns (bytes32 salt) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[missing-events-access-control]: `jobHash` is changed without an event but is used for access control\n    ╭▸ src/MarginaliaRouter.sol:303:16\n    │\n303 │         delete jobHash;\n    │                ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:114:47\n    │\n114 │         for (uint256 i = 0; i < all.length && n < MAX_JUDGED; ++i) {\n    │                                               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[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/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaHook.sol:84:38\n   │\n84 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' 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/MarginaliaJudge.sol:170:15\n    │\n170 │             ++n;\n    │               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:174:33\n    │\n174 │             out[i - 1] = bytes1(uint8(48 + v % 10));\n    │                                 ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:186:52\n    │\n186 │         return eligibleTheses(week).length == 0 || block.timestamp >= (uint256(week) + 1) * 7 days + 28 days;\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/MarginaliaJudge.sol:194:32\n    │\n194 │         if (judgedSet[week] || block.timestamp < requestedAt[week] + ANSWER_DEADLINE) {\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:214:9\n    │\n214 │         hook.drawForJudging(day, price, retry);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:217:21\n    │\n217 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n218 │ ┃             action, body, IIntake.Callback(address(this), this.onOracleResult.selector), imd, price\n219 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:206:41\n    │\n206 │         if (judgedSet[day] || (retry && block.timestamp < requestedAt[day] + ANSWER_DEADLINE)) {\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/MarginaliaJudge.sol:225:9\n    │\n225 │         emit Requested(day, requestId, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:223:28\n    │\n223 │         requestedAt[day] = uint64(block.timestamp);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaJudge.sol:255:9\n    │\n255 │ ┏         emit Judged(\n256 │ ┃             day,\n257 │ ┃             [\n258 │ ┃                 count > 0 ? ranked[0] : bytes32(0),\n    ‡ ┃\n262 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:269:50\n    │\n269 │         for (uint256 i = 0; i < ranked.length && kept < 3; ++i) {\n    │                                                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:276:17\n    │\n276 │             if (dup) continue;\n    │                 ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:270:77\n    │\n270 │             (address author, uint32 noteWeek, bool thesis, bool hasChild) = hook.noteMeta(ranked[i]);\n    │                                                                             ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaJudge.sol:288:9\n    │\n288 │         hook.payJudged(day, top);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaRouter.sol:251:13\n    │\n251 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:252:41\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:252:49\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/MarginaliaPricer.sol:85:13\n   │\n85 │             n += 1;\n   │             ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:120:33\n    │\n120 │         if (w.startedAt == 0 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:34\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:59\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:142:20\n    │\n142 │                 || block.timestamp < uint256(w.startedAt) + POST_MIN_SPAN\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/MarginaliaPricer.sol:143:20\n    │\n143 │                 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE\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/MarginaliaRouter.sol:338:9\n    │\n338 │         emit Noted(job.payer, job.sellMarg, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:149:69\n    │\n149 │             x = twap(v.kind, v.xIsToken0, w.xStart, w.startedAt, x, uint64(block.timestamp));\n    │                                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:320:18\n    │\n320 │                 -int256(job.amountIn),\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/MarginaliaRouter.sol:328:25\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:168:55\n    │\n168 │         else if (v.kind == T.VenueKind.UniV3) xRead = uint256(_v3Cumulative(ref));\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/MarginaliaRouter.sol:328:33\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:329:28\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:329:36\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\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/MarginaliaPricer.sol:213:28\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:213:41\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:214:35\n    │\n214 │             int256 mean = delta / int256(dt);\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/MarginaliaPricer.sol:215:38\n    │\n215 │             if (delta < 0 && delta % int256(dt) != 0) mean -= 1; // round toward negative infinity, as v3 does\n    │                                      ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:373:9\n    │\n373 │         emit XTraded(payer, X_V4, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:217:57\n    │\n217 │             return fromSqrt(TickMath.getSqrtPriceAtTick(int24(mean)), xIsToken0);\n    │                                                         ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' 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/MarginaliaRouter.sol:355:18\n    │\n355 │                 -int256(x.amountIn),\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/MarginaliaRouter.sol:363:25\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:363:33\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:364:20\n    │\n364 │         received = uint256(uint128(outputDelta));\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:364:28\n    │\n364 │         received = uint256(uint128(outputDelta));\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/MarginaliaPricer.sol:241:37\n    │\n241 │             (uint160 sqrtP,,,,,,) = IUniswapV3PoolOracle(ref).slot0();\n    │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:245:41\n    │\n245 │             (uint112 r0, uint112 r1,) = IUniswapV2PairOracle(ref).getReserves();\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:269:33\n    │\n269 │         (int56[] memory cum,) = IUniswapV3PoolOracle(pool).observe(ago);\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/MarginaliaRouter.sol:403:9\n    │\n403 │         emit XTraded(payer, X_V3, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:394:13\n    │\n394 │             int256(x.amountIn),\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/MarginaliaRouter.sol:399:25\n    │\n399 │         uint256 spent = uint256(zeroForOne ? a0 : a1);\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/MarginaliaPricer.sol:279:24\n    │\n279 │         uint32 nowTs = uint32(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/MarginaliaTreasury.sol:51:9\n   │\n51 │         emit Dripped(day, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaTreasury.sol:43:22\n   │\n43 │         uint32 day = uint32(block.timestamp / 1 days);\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:409:78\n    │\n409 │         if (amount0Delta > 0) IERC20(pool.token0()).safeTransfer(msg.sender, uint256(amount0Delta));\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/MarginaliaRouter.sol:410:78\n    │\n410 │         if (amount1Delta > 0) IERC20(pool.token1()).safeTransfer(msg.sender, uint256(amount1Delta));\n    │                                                                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:438:9\n    │\n438 │         emit XTraded(payer, X_V2, xIn, xOut, actualIn, received);\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/MarginaliaRouter.sol:426:37\n    │\n426 │         (uint112 r0, uint112 r1,) = pair.getReserves();\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:312:49\n    │\n312 │                 specifiedTake = STAMP + _bondOf(uint256(-params.amountSpecified));\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:389:9\n    │\n389 │         emit Accrued(day, amount);\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/MarginaliaHook.sol:471:17\n    │\n471 │                 emit Revealed(id, hash);\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/MarginaliaHook.sol:495:9\n    │\n495 │         emit NotePosted(id, author, p.x, class, p.side, p.targetBps, p.horizonDays, p.parentId, p.text);\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/MarginaliaHook.sol:348:13\n    │\n348 │             emit SwapFee(true, author, poolImd, 0, STAMP);\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/MarginaliaHook.sol:361:13\n    │\n361 │             emit SwapFee(false, author, poolImd, fee - STAMP, STAMP);\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/MarginaliaHook.sol:372:9\n    │\n372 │         emit SwapFee(false, tx.origin, poolImd, quietFee, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:335:33\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:41\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:63\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:71\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:340:36\n    │\n340 │             uint256 bond = _bondOf(uint256(-params.amountSpecified));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:342:31\n    │\n342 │             uint256 margOut = uint256(uint128(margDelta));\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/MarginaliaHook.sol:342:39\n    │\n342 │             uint256 margOut = uint256(uint128(margDelta));\n    │                                       ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:450:17\n    │\n450 │             if (weekTheses[w].length >= MAX_WEEK_THESES || thesesPerAuthor[w][author] >= MAX_AUTHOR_THESES) {\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/MarginaliaHook.sol:450:60\n    │\n450 │             if (weekTheses[w].length >= MAX_WEEK_THESES || thesesPerAuthor[w][author] >= MAX_AUTHOR_THESES) {\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/MarginaliaHook.sol:465:26\n    │\n465 │             if (bound && age < SEAL_MIN) revert TooEarly(); // the head start is the key holders', not the public's\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/MarginaliaHook.sol:466:26\n    │\n466 │             if (bound && age <= SEAL_MAX) {\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/MarginaliaHook.sol:484:32\n    │\n484 │ …                     || block.timestamp > uint256(parent.postedAt) + THESIS_GRACE\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:442:22\n    │\n442 │         n.postedAt = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:540:13\n    │\n540 │         if (block.timestamp < end) revert TooEarly();\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/MarginaliaHook.sol:541:13\n    │\n541 │         if (block.timestamp > end + SETTLE_WINDOW) revert TooLate();\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/MarginaliaHook.sol:554:47\n    │\n554 │                     || (len == OBS_MAX - 1 && block.timestamp < uint256(obs[0].timestamp) + OBS_MIN_SPAN))\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/MarginaliaHook.sol:562:9\n    │\n562 │         emit Observed(id, xRead, balance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:546:27\n    │\n546 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:546:52\n    │\n546 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                                                    ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:570:13\n    │\n570 │             x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.balanceOf.selector, who));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaHook.sol:651:35\n    │\n651 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │                                   ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:607:13\n    │\n607 │         if (block.timestamp <= end + SETTLE_WINDOW) revert TooEarly();\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/MarginaliaHook.sol:736:13\n    │\n736 │             emit ThesisReleased(n.parentId);\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/MarginaliaHook.sol:651:9\n    │\n651 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:634:26\n    │\n634 │             scoreDelta = int256(_difficulty(n));\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/MarginaliaHook.sol:639:27\n    │\n639 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:641:27\n    │\n641 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:645:27\n    │\n645 │             scoreDelta = -int256(_difficulty(n));\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[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:669:17\n    │\n669 │             try pricer().settlePrice(n.venue, buy, sample) returns (uint256 p) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:683:13\n    │\n683 │         if (block.timestamp >= horizonEnd(id)) revert TooLate();\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/MarginaliaHook.sol:693:9\n    │\n693 │         emit Retracted(id, text);\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/MarginaliaHook.sol:694:9\n    │\n694 │         emit Settled(id, T.Status.Retracted, 0, scoreDelta, address(0));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:687:30\n    │\n687 │         int256 scoreDelta = -int256(_difficulty(n) / 2);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:702:13\n    │\n702 │         if (block.timestamp <= uint256(n.postedAt) + THESIS_GRACE) revert TooEarly();\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/MarginaliaHook.sol:705:9\n    │\n705 │         emit ThesisForfeited(id);\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/MarginaliaHook.sol:719:9\n    │\n719 │         emit DepositClaimed(id, n.author, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:749:13\n    │\n749 │             n.x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.totalSupply.selector));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:758:16\n    │\n758 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:762:16\n    │\n762 │         return uint32(block.timestamp / 7 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:782:9\n    │\n782 │         emit PotFunded(_today(), amount, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `seals` is updated\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:816:25\n    │\n816 │         if ((at != 0 && block.timestamp - at <= SEAL_MAX) || x == address(0) || hash == bytes32(0)) {\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/MarginaliaHook.sol:830:9\n    │\n830 │         emit Sealed(hash, msg.sender, x, venue.ref);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:824:13\n    │\n824 │             uint64(block.timestamp),\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:837:23\n    │\n837 │         if (!retry && block.timestamp < (uint256(w) + 1) * 7 days + THESIS_GRACE) revert TooEarly();\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:851:27\n    │\n851 │         return (n.author, uint32(uint256(n.postedAt) / 7 days), n.targetBps == 0, n.children > 0);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `thesisPool` is updated\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:873:9\n    │\n873 │         emit JudgedPaid(w, paidAmounts);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaHook.sol:926:39\n    │\n926 │         if (unlockHash != bytes32(0)) revert InvalidUnlock();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:880:13\n    │\n880 │         if (n.day >= _today()) revert TooEarly();\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/MarginaliaHook.sol:890:9\n    │\n890 │         emit RefundClaimed(id, msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:888:30\n    │\n888 │         notesPerDay[n.day] = uint32(count - 1);\n    │                              ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:899:17\n    │\n899 │             if (block.timestamp < (uint256(epoch) + 1) * 1 days + SWEEP_AFTER) revert TooEarly();\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/MarginaliaHook.sol:903:17\n    │\n903 │             if (block.timestamp < (uint256(epoch) + 1) * 7 days + SWEEP_AFTER) revert TooEarly();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:936:40\n    │\n936 │             address currency = address(uint160(extra));\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[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaHook.sol:945:13\n    │\n945 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/AuditFindings.t.sol:19:30\n   │\n19 │         uint256 startBlock = block.number;\n   │                              ━━━━━━━━━━━━\n   ‡\n23 │             vm.roll(startBlock + 25 * (i + 1));\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/AuditFindings.t.sol:20:27\n   │\n20 │         uint256 startTs = block.timestamp;\n   │                           ━━━━━━━━━━━━━━━\n   ‡\n24 │             vm.warp(startTs + 31 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:18:9\n    │\n 18 │         vm.warp(hook.horizonEnd(id));\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:65:9\n    │\n 65 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookBoundaries.t.sol:347:9\n    │\n347 │         vm.warp(deadline - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:82:9\n    │\n 82 │         vm.warp(deadline - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:193:9\n    │\n193 │         vm.warp(weekEnd - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:195:9\n    │\n195 │         vm.warp(weekEnd + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:148:9\n    │\n148 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:149:30\n    │\n149 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n153 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:150:27\n    │\n150 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n154 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:176:9\n    │\n176 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:177:30\n    │\n177 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n181 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:178:27\n    │\n178 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n182 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:203:9\n    │\n203 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:204:30\n    │\n204 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n208 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:205:27\n    │\n205 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n209 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:302:9\n    │\n302 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:357:9\n    │\n357 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:358:30\n    │\n358 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n363 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:359:27\n    │\n359 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n364 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:421:9\n    │\n421 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:488:9\n    │\n488 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:489:30\n    │\n489 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n492 │         vm.roll(startBlock + 25);\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/Lifecycle.t.sol:490:27\n    │\n490 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n493 │         vm.warp(startTs + 30 minutes);\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:512:9\n    │\n512 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:513:30\n    │\n513 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n517 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:514:27\n    │\n514 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n518 │             vm.warp(startTs + 10 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:554:9\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:538:49\n    │\n538 │         router.note(rebuttal, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:554:17\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:583:9\n    │\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:575:49\n    │\n575 │         router.note(sameSide, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:584:30\n    │\n584 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n589 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:585:27\n    │\n585 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n590 │             vm.warp(startTs + 30 minutes * (i + 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/Lifecycle.t.sol:629:22\n    │\n629 │         assertEq(at, block.timestamp);\n    │                      ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:634:42\n    │\n634 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:638:17\n    │\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:653:17\n    │\n653 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:657:42\n    │\n657 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:663:17\n    │\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:679:17\n    │\n679 │         vm.warp(block.timestamp + hook.SEAL_MAX() + 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/Lifecycle.t.sol:682:17\n    │\n682 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:199:17\n    │\n199 │         vm.warp(block.timestamp + 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:267:9\n    │\n267 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/Round3Findings.t.sol:67:17\n   │\n67 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":7400,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/MainnetLaunch.t.sol:MainnetLaunchTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 547.15µs (0.00ns CPU time)\n\nRan 7 tests for test/Pricer.t.sol:PricerTest\n[PASS] testQuoteLegIsAdverseEvenUnderAV3Twap() (gas: 28455)\n[PASS] testTwapRefusesZeroSpanAndV4() (gas: 17708)\n[PASS] testV2TwapFromWrappingCumulative() (gas: 9503)\n[PASS] testV3TwapOfAConstantTickIsThatTick() (gas: 15459)\n[PASS] testV3TwapRoundsNegativeMeansDown() (gas: 14848)\n[PASS] testV3TwapWeightsByTime() (gas: 14715)\n[PASS] testV4SettlesOnTheAdverseExtreme() (gas: 26636)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 873.52µs (737.80µs CPU time)\n\nRan 14 tests for test/CompanionFailures.t.sol:RouterFailuresTest\n[PASS] testExpiredDeadlineTakesNothing() (gas: 668139)\n[PASS] testExpiredWindowRefusesPostsUntilAFreshCheckpointMatures() (gas: 1756378)\n[PASS] testInitRequiresAManagerWithCode() (gas: 4169863)\n[PASS] testSlippageFloorRefundsEverything() (gas: 639941)\n[PASS] testStrangersCannotEnterTheCallbacks() (gas: 133302)\n[PASS] testTradeAndNoteRefusesNoTradeZeroTradeAndNativeInput() (gas: 290673)\n[PASS] testTradedNoteMustBeAboutTheTokenTraded() (gas: 980650)\n[PASS] testTradedV4LegUnderAForeignHookOrEmptyPoolIsRefused() (gas: 396113)\n[PASS] testUnapprovedOrUnfundedAuthorIsRefused() (gas: 224265)\n[PASS] testV4VenueUnderAForeignHookIsRefused() (gas: 69759)\n[PASS] testV4VenueWithoutLiquidityIsRefused() (gas: 134961)\n[PASS] testVenueFieldsAreDerivedFromThePoolNotTheCaller() (gas: 48554)\n[PASS] testVenueKindNoneIsRefusedForAPricedCall() (gas: 116223)\n[PASS] testZeroAndOversizedAmountsAreRefused() (gas: 138593)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 10.38ms (5.18ms CPU time)\n\nRan 6 tests for test/AuditFindings.t.sol:AuditFindingsTest\n[PASS] testEmptyV4ObservationIsRefused() (gas: 918993)\n[PASS] testExpiredBaselineRejectsPostWithoutTakingFunds() (gas: 601798)\n[PASS] testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried() (gas: 2111077)\n[PASS] testSameBlockDumpPostUnwindDoesNotWinBuy() (gas: 1822381)\n[PASS] testSameBlockPumpPostUnwindDoesNotWinSell() (gas: 1691295)\n[PASS] testUnpayableRankingRollsTheWholePoolForward() (gas: 2384827)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 11.42ms (4.87ms CPU time)\n\nRan 8 tests for test/LaunchAuditFindings.t.sol:LaunchAuditFindingsTest\n[PASS] testAHugeSupplyBooksTierOneInsteadOfOverflowing() (gas: 2461200)\n[PASS] testALapsedSealCanBeSealedAgain() (gas: 703279)\n[PASS] testARetractedNoteLeavesTheDaysRefundSplit() (gas: 1382965)\n[PASS] testARetractionAfterTheRefundClaimDoesNotDoubleCount() (gas: 1359071)\n[PASS] testARevertingTotalSupplyDoesNotBlockARetraction() (gas: 1932201)\n[PASS] testARevertingTotalSupplyStillSettlesWrongAndPaysTheKeeper() (gas: 2554573)\n[PASS] testAStrangersSealNeitherBlocksNorPricesTheAuthorsNote() (gas: 2518397)\n[PASS] testAnAuthorsSealOnAnotherVenueDoesNotPriceTheNote() (gas: 2235395)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 16.64ms (11.30ms CPU time)\n\nRan 12 tests for test/HoldRule.t.sol:HoldRuleTest\n[PASS] testABreachIsNeverReplacedByANonBreachInsideTheGap() (gas: 1653878)\n[PASS] testABreachReplacesANonBreachInsideTheGap() (gas: 1661691)\n[PASS] testABuyCallWithAnUnreadableBalanceIsVoidSold() (gas: 1484869)\n[PASS] testASellAuthorMayDumpTheirWholeRemainingBalance() (gas: 1622310)\n[PASS] testASellAuthorWhoBuysBackTheirWholePostBalanceIsStillRight() (gas: 1717897)\n[PASS] testASellCallWithAnUnreadableBalanceStillSettlesOnPrice() (gas: 1510057)\n[PASS] testASellCallsBalanceIsNeverAnAdverseReading() (gas: 1360897)\n[PASS] testAWrongSellCallForfeitsWhateverTheBalanceDid() (gas: 1426628)\n[PASS] testAnEqualReadingInsideTheGapIsRefused() (gas: 1031930)\n[PASS] testAtTheCapAHigherReadingCannotLiftABuyCallsMinimum() (gas: 3939441)\n[PASS] testAtTheCapOnlyAMoreAdverseReadingGetsIn() (gas: 4186133)\n[PASS] testBuyCallHasNoToleranceDownwards() (gas: 1570913)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 18.22ms (11.36ms CPU time)\n\nRan 7 tests for test/JudgeOracle.t.sol:JudgeOracleTest\n[PASS] testEmptySignedRankingIsAnExecutableNoWinnerResult() (gas: 248153)\n[PASS] testFiveIdsWithEoaSignatureFitStipend() (gas: 554052)\n[PASS] testFullRankingWithEoaSignatureFitsStipend() (gas: 633672)\n[PASS] testProtocolDigestSignatureAndSelectorConformanceOnClone() (gas: 3322442)\n[PASS] testRejectedAnswersDoNotConsumeThePendingRequest() (gas: 892875)\n[PASS] testRequestedHeadIsFilteredAndDeduplicatedWithoutPromotingTheTail() (gas: 250679)\n[PASS] testTimeoutRetryInvalidatesOldIntakeRequest() (gas: 523953)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 5.29ms (4.13ms CPU time)\n\nRan 10 tests for test/Round3Findings.t.sol:Round3FindingsTest\n[PASS] testABuyCallStillBreaksWhenTheAuthorSells() (gas: 1669522)\n[PASS] testAGiftOfAnySizeDoesNotVoidACorrectSellCall() (gas: 1584170)\n[PASS] testAGiftWorthTheDepositDoesNotVoidACorrectSellCall() (gas: 1663423)\n[PASS] testALaunchPoolCallScoresTheSameWay() (gas: 1417891)\n[PASS] testASelfPricedVenueBooksReputationOnlyAndNoPoolPaysForIt() (gas: 3007470)\n[PASS] testAWrongCallOnAnotherVenueStillForfeitsAndBooksANegativeScore() (gas: 2707061)\n[PASS] testAWrongSellCallStillForfeits() (gas: 1395988)\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 256, μ: 21712, ~: 19145)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1945010)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204563)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 29.56ms (23.48ms CPU time)\n\nRan 31 tests for test/Lifecycle.t.sol:LifecycleTest\n[PASS] testAttestedClassCannotBeSelfDeclared() (gas: 294892)\n[PASS] testCallbackSelectorPinned() (gas: 3383)\n[PASS] testCounterCallDuel() (gas: 3589375)\n[PASS] testCounterThesisEntersTheJudgedSet() (gas: 2688706)\n[PASS] testFakeVenueIsRefused() (gas: 382766)\n[PASS] testFlagsAndBinding() (gas: 56048)\n[PASS] testForfeitsAreImdAndNeedNoConversion() (gas: 861195)\n[PASS] testNoDataRefunds() (gas: 880570)\n[PASS] testNoteTooSmall() (gas: 1644543)\n[PASS] testNotedBuyTakesStampAndDeposit() (gas: 729443)\n[PASS] testNotedSellPaysOnePercentPlusStamp() (gas: 988516)\n[PASS] testObservationsMustSpanAnHour() (gas: 1384019)\n[PASS] testPlainBuyTakesNothing() (gas: 211688)\n[PASS] testQuietSellPaysThreePercent() (gas: 295440)\n[PASS] testQuietThesisPoolSweeps() (gas: 300271)\n[PASS] testRetract() (gas: 866644)\n[PASS] testRightCallReturnsDeposit() (gas: 1623568)\n[PASS] testScoreIsReputationAndAccrualsSplitSeventyThirty() (gas: 2887924)\n[PASS] testSealedBuyMustKeepItsPositionFromTheSeal() (gas: 2165657)\n[PASS] testSealedNoteRevealsAgainstTheSealBaseline() (gas: 1770762)\n[PASS] testSellingEarlyBreaksTheCall() (gas: 1678252)\n[PASS] testThesisParentChild() (gas: 1362912)\n[PASS] testThesisWithoutChildForfeits() (gas: 828214)\n[PASS] testTreasuryDrip() (gas: 320866)\n[PASS] testTwoBlockPumpObserveUnwindSettlesWrong() (gas: 1692826)\n[PASS] testUnansweredWeekCanBeRetried() (gas: 2356119)\n[PASS] testUnrevealedSealIsNotAFreeOptionAndLapses() (gas: 1361008)\n[PASS] testUpOnlyIsRefused() (gas: 291916)\n[PASS] testWeeklyThesisJudging() (gas: 3728190)\n[PASS] testWriterRefundCappedAtStamp() (gas: 1589580)\n[PASS] testWrongCallForfeitsWithKeeperReward() (gas: 1511685)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 33.55ms (27.20ms CPU time)\n\nRan 3 tests for test/Implementations.t.sol:ImplementationsTest\n[PASS] testClonesInitializeOnceOnlyFromTheirHook() (gas: 4551335)\n[PASS] testFactoryDeploysAllFourWithoutArgumentsOrExternalDependencies() (gas: 34608585)\nLogs:\n  four implementation CREATE2 deployments (gas): 8829579\n\n[PASS] testImplementationsRejectInitialization() (gas: 81376)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 58.25ms (56.42ms CPU time)\n\nRan 18 tests for test/HookReview.t.sol:HookReviewTest\n[PASS] testBuyCallOnImdRefusedBeforeTakingBond() (gas: 695548)\n[PASS] testBuySettlementUsesSameObservationForBothLegs() (gas: 2194208)\n[PASS] testChildAtExactlyGraceDeadlineReleasesThesis() (gas: 1501471)\n[PASS] testDustReplacementsCannotMonopolizeObservationWindow() (gas: 30914015)\n[PASS] testJudgingWaitsForEveryThesisChildGrace() (gas: 3710217)\n[PASS] testLateChildCannotRescueThesis() (gas: 1480370)\n[PASS] testOneAuthorCannotFillTheWeeklyThesisSet() (gas: 43417988)\n[PASS] testOneHostileReadingRemainsAdverseAfterPriceRecovers() (gas: 2182461)\n[PASS] testReplacementCannotLeaveAFullSeriesShortOfOneHour() (gas: 4017959)\n[PASS] testReplacementDoesNotRestartTwentyBlockGap() (gas: 1296953)\n[PASS] testSealOnImdRefusedBeforeTakingStamp() (gas: 389434)\n[PASS] testSellCallOnImdRefusedBeforeTakingBond() (gas: 695149)\n[PASS] testSellSettlementUsesSameObservationForBothLegs() (gas: 2196149)\n[PASS] testSingleSidedLiquidityExitPaysNoHookSwapFee() (gas: 1189966)\n[PASS] testV2AliasPostRefused() (gas: 2486105)\n[PASS] testV2AliasSealRefused() (gas: 2230883)\n[PASS] testV3AliasPostRefused() (gas: 2323854)\n[PASS] testV3AliasSealRefused() (gas: 2067752)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 72.38ms (63.45ms CPU time)\n\nRan 28 tests for test/CompanionFailures.t.sol:JudgeFailuresTest\n[PASS] testAJudgedWeekCannotBeAbandoned() (gas: 1257630)\n[PASS] testAbandonNeedsALiveRequestPastItsDeadline() (gas: 1190393)\n[PASS] testAbandonTakesNothingAndTheRetryDrawsAgain() (gas: 1467522)\n[PASS] testAnswerAtTheExactExpiryStillCountsAndOneSecondLaterDoesNot() (gas: 1257046)\n[PASS] testAnswerForAWeekAlreadyJudgedIsRefused() (gas: 1320679)\n[PASS] testAnswerSignedByAnotherKeyIsRefused() (gas: 1069433)\n[PASS] testAnswerSignedForAnotherConsumerIsRefused() (gas: 3952788)\n[PASS] testConvertForfeitsWithAnEmptyPotIsANoOp() (gas: 236930)\n[PASS] testConvertNeverSellsMoreThanThePot() (gas: 236488)\n[PASS] testConvertSellsTheLargestHalvingThePoolAbsorbs() (gas: 275386)\n[PASS] testConvertTriesExactlyNineTranchesDownToOneTwoHundredFiftySixth() (gas: 363686)\n[PASS] testCurrentAndFutureWeeksCannotBeRequested() (gas: 128617)\n[PASS] testEligibleThesesAreCappedAtTheJudgedMaximum() (gas: 14217218)\n[PASS] testImplementationHasAPlaceholderSignerAndCannotBeConfigured() (gas: 2726709)\n[PASS] testInitRequiresEveryConfigurationValue() (gas: 2953442)\n[PASS] testIntakeReturningAnIdAlreadyPendingIsRefused() (gas: 1599187)\n[PASS] testJudgedOfFiltersWrongWeekShortFormAndChildlessIds() (gas: 1439829)\n[PASS] testJudgedWeekCannotBeRequestedAgainEvenAfterTheDeadline() (gas: 1242650)\n[PASS] testMalformedAnswerBytesAreRefused() (gas: 1067354)\n[PASS] testOnlyTheHeadOfThreeIsStoredAndTheTailNeverPromotes() (gas: 1221812)\n[PASS] testPayBeforeAnAnswerReverts() (gas: 1064318)\n[PASS] testPayIsPermissionlessAndOnce() (gas: 1438634)\n[PASS] testQuestionBodyNamesTheConsumerChainAndEligibleIdsOnly() (gas: 2516225)\n[PASS] testRepeatRequestBeforeTheDeadlineIsRefused() (gas: 1419149)\n[PASS] testRequestDrawsExactlyThePriceAndKeepsNothing() (gas: 1028228)\n[PASS] testWeekClosedStates() (gas: 1940695)\n[PASS] testWeekWithoutEligibleThesesCannotBeRequested() (gas: 244665)\n[PASS] testZeroAndExcessiveOraclePricesAreRefused() (gas: 1345941)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 76.68ms (32.37ms CPU time)\n\nRan 10 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testABuyBackNoLongerVoidsASellCallItSettlesOnPrice() (gas: 1599565)\n[PASS] testADustPricedV4VenueCannotBePostedOn() (gas: 1574208)\n[PASS] testARevertingBalanceOfVoidsTheCallAsSoldNotAsNoData() (gas: 2592032)\n[PASS] testAStrangersDustTransferDoesNotVoidASellCall() (gas: 1564471)\n[PASS] testAnAttestationAboutAnotherChainIsRefused() (gas: 2243391)\n[PASS] testAnEmptyCanonicalV3PoolIsRefusedAsAVenue() (gas: 567783)\n[PASS] testHonestObserverOverwritesAPumpObserveUnwindInTheNextBlock() (gas: 3639686)\n[PASS] testPricerRefusesAPriceThatRoundsToZeroInBothOrientations() (gas: 58756)\n[PASS] testSweepNeedsTheStaleRequestAbandonedAndALateAnswerIsThenRefused() (gas: 2379400)\n[PASS] testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment() (gas: 68883218)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 89.71ms (80.60ms CPU time)\n\nRan 13 tests for test/LaunchBinding.t.sol:LaunchBindingTest\n[PASS] testCompanionsAreThePinnedImmutableMinimalProxies() (gas: 30808)\n[PASS] testConstructorWorksWithoutCompanionOrManagerCode() (gas: 55770870)\n[PASS] testExactFeeAccountingWhenImdIsCurrencyOne() (gas: 43621657)\n[PASS] testExactFeeAccountingWhenImdIsCurrencyZero() (gas: 43621441)\n[PASS] testHookAndTokenHaveNoCommonAdminOrWithdrawalSurface() (gas: 533665)\n[PASS] testLiquidityFeesAndFullWithdrawalRemainAvailable() (gas: 753870)\n[PASS] testNativeAndCodelessPairsAreRefused() (gas: 18139513)\n[PASS] testNotedBuyOnFreshManagerSeededOnlyWithMarg() (gas: 42084867)\n[PASS] testOnlyTheSuppliedFactoryCanInitializeAndFailureDoesNotConsumeBinding() (gas: 18283610)\n[PASS] testPermissionsEnableOnlyTheFiveRequiredFlags() (gas: 14213)\n[PASS] testPoolCannotBeReadOrSwappedBeforeBinding() (gas: 18067221)\n[PASS] testPoolMustContainTheConstructorToken() (gas: 18069867)\n[PASS] testWrongFeeIsRefusedBeforeCorrectFeeBinds() (gas: 18253068)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 106.08ms (141.79ms CPU time)\n\nRan 27 tests for test/HookBoundaries.t.sol:HookBoundariesTest\n[PASS] testAfterSwapRejectsZeroOrWrongSignedOutput() (gas: 120869)\n[PASS] testCallCannotBeAChildOfItsOwnCallOrAClosedThesis() (gas: 2942983)\n[PASS] testChildAtTheSevenDayDeadlineCanReleaseTheThesis() (gas: 1486425)\n[PASS] testChildlessThesisForfeitureBoundaryAndKeeperPayment() (gas: 862151)\n[PASS] testEmptyCallAndThesisTextAreRejectedAtomically() (gas: 841850)\n[PASS] testEveryEnabledCallbackRejectsAStranger() (gas: 130741)\n[PASS] testExactOutputPlainBuyHasNoHookDelta() (gas: 54500)\n[PASS] testExactOutputQuietSellsAndNotedTradesAreRejected() (gas: 120205)\n[PASS] testFactoryCannotBindASecondPool() (gas: 73530)\n[PASS] testForeignPoolRejectedByBothSwapCallbacks() (gas: 85794)\n[PASS] testForgedNoteAndExemptionAreRejected() (gas: 153341)\n[PASS] testFuzzBondRoundTripReturnsOnlyTheBond(uint256) (runs: 1000, μ: 838168, ~: 838176)\nLogs:\n  Bound result 8202642105412305055\n\n[PASS] testFuzzNotedInputLeavesExactlyQuarterImdForThePool(uint256) (runs: 1000, μ: 58961, ~: 58968)\nLogs:\n  Bound result 435897435897435908\n\n[PASS] testHorizonEdgesAndTargetEdges() (gas: 2708698)\n[PASS] testManagerCannotInventAnUnlockOutsideAnActiveOperation() (gas: 43865)\n[PASS] testMissingParentAndSameSideCounterAreRejectedAtomically() (gas: 2534248)\n[PASS] testNoDataBondCannotBeStolenOrClaimedTwice() (gas: 901173)\n[PASS] testObservationAndSettlementWindowExactEdges() (gas: 1479155)\n[PASS] testOnlyJudgeCanDrawOrPayAndZeroFundingIsRefused() (gas: 79405)\n[PASS] testRefundRequiresNextDayAuthorAndSingleUse() (gas: 841825)\n[PASS] testRetractAtHorizonIsTooLateAndBeforeItIsFinal() (gas: 1344006)\n[PASS] testSealMaximumAgeUsesSealedPriceDespiteExpiredPostingCheckpoint() (gas: 1102590)\n[PASS] testSealMinimumAgeIsInclusiveAndFailedRevealPreservesCommitment() (gas: 1553352)\n[PASS] testSealRejectsZeroHashAndDuplicateWithoutTakingAnotherStamp() (gas: 481566)\n[PASS] testSweepBoundaryMovesClaimsWithoutWithdrawingThem() (gas: 308016)\n[PASS] testTextLimitIsInclusiveForBothForms() (gas: 2027590)\n[PASS] testUnknownNotesFailEveryLifecycleEntry() (gas: 164079)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 111.26ms (140.37ms CPU time)\n\nRan 9 tests for test/CompanionFailures.t.sol:TreasuryFailuresTest\n[PASS] testDripFailsWhenTheHookCannotTakeTheFunds() (gas: 673929)\n[PASS] testDripIsPermissionlessAndCompounds() (gas: 518661)\n[PASS] testDripOfDustRoundsToZeroAndReverts() (gas: 258318)\n[PASS] testDripWithNothingHeldReverts() (gas: 54033)\n[PASS] testInitOnlyByTheNamedHookAndOnlyOnce() (gas: 623926)\n[PASS] testInitRefusesTheZeroHook() (gas: 556415)\n[PASS] testNoWithdrawOrAdminSurface() (gas: 274868)\n[PASS] testSecondDripOnTheSameDayRevertsAndTheNextDayWorks() (gas: 372660)\n[PASS] testTreasuryRefusesEth() (gas: 71164)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 112.58ms (1.92ms CPU time)\n\nRan 31 tests for test/PricerProperties.t.sol:PricerPropertiesTest\n[PASS] testDifficultyAnchors() (gas: 56436)\n[PASS] testDifficultyRefusesAZeroHorizon() (gas: 10063)\n[PASS] testDifficultyTiersStepExactlyAtTheThresholds() (gas: 79314)\n[PASS] testEmptyPoolsAreRefusedOnBothLegs() (gas: 161813)\n[PASS] testEthQuoteIsOnlyPriceableOnMainnet() (gas: 40894)\n[PASS] testFromSqrtRefusesAnEmptyOrUnpriceableReading() (gas: 53891)\n[PASS] testFromSqrtZeroThresholdIsSharpInBothOrientations() (gas: 1024182)\n[PASS] testFuzzAppendingAnObservationNeverHelpsTheCall(uint256[16],uint256[16],uint8) (runs: 1000, μ: 129215, ~: 101917)\nLogs:\n  Bound result 14\n  Bound result 999999999999999999999000000282\n  Bound result 999999999999999999999060480001\n  Bound result 999999999999999999999000001667\n  Bound result 999999999999999999999000200001\n  Bound result 111000000000000000000000\n  Bound result 999999999999999999999000000017\n  Bound result 999999999999999999999000033025\n  Bound result 999999999999999999999000000245\n  Bound result 999999999999999999999000008151\n  Bound result 999999999999999999999000020001\n  Bound result 999999999999999999999000000241\n  Bound result 111000000000000000000000\n  Bound result 999999999999999999999000003567\n  Bound result 70000000000000000000\n  Bound result 814654753487572537632266270993\n  Bound result 999999999999999999999000007104\n  Bound result 999999999999999999999000021144\n  Bound result 999999999999999999999000000243\n  Bound result 999999999999999999999000020001\n  Bound result 999999999999999999999000003664\n  Bound result 999999999999999999999000016635\n  Bound result 79228162514264337593543950336\n  Bound result 999999999999999999999000000256\n  Bound result 999999999999999999999000002052\n  Bound result 1359182279\n  Bound result 999999999999999999999000003703\n  Bound result 4202047188\n  Bound result 999999999999999999999000012501\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36931, ~: 36992)\nLogs:\n  Bound result 11000\n  Bound result 9989252\n  Bound result 29\n  Bound result 367317649462515307635691077187\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141549, ~: 141901)\nLogs:\n  Bound result 1266412660188944021221804095289\n  Bound result 1267650600228229401496703205376\n  Bound result 2849\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36733, ~: 36833)\nLogs:\n  Bound result 990025\n  Bound result 7\n  Bound result 60\n  Bound result 240\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23313, ~: 21564)\nLogs:\n  Bound result 1461446703485210103287273052103988822378724137641\n  Bound result 9447201179601352393659671095939172653\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39057, ~: 38043)\nLogs:\n  Bound result 87314228502780980959185366817192\n  Bound result 1075463729682\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16187, ~: 14429)\nLogs:\n  Bound result 0\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 53859, ~: 51987)\nLogs:\n  Bound result 12723\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36425, ~: 36390)\nLogs:\n  Bound result 1024\n  Bound result 7387\n  Bound result 60\n  Bound result 240\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18798, ~: 16591)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21354, ~: 21299)\nLogs:\n  Bound result 8093\n  Bound result 5192296858534827628530496329220095\n  Bound result 16490\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 63220, ~: 58274)\nLogs:\n  Bound result -6000\n  Bound result 11\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 99865, ~: 83676)\nLogs:\n  Bound result 2\n  Bound result 630352224917511558756801510457\n  Bound result 820142728340543976072138999939\n  Bound result 8362429351092002440\n  Bound result 600003014551838927145980739026\n\n[PASS] testObserveRefusesUnknownVenuesAndUnpriceableQuotes() (gas: 150448)\n[PASS] testPostPriceRefusesAnEmptyWindow() (gas: 15317)\n[PASS] testPostPriceWhoseProductRoundsToZeroIsRefused() (gas: 293627)\n[PASS] testSellDifficultyRefusesAZeroTarget() (gas: 9518)\n[PASS] testSettlementRefusesAnEmptyOrUnspannedSeries() (gas: 39083)\n[PASS] testSqrtIsExactOnEveryHorizonDifficultyUses() (gas: 903275)\n[PASS] testSqrtPins() (gas: 123131)\n[PASS] testTwapRefusesTimeRunningBackwards() (gas: 9132)\n[PASS] testV2TwapAndSpotOfADustRatioAreRefused() (gas: 220677)\n[PASS] testV3TwapRefusesAMeanTickOutsideTheRange() (gas: 27255)\n[PASS] testV4SeriesWithADustExtremeIsRefusedNotSettledAtZero() (gas: 33519)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 112.58ms (1.09s CPU time)\n\nRan 8 tests for test/PriceHistory.t.sol:PriceHistoryTest\n[PASS] testBaselineRequiresMatureFreshHistory() (gas: 188472)\n[PASS] testEmptyVenueAndHubCannotBeCheckpointedObservedOrPriced() (gas: 284549)\n[PASS] testFuzzV4BaselineIsNeverFavourableToTheCall(int24,bool) (runs: 256, μ: 105978, ~: 106112)\nLogs:\n  Bound result 3\n\n[PASS] testHubBaselineUsesOppositeExtremeFromSettlement() (gas: 180334)\n[PASS] testLiveCheckpointCannotEraseHonestExtremesOrRestartTheClock() (gas: 224282)\n[PASS] testV2BaselineIgnoresSameBlockReservesDumpAndPumpBothOrientations() (gas: 467543)\n[PASS] testV3BaselineIgnoresSameBlockTickChangesBothOrientations() (gas: 418025)\n[PASS] testV3BaselineWeightsElapsedTime() (gas: 371037)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 112.62ms (24.96ms CPU time)\n\nRan 1 test for test/RouterInvariant.t.sol:RouterInvariantTest\n[PASS]\nRouterInvariantTest invariants:\n[PASS] invariant_bindingsPinned\n[PASS] invariant_everyNoteCameThroughTheRouter\n[PASS] invariant_managerBacksTheHooksClaims\n[PASS] invariant_routerKeepsNothing\n RouterInvariantTest invariants (runs: 48, calls: 1920, reverts: 3)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| RouterHandler | advance        | 226   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 203   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 413   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 206   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 223   | 3       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 204   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 227   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 218   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8776\n  Bound result 1\n  Bound result 98\n  Bound result 1\n  Bound result 1\n  Bound result 50013\n  Bound result 0\n  Bound result 1\n  Bound result 6424\n  Bound result 58194\n  Bound result 19\n  Bound result 1\n  Bound result 2\n  Bound result 3811836362\n  Bound result 1\n  Bound result 1\n  Bound result 18666\n  Bound result 2\n  Bound result 7\n  Bound result 0\n  Bound result 21050\n  Bound result 52655\n  Bound result 25\n  Bound result 0\n  Bound result 6\n  Bound result 50281\n  Bound result 53\n  Bound result 2\n  Bound result 1\n  Bound result 1000000000000000000000\n  Bound result 16384\n  Bound result 4\n  Bound result 2\n  Bound result 21655\n  Bound result 7796\n  Bound result 12\n  Bound result 0\n  Bound result 8197\n  Bound result 10000\n  Bound result 98\n  Bound result 0\n  Bound result 428868784498273773319\n  Bound result 1\n  Bound result 60566400\n  Bound result 2\n  Bound result 770713365151035836825\n  Bound result 50132\n  Bound result 19\n  Bound result 2\n  Bound result 1\n  Bound result 2293\n  Bound result 50257\n  Bound result 51\n  Bound result 0\n  Bound result 10777\n  Bound result 15484\n  Bound result 48\n  Bound result 2\n  Bound result 10604\n  Bound result 11834\n  Bound result 41\n  Bound result 0\n  Bound result 1\n  Bound result 242\n  Bound result 13797\n  Bound result 53\n  Bound result 1\n  Bound result 75000000000000000000\n  Bound result 11888\n  Bound result 76\n  Bound result 0\n  Bound result 13\n  Bound result 2701\n  Bound result 67\n  Bound result 0\n  Bound result 2\n  Bound result 5000000000000000000000\n  Bound result 2\n  Bound result 1\n  Bound result 1877468907\n  Bound result 6584\n  Bound result 45\n  Bound result 4139\n  Bound result 2\n  Bound result 1733\n  Bound result 5337\n  Bound result 0\n  Bound result 2748\n  Bound result 0\n  Bound result 2413\n  Bound result 51580\n  Bound result 19\n  Bound result 0\n  Bound result 6931\n  Bound result 59109\n  Bound result 57\n  Bound result 0\n  Bound result 20000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 3700\n  Bound result 130\n  Bound result 50\n  Bound result 1\n  Bound result 40000\n  Bound result 1105\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 470.24ms (462.01ms CPU time)\n\nRan 1 test for test/TreasuryInvariant.t.sol:TreasuryInvariantTest\n[PASS]\nTreasuryInvariantTest invariants:\n[PASS] invariant_balanceIsGiftsMinusDrips\n[PASS] invariant_dripNeverExceedsTwoPercent\n[PASS] invariant_holdsNoEth\n[PASS] invariant_hookHoldsExactlyTheDrips\n[PASS] invariant_hookIsPinned\n[PASS] invariant_lastDripDayMatchesTheLastSuccessfulDrip\n TreasuryInvariantTest invariants (runs: 256, calls: 12288, reverts: 0)\n\n╭-----------------+-----------+-------+---------+----------╮\n| Contract        | Selector  | Calls | Reverts | Discards |\n+==========================================================+\n| TreasuryHandler | advance   | 2448  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2477  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2452  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2462  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2449  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 3000000000\n  Bound result 400000\n  Bound result 743174435838183670646648\n  Bound result 3921\n  Bound result 28800\n  Bound result 9000000000000000000\n  Bound result 259199\n  Bound result 80\n  Bound result 86167\n  Bound result 2560\n  Bound result 20000000000000000000\n  Bound result 10000000000000000000\n  Bound result 2400\n  Bound result 1063\n  Bound result 173097\n  Bound result 3000000000000000000000000\n  Bound result 79499\n  Bound result 25\n  Bound result 2\n  Bound result 10000000000000000000\n  Bound result 20000000000000000000\n  Bound result 56448\n  Bound result 1000000\n  Bound result 1885\n  Bound result 100000000\n  Bound result 555332233504553101173475911116920\n  Bound result 160799\n  Bound result 887220\n  Bound result 12500\n  Bound result 1886\n  Bound result 49\n  Bound result 100\n  Bound result 2178\n  Bound result 166462\n  Bound result 70162658179134442947525\n  Bound result 564\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.12s (1.12s CPU time)\n\nRan 5 tests for test/HookAccountingInvariant.t.sol:HookAccountingInvariantTest\n[PASS] invariant_everyImdClaimHasExactlyOneObligation() (runs: 128, calls: 10240, reverts: 0)\n\n╭-----------------------+-------------------+-------+---------+----------╮\n| Contract              | Selector          | Calls | Reverts | Discards |\n+========================================================================+\n| HookAccountingHandler | abandonJudging    | 528   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | advance           | 520   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | answerJudging     | 497   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | child             | 514   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimDeposit      | 492   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimRefund       | 489   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | fund              | 529   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | giftAndDrip       | 558   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | notedSell         | 485   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | observeSeries     | 552   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | payJudging        | 462   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | post              | 1080  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | requestJudging    | 520   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | retract           | 531   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | seal              | 537   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | settle            | 512   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | sweep             | 483   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | trade             | 498   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | unauthorizedClaim | 453   | 0       | 0        |\n╰-----------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 3000000000000000000\n  Bound result 3\n  Bound result 10000000000000000000\n  Bound result 1\n  Bound result 9750000000000000018\n  Bound result 98000000000000000027\n  Bound result 1\n  Bound result 9750000003000000001\n  Bound result 6\n  Bound result 3\n  Bound result 24960296808417182485\n  Bound result 99999000000000000040001\n  Bound result 3\n  Bound result 2749999999999999949\n  Bound result 98000000000000019761\n  Bound result 8\n  Bound result 98000000000000020718\n  Bound result 10237\n  Bound result 10\n  Bound result 9750000000000000282\n  Bound result 5400\n  Bound result 71613641250041835177\n  Bound result 12197\n  Bound result 14827\n  Bound result 9750000000000020539\n  Bound result 12\n  Bound result 9\n  Bound result 4\n  Bound result 98000000000000000129\n  Bound result 99999000000000000018938\n  Bound result 87201981651533089310\n  Bound result 1860\n  Bound result 4\n  Bound result 1\n  Bound result 12\n  Bound result 1\n  Bound result 1\n  Bound result 13\n  Bound result 1000000000000000001\n  Bound result 8337265927845433742\n  Bound result 9750000000000000194\n  Bound result 7\n  Bound result 1860\n  Bound result 4\n  Bound result 9750000000000018285\n  Bound result 24576\n  Bound result 14\n  Bound result 13\n  Bound result 99999000000000366446895\n  Bound result 99999000000000000000742\n  Bound result 14\n  Bound result 2\n  Bound result 16\n  Bound result 98000000000000015618\n  Bound result 99999999999999999976\n  Bound result 98000000000000000429\n  Bound result 10350000000000000000\n  Bound result 36191114903625715570522\n\n[PASS] testAccountingHandlerChecksGraceThenAllowsPaidRetry() (gas: 2362804)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 3000000000000000000\n  Bound result 3\n  Bound result 10000000000000000000\n\n[PASS] testAccountingHandlerExercisesPayoutsForfeitsSealsDripsAndSweeps() (gas: 5432494)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 3000000000000000000\n  Bound result 3\n  Bound result 10000000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 4\n  Bound result 3\n  Bound result 4000000000000000000\n  Bound result 5\n  Bound result 50000000000000000000\n\n[PASS] testAccountingHandlerModelsThesisCapAcrossClosureAndWeekRollover() (gas: 4227583)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 3000000000000000000\n  Bound result 3\n  Bound result 10000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 4\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n\n[PASS] testAccountingHandlerRefusesChildWhoseCheckpointMaturesAfterGrace() (gas: 2660729)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 3000000000000000000\n  Bound result 3\n  Bound result 10000000000000000000\n  Bound result 2000000000000000000\n  Bound result 5\n  Bound result 5\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 7.28s (7.28s CPU time)\n\nRan 21 test suites in 7.29s (9.85s CPU time): 249 tests passed, 0 failed, 1 skipped (250 total tests)\n","passed":true},{"durationMs":82,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Marginalia.approve(address,uint256)\",\"Marginalia.transfer(address,uint256)\",\"Marginalia.transferFrom(address,address,uint256)\",\"MarginaliaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"MarginaliaHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"MarginaliaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"MarginaliaHook.claimDeposit(bytes32)\",\"MarginaliaHook.claimRefund(bytes32)\",\"MarginaliaHook.drawForJudging(uint32,uint256,bool)\",\"MarginaliaHook.fundPot(uint256)\",\"MarginaliaHook.observe(bytes32)\",\"MarginaliaHook.payJudged(uint32,bytes32[3])\",\"MarginaliaHook.retract(bytes32,string)\",\"MarginaliaHook.seal(address,(uint8,bytes32,address,bool),bytes32)\",\"MarginaliaHook.settle(bytes32)\",\"MarginaliaHook.settleThesis(bytes32)\",\"MarginaliaHook.sweep(uint8,uint32)\",\"MarginaliaHook.unlockCallback(bytes)\",\"MarginaliaJudge.abandonRequest(uint32)\",\"MarginaliaJudge.convertForfeits()\",\"MarginaliaJudge.init(address,address,bytes32,address)\",\"MarginaliaJudge.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaJudge.payJudged(uint32)\",\"MarginaliaJudge.requestJudging(uint32)\",\"MarginaliaRouter.checkpointVenue((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address))\",\"MarginaliaRouter.init(address,address)\",\"MarginaliaRouter.note((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.sellWithNote((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.uniswapV3SwapCallback(int256,int256,bytes)\",\"MarginaliaRouter.unlockCallback(bytes)\",\"MarginaliaTreasury.drip()\",\"MarginaliaTreasury.init(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":446,\"README.md\":209,\"SPEC.md\":285,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":82,\"helper/server.js\":90,\"helper/src/app.js\":203,\"jobs/launch-1-hook.json\":43,\"jobs/launch-2-contracts.json\":38,\"jobs/launch-A-implementations.json\":47,\"jobs/launch-A2-implementations.json\":99,\"jobs/launch-B-hook.json\":36,\"jobs/launch-hook-v3.json\":43,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":975,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPricer.sol\":305,\"src/MarginaliaRouter.sol\":446,\"src/MarginaliaTreasury.sol\":53,\"src/MarginaliaTypes.sol\":127,\"src/OracleAttestation.sol\":221,\"src/interfaces/IIntake.sol\":15,\"src/interfaces/ILaunchFactory.sol\":49,\"test/ADVERSARIAL_COVERAGE.md\":59,\"test/AuditFindings.t.sol\":156,\"test/CompanionFailures.t.sol\":941,\"test/HoldRule.t.sol\":259,\"test/HookAccountingInvariant.t.sol\":776,\"test/HookBoundaries.t.sol\":475,\"test/HookReview.t.sol\":432,\"test/Implementations.t.sol\":96,\"test/JudgeOracle.t.sol\":270,\"test/LaunchAuditFindings.t.sol\":230,\"test/LaunchBinding.t.sol\":305,\"test/Lifecycle.t.sol\":696,\"test/PriceHistory.t.sol\":233,\"test/Pricer.t.sol\":88,\"test/PricerProperties.t.sol\":569,\"test/RevisionFindings.t.sol\":324,\"test/Round3Findings.t.sol\":218,\"test/RouterInvariant.t.sol\":248,\"test/TreasuryInvariant.t.sol\":167,\"test/fork/MainnetLaunch.t.sol\":374,\"test/helpers/Fixture.sol\":285,\"test/mocks/MockERC20.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0a5d14ae71e03fd5bf1dcdd59f842ed95321186b8af8081ddcc55ea4af59e97b","verifiedTreeHash":"e179ef751c500f274c6a388fe6189bd16e9667b6","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":207500,"exitCode":0,"name":"build","output":"Compiling 115 files with Solc 0.8.26\nSolc 0.8.26 finished in 207.21s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n   --> src/MarginaliaHook.sol:859:9:\n    |\n859 |         uint256 pool = thesisPool[w];\n    |         ^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> src/MarginaliaHook.sol:99:5:\n   |\n99 |     PoolKey private pool;\n   |     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n   --> src/MarginaliaHook.sol:299:5:\n    |\n299 |     function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata data)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/helpers/Fixture.sol:114:5:\n    |\n114 |     function priceOf(bytes32, address) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  --> test/fork/MainnetLaunch.t.sol:78:5:\n   |\n78 |     function _mine(bytes memory hookCode) internal view returns (bytes32 salt) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/MarginaliaTreasury.sol:51:9\n   │\n51 │         emit Dripped(day, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaTreasury.sol:43:22\n   │\n43 │         uint32 day = uint32(block.timestamp / 1 days);\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `jobHash` is changed without an event but is used for access control\n    ╭▸ src/MarginaliaRouter.sol:303:16\n    │\n303 │         delete jobHash;\n    │                ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/MarginaliaPricer.sol:85:13\n   │\n85 │             n += 1;\n   │             ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:120:33\n    │\n120 │         if (w.startedAt == 0 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:114:47\n    │\n114 │         for (uint256 i = 0; i < all.length && n < MAX_JUDGED; ++i) {\n    │                                               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:34\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:59\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:142:20\n    │\n142 │                 || block.timestamp < uint256(w.startedAt) + POST_MIN_SPAN\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/MarginaliaPricer.sol:143:20\n    │\n143 │                 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:149:69\n    │\n149 │             x = twap(v.kind, v.xIsToken0, w.xStart, w.startedAt, x, uint64(block.timestamp));\n    │                                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:170:15\n    │\n170 │             ++n;\n    │               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:174:33\n    │\n174 │             out[i - 1] = bytes1(uint8(48 + v % 10));\n    │                                 ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' 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/MarginaliaPricer.sol:168:55\n    │\n168 │         else if (v.kind == T.VenueKind.UniV3) xRead = uint256(_v3Cumulative(ref));\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:186:52\n    │\n186 │         return eligibleTheses(week).length == 0 || block.timestamp >= (uint256(week) + 1) * 7 days + 28 days;\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/MarginaliaJudge.sol:194:32\n    │\n194 │         if (judgedSet[week] || block.timestamp < requestedAt[week] + ANSWER_DEADLINE) {\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:213:28\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:213:41\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:214:35\n    │\n214 │             int256 mean = delta / int256(dt);\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/MarginaliaPricer.sol:215:38\n    │\n215 │             if (delta < 0 && delta % int256(dt) != 0) mean -= 1; // round toward negative infinity, as v3 does\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/MarginaliaPricer.sol:217:57\n    │\n217 │             return fromSqrt(TickMath.getSqrtPriceAtTick(int24(mean)), xIsToken0);\n    │                                                         ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' 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/MarginaliaPricer.sol:241:37\n    │\n241 │             (uint160 sqrtP,,,,,,) = IUniswapV3PoolOracle(ref).slot0();\n    │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:245:41\n    │\n245 │             (uint112 r0, uint112 r1,) = IUniswapV2PairOracle(ref).getReserves();\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:269:33\n    │\n269 │         (int56[] memory cum,) = IUniswapV3PoolOracle(pool).observe(ago);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:279:24\n    │\n279 │         uint32 nowTs = uint32(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:214:9\n    │\n214 │         hook.drawForJudging(day, price, retry);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:217:21\n    │\n217 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n218 │ ┃             action, body, IIntake.Callback(address(this), this.onOracleResult.selector), imd, price\n219 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:206:41\n    │\n206 │         if (judgedSet[day] || (retry && block.timestamp < requestedAt[day] + ANSWER_DEADLINE)) {\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/MarginaliaJudge.sol:225:9\n    │\n225 │         emit Requested(day, requestId, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:223:28\n    │\n223 │         requestedAt[day] = uint64(block.timestamp);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaHook.sol:84:38\n   │\n84 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' 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/MarginaliaJudge.sol:255:9\n    │\n255 │ ┏         emit Judged(\n256 │ ┃             day,\n257 │ ┃             [\n258 │ ┃                 count > 0 ? ranked[0] : bytes32(0),\n    ‡ ┃\n262 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:276:17\n    │\n276 │             if (dup) continue;\n    │                 ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:269:50\n    │\n269 │         for (uint256 i = 0; i < ranked.length && kept < 3; ++i) {\n    │                                                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:270:77\n    │\n270 │             (address author, uint32 noteWeek, bool thesis, bool hasChild) = hook.noteMeta(ranked[i]);\n    │                                                                             ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaJudge.sol:288:9\n    │\n288 │         hook.payJudged(day, top);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaRouter.sol:251:13\n    │\n251 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:252:41\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:252:49\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:338:9\n    │\n338 │         emit Noted(job.payer, job.sellMarg, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:320:18\n    │\n320 │                 -int256(job.amountIn),\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/MarginaliaRouter.sol:328:25\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:328:33\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:329:28\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:329:36\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:373:9\n    │\n373 │         emit XTraded(payer, X_V4, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:355:18\n    │\n355 │                 -int256(x.amountIn),\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/MarginaliaRouter.sol:363:25\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:363:33\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:364:20\n    │\n364 │         received = uint256(uint128(outputDelta));\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:364:28\n    │\n364 │         received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:403:9\n    │\n403 │         emit XTraded(payer, X_V3, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:394:13\n    │\n394 │             int256(x.amountIn),\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/MarginaliaRouter.sol:399:25\n    │\n399 │         uint256 spent = uint256(zeroForOne ? a0 : a1);\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/MarginaliaRouter.sol:409:78\n    │\n409 │         if (amount0Delta > 0) IERC20(pool.token0()).safeTransfer(msg.sender, uint256(amount0Delta));\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/MarginaliaRouter.sol:410:78\n    │\n410 │         if (amount1Delta > 0) IERC20(pool.token1()).safeTransfer(msg.sender, uint256(amount1Delta));\n    │                                                                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:438:9\n    │\n438 │         emit XTraded(payer, X_V2, xIn, xOut, actualIn, received);\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/MarginaliaRouter.sol:426:37\n    │\n426 │         (uint112 r0, uint112 r1,) = pair.getReserves();\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:312:49\n    │\n312 │                 specifiedTake = STAMP + _bondOf(uint256(-params.amountSpecified));\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:389:9\n    │\n389 │         emit Accrued(day, amount);\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/MarginaliaHook.sol:471:17\n    │\n471 │                 emit Revealed(id, hash);\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/MarginaliaHook.sol:495:9\n    │\n495 │         emit NotePosted(id, author, p.x, class, p.side, p.targetBps, p.horizonDays, p.parentId, p.text);\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/MarginaliaHook.sol:348:13\n    │\n348 │             emit SwapFee(true, author, poolImd, 0, STAMP);\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/MarginaliaHook.sol:361:13\n    │\n361 │             emit SwapFee(false, author, poolImd, fee - STAMP, STAMP);\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/MarginaliaHook.sol:372:9\n    │\n372 │         emit SwapFee(false, tx.origin, poolImd, quietFee, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:335:33\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:41\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:63\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:71\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:340:36\n    │\n340 │             uint256 bond = _bondOf(uint256(-params.amountSpecified));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:342:31\n    │\n342 │             uint256 margOut = uint256(uint128(margDelta));\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/MarginaliaHook.sol:342:39\n    │\n342 │             uint256 margOut = uint256(uint128(margDelta));\n    │                                       ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:450:17\n    │\n450 │             if (weekTheses[w].length >= MAX_WEEK_THESES || thesesPerAuthor[w][author] >= MAX_AUTHOR_THESES) {\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/MarginaliaHook.sol:450:60\n    │\n450 │             if (weekTheses[w].length >= MAX_WEEK_THESES || thesesPerAuthor[w][author] >= MAX_AUTHOR_THESES) {\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/MarginaliaHook.sol:465:26\n    │\n465 │             if (bound && age < SEAL_MIN) revert TooEarly(); // the head start is the key holders', not the public's\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/MarginaliaHook.sol:466:26\n    │\n466 │             if (bound && age <= SEAL_MAX) {\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/MarginaliaHook.sol:484:32\n    │\n484 │ …                     || block.timestamp > uint256(parent.postedAt) + THESIS_GRACE\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:442:22\n    │\n442 │         n.postedAt = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:540:13\n    │\n540 │         if (block.timestamp < end) revert TooEarly();\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/MarginaliaHook.sol:541:13\n    │\n541 │         if (block.timestamp > end + SETTLE_WINDOW) revert TooLate();\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/MarginaliaHook.sol:554:47\n    │\n554 │                     || (len == OBS_MAX - 1 && block.timestamp < uint256(obs[0].timestamp) + OBS_MIN_SPAN))\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/MarginaliaHook.sol:562:9\n    │\n562 │         emit Observed(id, xRead, balance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:546:27\n    │\n546 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:546:52\n    │\n546 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                                                    ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:570:13\n    │\n570 │             x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.balanceOf.selector, who));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaHook.sol:651:35\n    │\n651 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │                                   ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:607:13\n    │\n607 │         if (block.timestamp <= end + SETTLE_WINDOW) revert TooEarly();\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/MarginaliaHook.sol:736:13\n    │\n736 │             emit ThesisReleased(n.parentId);\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/MarginaliaHook.sol:651:9\n    │\n651 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:634:26\n    │\n634 │             scoreDelta = int256(_difficulty(n));\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/MarginaliaHook.sol:639:27\n    │\n639 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:641:27\n    │\n641 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:645:27\n    │\n645 │             scoreDelta = -int256(_difficulty(n));\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[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:669:17\n    │\n669 │             try pricer().settlePrice(n.venue, buy, sample) returns (uint256 p) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:683:13\n    │\n683 │         if (block.timestamp >= horizonEnd(id)) revert TooLate();\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/MarginaliaHook.sol:693:9\n    │\n693 │         emit Retracted(id, text);\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/MarginaliaHook.sol:694:9\n    │\n694 │         emit Settled(id, T.Status.Retracted, 0, scoreDelta, address(0));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:687:30\n    │\n687 │         int256 scoreDelta = -int256(_difficulty(n) / 2);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:702:13\n    │\n702 │         if (block.timestamp <= uint256(n.postedAt) + THESIS_GRACE) revert TooEarly();\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/MarginaliaHook.sol:705:9\n    │\n705 │         emit ThesisForfeited(id);\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/MarginaliaHook.sol:719:9\n    │\n719 │         emit DepositClaimed(id, n.author, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:749:13\n    │\n749 │             n.x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.totalSupply.selector));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:758:16\n    │\n758 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:762:16\n    │\n762 │         return uint32(block.timestamp / 7 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:782:9\n    │\n782 │         emit PotFunded(_today(), amount, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `seals` is updated\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:816:25\n    │\n816 │         if ((at != 0 && block.timestamp - at <= SEAL_MAX) || x == address(0) || hash == bytes32(0)) {\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/MarginaliaHook.sol:830:9\n    │\n830 │         emit Sealed(hash, msg.sender, x, venue.ref);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:824:13\n    │\n824 │             uint64(block.timestamp),\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:837:23\n    │\n837 │         if (!retry && block.timestamp < (uint256(w) + 1) * 7 days + THESIS_GRACE) revert TooEarly();\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:851:27\n    │\n851 │         return (n.author, uint32(uint256(n.postedAt) / 7 days), n.targetBps == 0, n.children > 0);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `thesisPool` is updated\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:873:9\n    │\n873 │         emit JudgedPaid(w, paidAmounts);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaHook.sol:926:39\n    │\n926 │         if (unlockHash != bytes32(0)) revert InvalidUnlock();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:880:13\n    │\n880 │         if (n.day >= _today()) revert TooEarly();\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/MarginaliaHook.sol:890:9\n    │\n890 │         emit RefundClaimed(id, msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:888:30\n    │\n888 │         notesPerDay[n.day] = uint32(count - 1);\n    │                              ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:899:17\n    │\n899 │             if (block.timestamp < (uint256(epoch) + 1) * 1 days + SWEEP_AFTER) revert TooEarly();\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/MarginaliaHook.sol:903:17\n    │\n903 │             if (block.timestamp < (uint256(epoch) + 1) * 7 days + SWEEP_AFTER) revert TooEarly();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:936:40\n    │\n936 │             address currency = address(uint160(extra));\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[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaHook.sol:945:13\n    │\n945 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/AuditFindings.t.sol:19:30\n   │\n19 │         uint256 startBlock = block.number;\n   │                              ━━━━━━━━━━━━\n   ‡\n23 │             vm.roll(startBlock + 25 * (i + 1));\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/AuditFindings.t.sol:20:27\n   │\n20 │         uint256 startTs = block.timestamp;\n   │                           ━━━━━━━━━━━━━━━\n   ‡\n24 │             vm.warp(startTs + 31 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:18:9\n    │\n 18 │         vm.warp(hook.horizonEnd(id));\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:65:9\n    │\n 65 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:82:9\n    │\n 82 │         vm.warp(deadline - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:193:9\n    │\n193 │         vm.warp(weekEnd - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:195:9\n    │\n195 │         vm.warp(weekEnd + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:148:9\n    │\n148 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:149:30\n    │\n149 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n153 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:150:27\n    │\n150 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n154 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:176:9\n    │\n176 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:177:30\n    │\n177 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n181 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:178:27\n    │\n178 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n182 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:203:9\n    │\n203 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:204:30\n    │\n204 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n208 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:205:27\n    │\n205 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n209 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:302:9\n    │\n302 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:357:9\n    │\n357 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:358:30\n    │\n358 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n363 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:359:27\n    │\n359 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n364 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:421:9\n    │\n421 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:488:9\n    │\n488 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:489:30\n    │\n489 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n492 │         vm.roll(startBlock + 25);\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/Lifecycle.t.sol:490:27\n    │\n490 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n493 │         vm.warp(startTs + 30 minutes);\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:512:9\n    │\n512 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:513:30\n    │\n513 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n517 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:514:27\n    │\n514 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n518 │             vm.warp(startTs + 10 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:554:9\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:538:49\n    │\n538 │         router.note(rebuttal, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:554:17\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:583:9\n    │\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:575:49\n    │\n575 │         router.note(sameSide, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:584:30\n    │\n584 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n589 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:585:27\n    │\n585 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n590 │             vm.warp(startTs + 30 minutes * (i + 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/Lifecycle.t.sol:629:22\n    │\n629 │         assertEq(at, block.timestamp);\n    │                      ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:634:42\n    │\n634 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:638:17\n    │\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:653:17\n    │\n653 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:657:42\n    │\n657 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:663:17\n    │\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:679:17\n    │\n679 │         vm.warp(block.timestamp + hook.SEAL_MAX() + 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/Lifecycle.t.sol:682:17\n    │\n682 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:199:17\n    │\n199 │         vm.warp(block.timestamp + 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:267:9\n    │\n267 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/Round3Findings.t.sol:67:17\n   │\n67 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":1408,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/MainnetLaunch.t.sol:MainnetLaunchTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 828.96µs (0.00ns CPU time)\n\nRan 7 tests for test/Pricer.t.sol:PricerTest\n[PASS] testQuoteLegIsAdverseEvenUnderAV3Twap() (gas: 28455)\n[PASS] testTwapRefusesZeroSpanAndV4() (gas: 17708)\n[PASS] testV2TwapFromWrappingCumulative() (gas: 9503)\n[PASS] testV3TwapOfAConstantTickIsThatTick() (gas: 15459)\n[PASS] testV3TwapRoundsNegativeMeansDown() (gas: 14848)\n[PASS] testV3TwapWeightsByTime() (gas: 14715)\n[PASS] testV4SettlesOnTheAdverseExtreme() (gas: 26636)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 919.04µs (1.47ms CPU time)\n\nRan 9 tests for test/CompanionFailures.t.sol:TreasuryFailuresTest\n[PASS] testDripFailsWhenTheHookCannotTakeTheFunds() (gas: 673929)\n[PASS] testDripIsPermissionlessAndCompounds() (gas: 518661)\n[PASS] testDripOfDustRoundsToZeroAndReverts() (gas: 258318)\n[PASS] testDripWithNothingHeldReverts() (gas: 54033)\n[PASS] testInitOnlyByTheNamedHookAndOnlyOnce() (gas: 623926)\n[PASS] testInitRefusesTheZeroHook() (gas: 556415)\n[PASS] testNoWithdrawOrAdminSurface() (gas: 274868)\n[PASS] testSecondDripOnTheSameDayRevertsAndTheNextDayWorks() (gas: 372660)\n[PASS] testTreasuryRefusesEth() (gas: 71164)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 6.59ms (1.38ms CPU time)\n\nRan 14 tests for test/CompanionFailures.t.sol:RouterFailuresTest\n[PASS] testExpiredDeadlineTakesNothing() (gas: 668139)\n[PASS] testExpiredWindowRefusesPostsUntilAFreshCheckpointMatures() (gas: 1756378)\n[PASS] testInitRequiresAManagerWithCode() (gas: 4169863)\n[PASS] testSlippageFloorRefundsEverything() (gas: 639941)\n[PASS] testStrangersCannotEnterTheCallbacks() (gas: 133302)\n[PASS] testTradeAndNoteRefusesNoTradeZeroTradeAndNativeInput() (gas: 290673)\n[PASS] testTradedNoteMustBeAboutTheTokenTraded() (gas: 980650)\n[PASS] testTradedV4LegUnderAForeignHookOrEmptyPoolIsRefused() (gas: 396113)\n[PASS] testUnapprovedOrUnfundedAuthorIsRefused() (gas: 224265)\n[PASS] testV4VenueUnderAForeignHookIsRefused() (gas: 69759)\n[PASS] testV4VenueWithoutLiquidityIsRefused() (gas: 134961)\n[PASS] testVenueFieldsAreDerivedFromThePoolNotTheCaller() (gas: 48554)\n[PASS] testVenueKindNoneIsRefusedForAPricedCall() (gas: 116223)\n[PASS] testZeroAndOversizedAmountsAreRefused() (gas: 138593)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 15.07ms (5.41ms CPU time)\n\nRan 8 tests for test/LaunchAuditFindings.t.sol:LaunchAuditFindingsTest\n[PASS] testAHugeSupplyBooksTierOneInsteadOfOverflowing() (gas: 2461200)\n[PASS] testALapsedSealCanBeSealedAgain() (gas: 703279)\n[PASS] testARetractedNoteLeavesTheDaysRefundSplit() (gas: 1382965)\n[PASS] testARetractionAfterTheRefundClaimDoesNotDoubleCount() (gas: 1359071)\n[PASS] testARevertingTotalSupplyDoesNotBlockARetraction() (gas: 1932201)\n[PASS] testARevertingTotalSupplyStillSettlesWrongAndPaysTheKeeper() (gas: 2554573)\n[PASS] testAStrangersSealNeitherBlocksNorPricesTheAuthorsNote() (gas: 2518397)\n[PASS] testAnAuthorsSealOnAnotherVenueDoesNotPriceTheNote() (gas: 2235395)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 22.66ms (11.69ms CPU time)\n\nRan 6 tests for test/AuditFindings.t.sol:AuditFindingsTest\n[PASS] testEmptyV4ObservationIsRefused() (gas: 918993)\n[PASS] testExpiredBaselineRejectsPostWithoutTakingFunds() (gas: 601798)\n[PASS] testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried() (gas: 2111077)\n[PASS] testSameBlockDumpPostUnwindDoesNotWinBuy() (gas: 1822381)\n[PASS] testSameBlockPumpPostUnwindDoesNotWinSell() (gas: 1691295)\n[PASS] testUnpayableRankingRollsTheWholePoolForward() (gas: 2384827)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 25.82ms (15.35ms CPU time)\n\nRan 12 tests for test/HoldRule.t.sol:HoldRuleTest\n[PASS] testABreachIsNeverReplacedByANonBreachInsideTheGap() (gas: 1653878)\n[PASS] testABreachReplacesANonBreachInsideTheGap() (gas: 1661691)\n[PASS] testABuyCallWithAnUnreadableBalanceIsVoidSold() (gas: 1484869)\n[PASS] testASellAuthorMayDumpTheirWholeRemainingBalance() (gas: 1622310)\n[PASS] testASellAuthorWhoBuysBackTheirWholePostBalanceIsStillRight() (gas: 1717897)\n[PASS] testASellCallWithAnUnreadableBalanceStillSettlesOnPrice() (gas: 1510057)\n[PASS] testASellCallsBalanceIsNeverAnAdverseReading() (gas: 1360897)\n[PASS] testAWrongSellCallForfeitsWhateverTheBalanceDid() (gas: 1426628)\n[PASS] testAnEqualReadingInsideTheGapIsRefused() (gas: 1031930)\n[PASS] testAtTheCapAHigherReadingCannotLiftABuyCallsMinimum() (gas: 3939441)\n[PASS] testAtTheCapOnlyAMoreAdverseReadingGetsIn() (gas: 4186133)\n[PASS] testBuyCallHasNoToleranceDownwards() (gas: 1570913)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 29.90ms (17.21ms CPU time)\n\nRan 31 tests for test/Lifecycle.t.sol:LifecycleTest\n[PASS] testAttestedClassCannotBeSelfDeclared() (gas: 294892)\n[PASS] testCallbackSelectorPinned() (gas: 3383)\n[PASS] testCounterCallDuel() (gas: 3589375)\n[PASS] testCounterThesisEntersTheJudgedSet() (gas: 2688706)\n[PASS] testFakeVenueIsRefused() (gas: 382766)\n[PASS] testFlagsAndBinding() (gas: 56048)\n[PASS] testForfeitsAreImdAndNeedNoConversion() (gas: 861195)\n[PASS] testNoDataRefunds() (gas: 880570)\n[PASS] testNoteTooSmall() (gas: 1644543)\n[PASS] testNotedBuyTakesStampAndDeposit() (gas: 729443)\n[PASS] testNotedSellPaysOnePercentPlusStamp() (gas: 988516)\n[PASS] testObservationsMustSpanAnHour() (gas: 1384019)\n[PASS] testPlainBuyTakesNothing() (gas: 211688)\n[PASS] testQuietSellPaysThreePercent() (gas: 295440)\n[PASS] testQuietThesisPoolSweeps() (gas: 300271)\n[PASS] testRetract() (gas: 866644)\n[PASS] testRightCallReturnsDeposit() (gas: 1623568)\n[PASS] testScoreIsReputationAndAccrualsSplitSeventyThirty() (gas: 2887924)\n[PASS] testSealedBuyMustKeepItsPositionFromTheSeal() (gas: 2165657)\n[PASS] testSealedNoteRevealsAgainstTheSealBaseline() (gas: 1770762)\n[PASS] testSellingEarlyBreaksTheCall() (gas: 1678252)\n[PASS] testThesisParentChild() (gas: 1362912)\n[PASS] testThesisWithoutChildForfeits() (gas: 828214)\n[PASS] testTreasuryDrip() (gas: 320866)\n[PASS] testTwoBlockPumpObserveUnwindSettlesWrong() (gas: 1692826)\n[PASS] testUnansweredWeekCanBeRetried() (gas: 2356119)\n[PASS] testUnrevealedSealIsNotAFreeOptionAndLapses() (gas: 1361008)\n[PASS] testUpOnlyIsRefused() (gas: 291916)\n[PASS] testWeeklyThesisJudging() (gas: 3728190)\n[PASS] testWriterRefundCappedAtStamp() (gas: 1589580)\n[PASS] testWrongCallForfeitsWithKeeperReward() (gas: 1511685)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 61.02ms (42.47ms CPU time)\n\nRan 3 tests for test/Implementations.t.sol:ImplementationsTest\n[PASS] testClonesInitializeOnceOnlyFromTheirHook() (gas: 4551335)\n[PASS] testFactoryDeploysAllFourWithoutArgumentsOrExternalDependencies() (gas: 34608585)\nLogs:\n  four implementation CREATE2 deployments (gas): 8829579\n\n[PASS] testImplementationsRejectInitialization() (gas: 81376)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 92.57ms (94.55ms CPU time)\n\nRan 10 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testABuyBackNoLongerVoidsASellCallItSettlesOnPrice() (gas: 1599565)\n[PASS] testADustPricedV4VenueCannotBePostedOn() (gas: 1574208)\n[PASS] testARevertingBalanceOfVoidsTheCallAsSoldNotAsNoData() (gas: 2592032)\n[PASS] testAStrangersDustTransferDoesNotVoidASellCall() (gas: 1564471)\n[PASS] testAnAttestationAboutAnotherChainIsRefused() (gas: 2243391)\n[PASS] testAnEmptyCanonicalV3PoolIsRefusedAsAVenue() (gas: 567783)\n[PASS] testHonestObserverOverwritesAPumpObserveUnwindInTheNextBlock() (gas: 3639686)\n[PASS] testPricerRefusesAPriceThatRoundsToZeroInBothOrientations() (gas: 58756)\n[PASS] testSweepNeedsTheStaleRequestAbandonedAndALateAnswerIsThenRefused() (gas: 2379400)\n[PASS] testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment() (gas: 68883218)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 95.02ms (85.57ms CPU time)\n\nRan 7 tests for test/JudgeOracle.t.sol:JudgeOracleTest\n[PASS] testEmptySignedRankingIsAnExecutableNoWinnerResult() (gas: 248153)\n[PASS] testFiveIdsWithEoaSignatureFitStipend() (gas: 554052)\n[PASS] testFullRankingWithEoaSignatureFitsStipend() (gas: 633672)\n[PASS] testProtocolDigestSignatureAndSelectorConformanceOnClone() (gas: 3322442)\n[PASS] testRejectedAnswersDoNotConsumeThePendingRequest() (gas: 892875)\n[PASS] testRequestedHeadIsFilteredAndDeduplicatedWithoutPromotingTheTail() (gas: 250679)\n[PASS] testTimeoutRetryInvalidatesOldIntakeRequest() (gas: 523953)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 98.32ms (9.63ms CPU time)\n\nRan 28 tests for test/CompanionFailures.t.sol:JudgeFailuresTest\n[PASS] testAJudgedWeekCannotBeAbandoned() (gas: 1257630)\n[PASS] testAbandonNeedsALiveRequestPastItsDeadline() (gas: 1190393)\n[PASS] testAbandonTakesNothingAndTheRetryDrawsAgain() (gas: 1467522)\n[PASS] testAnswerAtTheExactExpiryStillCountsAndOneSecondLaterDoesNot() (gas: 1257046)\n[PASS] testAnswerForAWeekAlreadyJudgedIsRefused() (gas: 1320679)\n[PASS] testAnswerSignedByAnotherKeyIsRefused() (gas: 1069433)\n[PASS] testAnswerSignedForAnotherConsumerIsRefused() (gas: 3952788)\n[PASS] testConvertForfeitsWithAnEmptyPotIsANoOp() (gas: 236930)\n[PASS] testConvertNeverSellsMoreThanThePot() (gas: 236488)\n[PASS] testConvertSellsTheLargestHalvingThePoolAbsorbs() (gas: 275386)\n[PASS] testConvertTriesExactlyNineTranchesDownToOneTwoHundredFiftySixth() (gas: 363686)\n[PASS] testCurrentAndFutureWeeksCannotBeRequested() (gas: 128617)\n[PASS] testEligibleThesesAreCappedAtTheJudgedMaximum() (gas: 14217218)\n[PASS] testImplementationHasAPlaceholderSignerAndCannotBeConfigured() (gas: 2726709)\n[PASS] testInitRequiresEveryConfigurationValue() (gas: 2953442)\n[PASS] testIntakeReturningAnIdAlreadyPendingIsRefused() (gas: 1599187)\n[PASS] testJudgedOfFiltersWrongWeekShortFormAndChildlessIds() (gas: 1439829)\n[PASS] testJudgedWeekCannotBeRequestedAgainEvenAfterTheDeadline() (gas: 1242650)\n[PASS] testMalformedAnswerBytesAreRefused() (gas: 1067354)\n[PASS] testOnlyTheHeadOfThreeIsStoredAndTheTailNeverPromotes() (gas: 1221812)\n[PASS] testPayBeforeAnAnswerReverts() (gas: 1064318)\n[PASS] testPayIsPermissionlessAndOnce() (gas: 1438634)\n[PASS] testQuestionBodyNamesTheConsumerChainAndEligibleIdsOnly() (gas: 2516225)\n[PASS] testRepeatRequestBeforeTheDeadlineIsRefused() (gas: 1419149)\n[PASS] testRequestDrawsExactlyThePriceAndKeepsNothing() (gas: 1028228)\n[PASS] testWeekClosedStates() (gas: 1940695)\n[PASS] testWeekWithoutEligibleThesesCannotBeRequested() (gas: 244665)\n[PASS] testZeroAndExcessiveOraclePricesAreRefused() (gas: 1345941)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 98.51ms (34.66ms CPU time)\n\nRan 10 tests for test/Round3Findings.t.sol:Round3FindingsTest\n[PASS] testABuyCallStillBreaksWhenTheAuthorSells() (gas: 1669522)\n[PASS] testAGiftOfAnySizeDoesNotVoidACorrectSellCall() (gas: 1584170)\n[PASS] testAGiftWorthTheDepositDoesNotVoidACorrectSellCall() (gas: 1663423)\n[PASS] testALaunchPoolCallScoresTheSameWay() (gas: 1417891)\n[PASS] testASelfPricedVenueBooksReputationOnlyAndNoPoolPaysForIt() (gas: 3007470)\n[PASS] testAWrongCallOnAnotherVenueStillForfeitsAndBooksANegativeScore() (gas: 2707061)\n[PASS] testAWrongSellCallStillForfeits() (gas: 1395988)\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 256, μ: 22655, ~: 20760)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1945010)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204563)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 99.34ms (42.86ms CPU time)\n\nRan 8 tests for test/PriceHistory.t.sol:PriceHistoryTest\n[PASS] testBaselineRequiresMatureFreshHistory() (gas: 188472)\n[PASS] testEmptyVenueAndHubCannotBeCheckpointedObservedOrPriced() (gas: 284549)\n[PASS] testFuzzV4BaselineIsNeverFavourableToTheCall(int24,bool) (runs: 256, μ: 106008, ~: 106088)\nLogs:\n  Bound result -4\n\n[PASS] testHubBaselineUsesOppositeExtremeFromSettlement() (gas: 180334)\n[PASS] testLiveCheckpointCannotEraseHonestExtremesOrRestartTheClock() (gas: 224282)\n[PASS] testV2BaselineIgnoresSameBlockReservesDumpAndPumpBothOrientations() (gas: 467543)\n[PASS] testV3BaselineIgnoresSameBlockTickChangesBothOrientations() (gas: 418025)\n[PASS] testV3BaselineWeightsElapsedTime() (gas: 371037)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 99.54ms (100.73ms CPU time)\n\nRan 31 tests for test/PricerProperties.t.sol:PricerPropertiesTest\n[PASS] testDifficultyAnchors() (gas: 56436)\n[PASS] testDifficultyRefusesAZeroHorizon() (gas: 10063)\n[PASS] testDifficultyTiersStepExactlyAtTheThresholds() (gas: 79314)\n[PASS] testEmptyPoolsAreRefusedOnBothLegs() (gas: 161813)\n[PASS] testEthQuoteIsOnlyPriceableOnMainnet() (gas: 40894)\n[PASS] testFromSqrtRefusesAnEmptyOrUnpriceableReading() (gas: 53891)\n[PASS] testFromSqrtZeroThresholdIsSharpInBothOrientations() (gas: 1024182)\n[PASS] testFuzzAppendingAnObservationNeverHelpsTheCall(uint256[16],uint256[16],uint8) (runs: 1000, μ: 133844, ~: 116367)\nLogs:\n  Bound result 6\n  Bound result 999999999999999999999000000061\n  Bound result 999999999999999999999000020001\n  Bound result 999999999999999999999000008152\n  Bound result 314686694319230931200673284582\n  Bound result 999999999999999999999000008454\n  Bound result 296858534827628535688329214904\n  Bound result 999999999999999999999000000016\n  Bound result 999999999999999999999000002401\n  Bound result 999999999999999999999000003601\n  Bound result 999999999999999999999000000257\n  Bound result 20000000000000000000000\n  Bound result 999999999999999999999000000193\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36922, ~: 36971)\nLogs:\n  Bound result 9993952\n  Bound result 9685866\n  Bound result 14\n  Bound result 740179410081276459204394667819\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141525, ~: 141851)\nLogs:\n  Bound result 733660534941836899111124650419\n  Bound result 1237940039285380274899124225\n  Bound result 17150\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36735, ~: 36900)\nLogs:\n  Bound result 994117\n  Bound result 44\n  Bound result 3\n  Bound result 15000\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23480, ~: 21639)\nLogs:\n  Bound result 1237940039285380274899124224\n  Bound result 1461446703485210103287273052103988822381498382959\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39578, ~: 39185)\nLogs:\n  Bound result 6000000\n  Bound result 2774412616\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 15943, ~: 14210)\nLogs:\n  Bound result 4\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 53926, ~: 51987)\nLogs:\n  Bound result 514\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36406, ~: 36397)\nLogs:\n  Bound result 225\n  Bound result 785\n  Bound result 21\n  Bound result 16676\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18774, ~: 16761)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21347, ~: 21299)\nLogs:\n  Bound result 144872985772\n  Bound result 797703\n  Bound result 48\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 62792, ~: 58209)\nLogs:\n  Bound result -388597\n  Bound result 10\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 102488, ~: 92022)\nLogs:\n  Bound result 16\n  Bound result 60\n  Bound result 20000\n  Bound result 8151\n  Bound result 640564039457584007913129639829\n  Bound result 8453\n  Bound result 296858534827628530496329220096\n  Bound result 15\n  Bound result 2400\n  Bound result 3600\n  Bound result 256\n  Bound result 20000000000000000000000\n  Bound result 192\n  Bound result 848\n  Bound result 95\n  Bound result 28800\n  Bound result 26911\n  Bound result 158456325028528675187087900672\n  Bound result 2048\n  Bound result 1\n  Bound result 10794\n  Bound result 16434\n  Bound result 18705\n  Bound result 316912650057057350374175801344\n  Bound result 79228162514264337593543950336\n  Bound result 360\n  Bound result 12073\n  Bound result 8453\n  Bound result 5019\n  Bound result 39600000000000000000\n  Bound result 104\n  Bound result 14404\n  Bound result 18997\n\n[PASS] testObserveRefusesUnknownVenuesAndUnpriceableQuotes() (gas: 150448)\n[PASS] testPostPriceRefusesAnEmptyWindow() (gas: 15317)\n[PASS] testPostPriceWhoseProductRoundsToZeroIsRefused() (gas: 293627)\n[PASS] testSellDifficultyRefusesAZeroTarget() (gas: 9518)\n[PASS] testSettlementRefusesAnEmptyOrUnspannedSeries() (gas: 39083)\n[PASS] testSqrtIsExactOnEveryHorizonDifficultyUses() (gas: 903275)\n[PASS] testSqrtPins() (gas: 123131)\n[PASS] testTwapRefusesTimeRunningBackwards() (gas: 9132)\n[PASS] testV2TwapAndSpotOfADustRatioAreRefused() (gas: 220677)\n[PASS] testV3TwapRefusesAMeanTickOutsideTheRange() (gas: 27255)\n[PASS] testV4SeriesWithADustExtremeIsRefusedNotSettledAtZero() (gas: 33519)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 99.57ms (1.10s CPU time)\n\nRan 18 tests for test/HookReview.t.sol:HookReviewTest\n[PASS] testBuyCallOnImdRefusedBeforeTakingBond() (gas: 695548)\n[PASS] testBuySettlementUsesSameObservationForBothLegs() (gas: 2194208)\n[PASS] testChildAtExactlyGraceDeadlineReleasesThesis() (gas: 1501471)\n[PASS] testDustReplacementsCannotMonopolizeObservationWindow() (gas: 30914015)\n[PASS] testJudgingWaitsForEveryThesisChildGrace() (gas: 3710217)\n[PASS] testLateChildCannotRescueThesis() (gas: 1480370)\n[PASS] testOneAuthorCannotFillTheWeeklyThesisSet() (gas: 43417988)\n[PASS] testOneHostileReadingRemainsAdverseAfterPriceRecovers() (gas: 2182461)\n[PASS] testReplacementCannotLeaveAFullSeriesShortOfOneHour() (gas: 4017959)\n[PASS] testReplacementDoesNotRestartTwentyBlockGap() (gas: 1296953)\n[PASS] testSealOnImdRefusedBeforeTakingStamp() (gas: 389434)\n[PASS] testSellCallOnImdRefusedBeforeTakingBond() (gas: 695149)\n[PASS] testSellSettlementUsesSameObservationForBothLegs() (gas: 2196149)\n[PASS] testSingleSidedLiquidityExitPaysNoHookSwapFee() (gas: 1189966)\n[PASS] testV2AliasPostRefused() (gas: 2486105)\n[PASS] testV2AliasSealRefused() (gas: 2230883)\n[PASS] testV3AliasPostRefused() (gas: 2323854)\n[PASS] testV3AliasSealRefused() (gas: 2067752)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 101.12ms (139.15ms CPU time)\n\nRan 1 test for test/RouterInvariant.t.sol:RouterInvariantTest\n[PASS]\nRouterInvariantTest invariants:\n[PASS] invariant_bindingsPinned\n[PASS] invariant_everyNoteCameThroughTheRouter\n[PASS] invariant_managerBacksTheHooksClaims\n[PASS] invariant_routerKeepsNothing\n RouterInvariantTest invariants (runs: 48, calls: 1920, reverts: 3)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| RouterHandler | advance        | 190   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 214   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 444   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 213   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 226   | 3       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 200   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 211   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 222   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 1094\n  Bound result 0\n  Bound result 3769\n  Bound result 48879\n  Bound result 55\n  Bound result 2\n  Bound result 8453\n  Bound result 50013\n  Bound result 4\n  Bound result 0\n  Bound result 6\n  Bound result 56123\n  Bound result 13\n  Bound result 0\n  Bound result 2827\n  Bound result 1\n  Bound result 1\n  Bound result 372273257586497171393\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 10000000\n  Bound result 3053\n  Bound result 10\n  Bound result 0\n  Bound result 827628530496329220095\n  Bound result 51453\n  Bound result 82\n  Bound result 0\n  Bound result 6852\n  Bound result 107\n  Bound result 48\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 1731687303715884105728\n  Bound result 3289\n  Bound result 61\n  Bound result 2\n  Bound result 49999999999999980000001\n  Bound result 0\n  Bound result 97\n  Bound result 10717\n  Bound result 39\n  Bound result 1665\n  Bound result 2963804580786986622282\n  Bound result 1\n  Bound result 248764154123456102762\n  Bound result 0\n  Bound result 0\n  Bound result 47177160\n  Bound result 58430\n  Bound result 15\n  Bound result 0\n  Bound result 16899\n  Bound result 1\n  Bound result 1179175234\n  Bound result 59001\n  Bound result 32\n  Bound result 1\n  Bound result 48\n  Bound result 7756\n  Bound result 0\n  Bound result 0\n  Bound result 64414243438082242997860\n  Bound result 1\n  Bound result 46154119676518008029617\n  Bound result 2\n  Bound result 11155111\n  Bound result 6711\n  Bound result 5\n  Bound result 4965149863846169112097\n  Bound result 2\n  Bound result 1356570591098110684204\n  Bound result 0\n  Bound result 3836926997903523773049\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 506375854\n  Bound result 50156\n  Bound result 11\n  Bound result 2\n  Bound result 3167\n  Bound result 6852\n  Bound result 0\n  Bound result 2\n  Bound result 1382\n  Bound result 0\n  Bound result 0\n  Bound result 10806\n  Bound result 2\n  Bound result 39285380274899124224\n  Bound result 35703\n  Bound result 82\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 603.20ms (587.75ms CPU time)\n\nRan 1 test for test/TreasuryInvariant.t.sol:TreasuryInvariantTest\n[PASS]\nTreasuryInvariantTest invariants:\n[PASS] invariant_balanceIsGiftsMinusDrips\n[PASS] invariant_dripNeverExceedsTwoPercent\n[PASS] invariant_holdsNoEth\n[PASS] invariant_hookHoldsExactlyTheDrips\n[PASS] invariant_hookIsPinned\n[PASS] invariant_lastDripDayMatchesTheLastSuccessfulDrip\n TreasuryInvariantTest invariants (runs: 256, calls: 12288, reverts: 0)\n\n╭-----------------+-----------+-------+---------+----------╮\n| Contract        | Selector  | Calls | Reverts | Discards |\n+==========================================================+\n| TreasuryHandler | advance   | 2490  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2460  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2466  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2472  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2400  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 92699\n  Bound result 1000000000000\n  Bound result 109074\n  Bound result 9264\n  Bound result 4096\n  Bound result 680564733841876926926749285234428084224\n  Bound result 1000000000000000000\n  Bound result 1539\n  Bound result 6299\n  Bound result 85471\n  Bound result 1\n  Bound result 795203872563606049\n  Bound result 77\n  Bound result 5249\n  Bound result 4976\n  Bound result 2160164185548573833\n  Bound result 938347266921645642817259\n  Bound result 30\n  Bound result 7807\n  Bound result 9676\n  Bound result 7321\n  Bound result 7244506112580685368\n  Bound result 7200\n  Bound result 10000000000000000000\n  Bound result 729\n  Bound result 530928402780972177752\n  Bound result 874\n  Bound result 6365\n  Bound result 199390\n  Bound result 5994\n  Bound result 2400\n  Bound result 5632\n  Bound result 8\n  Bound result 807570950\n  Bound result 6494\n  Bound result 188351\n  Bound result 10000000000000000000\n  Bound result 20000000000000000\n  Bound result 204513\n  Bound result 1\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.25s (1.24s CPU time)\n\nRan 18 test suites in 1.25s (2.80s CPU time): 204 tests passed, 0 failed, 1 skipped (205 total tests)\n","passed":true},{"durationMs":94,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Marginalia.approve(address,uint256)\",\"Marginalia.transfer(address,uint256)\",\"Marginalia.transferFrom(address,address,uint256)\",\"MarginaliaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"MarginaliaHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"MarginaliaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"MarginaliaHook.claimDeposit(bytes32)\",\"MarginaliaHook.claimRefund(bytes32)\",\"MarginaliaHook.drawForJudging(uint32,uint256,bool)\",\"MarginaliaHook.fundPot(uint256)\",\"MarginaliaHook.observe(bytes32)\",\"MarginaliaHook.payJudged(uint32,bytes32[3])\",\"MarginaliaHook.retract(bytes32,string)\",\"MarginaliaHook.seal(address,(uint8,bytes32,address,bool),bytes32)\",\"MarginaliaHook.settle(bytes32)\",\"MarginaliaHook.settleThesis(bytes32)\",\"MarginaliaHook.sweep(uint8,uint32)\",\"MarginaliaHook.unlockCallback(bytes)\",\"MarginaliaJudge.abandonRequest(uint32)\",\"MarginaliaJudge.convertForfeits()\",\"MarginaliaJudge.init(address,address,bytes32,address)\",\"MarginaliaJudge.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaJudge.payJudged(uint32)\",\"MarginaliaJudge.requestJudging(uint32)\",\"MarginaliaRouter.checkpointVenue((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address))\",\"MarginaliaRouter.init(address,address)\",\"MarginaliaRouter.note((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.sellWithNote((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.uniswapV3SwapCallback(int256,int256,bytes)\",\"MarginaliaRouter.unlockCallback(bytes)\",\"MarginaliaTreasury.drip()\",\"MarginaliaTreasury.init(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":446,\"README.md\":209,\"SPEC.md\":285,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":82,\"helper/server.js\":90,\"helper/src/app.js\":203,\"jobs/launch-1-hook.json\":43,\"jobs/launch-2-contracts.json\":38,\"jobs/launch-A-implementations.json\":47,\"jobs/launch-A2-implementations.json\":99,\"jobs/launch-B-hook.json\":36,\"jobs/launch-hook-v3.json\":43,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":975,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPricer.sol\":305,\"src/MarginaliaRouter.sol\":446,\"src/MarginaliaTreasury.sol\":53,\"src/MarginaliaTypes.sol\":127,\"src/OracleAttestation.sol\":221,\"src/interfaces/IIntake.sol\":15,\"src/interfaces/ILaunchFactory.sol\":49,\"test/AuditFindings.t.sol\":156,\"test/CompanionFailures.t.sol\":941,\"test/HoldRule.t.sol\":259,\"test/HookReview.t.sol\":432,\"test/Implementations.t.sol\":96,\"test/JudgeOracle.t.sol\":270,\"test/LaunchAuditFindings.t.sol\":230,\"test/Lifecycle.t.sol\":696,\"test/PriceHistory.t.sol\":233,\"test/Pricer.t.sol\":88,\"test/PricerProperties.t.sol\":569,\"test/RevisionFindings.t.sol\":324,\"test/Round3Findings.t.sol\":218,\"test/RouterInvariant.t.sol\":248,\"test/TreasuryInvariant.t.sol\":167,\"test/fork/MainnetLaunch.t.sol\":374,\"test/helpers/Fixture.sol\":285,\"test/mocks/MockERC20.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":12867,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/MarginaliaPricer.sol:205: MarginaliaPricer.twap(MarginaliaTypes.VenueKind,bool,uint256,uint64,uint256,uint64) (src/MarginaliaPricer.sol#205-229) uses a weak PRNG: \"delta < 0 && delta % int256(dt) != 0 (src/MarginaliaPricer.sol#215)\"\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:414: Reentrancy in MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:414: Reentrancy in MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:377: Reentrancy in MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:377: Reentrancy in MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:414: Reentrancy in MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:287: Reentrancy in MarginaliaRouter._pull(address,uint256) (src/MarginaliaRouter.sol#287-292):\n[high/high] uninitialized-state at src/MarginaliaHook.sol:536: MarginaliaHook.observations (src/MarginaliaHook.sol#106) is never initialized. It is used in:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:295: MarginaliaPricer.fromSqrt(uint160,bool) (src/MarginaliaPricer.sol#295-304) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:377: MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:414: MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:299: MarginaliaRouter.unlockCallback(bytes) (src/MarginaliaRouter.sol#299-340) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:294: MarginaliaRouter._checkSubject(MarginaliaRouter.Job) (src/MarginaliaRouter.sol#294-297) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:295: MarginaliaPricer.fromSqrt(uint160,bool) (src/MarginaliaPricer.sol#295-304) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:176: MarginaliaPricer.settlePrice(MarginaliaTypes.Venue,bool,MarginaliaTypes.Observation[]) (src/MarginaliaPricer.sol#176-201) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:287: MarginaliaRouter._pull(address,uint256) (src/MarginaliaRouter.sol#287-292) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:205: MarginaliaPricer.twap(MarginaliaTypes.VenueKind,bool,uint256,uint64,uint256,uint64) (src/MarginaliaPricer.sol#205-229) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaTreasury.sol:42: MarginaliaTreasury.drip() (src/MarginaliaTreasury.sol#42-52) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaHook.sol:579: MarginaliaHook._broken(MarginaliaTypes.Note,uint256) (src/MarginaliaHook.sol#579-582) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaHook.sol:919: MarginaliaHook._unlock(uint8,address,uint256,uint256) (src/MarginaliaHook.sol#919-928) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaTreasury.sol:42: MarginaliaTreasury.drip() (src/MarginaliaTreasury.sol#42-52) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:414: MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:135: MarginaliaPricer.postPrice(IPoolManager,MarginaliaTypes.Venue,address,bool,MarginaliaTypes.PriceWindow) (src/MarginaliaPricer.sol#135-155) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:242: MarginaliaRouter._run(bool,uint256,uint256,uint256,MarginaliaRouter.XTrade,MarginaliaTypes.NoteParams,PoolKey) (src/MarginaliaRouter.sol#242-284) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:295: MarginaliaPricer.fromSqrt(uint160,bool) (src/MarginaliaPricer.sol#295-304) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/MarginaliaHook.sol:603: Reentrancy in MarginaliaHook.settle(bytes32) (src/MarginaliaHook.sol#603-652):\n[medium/medium] reentrancy-no-eth at src/MarginaliaHook.sol:855: Reentrancy in MarginaliaHook.payJudged(uint32,bytes32[3]) (src/MarginaliaHook.sol#855-874):\n[medium/medium] reentrancy-no-eth at src/MarginaliaJudge.sol:203: Reentrancy in MarginaliaJudge.requestJudging(uint32) (src/MarginaliaJudge.sol#203-226):\n[medium/medium] reentrancy-no-eth at src/MarginaliaHook.sol:679: Reentrancy in MarginaliaHook.retract(bytes32,string) (src/MarginaliaHook.sol#679-695):\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:179: MarginaliaRouter.sellWithNote(MarginaliaTypes.NoteParams,PoolKey,uint256,uint256,uint256).noX (src/MarginaliaRouter.sol#179) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:127: MarginaliaJudge.questionBody(uint32).allow (src/MarginaliaJudge.sol#127) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaHook.sol:611: MarginaliaHook.settle(bytes32).settlePrice (src/MarginaliaHook.sol#611) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:166: MarginaliaRouter.note(MarginaliaTypes.NoteParams,PoolKey,uint256,uint256,uint256).noX (src/MarginaliaRouter.sol#166) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:257: MarginaliaRouter._run(bool,uint256,uint256,uint256,MarginaliaRouter.XTrade,MarginaliaTypes.NoteParams,PoolKey).job (src/MarginaliaRouter.sol#257) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:113: MarginaliaJudge.eligibleTheses(uint32).n (src/MarginaliaJudge.sol#113) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:205: MarginaliaRouter.validateVenue(MarginaliaTypes.NoteParams,PoolKey).t1 (src/MarginaliaRouter.sol#205) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:272: MarginaliaJudge.judgedOf(uint32).dup (src/MarginaliaJudge.sol#272) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:268: MarginaliaJudge.judgedOf(uint32).kept (src/MarginaliaJudge.sol#268) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaHook.sol:862: MarginaliaHook.payJudged(uint32,bytes32[3]).paidAmounts (src/MarginaliaHook.sol#862) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:168: MarginaliaJudge._dec(uint256).n (src/MarginaliaJudge.sol#168) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:204: MarginaliaRouter.validateVenue(MarginaliaTypes.NoteParams,PoolKey).t0 (src/MarginaliaRouter.sol#204) is a local variable never initialized\n[medium/medium] unused-return at src/MarginaliaPricer.sol:255: MarginaliaPricer._quoteSpot(IPoolManager,address,address) (src/MarginaliaPricer.sol#255-264) ignores return value by (sqrtP,None,None,None) = manager.getSlot0(PoolId.wrap(HUB_POOL_ID)) (src/MarginaliaPricer.sol#260)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:233: MarginaliaPricer._spotInQuote(IPoolManager,MarginaliaTypes.Venue) (src/MarginaliaPricer.sol#233-252) ignores return value by (r0,r1,None) = IUniswapV2PairOracle(ref).getReserves() (src/MarginaliaPricer.sol#245)\n[medium/medium] unused-return at src/MarginaliaHook.sol:930: MarginaliaHook.unlockCallback(bytes) (src/MarginaliaHook.sol#930-950) ignores return value by poolManager.settle() (src/MarginaliaHook.sol#945)\n[medium/medium] unused-return at src/MarginaliaHook.sol:294: MarginaliaHook.margPriceInImd() (src/MarginaliaHook.sol#294-297) ignores return value by (sqrtP,None,None,None) = poolManager.getSlot0(poolId) (src/MarginaliaHook.sol#295)\n[medium/medium] unused-return at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) ignores return value by (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:233: MarginaliaPricer._spotInQuote(IPoolManager,MarginaliaTypes.Venue) (src/MarginaliaPricer.sol#233-252) ignores return value by (sqrtP_scope_0,None,None,None,None,None,None) = IUniswapV3PoolOracle(ref).slot0() (src/MarginaliaPricer.sol#241)\n[medium/medium] unused-return at src/MarginaliaRouter.sol:414: MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439) ignores return value by (r0,r1,None) = pair.getReserves() (src/MarginaliaRouter.sol#426)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:267: MarginaliaPricer._v3Cumulative(address) (src/MarginaliaPricer.sol#267-271) ignores return value by (cum,None) = IUniswapV3PoolOracle(pool).observe(ago) (src/MarginaliaPricer.sol#269)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:233: MarginaliaPricer._spotInQuote(IPoolManager,MarginaliaTypes.Venue) (src/MarginaliaPricer.sol#233-252) ignores return value by (sqrtP,None,None,None) = manager.getSlot0(PoolId.wrap(v.ref)) (src/MarginaliaPricer.sol#237)\n[low/high] shadowing-local at src/MarginaliaHook.sol:859: MarginaliaHook.payJudged(uint32,bytes32[3]).pool (src/MarginaliaHook.sol#859) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.noteMeta(bytes32).week (src/MarginaliaJudge.sol#19) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.thesesOfWeek(uint32).week (src/MarginaliaJudge.sol#15) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.thesisPool(uint32).week (src/MarginaliaJudge.sol#12) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.drawForJudging(uint32,uint256,bool).week (src/MarginaliaJudge.sol#21) shadows:\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:266: MarginaliaJudge.judgedOf(uint32) (src/MarginaliaJudge.sol#266-279) has external calls inside a loop: (author,noteWeek,thesis,hasChild) = hook.noteMeta(ranked[i]) (src/MarginaliaJudge.sol#270)\n[low/medium] calls-loop at src/MarginaliaHook.sol:919: MarginaliaHook._unlock(uint8,address,uint256,uint256) (src/MarginaliaHook.sol#919-928) has external calls inside a loop: out = poolManager.unlock(data) (src/MarginaliaHook.sol#925)\n[low/medium] calls-loop at src/MarginaliaHook.sol:658: MarginaliaHook._settlementPrice(MarginaliaTypes.Note,MarginaliaTypes.Observation[]) (src/MarginaliaHook.sol#658-676) has external calls inside a loop: p = pricer().settlePrice(n.venue,buy,sample) (src/MarginaliaHook.sol#669-674)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:91: MarginaliaJudge.convertForfeits() (src/MarginaliaJudge.sol#91-106) has external calls inside a loop: out = hook.sellPotMarg(marg) (src/MarginaliaJudge.sol#96-100)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:266: MarginaliaJudge.judgedOf(uint32) (src/MarginaliaJudge.sol#266-279) has external calls inside a loop: (author,noteWeek,thesis,hasChild) = hook.noteMeta(ranked[i]) (src/MarginaliaJudge.sol#270)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:323: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#323-374):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:323: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#323-374):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:323: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#323-374):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:722: Reentrancy in MarginaliaHook._forfeit(MarginaliaTypes.Note,address) (src/MarginaliaHook.sol#722-729):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:785: Reentrancy in MarginaliaHook._fund(uint256) (src/MarginaliaHook.sol#785-789):\n[low/medium] reentrancy-benign at src/MarginaliaRouter.sol:377: Reentrancy in MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:722: Reentrancy in MarginaliaHook._forfeit(MarginaliaTypes.Note,address) (src/MarginaliaHook.sol#722-729):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:698: Reentrancy in MarginaliaHook.settleThesis(bytes32) (src/MarginaliaHook.sol#698-706):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:323: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#323-374):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:785: Reentrancy in MarginaliaHook._fund(uint256) (src/MarginaliaHook.sol#785-789):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:709: Reentrancy in MarginaliaHook.claimDeposit(bytes32) (src/MarginaliaHook.sol#709-720):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:855: Reentrancy in MarginaliaHook.payJudged(uint32,bytes32[3]) (src/MarginaliaHook.sol#855-874):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:323: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#323-374):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:679: Reentrancy in MarginaliaHook.retract(bytes32,string) (src/MarginaliaHook.sol#679-695):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:877: Reentrancy in MarginaliaHook.claimRefund(bytes32) (src/MarginaliaHook.sol#877-891):\n[low/medium] reentrancy-events at src/MarginaliaTreasury.sol:42: Reentrancy in MarginaliaTreasury.drip() (src/MarginaliaTreasury.sol#42-52):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:323: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#323-374):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:603: Reentrancy in MarginaliaHook.settle(bytes32) (src/MarginaliaHook.sol#603-652):\n[low/medium] return-bomb at src/MarginaliaHook.sol:568: MarginaliaHook._balanceOf(address,address) (src/MarginaliaHook.sol#568-573) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] ","passed":true},{"durationMs":917,"exitCode":0,"name":"aderyn","output":"[high] eth-send-unchecked-address at src/MarginaliaHook.sol:779: ETH transferred without address checks (3 places)\n[high] reentrancy-state-change at src/MarginaliaHook.sol:224: Reentrancy: State change after external call (15 places)\n[high] storage-array-memory-edit at src/MarginaliaHook.sol:556: Storage Array Edited with Memory\n[high] unsafe-casting at src/MarginaliaHook.sol:936: Unsafe Casting of integers\n[low] costly-loop at src/MarginaliaHook.sol:864: Costly operations inside loop (2 places)\n[low] internal-function-used-once at src/HookFlags.sol:26: Internal Function Used Only Once (2 places)\n[low] large-numeric-literal at src/Marginalia.sol:10: Large Numeric Literal (17 places)\n[low] literal-instead-of-constant at src/MarginaliaHook.sol:355: Literal Instead of Constant (52 places)\n[low] local-variable-shadowing at src/MarginaliaHook.sol:859: Local Variable Shadows State Variable\n[low] require-revert-in-loop at src/MarginaliaHook.sol:864: Loop Contains `require`/`revert`\n[low] state-change-without-event at src/MarginaliaHook.sol:835: State Change Without Event (6 places)\n[low] state-no-address-check at src/MarginaliaRouter.sol:135: Address State Variable Set Without Checks\n[low] unchecked-return at src/MarginaliaHook.sol:718: Unchecked Return (6 places)\n[low] uninitialized-local-variable at src/MarginaliaHook.sol:667: Uninitialized Local Variable (3 places)\n[low] unused-import at src/MarginaliaHook.sol:10: Unused Import\n[low] unused-public-function at src/MarginaliaHook.sol:294: Public Function Not Used Internally","passed":true},{"durationMs":18101,"exitCode":0,"name":"proof 7ee86ab40f33","output":"Compiling 100 files with Solc 0.8.26\nSolc 0.8.26 finished in 17.30s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n   --> src/MarginaliaHook.sol:859:9:\n    |\n859 |         uint256 pool = thesisPool[w];\n    |         ^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> src/MarginaliaHook.sol:99:5:\n   |\n99 |     PoolKey private pool;\n   |     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n   --> src/MarginaliaHook.sol:299:5:\n    |\n299 |     function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata data)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/helpers/Fixture.sol:114:5:\n    |\n114 |     function priceOf(bytes32, address) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n\nRan 1 test for test/imd-proof-d3880313/Proof_7ee86ab40f33.t.sol:LateThesisChildTest\n[PASS] testAChildPostedAfterTheGraceStillRescuesTheThesisBond() (gas: 1559417)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.02ms (733.54µs CPU time)\n\nRan 1 test suite in 5.52ms (5.02ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"30550e36665b697d8ef4edf5261e2779cc997e6b8a957180ddfb72978df7fe3f","verifiedTreeHash":"798b7243c8d52583d4fcfd37ca62f45c1e859de8","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":172017,"exitCode":0,"name":"build","output":"Compiling 115 files with Solc 0.8.26\nSolc 0.8.26 finished in 171.80s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n   --> src/MarginaliaHook.sol:859:9:\n    |\n859 |         uint256 pool = thesisPool[w];\n    |         ^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> src/MarginaliaHook.sol:99:5:\n   |\n99 |     PoolKey private pool;\n   |     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n   --> src/MarginaliaHook.sol:299:5:\n    |\n299 |     function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata data)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/helpers/Fixture.sol:114:5:\n    |\n114 |     function priceOf(bytes32, address) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  --> test/fork/MainnetLaunch.t.sol:78:5:\n   |\n78 |     function _mine(bytes memory hookCode) internal view returns (bytes32 salt) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/MarginaliaTreasury.sol:51:9\n   │\n51 │         emit Dripped(day, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaTreasury.sol:43:22\n   │\n43 │         uint32 day = uint32(block.timestamp / 1 days);\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `jobHash` is changed without an event but is used for access control\n    ╭▸ src/MarginaliaRouter.sol:303:16\n    │\n303 │         delete jobHash;\n    │                ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:114:47\n    │\n114 │         for (uint256 i = 0; i < all.length && n < MAX_JUDGED; ++i) {\n    │                                               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[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/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:170:15\n    │\n170 │             ++n;\n    │               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:174:33\n    │\n174 │             out[i - 1] = bytes1(uint8(48 + v % 10));\n    │                                 ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' 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/MarginaliaHook.sol:84:38\n   │\n84 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:186:52\n    │\n186 │         return eligibleTheses(week).length == 0 || block.timestamp >= (uint256(week) + 1) * 7 days + 28 days;\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/MarginaliaJudge.sol:194:32\n    │\n194 │         if (judgedSet[week] || block.timestamp < requestedAt[week] + ANSWER_DEADLINE) {\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:214:9\n    │\n214 │         hook.drawForJudging(day, price, retry);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:217:21\n    │\n217 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n218 │ ┃             action, body, IIntake.Callback(address(this), this.onOracleResult.selector), imd, price\n219 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:206:41\n    │\n206 │         if (judgedSet[day] || (retry && block.timestamp < requestedAt[day] + ANSWER_DEADLINE)) {\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/MarginaliaJudge.sol:225:9\n    │\n225 │         emit Requested(day, requestId, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:223:28\n    │\n223 │         requestedAt[day] = uint64(block.timestamp);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/MarginaliaPricer.sol:85:13\n   │\n85 │             n += 1;\n   │             ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:120:33\n    │\n120 │         if (w.startedAt == 0 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:34\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:59\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:142:20\n    │\n142 │                 || block.timestamp < uint256(w.startedAt) + POST_MIN_SPAN\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/MarginaliaPricer.sol:143:20\n    │\n143 │                 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:149:69\n    │\n149 │             x = twap(v.kind, v.xIsToken0, w.xStart, w.startedAt, x, uint64(block.timestamp));\n    │                                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:168:55\n    │\n168 │         else if (v.kind == T.VenueKind.UniV3) xRead = uint256(_v3Cumulative(ref));\n    │                                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaJudge.sol:255:9\n    │\n255 │ ┏         emit Judged(\n256 │ ┃             day,\n257 │ ┃             [\n258 │ ┃                 count > 0 ? ranked[0] : bytes32(0),\n    ‡ ┃\n262 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:213:28\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:213:41\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:214:35\n    │\n214 │             int256 mean = delta / int256(dt);\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/MarginaliaPricer.sol:215:38\n    │\n215 │             if (delta < 0 && delta % int256(dt) != 0) mean -= 1; // round toward negative infinity, as v3 does\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/MarginaliaPricer.sol:217:57\n    │\n217 │             return fromSqrt(TickMath.getSqrtPriceAtTick(int24(mean)), xIsToken0);\n    │                                                         ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' 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/MarginaliaJudge.sol:276:17\n    │\n276 │             if (dup) continue;\n    │                 ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:269:50\n    │\n269 │         for (uint256 i = 0; i < ranked.length && kept < 3; ++i) {\n    │                                                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:270:77\n    │\n270 │             (address author, uint32 noteWeek, bool thesis, bool hasChild) = hook.noteMeta(ranked[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/MarginaliaPricer.sol:241:37\n    │\n241 │             (uint160 sqrtP,,,,,,) = IUniswapV3PoolOracle(ref).slot0();\n    │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:245:41\n    │\n245 │             (uint112 r0, uint112 r1,) = IUniswapV2PairOracle(ref).getReserves();\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaJudge.sol:288:9\n    │\n288 │         hook.payJudged(day, top);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:269:33\n    │\n269 │         (int56[] memory cum,) = IUniswapV3PoolOracle(pool).observe(ago);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:279:24\n    │\n279 │         uint32 nowTs = uint32(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaRouter.sol:251:13\n    │\n251 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:252:41\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:252:49\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:338:9\n    │\n338 │         emit Noted(job.payer, job.sellMarg, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:320:18\n    │\n320 │                 -int256(job.amountIn),\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/MarginaliaRouter.sol:328:25\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:328:33\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:329:28\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:329:36\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:373:9\n    │\n373 │         emit XTraded(payer, X_V4, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:355:18\n    │\n355 │                 -int256(x.amountIn),\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/MarginaliaRouter.sol:363:25\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:363:33\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:364:20\n    │\n364 │         received = uint256(uint128(outputDelta));\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:364:28\n    │\n364 │         received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:403:9\n    │\n403 │         emit XTraded(payer, X_V3, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:394:13\n    │\n394 │             int256(x.amountIn),\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/MarginaliaRouter.sol:399:25\n    │\n399 │         uint256 spent = uint256(zeroForOne ? a0 : a1);\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/MarginaliaRouter.sol:409:78\n    │\n409 │         if (amount0Delta > 0) IERC20(pool.token0()).safeTransfer(msg.sender, uint256(amount0Delta));\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/MarginaliaRouter.sol:410:78\n    │\n410 │         if (amount1Delta > 0) IERC20(pool.token1()).safeTransfer(msg.sender, uint256(amount1Delta));\n    │                                                                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:438:9\n    │\n438 │         emit XTraded(payer, X_V2, xIn, xOut, actualIn, received);\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/MarginaliaRouter.sol:426:37\n    │\n426 │         (uint112 r0, uint112 r1,) = pair.getReserves();\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:312:49\n    │\n312 │                 specifiedTake = STAMP + _bondOf(uint256(-params.amountSpecified));\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:389:9\n    │\n389 │         emit Accrued(day, amount);\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/MarginaliaHook.sol:471:17\n    │\n471 │                 emit Revealed(id, hash);\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/MarginaliaHook.sol:495:9\n    │\n495 │         emit NotePosted(id, author, p.x, class, p.side, p.targetBps, p.horizonDays, p.parentId, p.text);\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/MarginaliaHook.sol:348:13\n    │\n348 │             emit SwapFee(true, author, poolImd, 0, STAMP);\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/MarginaliaHook.sol:361:13\n    │\n361 │             emit SwapFee(false, author, poolImd, fee - STAMP, STAMP);\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/MarginaliaHook.sol:372:9\n    │\n372 │         emit SwapFee(false, tx.origin, poolImd, quietFee, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:335:33\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:41\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:63\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:335:71\n    │\n335 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:340:36\n    │\n340 │             uint256 bond = _bondOf(uint256(-params.amountSpecified));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:342:31\n    │\n342 │             uint256 margOut = uint256(uint128(margDelta));\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/MarginaliaHook.sol:342:39\n    │\n342 │             uint256 margOut = uint256(uint128(margDelta));\n    │                                       ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:450:17\n    │\n450 │             if (weekTheses[w].length >= MAX_WEEK_THESES || thesesPerAuthor[w][author] >= MAX_AUTHOR_THESES) {\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/MarginaliaHook.sol:450:60\n    │\n450 │             if (weekTheses[w].length >= MAX_WEEK_THESES || thesesPerAuthor[w][author] >= MAX_AUTHOR_THESES) {\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/MarginaliaHook.sol:465:26\n    │\n465 │             if (bound && age < SEAL_MIN) revert TooEarly(); // the head start is the key holders', not the public's\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/MarginaliaHook.sol:466:26\n    │\n466 │             if (bound && age <= SEAL_MAX) {\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/MarginaliaHook.sol:484:32\n    │\n484 │ …                     || block.timestamp > uint256(parent.postedAt) + THESIS_GRACE\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:442:22\n    │\n442 │         n.postedAt = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:540:13\n    │\n540 │         if (block.timestamp < end) revert TooEarly();\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/MarginaliaHook.sol:541:13\n    │\n541 │         if (block.timestamp > end + SETTLE_WINDOW) revert TooLate();\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/MarginaliaHook.sol:554:47\n    │\n554 │                     || (len == OBS_MAX - 1 && block.timestamp < uint256(obs[0].timestamp) + OBS_MIN_SPAN))\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/MarginaliaHook.sol:562:9\n    │\n562 │         emit Observed(id, xRead, balance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:546:27\n    │\n546 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:546:52\n    │\n546 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                                                    ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:570:13\n    │\n570 │             x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.balanceOf.selector, who));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaHook.sol:651:35\n    │\n651 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │                                   ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:607:13\n    │\n607 │         if (block.timestamp <= end + SETTLE_WINDOW) revert TooEarly();\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/MarginaliaHook.sol:736:13\n    │\n736 │             emit ThesisReleased(n.parentId);\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/MarginaliaHook.sol:651:9\n    │\n651 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:634:26\n    │\n634 │             scoreDelta = int256(_difficulty(n));\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/MarginaliaHook.sol:639:27\n    │\n639 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:641:27\n    │\n641 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:645:27\n    │\n645 │             scoreDelta = -int256(_difficulty(n));\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[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:669:17\n    │\n669 │             try pricer().settlePrice(n.venue, buy, sample) returns (uint256 p) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:683:13\n    │\n683 │         if (block.timestamp >= horizonEnd(id)) revert TooLate();\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/MarginaliaHook.sol:693:9\n    │\n693 │         emit Retracted(id, text);\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/MarginaliaHook.sol:694:9\n    │\n694 │         emit Settled(id, T.Status.Retracted, 0, scoreDelta, address(0));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:687:30\n    │\n687 │         int256 scoreDelta = -int256(_difficulty(n) / 2);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:702:13\n    │\n702 │         if (block.timestamp <= uint256(n.postedAt) + THESIS_GRACE) revert TooEarly();\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/MarginaliaHook.sol:705:9\n    │\n705 │         emit ThesisForfeited(id);\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/MarginaliaHook.sol:719:9\n    │\n719 │         emit DepositClaimed(id, n.author, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:749:13\n    │\n749 │             n.x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.totalSupply.selector));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:758:16\n    │\n758 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:762:16\n    │\n762 │         return uint32(block.timestamp / 7 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:782:9\n    │\n782 │         emit PotFunded(_today(), amount, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `seals` is updated\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:816:25\n    │\n816 │         if ((at != 0 && block.timestamp - at <= SEAL_MAX) || x == address(0) || hash == bytes32(0)) {\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/MarginaliaHook.sol:830:9\n    │\n830 │         emit Sealed(hash, msg.sender, x, venue.ref);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:824:13\n    │\n824 │             uint64(block.timestamp),\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:837:23\n    │\n837 │         if (!retry && block.timestamp < (uint256(w) + 1) * 7 days + THESIS_GRACE) revert TooEarly();\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:851:27\n    │\n851 │         return (n.author, uint32(uint256(n.postedAt) / 7 days), n.targetBps == 0, n.children > 0);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `thesisPool` is updated\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:925:28\n    │\n925 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:873:9\n    │\n873 │         emit JudgedPaid(w, paidAmounts);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaHook.sol:926:39\n    │\n926 │         if (unlockHash != bytes32(0)) revert InvalidUnlock();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:880:13\n    │\n880 │         if (n.day >= _today()) revert TooEarly();\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/MarginaliaHook.sol:890:9\n    │\n890 │         emit RefundClaimed(id, msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:888:30\n    │\n888 │         notesPerDay[n.day] = uint32(count - 1);\n    │                              ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:899:17\n    │\n899 │             if (block.timestamp < (uint256(epoch) + 1) * 1 days + SWEEP_AFTER) revert TooEarly();\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/MarginaliaHook.sol:903:17\n    │\n903 │             if (block.timestamp < (uint256(epoch) + 1) * 7 days + SWEEP_AFTER) revert TooEarly();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:936:40\n    │\n936 │             address currency = address(uint160(extra));\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[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaHook.sol:945:13\n    │\n945 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/AuditFindings.t.sol:19:30\n   │\n19 │         uint256 startBlock = block.number;\n   │                              ━━━━━━━━━━━━\n   ‡\n23 │             vm.roll(startBlock + 25 * (i + 1));\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/AuditFindings.t.sol:20:27\n   │\n20 │         uint256 startTs = block.timestamp;\n   │                           ━━━━━━━━━━━━━━━\n   ‡\n24 │             vm.warp(startTs + 31 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:18:9\n    │\n 18 │         vm.warp(hook.horizonEnd(id));\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:65:9\n    │\n 65 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:82:9\n    │\n 82 │         vm.warp(deadline - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:193:9\n    │\n193 │         vm.warp(weekEnd - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookReview.t.sol:195:9\n    │\n195 │         vm.warp(weekEnd + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:148:9\n    │\n148 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:149:30\n    │\n149 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n153 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:150:27\n    │\n150 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n154 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:176:9\n    │\n176 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:177:30\n    │\n177 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n181 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:178:27\n    │\n178 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n182 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:203:9\n    │\n203 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:204:30\n    │\n204 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n208 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:205:27\n    │\n205 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n209 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:302:9\n    │\n302 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:357:9\n    │\n357 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:358:30\n    │\n358 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n363 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:359:27\n    │\n359 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n364 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:421:9\n    │\n421 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:488:9\n    │\n488 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:489:30\n    │\n489 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n492 │         vm.roll(startBlock + 25);\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/Lifecycle.t.sol:490:27\n    │\n490 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n493 │         vm.warp(startTs + 30 minutes);\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:512:9\n    │\n512 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:513:30\n    │\n513 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n517 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:514:27\n    │\n514 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n518 │             vm.warp(startTs + 10 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:554:9\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:538:49\n    │\n538 │         router.note(rebuttal, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:554:17\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:583:9\n    │\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:575:49\n    │\n575 │         router.note(sameSide, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:584:30\n    │\n584 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n589 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:585:27\n    │\n585 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n590 │             vm.warp(startTs + 30 minutes * (i + 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/Lifecycle.t.sol:629:22\n    │\n629 │         assertEq(at, block.timestamp);\n    │                      ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:634:42\n    │\n634 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:638:17\n    │\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:653:17\n    │\n653 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:657:42\n    │\n657 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:663:17\n    │\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:679:17\n    │\n679 │         vm.warp(block.timestamp + hook.SEAL_MAX() + 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/Lifecycle.t.sol:682:17\n    │\n682 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:199:17\n    │\n199 │         vm.warp(block.timestamp + 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:267:9\n    │\n267 │         vm.warp((uint256(w) + 1) * 7 days + hook.THESIS_GRACE());\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/Round3Findings.t.sol:67:17\n   │\n67 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":1137,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/MainnetLaunch.t.sol:MainnetLaunchTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 744.48µs (0.00ns CPU time)\n\nRan 14 tests for test/CompanionFailures.t.sol:RouterFailuresTest\n[PASS] testExpiredDeadlineTakesNothing() (gas: 668139)\n[PASS] testExpiredWindowRefusesPostsUntilAFreshCheckpointMatures() (gas: 1756378)\n[PASS] testInitRequiresAManagerWithCode() (gas: 4169863)\n[PASS] testSlippageFloorRefundsEverything() (gas: 639941)\n[PASS] testStrangersCannotEnterTheCallbacks() (gas: 133302)\n[PASS] testTradeAndNoteRefusesNoTradeZeroTradeAndNativeInput() (gas: 290673)\n[PASS] testTradedNoteMustBeAboutTheTokenTraded() (gas: 980650)\n[PASS] testTradedV4LegUnderAForeignHookOrEmptyPoolIsRefused() (gas: 396113)\n[PASS] testUnapprovedOrUnfundedAuthorIsRefused() (gas: 224265)\n[PASS] testV4VenueUnderAForeignHookIsRefused() (gas: 69759)\n[PASS] testV4VenueWithoutLiquidityIsRefused() (gas: 134961)\n[PASS] testVenueFieldsAreDerivedFromThePoolNotTheCaller() (gas: 48554)\n[PASS] testVenueKindNoneIsRefusedForAPricedCall() (gas: 116223)\n[PASS] testZeroAndOversizedAmountsAreRefused() (gas: 138593)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 13.95ms (5.10ms CPU time)\n\nRan 6 tests for test/AuditFindings.t.sol:AuditFindingsTest\n[PASS] testEmptyV4ObservationIsRefused() (gas: 918993)\n[PASS] testExpiredBaselineRejectsPostWithoutTakingFunds() (gas: 601798)\n[PASS] testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried() (gas: 2111077)\n[PASS] testSameBlockDumpPostUnwindDoesNotWinBuy() (gas: 1822381)\n[PASS] testSameBlockPumpPostUnwindDoesNotWinSell() (gas: 1691295)\n[PASS] testUnpayableRankingRollsTheWholePoolForward() (gas: 2384827)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 17.10ms (7.74ms CPU time)\n\nRan 12 tests for test/HoldRule.t.sol:HoldRuleTest\n[PASS] testABreachIsNeverReplacedByANonBreachInsideTheGap() (gas: 1653878)\n[PASS] testABreachReplacesANonBreachInsideTheGap() (gas: 1661691)\n[PASS] testABuyCallWithAnUnreadableBalanceIsVoidSold() (gas: 1484869)\n[PASS] testASellAuthorMayDumpTheirWholeRemainingBalance() (gas: 1622310)\n[PASS] testASellAuthorWhoBuysBackTheirWholePostBalanceIsStillRight() (gas: 1717897)\n[PASS] testASellCallWithAnUnreadableBalanceStillSettlesOnPrice() (gas: 1510057)\n[PASS] testASellCallsBalanceIsNeverAnAdverseReading() (gas: 1360897)\n[PASS] testAWrongSellCallForfeitsWhateverTheBalanceDid() (gas: 1426628)\n[PASS] testAnEqualReadingInsideTheGapIsRefused() (gas: 1031930)\n[PASS] testAtTheCapAHigherReadingCannotLiftABuyCallsMinimum() (gas: 3939441)\n[PASS] testAtTheCapOnlyAMoreAdverseReadingGetsIn() (gas: 4186133)\n[PASS] testBuyCallHasNoToleranceDownwards() (gas: 1570913)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 25.40ms (14.98ms CPU time)\n\nRan 31 tests for test/Lifecycle.t.sol:LifecycleTest\n[PASS] testAttestedClassCannotBeSelfDeclared() (gas: 294892)\n[PASS] testCallbackSelectorPinned() (gas: 3383)\n[PASS] testCounterCallDuel() (gas: 3589375)\n[PASS] testCounterThesisEntersTheJudgedSet() (gas: 2688706)\n[PASS] testFakeVenueIsRefused() (gas: 382766)\n[PASS] testFlagsAndBinding() (gas: 56048)\n[PASS] testForfeitsAreImdAndNeedNoConversion() (gas: 861195)\n[PASS] testNoDataRefunds() (gas: 880570)\n[PASS] testNoteTooSmall() (gas: 1644543)\n[PASS] testNotedBuyTakesStampAndDeposit() (gas: 729443)\n[PASS] testNotedSellPaysOnePercentPlusStamp() (gas: 988516)\n[PASS] testObservationsMustSpanAnHour() (gas: 1384019)\n[PASS] testPlainBuyTakesNothing() (gas: 211688)\n[PASS] testQuietSellPaysThreePercent() (gas: 295440)\n[PASS] testQuietThesisPoolSweeps() (gas: 300271)\n[PASS] testRetract() (gas: 866644)\n[PASS] testRightCallReturnsDeposit() (gas: 1623568)\n[PASS] testScoreIsReputationAndAccrualsSplitSeventyThirty() (gas: 2887924)\n[PASS] testSealedBuyMustKeepItsPositionFromTheSeal() (gas: 2165657)\n[PASS] testSealedNoteRevealsAgainstTheSealBaseline() (gas: 1770762)\n[PASS] testSellingEarlyBreaksTheCall() (gas: 1678252)\n[PASS] testThesisParentChild() (gas: 1362912)\n[PASS] testThesisWithoutChildForfeits() (gas: 828214)\n[PASS] testTreasuryDrip() (gas: 320866)\n[PASS] testTwoBlockPumpObserveUnwindSettlesWrong() (gas: 1692826)\n[PASS] testUnansweredWeekCanBeRetried() (gas: 2356119)\n[PASS] testUnrevealedSealIsNotAFreeOptionAndLapses() (gas: 1361008)\n[PASS] testUpOnlyIsRefused() (gas: 291916)\n[PASS] testWeeklyThesisJudging() (gas: 3728190)\n[PASS] testWriterRefundCappedAtStamp() (gas: 1589580)\n[PASS] testWrongCallForfeitsWithKeeperReward() (gas: 1511685)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 42.03ms (28.04ms CPU time)\n\nRan 10 tests for test/Round3Findings.t.sol:Round3FindingsTest\n[PASS] testABuyCallStillBreaksWhenTheAuthorSells() (gas: 1669522)\n[PASS] testAGiftOfAnySizeDoesNotVoidACorrectSellCall() (gas: 1584170)\n[PASS] testAGiftWorthTheDepositDoesNotVoidACorrectSellCall() (gas: 1663423)\n[PASS] testALaunchPoolCallScoresTheSameWay() (gas: 1417891)\n[PASS] testASelfPricedVenueBooksReputationOnlyAndNoPoolPaysForIt() (gas: 3007470)\n[PASS] testAWrongCallOnAnotherVenueStillForfeitsAndBooksANegativeScore() (gas: 2707061)\n[PASS] testAWrongSellCallStillForfeits() (gas: 1395988)\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 256, μ: 21518, ~: 18720)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1945010)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204563)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 68.31ms (24.25ms CPU time)\n\nRan 3 tests for test/Implementations.t.sol:ImplementationsTest\n[PASS] testClonesInitializeOnceOnlyFromTheirHook() (gas: 4551335)\n[PASS] testFactoryDeploysAllFourWithoutArgumentsOrExternalDependencies() (gas: 34608585)\nLogs:\n  four implementation CREATE2 deployments (gas): 8829579\n\n[PASS] testImplementationsRejectInitialization() (gas: 81376)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 69.12ms (40.76ms CPU time)\n\nRan 9 tests for test/CompanionFailures.t.sol:TreasuryFailuresTest\n[PASS] testDripFailsWhenTheHookCannotTakeTheFunds() (gas: 673929)\n[PASS] testDripIsPermissionlessAndCompounds() (gas: 518661)\n[PASS] testDripOfDustRoundsToZeroAndReverts() (gas: 258318)\n[PASS] testDripWithNothingHeldReverts() (gas: 54033)\n[PASS] testInitOnlyByTheNamedHookAndOnlyOnce() (gas: 623926)\n[PASS] testInitRefusesTheZeroHook() (gas: 556415)\n[PASS] testNoWithdrawOrAdminSurface() (gas: 274868)\n[PASS] testSecondDripOnTheSameDayRevertsAndTheNextDayWorks() (gas: 372660)\n[PASS] testTreasuryRefusesEth() (gas: 71164)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 77.55ms (1.65ms CPU time)\n\nRan 8 tests for test/LaunchAuditFindings.t.sol:LaunchAuditFindingsTest\n[PASS] testAHugeSupplyBooksTierOneInsteadOfOverflowing() (gas: 2461200)\n[PASS] testALapsedSealCanBeSealedAgain() (gas: 703279)\n[PASS] testARetractedNoteLeavesTheDaysRefundSplit() (gas: 1382965)\n[PASS] testARetractionAfterTheRefundClaimDoesNotDoubleCount() (gas: 1359071)\n[PASS] testARevertingTotalSupplyDoesNotBlockARetraction() (gas: 1932201)\n[PASS] testARevertingTotalSupplyStillSettlesWrongAndPaysTheKeeper() (gas: 2554573)\n[PASS] testAStrangersSealNeitherBlocksNorPricesTheAuthorsNote() (gas: 2518397)\n[PASS] testAnAuthorsSealOnAnotherVenueDoesNotPriceTheNote() (gas: 2235395)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 77.57ms (7.28ms CPU time)\n\nRan 7 tests for test/JudgeOracle.t.sol:JudgeOracleTest\n[PASS] testEmptySignedRankingIsAnExecutableNoWinnerResult() (gas: 248153)\n[PASS] testFiveIdsWithEoaSignatureFitStipend() (gas: 554052)\n[PASS] testFullRankingWithEoaSignatureFitsStipend() (gas: 633672)\n[PASS] testProtocolDigestSignatureAndSelectorConformanceOnClone() (gas: 3322442)\n[PASS] testRejectedAnswersDoNotConsumeThePendingRequest() (gas: 892875)\n[PASS] testRequestedHeadIsFilteredAndDeduplicatedWithoutPromotingTheTail() (gas: 250679)\n[PASS] testTimeoutRetryInvalidatesOldIntakeRequest() (gas: 523953)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 78.19ms (5.60ms CPU time)\n\nRan 7 tests for test/Pricer.t.sol:PricerTest\n[PASS] testQuoteLegIsAdverseEvenUnderAV3Twap() (gas: 28455)\n[PASS] testTwapRefusesZeroSpanAndV4() (gas: 17708)\n[PASS] testV2TwapFromWrappingCumulative() (gas: 9503)\n[PASS] testV3TwapOfAConstantTickIsThatTick() (gas: 15459)\n[PASS] testV3TwapRoundsNegativeMeansDown() (gas: 14848)\n[PASS] testV3TwapWeightsByTime() (gas: 14715)\n[PASS] testV4SettlesOnTheAdverseExtreme() (gas: 26636)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 78.20ms (821.43µs CPU time)\n\nRan 10 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testABuyBackNoLongerVoidsASellCallItSettlesOnPrice() (gas: 1599565)\n[PASS] testADustPricedV4VenueCannotBePostedOn() (gas: 1574208)\n[PASS] testARevertingBalanceOfVoidsTheCallAsSoldNotAsNoData() (gas: 2592032)\n[PASS] testAStrangersDustTransferDoesNotVoidASellCall() (gas: 1564471)\n[PASS] testAnAttestationAboutAnotherChainIsRefused() (gas: 2243391)\n[PASS] testAnEmptyCanonicalV3PoolIsRefusedAsAVenue() (gas: 567783)\n[PASS] testHonestObserverOverwritesAPumpObserveUnwindInTheNextBlock() (gas: 3639686)\n[PASS] testPricerRefusesAPriceThatRoundsToZeroInBothOrientations() (gas: 58756)\n[PASS] testSweepNeedsTheStaleRequestAbandonedAndALateAnswerIsThenRefused() (gas: 2379400)\n[PASS] testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment() (gas: 68883218)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 78.09ms (66.24ms CPU time)\n\nRan 8 tests for test/PriceHistory.t.sol:PriceHistoryTest\n[PASS] testBaselineRequiresMatureFreshHistory() (gas: 188472)\n[PASS] testEmptyVenueAndHubCannotBeCheckpointedObservedOrPriced() (gas: 284549)\n[PASS] testFuzzV4BaselineIsNeverFavourableToTheCall(int24,bool) (runs: 256, μ: 106059, ~: 106111)\nLogs:\n  Bound result -75015\n\n[PASS] testHubBaselineUsesOppositeExtremeFromSettlement() (gas: 180334)\n[PASS] testLiveCheckpointCannotEraseHonestExtremesOrRestartTheClock() (gas: 224282)\n[PASS] testV2BaselineIgnoresSameBlockReservesDumpAndPumpBothOrientations() (gas: 467543)\n[PASS] testV3BaselineIgnoresSameBlockTickChangesBothOrientations() (gas: 418025)\n[PASS] testV3BaselineWeightsElapsedTime() (gas: 371037)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 78.24ms (80.00ms CPU time)\n\nRan 28 tests for test/CompanionFailures.t.sol:JudgeFailuresTest\n[PASS] testAJudgedWeekCannotBeAbandoned() (gas: 1257630)\n[PASS] testAbandonNeedsALiveRequestPastItsDeadline() (gas: 1190393)\n[PASS] testAbandonTakesNothingAndTheRetryDrawsAgain() (gas: 1467522)\n[PASS] testAnswerAtTheExactExpiryStillCountsAndOneSecondLaterDoesNot() (gas: 1257046)\n[PASS] testAnswerForAWeekAlreadyJudgedIsRefused() (gas: 1320679)\n[PASS] testAnswerSignedByAnotherKeyIsRefused() (gas: 1069433)\n[PASS] testAnswerSignedForAnotherConsumerIsRefused() (gas: 3952788)\n[PASS] testConvertForfeitsWithAnEmptyPotIsANoOp() (gas: 236930)\n[PASS] testConvertNeverSellsMoreThanThePot() (gas: 236488)\n[PASS] testConvertSellsTheLargestHalvingThePoolAbsorbs() (gas: 275386)\n[PASS] testConvertTriesExactlyNineTranchesDownToOneTwoHundredFiftySixth() (gas: 363686)\n[PASS] testCurrentAndFutureWeeksCannotBeRequested() (gas: 128617)\n[PASS] testEligibleThesesAreCappedAtTheJudgedMaximum() (gas: 14217218)\n[PASS] testImplementationHasAPlaceholderSignerAndCannotBeConfigured() (gas: 2726709)\n[PASS] testInitRequiresEveryConfigurationValue() (gas: 2953442)\n[PASS] testIntakeReturningAnIdAlreadyPendingIsRefused() (gas: 1599187)\n[PASS] testJudgedOfFiltersWrongWeekShortFormAndChildlessIds() (gas: 1439829)\n[PASS] testJudgedWeekCannotBeRequestedAgainEvenAfterTheDeadline() (gas: 1242650)\n[PASS] testMalformedAnswerBytesAreRefused() (gas: 1067354)\n[PASS] testOnlyTheHeadOfThreeIsStoredAndTheTailNeverPromotes() (gas: 1221812)\n[PASS] testPayBeforeAnAnswerReverts() (gas: 1064318)\n[PASS] testPayIsPermissionlessAndOnce() (gas: 1438634)\n[PASS] testQuestionBodyNamesTheConsumerChainAndEligibleIdsOnly() (gas: 2516225)\n[PASS] testRepeatRequestBeforeTheDeadlineIsRefused() (gas: 1419149)\n[PASS] testRequestDrawsExactlyThePriceAndKeepsNothing() (gas: 1028228)\n[PASS] testWeekClosedStates() (gas: 1940695)\n[PASS] testWeekWithoutEligibleThesesCannotBeRequested() (gas: 244665)\n[PASS] testZeroAndExcessiveOraclePricesAreRefused() (gas: 1345941)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 78.37ms (41.49ms CPU time)\n\nRan 31 tests for test/PricerProperties.t.sol:PricerPropertiesTest\n[PASS] testDifficultyAnchors() (gas: 56436)\n[PASS] testDifficultyRefusesAZeroHorizon() (gas: 10063)\n[PASS] testDifficultyTiersStepExactlyAtTheThresholds() (gas: 79314)\n[PASS] testEmptyPoolsAreRefusedOnBothLegs() (gas: 161813)\n[PASS] testEthQuoteIsOnlyPriceableOnMainnet() (gas: 40894)\n[PASS] testFromSqrtRefusesAnEmptyOrUnpriceableReading() (gas: 53891)\n[PASS] testFromSqrtZeroThresholdIsSharpInBothOrientations() (gas: 1024182)\n[PASS] testFuzzAppendingAnObservationNeverHelpsTheCall(uint256[16],uint256[16],uint8) (runs: 1000, μ: 132473, ~: 115643)\nLogs:\n  Bound result 10\n  Bound result 9999999990000000000\n  Bound result 999999999999999999999000000005\n  Bound result 999999999999999999999000259201\n  Bound result 999999999999999999999000000361\n  Bound result 999999999999999999999011155112\n  Bound result 999999999999999999999000000102\n  Bound result 999999999999999999999000007462\n  Bound result 999999999999999999999000000099\n  Bound result 999999999999999999999000000256\n  Bound result 999999999999999999999000000061\n  Bound result 999999999999999999999000000078\n  Bound result 999999999999999999999000004547\n  Bound result 999999999999999999999000024726\n  Bound result 999999999999999999999000019215\n  Bound result 999999999999999999999000001667\n  Bound result 999999999999999999999000009334\n  Bound result 999999999999999999999000000061\n  Bound result 39614081257132168796771975168\n  Bound result 999999999999999999999000005240\n  Bound result 111000000000000000000000\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36906, ~: 36946)\nLogs:\n  Bound result 9989128\n  Bound result 9989051\n  Bound result 90\n  Bound result 1300000000000000000000000\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141552, ~: 141878)\nLogs:\n  Bound result 1266412660188944021222707332547\n  Bound result 71964150694565804643617499196\n  Bound result 26885\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36715, ~: 36840)\nLogs:\n  Bound result 989065\n  Bound result 32\n  Bound result 39\n  Bound result 21093\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23330, ~: 21255)\nLogs:\n  Bound result 316912650057057350374175801344\n  Bound result 1267650600228229401496703205376\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39944, ~: 39734)\nLogs:\n  Bound result 999001\n  Bound result 3264592782\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16183, ~: 14502)\nLogs:\n  Bound result 0\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 54014, ~: 51987)\nLogs:\n  Bound result 14575\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36398, ~: 36380)\nLogs:\n  Bound result 2\n  Bound result 6\n  Bound result 62\n  Bound result 512\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18498, ~: 16591)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21358, ~: 21299)\nLogs:\n  Bound result 14434802388970472\n  Bound result 1\n  Bound result 3\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 63838, ~: 61082)\nLogs:\n  Bound result 17931\n  Bound result 14\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 101120, ~: 91574)\nLogs:\n  Bound result 16\n  Bound result 7174\n  Bound result 1264\n  Bound result 40000\n  Bound result 5000000000000000000\n  Bound result 19915\n  Bound result 70\n  Bound result 5000000000000000000\n  Bound result 27978\n  Bound result 26\n  Bound result 1000000000000000000\n  Bound result 4932\n  Bound result 4000000000000000000\n  Bound result 24695\n  Bound result 858811238160587340303074464592\n  Bound result 6712\n  Bound result 200000000000000000000000\n  Bound result 77\n  Bound result 6702\n  Bound result 500000000000000000\n  Bound result 100000000000000000000\n  Bound result 2000000000000000000000\n  Bound result 20827\n  Bound result 316912650057057350374175801344\n  Bound result 95\n  Bound result 16501\n  Bound result 1576786069\n  Bound result 8243\n  Bound result 111000000000000000000000\n  Bound result 600000000000000000000000\n  Bound result 1801\n  Bound result 6397\n  Bound result 300000000000000000000\n\n[PASS] testObserveRefusesUnknownVenuesAndUnpriceableQuotes() (gas: 150448)\n[PASS] testPostPriceRefusesAnEmptyWindow() (gas: 15317)\n[PASS] testPostPriceWhoseProductRoundsToZeroIsRefused() (gas: 293627)\n[PASS] testSellDifficultyRefusesAZeroTarget() (gas: 9518)\n[PASS] testSettlementRefusesAnEmptyOrUnspannedSeries() (gas: 39083)\n[PASS] testSqrtIsExactOnEveryHorizonDifficultyUses() (gas: 903275)\n[PASS] testSqrtPins() (gas: 123131)\n[PASS] testTwapRefusesTimeRunningBackwards() (gas: 9132)\n[PASS] testV2TwapAndSpotOfADustRatioAreRefused() (gas: 220677)\n[PASS] testV3TwapRefusesAMeanTickOutsideTheRange() (gas: 27255)\n[PASS] testV4SeriesWithADustExtremeIsRefusedNotSettledAtZero() (gas: 33519)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 78.37ms (847.18ms CPU time)\n\nRan 18 tests for test/HookReview.t.sol:HookReviewTest\n[PASS] testBuyCallOnImdRefusedBeforeTakingBond() (gas: 695548)\n[PASS] testBuySettlementUsesSameObservationForBothLegs() (gas: 2194208)\n[PASS] testChildAtExactlyGraceDeadlineReleasesThesis() (gas: 1501471)\n[PASS] testDustReplacementsCannotMonopolizeObservationWindow() (gas: 30914015)\n[PASS] testJudgingWaitsForEveryThesisChildGrace() (gas: 3710217)\n[PASS] testLateChildCannotRescueThesis() (gas: 1480370)\n[PASS] testOneAuthorCannotFillTheWeeklyThesisSet() (gas: 43417988)\n[PASS] testOneHostileReadingRemainsAdverseAfterPriceRecovers() (gas: 2182461)\n[PASS] testReplacementCannotLeaveAFullSeriesShortOfOneHour() (gas: 4017959)\n[PASS] testReplacementDoesNotRestartTwentyBlockGap() (gas: 1296953)\n[PASS] testSealOnImdRefusedBeforeTakingStamp() (gas: 389434)\n[PASS] testSellCallOnImdRefusedBeforeTakingBond() (gas: 695149)\n[PASS] testSellSettlementUsesSameObservationForBothLegs() (gas: 2196149)\n[PASS] testSingleSidedLiquidityExitPaysNoHookSwapFee() (gas: 1189966)\n[PASS] testV2AliasPostRefused() (gas: 2486105)\n[PASS] testV2AliasSealRefused() (gas: 2230883)\n[PASS] testV3AliasPostRefused() (gas: 2323854)\n[PASS] testV3AliasSealRefused() (gas: 2067752)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 78.49ms (81.12ms CPU time)\n\nRan 1 test for test/RouterInvariant.t.sol:RouterInvariantTest\n[PASS]\nRouterInvariantTest invariants:\n[PASS] invariant_bindingsPinned\n[PASS] invariant_everyNoteCameThroughTheRouter\n[PASS] invariant_managerBacksTheHooksClaims\n[PASS] invariant_routerKeepsNothing\n RouterInvariantTest invariants (runs: 48, calls: 1920, reverts: 2)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| RouterHandler | advance        | 233   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 226   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 436   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 235   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 208   | 2       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 206   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 206   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 170   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1569\n  Bound result 2\n  Bound result 3688193970\n  Bound result 10\n  Bound result 62\n  Bound result 1\n  Bound result 0\n  Bound result 10154\n  Bound result 55114\n  Bound result 78\n  Bound result 2\n  Bound result 2\n  Bound result 2350000000000000000\n  Bound result 1464\n  Bound result 0\n  Bound result 347\n  Bound result 2\n  Bound result 16\n  Bound result 50128\n  Bound result 84\n  Bound result 1\n  Bound result 1\n  Bound result 300\n  Bound result 6734\n  Bound result 73\n  Bound result 1\n  Bound result 280\n  Bound result 8267\n  Bound result 44\n  Bound result 0\n  Bound result 0\n  Bound result 1345\n  Bound result 58454\n  Bound result 11\n  Bound result 14\n  Bound result 2\n  Bound result 79417864581411152892\n  Bound result 1874\n  Bound result 3\n  Bound result 0\n  Bound result 3443\n  Bound result 59196\n  Bound result 22\n  Bound result 2\n  Bound result 2000000000000000000\n  Bound result 49801\n  Bound result 37\n  Bound result 0\n  Bound result 12421\n  Bound result 50031\n  Bound result 90\n  Bound result 1787\n  Bound result 157\n  Bound result 0\n  Bound result 17067\n  Bound result 50120\n  Bound result 55\n  Bound result 2\n  Bound result 1489190552936884563621\n  Bound result 48444\n  Bound result 23\n  Bound result 0\n  Bound result 2000000000000000000000\n  Bound result 8959\n  Bound result 50\n  Bound result 2\n  Bound result 20000\n  Bound result 2\n  Bound result 26\n  Bound result 2\n  Bound result 1999999999999999999999\n  Bound result 57001\n  Bound result 54\n  Bound result 0\n  Bound result 11702\n  Bound result 3638\n  Bound result 3\n  Bound result 126\n  Bound result 0\n  Bound result 9008\n  Bound result 953\n  Bound result 8\n  Bound result 1\n  Bound result 58\n  Bound result 0\n  Bound result 5984\n  Bound result 1\n  Bound result 43126439639747923169738\n  Bound result 0\n  Bound result 3600\n  Bound result 54340\n  Bound result 50\n  Bound result 1\n  Bound result 400000000000000000000\n  Bound result 2\n  Bound result 6211\n  Bound result 50161\n  Bound result 83\n  Bound result 2\n  Bound result 6286\n  Bound result 1\n  Bound result 791539047114491387855\n  Bound result 7842\n  Bound result 13\n  Bound result 779137187705\n  Bound result 2\n  Bound result 2\n  Bound result 2428\n  Bound result 59494\n  Bound result 82\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 442.75ms (431.77ms CPU time)\n\nRan 1 test for test/TreasuryInvariant.t.sol:TreasuryInvariantTest\n[PASS]\nTreasuryInvariantTest invariants:\n[PASS] invariant_balanceIsGiftsMinusDrips\n[PASS] invariant_dripNeverExceedsTwoPercent\n[PASS] invariant_holdsNoEth\n[PASS] invariant_hookHoldsExactlyTheDrips\n[PASS] invariant_hookIsPinned\n[PASS] invariant_lastDripDayMatchesTheLastSuccessfulDrip\n TreasuryInvariantTest invariants (runs: 256, calls: 12288, reverts: 0)\n\n╭-----------------+-----------+-------+---------+----------╮\n| Contract        | Selector  | Calls | Reverts | Discards |\n+==========================================================+\n| TreasuryHandler | advance   | 2438  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2389  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2493  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2516  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2452  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 1928\n  Bound result 999\n  Bound result 109402097\n  Bound result 129\n  Bound result 5000000000000000000\n  Bound result 5833\n  Bound result 16383\n  Bound result 770891471883707677309744\n  Bound result 2350000000000000000\n  Bound result 3041954474\n  Bound result 54772\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 90\n  Bound result 5221\n  Bound result 49152\n  Bound result 9285380274899124224\n  Bound result 3660\n  Bound result 263400868551549723330807389252719309078400637035\n  Bound result 5247\n  Bound result 38377\n  Bound result 517440284\n  Bound result 6016\n  Bound result 132196\n  Bound result 9999999999999999997\n  Bound result 2464\n  Bound result 4658\n  Bound result 5270\n  Bound result 4180627706672338401\n  Bound result 3492\n  Bound result 2593680741767684017\n  Bound result 8334\n  Bound result 6142\n  Bound result 7500230396360868618\n  Bound result 3000000000000000000\n  Bound result 20\n  Bound result 70\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.02s (1.02s CPU time)\n\nRan 18 test suites in 1.02s (2.40s CPU time): 204 tests passed, 0 failed, 1 skipped (205 total tests)\n","passed":true},{"durationMs":81,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Marginalia.approve(address,uint256)\",\"Marginalia.transfer(address,uint256)\",\"Marginalia.transferFrom(address,address,uint256)\",\"MarginaliaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"MarginaliaHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"MarginaliaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"MarginaliaHook.claimDeposit(bytes32)\",\"MarginaliaHook.claimRefund(bytes32)\",\"MarginaliaHook.drawForJudging(uint32,uint256,bool)\",\"MarginaliaHook.fundPot(uint256)\",\"MarginaliaHook.observe(bytes32)\",\"MarginaliaHook.payJudged(uint32,bytes32[3])\",\"MarginaliaHook.retract(bytes32,string)\",\"MarginaliaHook.seal(address,(uint8,bytes32,address,bool),bytes32)\",\"MarginaliaHook.settle(bytes32)\",\"MarginaliaHook.settleThesis(bytes32)\",\"MarginaliaHook.sweep(uint8,uint32)\",\"MarginaliaHook.unlockCallback(bytes)\",\"MarginaliaJudge.abandonRequest(uint32)\",\"MarginaliaJudge.convertForfeits()\",\"MarginaliaJudge.init(address,address,bytes32,address)\",\"MarginaliaJudge.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaJudge.payJudged(uint32)\",\"MarginaliaJudge.requestJudging(uint32)\",\"MarginaliaRouter.checkpointVenue((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address))\",\"MarginaliaRouter.init(address,address)\",\"MarginaliaRouter.note((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.sellWithNote((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.uniswapV3SwapCallback(int256,int256,bytes)\",\"MarginaliaRouter.unlockCallback(bytes)\",\"MarginaliaTreasury.drip()\",\"MarginaliaTreasury.init(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":446,\"README.md\":209,\"SPEC.md\":285,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":82,\"helper/server.js\":90,\"helper/src/app.js\":203,\"jobs/launch-1-hook.json\":43,\"jobs/launch-2-contracts.json\":38,\"jobs/launch-A-implementations.json\":47,\"jobs/launch-A2-implementations.json\":99,\"jobs/launch-B-hook.json\":36,\"jobs/launch-hook-v3.json\":43,\"launch.json\":31,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":975,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPricer.sol\":305,\"src/MarginaliaRouter.sol\":446,\"src/MarginaliaTreasury.sol\":53,\"src/MarginaliaTypes.sol\":127,\"src/OracleAttestation.sol\":221,\"src/interfaces/IIntake.sol\":15,\"src/interfaces/ILaunchFactory.sol\":49,\"test/AuditFindings.t.sol\":156,\"test/CompanionFailures.t.sol\":941,\"test/HoldRule.t.sol\":259,\"test/HookReview.t.sol\":432,\"test/Implementations.t.sol\":96,\"test/JudgeOracle.t.sol\":270,\"test/LaunchAuditFindings.t.sol\":230,\"test/Lifecycle.t.sol\":696,\"test/PriceHistory.t.sol\":233,\"test/Pricer.t.sol\":88,\"test/PricerProperties.t.sol\":569,\"test/RevisionFindings.t.sol\":324,\"test/Round3Findings.t.sol\":218,\"test/RouterInvariant.t.sol\":248,\"test/TreasuryInvariant.t.sol\":167,\"test/fork/MainnetLaunch.t.sol\":374,\"test/helpers/Fixture.sol\":285,\"test/mocks/MockERC20.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"5ffee37d4b50c826eae12edbfd4accdfd0cfc52c9fecedce0eea4fe190faba46","verifiedTreeHash":"2cf2d7c24c542cdc8557d826032ee34d8fe643b5","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":155657,"exitCode":0,"name":"build","output":"Compiling 114 files with Solc 0.8.26\nSolc 0.8.26 finished in 155.44s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n   --> src/MarginaliaHook.sol:808:9:\n    |\n808 |         uint256 pool = thesisPool[w];\n    |         ^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> src/MarginaliaHook.sol:97:5:\n   |\n97 |     PoolKey private pool;\n   |     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n   --> src/MarginaliaHook.sol:296:5:\n    |\n296 |     function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata data)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/helpers/Fixture.sol:114:5:\n    |\n114 |     function priceOf(bytes32, address) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  --> test/fork/MainnetLaunch.t.sol:78:5:\n   |\n78 |     function _mine(bytes memory hookCode) internal view returns (bytes32 salt) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/MarginaliaTreasury.sol:51:9\n   │\n51 │         emit Dripped(day, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaTreasury.sol:43:22\n   │\n43 │         uint32 day = uint32(block.timestamp / 1 days);\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/MarginaliaPricer.sol:85:13\n   │\n85 │             n += 1;\n   │             ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-events-access-control]: `jobHash` is changed without an event but is used for access control\n    ╭▸ src/MarginaliaRouter.sol:303:16\n    │\n303 │         delete jobHash;\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/MarginaliaPricer.sol:120:33\n    │\n120 │         if (w.startedAt == 0 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:34\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:59\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:142:20\n    │\n142 │                 || block.timestamp < uint256(w.startedAt) + POST_MIN_SPAN\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/MarginaliaPricer.sol:143:20\n    │\n143 │                 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:149:69\n    │\n149 │             x = twap(v.kind, v.xIsToken0, w.xStart, w.startedAt, x, uint64(block.timestamp));\n    │                                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:168:55\n    │\n168 │         else if (v.kind == T.VenueKind.UniV3) xRead = uint256(_v3Cumulative(ref));\n    │                                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:213:28\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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[calls-loop]: external call inside a loop\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:213:41\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:214:35\n    │\n214 │             int256 mean = delta / int256(dt);\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/MarginaliaHook.sol:82:38\n   │\n82 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' 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/MarginaliaPricer.sol:215:38\n    │\n215 │             if (delta < 0 && delta % int256(dt) != 0) mean -= 1; // round toward negative infinity, as v3 does\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:114:47\n    │\n114 │         for (uint256 i = 0; i < all.length && n < MAX_JUDGED; ++i) {\n    │                                               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:217:57\n    │\n217 │             return fromSqrt(TickMath.getSqrtPriceAtTick(int24(mean)), xIsToken0);\n    │                                                         ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[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/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:241:37\n    │\n241 │             (uint160 sqrtP,,,,,,) = IUniswapV3PoolOracle(ref).slot0();\n    │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:245:41\n    │\n245 │             (uint112 r0, uint112 r1,) = IUniswapV2PairOracle(ref).getReserves();\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:269:33\n    │\n269 │         (int56[] memory cum,) = IUniswapV3PoolOracle(pool).observe(ago);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:170:15\n    │\n170 │             ++n;\n    │               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:174:33\n    │\n174 │             out[i - 1] = bytes1(uint8(48 + v % 10));\n    │                                 ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' 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/MarginaliaPricer.sol:279:24\n    │\n279 │         uint32 nowTs = uint32(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:186:52\n    │\n186 │         return eligibleTheses(week).length == 0 || block.timestamp >= (uint256(week) + 1) * 7 days + 28 days;\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/MarginaliaJudge.sol:194:32\n    │\n194 │         if (judgedSet[week] || block.timestamp < requestedAt[week] + ANSWER_DEADLINE) {\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:214:9\n    │\n214 │         hook.drawForJudging(day, price, retry);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:217:21\n    │\n217 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n218 │ ┃             action, body, IIntake.Callback(address(this), this.onOracleResult.selector), imd, price\n219 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:206:41\n    │\n206 │         if (judgedSet[day] || (retry && block.timestamp < requestedAt[day] + ANSWER_DEADLINE)) {\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/MarginaliaJudge.sol:225:9\n    │\n225 │         emit Requested(day, requestId, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:223:28\n    │\n223 │         requestedAt[day] = uint64(block.timestamp);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaJudge.sol:255:9\n    │\n255 │ ┏         emit Judged(\n256 │ ┃             day,\n257 │ ┃             [\n258 │ ┃                 count > 0 ? ranked[0] : bytes32(0),\n    ‡ ┃\n262 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:269:50\n    │\n269 │         for (uint256 i = 0; i < ranked.length && kept < 3; ++i) {\n    │                                                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:276:17\n    │\n276 │             if (dup) continue;\n    │                 ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:270:77\n    │\n270 │             (address author, uint32 noteWeek, bool thesis, bool hasChild) = hook.noteMeta(ranked[i]);\n    │                                                                             ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaJudge.sol:288:9\n    │\n288 │         hook.payJudged(day, top);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaRouter.sol:251:13\n    │\n251 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:252:41\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:252:49\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:338:9\n    │\n338 │         emit Noted(job.payer, job.sellMarg, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:320:18\n    │\n320 │                 -int256(job.amountIn),\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/MarginaliaRouter.sol:328:25\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:328:33\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:329:28\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:329:36\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:373:9\n    │\n373 │         emit XTraded(payer, X_V4, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:355:18\n    │\n355 │                 -int256(x.amountIn),\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/MarginaliaRouter.sol:363:25\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:363:33\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:364:20\n    │\n364 │         received = uint256(uint128(outputDelta));\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:364:28\n    │\n364 │         received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:403:9\n    │\n403 │         emit XTraded(payer, X_V3, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:394:13\n    │\n394 │             int256(x.amountIn),\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/MarginaliaRouter.sol:399:25\n    │\n399 │         uint256 spent = uint256(zeroForOne ? a0 : a1);\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/MarginaliaRouter.sol:409:78\n    │\n409 │         if (amount0Delta > 0) IERC20(pool.token0()).safeTransfer(msg.sender, uint256(amount0Delta));\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/MarginaliaRouter.sol:410:78\n    │\n410 │         if (amount1Delta > 0) IERC20(pool.token1()).safeTransfer(msg.sender, uint256(amount1Delta));\n    │                                                                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:438:9\n    │\n438 │         emit XTraded(payer, X_V2, xIn, xOut, actualIn, received);\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/MarginaliaRouter.sol:426:37\n    │\n426 │         (uint112 r0, uint112 r1,) = pair.getReserves();\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:309:49\n    │\n309 │                 specifiedTake = STAMP + _bondOf(uint256(-params.amountSpecified));\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:386:9\n    │\n386 │         emit Accrued(day, amount);\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/MarginaliaHook.sol:464:17\n    │\n464 │                 emit Revealed(id, hash);\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/MarginaliaHook.sol:483:9\n    │\n483 │         emit NotePosted(id, author, p.x, class, p.side, p.targetBps, p.horizonDays, p.parentId, p.text);\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/MarginaliaHook.sol:345:13\n    │\n345 │             emit SwapFee(true, author, poolImd, 0, STAMP);\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/MarginaliaHook.sol:358:13\n    │\n358 │             emit SwapFee(false, author, poolImd, fee - STAMP, STAMP);\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/MarginaliaHook.sol:369:9\n    │\n369 │         emit SwapFee(false, tx.origin, poolImd, quietFee, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:332:33\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:41\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:63\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:71\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:337:36\n    │\n337 │             uint256 bond = _bondOf(uint256(-params.amountSpecified));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:339:31\n    │\n339 │             uint256 margOut = uint256(uint128(margDelta));\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/MarginaliaHook.sol:339:39\n    │\n339 │             uint256 margOut = uint256(uint128(margDelta));\n    │                                       ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:446:17\n    │\n446 │             if (weekTheses[_week()].length >= MAX_WEEK_THESES) revert InvalidNote();\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/MarginaliaHook.sol:458:26\n    │\n458 │             if (bound && age < SEAL_MIN) revert TooEarly(); // the head start is the key holders', not the public's\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/MarginaliaHook.sol:459:26\n    │\n459 │             if (bound && age <= SEAL_MAX) {\n    │                          ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:439:22\n    │\n439 │         n.postedAt = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:518:13\n    │\n518 │         if (block.timestamp < end) revert TooEarly();\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/MarginaliaHook.sol:519:13\n    │\n519 │         if (block.timestamp > end + SETTLE_WINDOW) revert TooLate();\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/MarginaliaHook.sol:532:9\n    │\n532 │         emit Observed(id, xRead, balance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:524:27\n    │\n524 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:524:52\n    │\n524 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                                                    ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:540:13\n    │\n540 │             x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.balanceOf.selector, who));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaHook.sol:626:35\n    │\n626 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │                                   ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:577:13\n    │\n577 │         if (block.timestamp <= end + SETTLE_WINDOW) revert TooEarly();\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/MarginaliaHook.sol:687:13\n    │\n687 │             emit ThesisReleased(n.parentId);\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/MarginaliaHook.sol:626:9\n    │\n626 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:609:26\n    │\n609 │             scoreDelta = int256(_difficulty(n));\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/MarginaliaHook.sol:614:27\n    │\n614 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:616:27\n    │\n616 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:620:27\n    │\n620 │             scoreDelta = -int256(_difficulty(n));\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:634:13\n    │\n634 │         if (block.timestamp >= horizonEnd(id)) revert TooLate();\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/MarginaliaHook.sol:644:9\n    │\n644 │         emit Retracted(id, text);\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/MarginaliaHook.sol:645:9\n    │\n645 │         emit Settled(id, T.Status.Retracted, 0, scoreDelta, address(0));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:638:30\n    │\n638 │         int256 scoreDelta = -int256(_difficulty(n) / 2);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:653:13\n    │\n653 │         if (block.timestamp <= uint256(n.postedAt) + THESIS_GRACE) revert TooEarly();\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/MarginaliaHook.sol:656:9\n    │\n656 │         emit ThesisForfeited(id);\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/MarginaliaHook.sol:670:9\n    │\n670 │         emit DepositClaimed(id, n.author, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:700:13\n    │\n700 │             n.x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.totalSupply.selector));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:709:16\n    │\n709 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:713:16\n    │\n713 │         return uint32(block.timestamp / 7 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:733:9\n    │\n733 │         emit PotFunded(_today(), amount, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `seals` is updated\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:766:25\n    │\n766 │         if ((at != 0 && block.timestamp - at <= SEAL_MAX) || x == address(0) || hash == bytes32(0)) {\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/MarginaliaHook.sol:780:9\n    │\n780 │         emit Sealed(hash, msg.sender, x, venue.ref);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:774:13\n    │\n774 │             uint64(block.timestamp),\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:800:27\n    │\n800 │         return (n.author, uint32(uint256(n.postedAt) / 7 days), n.targetBps == 0, n.children > 0);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `thesisPool` is updated\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:822:9\n    │\n822 │         emit JudgedPaid(w, paidAmounts);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaHook.sol:875:39\n    │\n875 │         if (unlockHash != bytes32(0)) revert InvalidUnlock();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:829:13\n    │\n829 │         if (n.day >= _today()) revert TooEarly();\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/MarginaliaHook.sol:839:9\n    │\n839 │         emit RefundClaimed(id, msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:837:30\n    │\n837 │         notesPerDay[n.day] = uint32(count - 1);\n    │                              ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:848:17\n    │\n848 │             if (block.timestamp < (uint256(epoch) + 1) * 1 days + SWEEP_AFTER) revert TooEarly();\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/MarginaliaHook.sol:852:17\n    │\n852 │             if (block.timestamp < (uint256(epoch) + 1) * 7 days + SWEEP_AFTER) revert TooEarly();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:885:40\n    │\n885 │             address currency = address(uint160(extra));\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[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaHook.sol:894:13\n    │\n894 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/AuditFindings.t.sol:19:30\n   │\n19 │         uint256 startBlock = block.number;\n   │                              ━━━━━━━━━━━━\n   ‡\n23 │             vm.roll(startBlock + 25 * (i + 1));\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/AuditFindings.t.sol:20:27\n   │\n20 │         uint256 startTs = block.timestamp;\n   │                           ━━━━━━━━━━━━━━━\n   ‡\n24 │             vm.warp(startTs + 31 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:18:9\n    │\n 18 │         vm.warp(hook.horizonEnd(id));\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:65:9\n    │\n 65 │         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/AuditFindings.t.sol:65:17\n   │\n65 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:148:9\n    │\n148 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:149:30\n    │\n149 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n153 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:150:27\n    │\n150 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n154 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:176:9\n    │\n176 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:177:30\n    │\n177 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n181 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:178:27\n    │\n178 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n182 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:203:9\n    │\n203 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:204:30\n    │\n204 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n208 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:205:27\n    │\n205 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n209 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:302:9\n    │\n302 │         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/Lifecycle.t.sol:302:17\n    │\n302 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:357:9\n    │\n357 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:358:30\n    │\n358 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n363 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:359:27\n    │\n359 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n364 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:421:9\n    │\n421 │         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/Lifecycle.t.sol:421:17\n    │\n421 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:488:9\n    │\n488 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:489:30\n    │\n489 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n492 │         vm.roll(startBlock + 25);\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/Lifecycle.t.sol:490:27\n    │\n490 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n493 │         vm.warp(startTs + 30 minutes);\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:512:9\n    │\n512 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:513:30\n    │\n513 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n517 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:514:27\n    │\n514 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n518 │             vm.warp(startTs + 10 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:554:9\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:538:49\n    │\n538 │         router.note(rebuttal, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:554:17\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:583:9\n    │\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:575:49\n    │\n575 │         router.note(sameSide, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:584:30\n    │\n584 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n589 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:585:27\n    │\n585 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n590 │             vm.warp(startTs + 30 minutes * (i + 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/Lifecycle.t.sol:629:22\n    │\n629 │         assertEq(at, block.timestamp);\n    │                      ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:634:42\n    │\n634 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:638:17\n    │\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:653:17\n    │\n653 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:657:42\n    │\n657 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:663:17\n    │\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:679:17\n    │\n679 │         vm.warp(block.timestamp + hook.SEAL_MAX() + 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/Lifecycle.t.sol:682:17\n    │\n682 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:199:17\n    │\n199 │         vm.warp(block.timestamp + 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:262:9\n    │\n262 │         vm.warp((uint256(w) + 1) * 7 days + 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/Round3Findings.t.sol:67:17\n   │\n67 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":1132,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/MainnetLaunch.t.sol:MainnetLaunchTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 700.04µs (0.00ns CPU time)\n\nRan 7 tests for test/JudgeOracle.t.sol:JudgeOracleTest\n[PASS] testEmptySignedRankingIsAnExecutableNoWinnerResult() (gas: 248153)\n[PASS] testFiveIdsWithEoaSignatureFitStipend() (gas: 554052)\n[PASS] testFullRankingWithEoaSignatureFitsStipend() (gas: 633672)\n[PASS] testProtocolDigestSignatureAndSelectorConformanceOnClone() (gas: 3322442)\n[PASS] testRejectedAnswersDoNotConsumeThePendingRequest() (gas: 892875)\n[PASS] testRequestedHeadIsFilteredAndDeduplicatedWithoutPromotingTheTail() (gas: 250679)\n[PASS] testTimeoutRetryInvalidatesOldIntakeRequest() (gas: 523953)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 11.30ms (5.24ms CPU time)\n\nRan 8 tests for test/LaunchAuditFindings.t.sol:LaunchAuditFindingsTest\n[PASS] testAHugeSupplyBooksTierOneInsteadOfOverflowing() (gas: 2453892)\n[PASS] testALapsedSealCanBeSealedAgain() (gas: 695400)\n[PASS] testARetractedNoteLeavesTheDaysRefundSplit() (gas: 1381349)\n[PASS] testARetractionAfterTheRefundClaimDoesNotDoubleCount() (gas: 1357517)\n[PASS] testARevertingTotalSupplyDoesNotBlockARetraction() (gas: 1931368)\n[PASS] testARevertingTotalSupplyStillSettlesWrongAndPaysTheKeeper() (gas: 2547256)\n[PASS] testAStrangersSealNeitherBlocksNorPricesTheAuthorsNote() (gas: 2515168)\n[PASS] testAnAuthorsSealOnAnotherVenueDoesNotPriceTheNote() (gas: 2233321)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 15.08ms (6.43ms CPU time)\n\nRan 14 tests for test/CompanionFailures.t.sol:RouterFailuresTest\n[PASS] testExpiredDeadlineTakesNothing() (gas: 667396)\n[PASS] testExpiredWindowRefusesPostsUntilAFreshCheckpointMatures() (gas: 1754059)\n[PASS] testInitRequiresAManagerWithCode() (gas: 4169863)\n[PASS] testSlippageFloorRefundsEverything() (gas: 639186)\n[PASS] testStrangersCannotEnterTheCallbacks() (gas: 133302)\n[PASS] testTradeAndNoteRefusesNoTradeZeroTradeAndNativeInput() (gas: 290621)\n[PASS] testTradedNoteMustBeAboutTheTokenTraded() (gas: 979819)\n[PASS] testTradedV4LegUnderAForeignHookOrEmptyPoolIsRefused() (gas: 396049)\n[PASS] testUnapprovedOrUnfundedAuthorIsRefused() (gas: 224201)\n[PASS] testV4VenueUnderAForeignHookIsRefused() (gas: 69737)\n[PASS] testV4VenueWithoutLiquidityIsRefused() (gas: 134939)\n[PASS] testVenueFieldsAreDerivedFromThePoolNotTheCaller() (gas: 48532)\n[PASS] testVenueKindNoneIsRefusedForAPricedCall() (gas: 116203)\n[PASS] testZeroAndOversizedAmountsAreRefused() (gas: 138629)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 17.46ms (4.90ms CPU time)\n\nRan 6 tests for test/AuditFindings.t.sol:AuditFindingsTest\n[PASS] testEmptyV4ObservationIsRefused() (gas: 918187)\n[PASS] testExpiredBaselineRejectsPostWithoutTakingFunds() (gas: 601043)\n[PASS] testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried() (gas: 2078898)\n[PASS] testSameBlockDumpPostUnwindDoesNotWinBuy() (gas: 1815075)\n[PASS] testSameBlockPumpPostUnwindDoesNotWinSell() (gas: 1684045)\n[PASS] testUnpayableRankingRollsTheWholePoolForward() (gas: 2352594)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 43.76ms (5.59ms CPU time)\n\nRan 10 tests for test/Round3Findings.t.sol:Round3FindingsTest\n[PASS] testABuyCallStillBreaksWhenTheAuthorSells() (gas: 1662303)\n[PASS] testAGiftOfAnySizeDoesNotVoidACorrectSellCall() (gas: 1576984)\n[PASS] testAGiftWorthTheDepositDoesNotVoidACorrectSellCall() (gas: 1656237)\n[PASS] testALaunchPoolCallScoresTheSameWay() (gas: 1410703)\n[PASS] testASelfPricedVenueBooksReputationOnlyAndNoPoolPaysForIt() (gas: 3000040)\n[PASS] testAWrongCallOnAnotherVenueStillForfeitsAndBooksANegativeScore() (gas: 2699621)\n[PASS] testAWrongSellCallStillForfeits() (gas: 1388782)\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 256, μ: 21806, ~: 18188)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1944177)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204541)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 45.87ms (30.78ms CPU time)\n\nRan 10 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testABuyBackNoLongerVoidsASellCallItSettlesOnPrice() (gas: 1592379)\n[PASS] testADustPricedV4VenueCannotBePostedOn() (gas: 1573375)\n[PASS] testARevertingBalanceOfVoidsTheCallAsSoldNotAsNoData() (gas: 2584779)\n[PASS] testAStrangersDustTransferDoesNotVoidASellCall() (gas: 1557285)\n[PASS] testAnAttestationAboutAnotherChainIsRefused() (gas: 2211392)\n[PASS] testAnEmptyCanonicalV3PoolIsRefusedAsAVenue() (gas: 567739)\n[PASS] testHonestObserverOverwritesAPumpObserveUnwindInTheNextBlock() (gas: 3639225)\n[PASS] testPricerRefusesAPriceThatRoundsToZeroInBothOrientations() (gas: 58734)\n[PASS] testSweepNeedsTheStaleRequestAbandonedAndALateAnswerIsThenRefused() (gas: 2347244)\n[PASS] testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment() (gas: 50466529)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 47.10ms (37.58ms CPU time)\n\nRan 12 tests for test/HoldRule.t.sol:HoldRuleTest\n[PASS] testABreachIsNeverReplacedByANonBreachInsideTheGap() (gas: 1646626)\n[PASS] testABreachReplacesANonBreachInsideTheGap() (gas: 1656886)\n[PASS] testABuyCallWithAnUnreadableBalanceIsVoidSold() (gas: 1477672)\n[PASS] testASellAuthorMayDumpTheirWholeRemainingBalance() (gas: 1615102)\n[PASS] testASellAuthorWhoBuysBackTheirWholePostBalanceIsStillRight() (gas: 1710689)\n[PASS] testASellCallWithAnUnreadableBalanceStillSettlesOnPrice() (gas: 1502871)\n[PASS] testASellCallsBalanceIsNeverAnAdverseReading() (gas: 1362393)\n[PASS] testAWrongSellCallForfeitsWhateverTheBalanceDid() (gas: 1419422)\n[PASS] testAnEqualReadingInsideTheGapIsRefused() (gas: 1030985)\n[PASS] testAtTheCapAHigherReadingCannotLiftABuyCallsMinimum() (gas: 3896632)\n[PASS] testAtTheCapOnlyAMoreAdverseReadingGetsIn() (gas: 4142871)\n[PASS] testBuyCallHasNoToleranceDownwards() (gas: 1563716)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 55.85ms (11.62ms CPU time)\n\nRan 31 tests for test/Lifecycle.t.sol:LifecycleTest\n[PASS] testAttestedClassCannotBeSelfDeclared() (gas: 294181)\n[PASS] testCallbackSelectorPinned() (gas: 3383)\n[PASS] testCounterCallDuel() (gas: 3574228)\n[PASS] testCounterThesisEntersTheJudgedSet() (gas: 2619171)\n[PASS] testFakeVenueIsRefused() (gas: 382712)\n[PASS] testFlagsAndBinding() (gas: 56004)\n[PASS] testForfeitsAreImdAndNeedNoConversion() (gas: 860264)\n[PASS] testNoDataRefunds() (gas: 879778)\n[PASS] testNoteTooSmall() (gas: 1642643)\n[PASS] testNotedBuyTakesStampAndDeposit() (gas: 728512)\n[PASS] testNotedSellPaysOnePercentPlusStamp() (gas: 987443)\n[PASS] testObservationsMustSpanAnHour() (gas: 1382961)\n[PASS] testPlainBuyTakesNothing() (gas: 211534)\n[PASS] testQuietSellPaysThreePercent() (gas: 295286)\n[PASS] testQuietThesisPoolSweeps() (gas: 300148)\n[PASS] testRetract() (gas: 865757)\n[PASS] testRightCallReturnsDeposit() (gas: 1616318)\n[PASS] testScoreIsReputationAndAccrualsSplitSeventyThirty() (gas: 2873294)\n[PASS] testSealedBuyMustKeepItsPositionFromTheSeal() (gas: 2161817)\n[PASS] testSealedNoteRevealsAgainstTheSealBaseline() (gas: 1767999)\n[PASS] testSellingEarlyBreaksTheCall() (gas: 1671033)\n[PASS] testThesisParentChild() (gas: 1339191)\n[PASS] testThesisWithoutChildForfeits() (gas: 805132)\n[PASS] testTreasuryDrip() (gas: 320725)\n[PASS] testTwoBlockPumpObserveUnwindSettlesWrong() (gas: 1685550)\n[PASS] testUnansweredWeekCanBeRetried() (gas: 2328397)\n[PASS] testUnrevealedSealIsNotAFreeOptionAndLapses() (gas: 1353385)\n[PASS] testUpOnlyIsRefused() (gas: 291808)\n[PASS] testWeeklyThesisJudging() (gas: 3667556)\n[PASS] testWriterRefundCappedAtStamp() (gas: 1587968)\n[PASS] testWrongCallForfeitsWithKeeperReward() (gas: 1504323)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 55.91ms (22.47ms CPU time)\n\nRan 8 tests for test/PriceHistory.t.sol:PriceHistoryTest\n[PASS] testBaselineRequiresMatureFreshHistory() (gas: 188472)\n[PASS] testEmptyVenueAndHubCannotBeCheckpointedObservedOrPriced() (gas: 284549)\n[PASS] testFuzzV4BaselineIsNeverFavourableToTheCall(int24,bool) (runs: 256, μ: 106082, ~: 106152)\nLogs:\n  Bound result 1\n\n[PASS] testHubBaselineUsesOppositeExtremeFromSettlement() (gas: 180334)\n[PASS] testLiveCheckpointCannotEraseHonestExtremesOrRestartTheClock() (gas: 224282)\n[PASS] testV2BaselineIgnoresSameBlockReservesDumpAndPumpBothOrientations() (gas: 467543)\n[PASS] testV3BaselineIgnoresSameBlockTickChangesBothOrientations() (gas: 418025)\n[PASS] testV3BaselineWeightsElapsedTime() (gas: 371037)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 68.74ms (68.08ms CPU time)\n\nRan 3 tests for test/Implementations.t.sol:ImplementationsTest\n[PASS] testClonesInitializeOnceOnlyFromTheirHook() (gas: 4551335)\n[PASS] testFactoryDeploysAllFourWithoutArgumentsOrExternalDependencies() (gas: 34608585)\nLogs:\n  four implementation CREATE2 deployments (gas): 8829579\n\n[PASS] testImplementationsRejectInitialization() (gas: 81376)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 69.50ms (55.03ms CPU time)\n\nRan 28 tests for test/CompanionFailures.t.sol:JudgeFailuresTest\n[PASS] testAJudgedWeekCannotBeAbandoned() (gas: 1257630)\n[PASS] testAbandonNeedsALiveRequestPastItsDeadline() (gas: 1190393)\n[PASS] testAbandonTakesNothingAndTheRetryDrawsAgain() (gas: 1467522)\n[PASS] testAnswerAtTheExactExpiryStillCountsAndOneSecondLaterDoesNot() (gas: 1257046)\n[PASS] testAnswerForAWeekAlreadyJudgedIsRefused() (gas: 1320679)\n[PASS] testAnswerSignedByAnotherKeyIsRefused() (gas: 1069433)\n[PASS] testAnswerSignedForAnotherConsumerIsRefused() (gas: 3952788)\n[PASS] testConvertForfeitsWithAnEmptyPotIsANoOp() (gas: 236930)\n[PASS] testConvertNeverSellsMoreThanThePot() (gas: 236488)\n[PASS] testConvertSellsTheLargestHalvingThePoolAbsorbs() (gas: 275386)\n[PASS] testConvertTriesExactlyNineTranchesDownToOneTwoHundredFiftySixth() (gas: 363686)\n[PASS] testCurrentAndFutureWeeksCannotBeRequested() (gas: 128617)\n[PASS] testEligibleThesesAreCappedAtTheJudgedMaximum() (gas: 14217218)\n[PASS] testImplementationHasAPlaceholderSignerAndCannotBeConfigured() (gas: 2726709)\n[PASS] testInitRequiresEveryConfigurationValue() (gas: 2953442)\n[PASS] testIntakeReturningAnIdAlreadyPendingIsRefused() (gas: 1599187)\n[PASS] testJudgedOfFiltersWrongWeekShortFormAndChildlessIds() (gas: 1439829)\n[PASS] testJudgedWeekCannotBeRequestedAgainEvenAfterTheDeadline() (gas: 1242650)\n[PASS] testMalformedAnswerBytesAreRefused() (gas: 1067354)\n[PASS] testOnlyTheHeadOfThreeIsStoredAndTheTailNeverPromotes() (gas: 1221812)\n[PASS] testPayBeforeAnAnswerReverts() (gas: 1064318)\n[PASS] testPayIsPermissionlessAndOnce() (gas: 1438634)\n[PASS] testQuestionBodyNamesTheConsumerChainAndEligibleIdsOnly() (gas: 2516225)\n[PASS] testRepeatRequestBeforeTheDeadlineIsRefused() (gas: 1419149)\n[PASS] testRequestDrawsExactlyThePriceAndKeepsNothing() (gas: 1028228)\n[PASS] testWeekClosedStates() (gas: 1940695)\n[PASS] testWeekWithoutEligibleThesesCannotBeRequested() (gas: 244665)\n[PASS] testZeroAndExcessiveOraclePricesAreRefused() (gas: 1345941)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 69.68ms (30.99ms CPU time)\n\nRan 7 tests for test/Pricer.t.sol:PricerTest\n[PASS] testQuoteLegIsAdverseEvenUnderAV3Twap() (gas: 28455)\n[PASS] testTwapRefusesZeroSpanAndV4() (gas: 17708)\n[PASS] testV2TwapFromWrappingCumulative() (gas: 9503)\n[PASS] testV3TwapOfAConstantTickIsThatTick() (gas: 15459)\n[PASS] testV3TwapRoundsNegativeMeansDown() (gas: 14848)\n[PASS] testV3TwapWeightsByTime() (gas: 14715)\n[PASS] testV4SettlesOnTheAdverseExtreme() (gas: 26636)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 69.49ms (840.20µs CPU time)\n\nRan 9 tests for test/CompanionFailures.t.sol:TreasuryFailuresTest\n[PASS] testDripFailsWhenTheHookCannotTakeTheFunds() (gas: 673929)\n[PASS] testDripIsPermissionlessAndCompounds() (gas: 518661)\n[PASS] testDripOfDustRoundsToZeroAndReverts() (gas: 258318)\n[PASS] testDripWithNothingHeldReverts() (gas: 54033)\n[PASS] testInitOnlyByTheNamedHookAndOnlyOnce() (gas: 623926)\n[PASS] testInitRefusesTheZeroHook() (gas: 556415)\n[PASS] testNoWithdrawOrAdminSurface() (gas: 274868)\n[PASS] testSecondDripOnTheSameDayRevertsAndTheNextDayWorks() (gas: 372660)\n[PASS] testTreasuryRefusesEth() (gas: 71164)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 69.61ms (3.05ms CPU time)\n\nRan 31 tests for test/PricerProperties.t.sol:PricerPropertiesTest\n[PASS] testDifficultyAnchors() (gas: 56436)\n[PASS] testDifficultyRefusesAZeroHorizon() (gas: 10063)\n[PASS] testDifficultyTiersStepExactlyAtTheThresholds() (gas: 79314)\n[PASS] testEmptyPoolsAreRefusedOnBothLegs() (gas: 161813)\n[PASS] testEthQuoteIsOnlyPriceableOnMainnet() (gas: 40894)\n[PASS] testFromSqrtRefusesAnEmptyOrUnpriceableReading() (gas: 53891)\n[PASS] testFromSqrtZeroThresholdIsSharpInBothOrientations() (gas: 1024182)\n[PASS] testFuzzAppendingAnObservationNeverHelpsTheCall(uint256[16],uint256[16],uint8) (runs: 1000, μ: 132240, ~: 115390)\nLogs:\n  Bound result 3\n  Bound result 999999999999999999999000034915\n  Bound result 2500000000000000000000\n  Bound result 999999999999999999999000000113\n  Bound result 999999999999999999999000007593\n  Bound result 999999999999999999999000003540\n  Bound result 999999999999999999999000017843\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36924, ~: 36984)\nLogs:\n  Bound result 12345\n  Bound result 1979820\n  Bound result 18\n  Bound result 8192\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141538, ~: 141875)\nLogs:\n  Bound result 1266412660188944021221804082648\n  Bound result 1266412660188944021221804081674\n  Bound result 28797\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36716, ~: 36837)\nLogs:\n  Bound result 992068\n  Bound result 1\n  Bound result 50\n  Bound result 999999999999999999999999999999\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23294, ~: 21542)\nLogs:\n  Bound result 140446809859108252707810704400601573628\n  Bound result 100000000000000000002\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39177, ~: 38187)\nLogs:\n  Bound result 6344381235704876442547526313346812155557\n  Bound result 4335979695482341136633140882658166573642\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16004, ~: 14356)\nLogs:\n  Bound result 0\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 54113, ~: 51987)\nLogs:\n  Bound result 26811\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36424, ~: 36426)\nLogs:\n  Bound result 1700\n  Bound result 1877\n  Bound result 54\n  Bound result 293635516235839784956363446806\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18753, ~: 16421)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21356, ~: 21299)\nLogs:\n  Bound result 130017069192922759815406\n  Bound result 11249332808423858972769640343912\n  Bound result 18\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 63183, ~: 58253)\nLogs:\n  Bound result 741\n  Bound result 4\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 101147, ~: 91618)\nLogs:\n  Bound result 7\n  Bound result 7167\n  Bound result 17931\n  Bound result 21514\n  Bound result 4824\n  Bound result 371636862\n  Bound result 1000000000000000000000\n  Bound result 24049\n  Bound result 806583589928461891782872549115\n  Bound result 130\n  Bound result 20000000000000000\n  Bound result 3743\n  Bound result 2592000\n  Bound result 1\n  Bound result 60\n\n[PASS] testObserveRefusesUnknownVenuesAndUnpriceableQuotes() (gas: 150448)\n[PASS] testPostPriceRefusesAnEmptyWindow() (gas: 15317)\n[PASS] testPostPriceWhoseProductRoundsToZeroIsRefused() (gas: 293627)\n[PASS] testSellDifficultyRefusesAZeroTarget() (gas: 9518)\n[PASS] testSettlementRefusesAnEmptyOrUnspannedSeries() (gas: 39083)\n[PASS] testSqrtIsExactOnEveryHorizonDifficultyUses() (gas: 903275)\n[PASS] testSqrtPins() (gas: 123131)\n[PASS] testTwapRefusesTimeRunningBackwards() (gas: 9132)\n[PASS] testV2TwapAndSpotOfADustRatioAreRefused() (gas: 220677)\n[PASS] testV3TwapRefusesAMeanTickOutsideTheRange() (gas: 27255)\n[PASS] testV4SeriesWithADustExtremeIsRefusedNotSettledAtZero() (gas: 33519)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 69.67ms (704.60ms CPU time)\n\nRan 1 test for test/RouterInvariant.t.sol:RouterInvariantTest\n[PASS]\nRouterInvariantTest invariants:\n[PASS] invariant_bindingsPinned\n[PASS] invariant_everyNoteCameThroughTheRouter\n[PASS] invariant_managerBacksTheHooksClaims\n[PASS] invariant_routerKeepsNothing\n RouterInvariantTest invariants (runs: 48, calls: 1920, reverts: 3)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| RouterHandler | advance        | 225   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 218   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 409   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 223   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 205   | 3       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 210   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 205   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 225   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 2\n  Bound result 10000000000000000000\n  Bound result 12075\n  Bound result 5\n  Bound result 2\n  Bound result 0\n  Bound result 14319\n  Bound result 2\n  Bound result 5769\n  Bound result 50096\n  Bound result 36\n  Bound result 2\n  Bound result 408034634\n  Bound result 0\n  Bound result 8777\n  Bound result 1\n  Bound result 11000\n  Bound result 1\n  Bound result 12645\n  Bound result 4824\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 819536445311620575441\n  Bound result 8967\n  Bound result 33\n  Bound result 0\n  Bound result 5033\n  Bound result 3139\n  Bound result 52\n  Bound result 2\n  Bound result 50\n  Bound result 50998\n  Bound result 78\n  Bound result 2\n  Bound result 200000000000000000000\n  Bound result 326\n  Bound result 2\n  Bound result 15195\n  Bound result 10\n  Bound result 20\n  Bound result 0\n  Bound result 1\n  Bound result 3167\n  Bound result 50401\n  Bound result 51\n  Bound result 0\n  Bound result 1\n  Bound result 6000000\n  Bound result 8231\n  Bound result 25\n  Bound result 4780\n  Bound result 1\n  Bound result 2\n  Bound result 32358602125979232400008\n  Bound result 1\n  Bound result 1860\n  Bound result 13961\n  Bound result 48\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 15206\n  Bound result 5647\n  Bound result 25\n  Bound result 1\n  Bound result 2\n  Bound result 566363576999726590119\n  Bound result 50045\n  Bound result 6\n  Bound result 0\n  Bound result 12000000000000000000\n  Bound result 1\n  Bound result 2\n  Bound result 1916685990867733357813\n  Bound result 1399\n  Bound result 13\n  Bound result 10800\n  Bound result 1\n  Bound result 0\n  Bound result 1481\n  Bound result 49997\n  Bound result 21\n  Bound result 5397\n  Bound result 2\n  Bound result 567\n  Bound result 50129\n  Bound result 77\n  Bound result 1\n  Bound result 20538\n  Bound result 0\n  Bound result 75\n  Bound result 0\n  Bound result 420000\n  Bound result 50033\n  Bound result 54\n  Bound result 0\n  Bound result 0\n  Bound result 5000000000000000000000\n  Bound result 2\n  Bound result 659918\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 429.64ms (419.77ms CPU time)\n\nRan 1 test for test/TreasuryInvariant.t.sol:TreasuryInvariantTest\n[PASS]\nTreasuryInvariantTest invariants:\n[PASS] invariant_balanceIsGiftsMinusDrips\n[PASS] invariant_dripNeverExceedsTwoPercent\n[PASS] invariant_holdsNoEth\n[PASS] invariant_hookHoldsExactlyTheDrips\n[PASS] invariant_hookIsPinned\n[PASS] invariant_lastDripDayMatchesTheLastSuccessfulDrip\n TreasuryInvariantTest invariants (runs: 256, calls: 12288, reverts: 0)\n\n╭-----------------+-----------+-------+---------+----------╮\n| Contract        | Selector  | Calls | Reverts | Discards |\n+==========================================================+\n| TreasuryHandler | advance   | 2474  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2485  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2463  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2472  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2394  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 3041954473\n  Bound result 273\n  Bound result 2\n  Bound result 1000000000000\n  Bound result 6449\n  Bound result 2966\n  Bound result 1452\n  Bound result 2432\n  Bound result 150000000000000000\n  Bound result 10000000000000000000\n  Bound result 1119\n  Bound result 1665173\n  Bound result 8\n  Bound result 6000\n  Bound result 1461501637330902918203684832716283019655932542973\n  Bound result 73400581361186814187780176508855\n  Bound result 6900\n  Bound result 477338593233046903194337\n  Bound result 9459\n  Bound result 30\n  Bound result 90\n  Bound result 10000000000000000000\n  Bound result 259199\n  Bound result 1388\n  Bound result 800000000000000000\n  Bound result 5912\n  Bound result 10000000000000000000\n  Bound result 332543384276260032\n  Bound result 202187\n  Bound result 8899465090292739128\n  Bound result 640130297116561513058702838566803207926246074829\n  Bound result 192953\n  Bound result 400000000000000000000\n  Bound result 832\n  Bound result 6456\n  Bound result 1292\n  Bound result 1119\n  Bound result 1800000000\n  Bound result 3718940\n  Bound result 6372\n  Bound result 6352586338880161545\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.01s (1.01s CPU time)\n\nRan 17 test suites in 1.02s (2.15s CPU time): 186 tests passed, 0 failed, 1 skipped (187 total tests)\n","passed":true},{"durationMs":91,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Marginalia.approve(address,uint256)\",\"Marginalia.transfer(address,uint256)\",\"Marginalia.transferFrom(address,address,uint256)\",\"MarginaliaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"MarginaliaHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"MarginaliaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"MarginaliaHook.claimDeposit(bytes32)\",\"MarginaliaHook.claimRefund(bytes32)\",\"MarginaliaHook.drawForJudging(uint32,uint256,bool)\",\"MarginaliaHook.fundPot(uint256)\",\"MarginaliaHook.observe(bytes32)\",\"MarginaliaHook.payJudged(uint32,bytes32[3])\",\"MarginaliaHook.retract(bytes32,string)\",\"MarginaliaHook.seal(address,(uint8,bytes32,address,bool),bytes32)\",\"MarginaliaHook.settle(bytes32)\",\"MarginaliaHook.settleThesis(bytes32)\",\"MarginaliaHook.sweep(uint8,uint32)\",\"MarginaliaHook.unlockCallback(bytes)\",\"MarginaliaJudge.abandonRequest(uint32)\",\"MarginaliaJudge.convertForfeits()\",\"MarginaliaJudge.init(address,address,bytes32,address)\",\"MarginaliaJudge.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaJudge.payJudged(uint32)\",\"MarginaliaJudge.requestJudging(uint32)\",\"MarginaliaRouter.checkpointVenue((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address))\",\"MarginaliaRouter.init(address,address)\",\"MarginaliaRouter.note((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.sellWithNote((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.uniswapV3SwapCallback(int256,int256,bytes)\",\"MarginaliaRouter.unlockCallback(bytes)\",\"MarginaliaTreasury.drip()\",\"MarginaliaTreasury.init(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":335,\"README.md\":192,\"SPEC.md\":282,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":82,\"helper/server.js\":90,\"helper/src/app.js\":203,\"jobs/launch-1-hook.json\":43,\"jobs/launch-2-contracts.json\":38,\"jobs/launch-A-implementations.json\":47,\"jobs/launch-A2-implementations.json\":99,\"jobs/launch-B-hook.json\":36,\"jobs/launch-hook-v3.json\":43,\"launch.json\":31,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":924,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPricer.sol\":305,\"src/MarginaliaRouter.sol\":446,\"src/MarginaliaTreasury.sol\":53,\"src/MarginaliaTypes.sol\":127,\"src/OracleAttestation.sol\":221,\"src/interfaces/IIntake.sol\":15,\"src/interfaces/ILaunchFactory.sol\":49,\"test/AuditFindings.t.sol\":156,\"test/CompanionFailures.t.sol\":941,\"test/HoldRule.t.sol\":259,\"test/Implementations.t.sol\":96,\"test/JudgeOracle.t.sol\":270,\"test/LaunchAuditFindings.t.sol\":230,\"test/Lifecycle.t.sol\":696,\"test/PriceHistory.t.sol\":233,\"test/Pricer.t.sol\":88,\"test/PricerProperties.t.sol\":569,\"test/RevisionFindings.t.sol\":319,\"test/Round3Findings.t.sol\":218,\"test/RouterInvariant.t.sol\":248,\"test/TreasuryInvariant.t.sol\":167,\"test/fork/MainnetLaunch.t.sol\":378,\"test/helpers/Fixture.sol\":285,\"test/mocks/MockERC20.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d294b0095b9919d7e0fdcd5f9d968d1e2f548ab5686db9f5e61607dfab6b96a6","verifiedTreeHash":"ccd01a420af02076d538410bbd5d25378b19306b","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":232483,"exitCode":0,"name":"build","output":"Compiling 117 files with Solc 0.8.26\nSolc 0.8.26 finished in 232.22s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n   --> src/MarginaliaHook.sol:808:9:\n    |\n808 |         uint256 pool = thesisPool[w];\n    |         ^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> src/MarginaliaHook.sol:97:5:\n   |\n97 |     PoolKey private pool;\n   |     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n   --> src/MarginaliaHook.sol:296:5:\n    |\n296 |     function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata data)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/helpers/Fixture.sol:114:5:\n    |\n114 |     function priceOf(bytes32, address) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  --> test/fork/MainnetLaunch.t.sol:78:5:\n   |\n78 |     function _mine(bytes memory hookCode) internal view returns (bytes32 salt) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/MarginaliaPricer.sol:85:13\n   │\n85 │             n += 1;\n   │             ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/MarginaliaTreasury.sol:51:9\n   │\n51 │         emit Dripped(day, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaTreasury.sol:43:22\n   │\n43 │         uint32 day = uint32(block.timestamp / 1 days);\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:120:33\n    │\n120 │         if (w.startedAt == 0 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-events-access-control]: `jobHash` is changed without an event but is used for access control\n    ╭▸ src/MarginaliaRouter.sol:303:16\n    │\n303 │         delete jobHash;\n    │                ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:34\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[calls-loop]: external call inside a loop\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:59\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:114:47\n    │\n114 │         for (uint256 i = 0; i < all.length && n < MAX_JUDGED; ++i) {\n    │                                               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:142:20\n    │\n142 │                 || block.timestamp < uint256(w.startedAt) + POST_MIN_SPAN\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/MarginaliaPricer.sol:143:20\n    │\n143 │                 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:149:69\n    │\n149 │             x = twap(v.kind, v.xIsToken0, w.xStart, w.startedAt, x, uint64(block.timestamp));\n    │                                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:170:15\n    │\n170 │             ++n;\n    │               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:168:55\n    │\n168 │         else if (v.kind == T.VenueKind.UniV3) xRead = uint256(_v3Cumulative(ref));\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/MarginaliaJudge.sol:174:33\n    │\n174 │             out[i - 1] = bytes1(uint8(48 + v % 10));\n    │                                 ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' 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/MarginaliaHook.sol:82:38\n   │\n82 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:186:52\n    │\n186 │         return eligibleTheses(week).length == 0 || block.timestamp >= (uint256(week) + 1) * 7 days + 28 days;\n    │                                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:213:28\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:213:41\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:214:35\n    │\n214 │             int256 mean = delta / int256(dt);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:194:32\n    │\n194 │         if (judgedSet[week] || block.timestamp < requestedAt[week] + ANSWER_DEADLINE) {\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:215:38\n    │\n215 │             if (delta < 0 && delta % int256(dt) != 0) mean -= 1; // round toward negative infinity, as v3 does\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/MarginaliaPricer.sol:217:57\n    │\n217 │             return fromSqrt(TickMath.getSqrtPriceAtTick(int24(mean)), xIsToken0);\n    │                                                         ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' 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/MarginaliaPricer.sol:241:37\n    │\n241 │             (uint160 sqrtP,,,,,,) = IUniswapV3PoolOracle(ref).slot0();\n    │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:245:41\n    │\n245 │             (uint112 r0, uint112 r1,) = IUniswapV2PairOracle(ref).getReserves();\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:269:33\n    │\n269 │         (int56[] memory cum,) = IUniswapV3PoolOracle(pool).observe(ago);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:279:24\n    │\n279 │         uint32 nowTs = uint32(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:214:9\n    │\n214 │         hook.drawForJudging(day, price, retry);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:217:21\n    │\n217 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n218 │ ┃             action, body, IIntake.Callback(address(this), this.onOracleResult.selector), imd, price\n219 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:206:41\n    │\n206 │         if (judgedSet[day] || (retry && block.timestamp < requestedAt[day] + ANSWER_DEADLINE)) {\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/MarginaliaJudge.sol:225:9\n    │\n225 │         emit Requested(day, requestId, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:223:28\n    │\n223 │         requestedAt[day] = uint64(block.timestamp);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaJudge.sol:255:9\n    │\n255 │ ┏         emit Judged(\n256 │ ┃             day,\n257 │ ┃             [\n258 │ ┃                 count > 0 ? ranked[0] : bytes32(0),\n    ‡ ┃\n262 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:269:50\n    │\n269 │         for (uint256 i = 0; i < ranked.length && kept < 3; ++i) {\n    │                                                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:276:17\n    │\n276 │             if (dup) continue;\n    │                 ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:270:77\n    │\n270 │             (address author, uint32 noteWeek, bool thesis, bool hasChild) = hook.noteMeta(ranked[i]);\n    │                                                                             ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaJudge.sol:288:9\n    │\n288 │         hook.payJudged(day, top);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaRouter.sol:251:13\n    │\n251 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:252:41\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:252:49\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:338:9\n    │\n338 │         emit Noted(job.payer, job.sellMarg, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:320:18\n    │\n320 │                 -int256(job.amountIn),\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/MarginaliaRouter.sol:328:25\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:328:33\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:329:28\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:329:36\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:373:9\n    │\n373 │         emit XTraded(payer, X_V4, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:355:18\n    │\n355 │                 -int256(x.amountIn),\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/MarginaliaRouter.sol:363:25\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:363:33\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:364:20\n    │\n364 │         received = uint256(uint128(outputDelta));\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:364:28\n    │\n364 │         received = uint256(uint128(outputDelta));\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/MarginaliaRouter.sol:403:9\n    │\n403 │         emit XTraded(payer, X_V3, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:394:13\n    │\n394 │             int256(x.amountIn),\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/MarginaliaRouter.sol:399:25\n    │\n399 │         uint256 spent = uint256(zeroForOne ? a0 : a1);\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/MarginaliaRouter.sol:409:78\n    │\n409 │         if (amount0Delta > 0) IERC20(pool.token0()).safeTransfer(msg.sender, uint256(amount0Delta));\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/MarginaliaRouter.sol:410:78\n    │\n410 │         if (amount1Delta > 0) IERC20(pool.token1()).safeTransfer(msg.sender, uint256(amount1Delta));\n    │                                                                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:438:9\n    │\n438 │         emit XTraded(payer, X_V2, xIn, xOut, actualIn, received);\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/MarginaliaRouter.sol:426:37\n    │\n426 │         (uint112 r0, uint112 r1,) = pair.getReserves();\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:309:49\n    │\n309 │                 specifiedTake = STAMP + _bondOf(uint256(-params.amountSpecified));\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:386:9\n    │\n386 │         emit Accrued(day, amount);\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/MarginaliaHook.sol:464:17\n    │\n464 │                 emit Revealed(id, hash);\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/MarginaliaHook.sol:483:9\n    │\n483 │         emit NotePosted(id, author, p.x, class, p.side, p.targetBps, p.horizonDays, p.parentId, p.text);\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/MarginaliaHook.sol:345:13\n    │\n345 │             emit SwapFee(true, author, poolImd, 0, STAMP);\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/MarginaliaHook.sol:358:13\n    │\n358 │             emit SwapFee(false, author, poolImd, fee - STAMP, STAMP);\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/MarginaliaHook.sol:369:9\n    │\n369 │         emit SwapFee(false, tx.origin, poolImd, quietFee, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:332:33\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:41\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:63\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:71\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:337:36\n    │\n337 │             uint256 bond = _bondOf(uint256(-params.amountSpecified));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:339:31\n    │\n339 │             uint256 margOut = uint256(uint128(margDelta));\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/MarginaliaHook.sol:339:39\n    │\n339 │             uint256 margOut = uint256(uint128(margDelta));\n    │                                       ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:446:17\n    │\n446 │             if (weekTheses[_week()].length >= MAX_WEEK_THESES) revert InvalidNote();\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/MarginaliaHook.sol:458:26\n    │\n458 │             if (bound && age < SEAL_MIN) revert TooEarly(); // the head start is the key holders', not the public's\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/MarginaliaHook.sol:459:26\n    │\n459 │             if (bound && age <= SEAL_MAX) {\n    │                          ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:439:22\n    │\n439 │         n.postedAt = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:518:13\n    │\n518 │         if (block.timestamp < end) revert TooEarly();\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/MarginaliaHook.sol:519:13\n    │\n519 │         if (block.timestamp > end + SETTLE_WINDOW) revert TooLate();\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/MarginaliaHook.sol:532:9\n    │\n532 │         emit Observed(id, xRead, balance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:524:27\n    │\n524 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:524:52\n    │\n524 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                                                    ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:540:13\n    │\n540 │             x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.balanceOf.selector, who));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaHook.sol:626:35\n    │\n626 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │                                   ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:577:13\n    │\n577 │         if (block.timestamp <= end + SETTLE_WINDOW) revert TooEarly();\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/MarginaliaHook.sol:687:13\n    │\n687 │             emit ThesisReleased(n.parentId);\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/MarginaliaHook.sol:626:9\n    │\n626 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:609:26\n    │\n609 │             scoreDelta = int256(_difficulty(n));\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/MarginaliaHook.sol:614:27\n    │\n614 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:616:27\n    │\n616 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:620:27\n    │\n620 │             scoreDelta = -int256(_difficulty(n));\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:634:13\n    │\n634 │         if (block.timestamp >= horizonEnd(id)) revert TooLate();\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/MarginaliaHook.sol:644:9\n    │\n644 │         emit Retracted(id, text);\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/MarginaliaHook.sol:645:9\n    │\n645 │         emit Settled(id, T.Status.Retracted, 0, scoreDelta, address(0));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:638:30\n    │\n638 │         int256 scoreDelta = -int256(_difficulty(n) / 2);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:653:13\n    │\n653 │         if (block.timestamp <= uint256(n.postedAt) + THESIS_GRACE) revert TooEarly();\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/MarginaliaHook.sol:656:9\n    │\n656 │         emit ThesisForfeited(id);\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/MarginaliaHook.sol:670:9\n    │\n670 │         emit DepositClaimed(id, n.author, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:700:13\n    │\n700 │             n.x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.totalSupply.selector));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:709:16\n    │\n709 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:713:16\n    │\n713 │         return uint32(block.timestamp / 7 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:733:9\n    │\n733 │         emit PotFunded(_today(), amount, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `seals` is updated\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:766:25\n    │\n766 │         if ((at != 0 && block.timestamp - at <= SEAL_MAX) || x == address(0) || hash == bytes32(0)) {\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/MarginaliaHook.sol:780:9\n    │\n780 │         emit Sealed(hash, msg.sender, x, venue.ref);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:774:13\n    │\n774 │             uint64(block.timestamp),\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:800:27\n    │\n800 │         return (n.author, uint32(uint256(n.postedAt) / 7 days), n.targetBps == 0, n.children > 0);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `thesisPool` is updated\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:822:9\n    │\n822 │         emit JudgedPaid(w, paidAmounts);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaHook.sol:875:39\n    │\n875 │         if (unlockHash != bytes32(0)) revert InvalidUnlock();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:829:13\n    │\n829 │         if (n.day >= _today()) revert TooEarly();\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/MarginaliaHook.sol:839:9\n    │\n839 │         emit RefundClaimed(id, msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:837:30\n    │\n837 │         notesPerDay[n.day] = uint32(count - 1);\n    │                              ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:848:17\n    │\n848 │             if (block.timestamp < (uint256(epoch) + 1) * 1 days + SWEEP_AFTER) revert TooEarly();\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/MarginaliaHook.sol:852:17\n    │\n852 │             if (block.timestamp < (uint256(epoch) + 1) * 7 days + SWEEP_AFTER) revert TooEarly();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:885:40\n    │\n885 │             address currency = address(uint160(extra));\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[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaHook.sol:894:13\n    │\n894 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/AuditFindings.t.sol:19:30\n   │\n19 │         uint256 startBlock = block.number;\n   │                              ━━━━━━━━━━━━\n   ‡\n23 │             vm.roll(startBlock + 25 * (i + 1));\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/AuditFindings.t.sol:20:27\n   │\n20 │         uint256 startTs = block.timestamp;\n   │                           ━━━━━━━━━━━━━━━\n   ‡\n24 │             vm.warp(startTs + 31 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:18:9\n    │\n 18 │         vm.warp(hook.horizonEnd(id));\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:65:9\n    │\n 65 │         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/AuditFindings.t.sol:65:17\n   │\n65 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HookBoundaries.t.sol:347:9\n    │\n347 │         vm.warp(deadline - 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:148:9\n    │\n148 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:149:30\n    │\n149 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n153 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:150:27\n    │\n150 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n154 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:176:9\n    │\n176 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:177:30\n    │\n177 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n181 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:178:27\n    │\n178 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n182 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:203:9\n    │\n203 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:204:30\n    │\n204 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n208 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:205:27\n    │\n205 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n209 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:302:9\n    │\n302 │         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/Lifecycle.t.sol:302:17\n    │\n302 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:357:9\n    │\n357 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:358:30\n    │\n358 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n363 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:359:27\n    │\n359 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n364 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:421:9\n    │\n421 │         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/Lifecycle.t.sol:421:17\n    │\n421 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:488:9\n    │\n488 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:489:30\n    │\n489 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n492 │         vm.roll(startBlock + 25);\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/Lifecycle.t.sol:490:27\n    │\n490 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n493 │         vm.warp(startTs + 30 minutes);\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:512:9\n    │\n512 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:513:30\n    │\n513 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n517 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:514:27\n    │\n514 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n518 │             vm.warp(startTs + 10 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:554:9\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:538:49\n    │\n538 │         router.note(rebuttal, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:554:17\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:583:9\n    │\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:575:49\n    │\n575 │         router.note(sameSide, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:584:30\n    │\n584 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n589 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:585:27\n    │\n585 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n590 │             vm.warp(startTs + 30 minutes * (i + 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/Lifecycle.t.sol:629:22\n    │\n629 │         assertEq(at, block.timestamp);\n    │                      ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:634:42\n    │\n634 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:638:17\n    │\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:653:17\n    │\n653 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:657:42\n    │\n657 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:663:17\n    │\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:679:17\n    │\n679 │         vm.warp(block.timestamp + hook.SEAL_MAX() + 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/Lifecycle.t.sol:682:17\n    │\n682 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:199:17\n    │\n199 │         vm.warp(block.timestamp + 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:262:9\n    │\n262 │         vm.warp((uint256(w) + 1) * 7 days + 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/Round3Findings.t.sol:67:17\n   │\n67 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":7184,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 7 tests for test/Pricer.t.sol:PricerTest\n[PASS] testQuoteLegIsAdverseEvenUnderAV3Twap() (gas: 28455)\n[PASS] testTwapRefusesZeroSpanAndV4() (gas: 17708)\n[PASS] testV2TwapFromWrappingCumulative() (gas: 9503)\n[PASS] testV3TwapOfAConstantTickIsThatTick() (gas: 15459)\n[PASS] testV3TwapRoundsNegativeMeansDown() (gas: 14848)\n[PASS] testV3TwapWeightsByTime() (gas: 14715)\n[PASS] testV4SettlesOnTheAdverseExtreme() (gas: 26636)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 828.98µs (729.89µs CPU time)\n\nRan 1 test for test/fork/MainnetLaunch.t.sol:MainnetLaunchTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 929.74µs (0.00ns CPU time)\n\nRan 8 tests for test/LaunchAuditFindings.t.sol:LaunchAuditFindingsTest\n[PASS] testAHugeSupplyBooksTierOneInsteadOfOverflowing() (gas: 2453892)\n[PASS] testALapsedSealCanBeSealedAgain() (gas: 695400)\n[PASS] testARetractedNoteLeavesTheDaysRefundSplit() (gas: 1381349)\n[PASS] testARetractionAfterTheRefundClaimDoesNotDoubleCount() (gas: 1357517)\n[PASS] testARevertingTotalSupplyDoesNotBlockARetraction() (gas: 1931368)\n[PASS] testARevertingTotalSupplyStillSettlesWrongAndPaysTheKeeper() (gas: 2547256)\n[PASS] testAStrangersSealNeitherBlocksNorPricesTheAuthorsNote() (gas: 2515168)\n[PASS] testAnAuthorsSealOnAnotherVenueDoesNotPriceTheNote() (gas: 2233321)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 14.41ms (6.59ms CPU time)\n\nRan 14 tests for test/CompanionFailures.t.sol:RouterFailuresTest\n[PASS] testExpiredDeadlineTakesNothing() (gas: 667396)\n[PASS] testExpiredWindowRefusesPostsUntilAFreshCheckpointMatures() (gas: 1754059)\n[PASS] testInitRequiresAManagerWithCode() (gas: 4169863)\n[PASS] testSlippageFloorRefundsEverything() (gas: 639186)\n[PASS] testStrangersCannotEnterTheCallbacks() (gas: 133302)\n[PASS] testTradeAndNoteRefusesNoTradeZeroTradeAndNativeInput() (gas: 290621)\n[PASS] testTradedNoteMustBeAboutTheTokenTraded() (gas: 979819)\n[PASS] testTradedV4LegUnderAForeignHookOrEmptyPoolIsRefused() (gas: 396049)\n[PASS] testUnapprovedOrUnfundedAuthorIsRefused() (gas: 224201)\n[PASS] testV4VenueUnderAForeignHookIsRefused() (gas: 69737)\n[PASS] testV4VenueWithoutLiquidityIsRefused() (gas: 134939)\n[PASS] testVenueFieldsAreDerivedFromThePoolNotTheCaller() (gas: 48532)\n[PASS] testVenueKindNoneIsRefusedForAPricedCall() (gas: 116203)\n[PASS] testZeroAndOversizedAmountsAreRefused() (gas: 138629)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 16.84ms (5.13ms CPU time)\n\nRan 6 tests for test/AuditFindings.t.sol:AuditFindingsTest\n[PASS] testEmptyV4ObservationIsRefused() (gas: 918187)\n[PASS] testExpiredBaselineRejectsPostWithoutTakingFunds() (gas: 601043)\n[PASS] testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried() (gas: 2078898)\n[PASS] testSameBlockDumpPostUnwindDoesNotWinBuy() (gas: 1815075)\n[PASS] testSameBlockPumpPostUnwindDoesNotWinSell() (gas: 1684045)\n[PASS] testUnpayableRankingRollsTheWholePoolForward() (gas: 2352594)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 18.47ms (7.18ms CPU time)\n\nRan 12 tests for test/HoldRule.t.sol:HoldRuleTest\n[PASS] testABreachIsNeverReplacedByANonBreachInsideTheGap() (gas: 1646626)\n[PASS] testABreachReplacesANonBreachInsideTheGap() (gas: 1656886)\n[PASS] testABuyCallWithAnUnreadableBalanceIsVoidSold() (gas: 1477672)\n[PASS] testASellAuthorMayDumpTheirWholeRemainingBalance() (gas: 1615102)\n[PASS] testASellAuthorWhoBuysBackTheirWholePostBalanceIsStillRight() (gas: 1710689)\n[PASS] testASellCallWithAnUnreadableBalanceStillSettlesOnPrice() (gas: 1502871)\n[PASS] testASellCallsBalanceIsNeverAnAdverseReading() (gas: 1362393)\n[PASS] testAWrongSellCallForfeitsWhateverTheBalanceDid() (gas: 1419422)\n[PASS] testAnEqualReadingInsideTheGapIsRefused() (gas: 1030985)\n[PASS] testAtTheCapAHigherReadingCannotLiftABuyCallsMinimum() (gas: 3896632)\n[PASS] testAtTheCapOnlyAMoreAdverseReadingGetsIn() (gas: 4142871)\n[PASS] testBuyCallHasNoToleranceDownwards() (gas: 1563716)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 25.03ms (14.48ms CPU time)\n\nRan 10 tests for test/Round3Findings.t.sol:Round3FindingsTest\n[PASS] testABuyCallStillBreaksWhenTheAuthorSells() (gas: 1662303)\n[PASS] testAGiftOfAnySizeDoesNotVoidACorrectSellCall() (gas: 1576984)\n[PASS] testAGiftWorthTheDepositDoesNotVoidACorrectSellCall() (gas: 1656237)\n[PASS] testALaunchPoolCallScoresTheSameWay() (gas: 1410703)\n[PASS] testASelfPricedVenueBooksReputationOnlyAndNoPoolPaysForIt() (gas: 3000040)\n[PASS] testAWrongCallOnAnotherVenueStillForfeitsAndBooksANegativeScore() (gas: 2699621)\n[PASS] testAWrongSellCallStillForfeits() (gas: 1388782)\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 256, μ: 22069, ~: 19378)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1944177)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204541)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 32.21ms (23.00ms CPU time)\n\nRan 10 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testABuyBackNoLongerVoidsASellCallItSettlesOnPrice() (gas: 1592379)\n[PASS] testADustPricedV4VenueCannotBePostedOn() (gas: 1573375)\n[PASS] testARevertingBalanceOfVoidsTheCallAsSoldNotAsNoData() (gas: 2584779)\n[PASS] testAStrangersDustTransferDoesNotVoidASellCall() (gas: 1557285)\n[PASS] testAnAttestationAboutAnotherChainIsRefused() (gas: 2211392)\n[PASS] testAnEmptyCanonicalV3PoolIsRefusedAsAVenue() (gas: 567739)\n[PASS] testHonestObserverOverwritesAPumpObserveUnwindInTheNextBlock() (gas: 3639225)\n[PASS] testPricerRefusesAPriceThatRoundsToZeroInBothOrientations() (gas: 58734)\n[PASS] testSweepNeedsTheStaleRequestAbandonedAndALateAnswerIsThenRefused() (gas: 2347244)\n[PASS] testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment() (gas: 50466529)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 53.00ms (44.26ms CPU time)\n\nRan 13 tests for test/LaunchBinding.t.sol:LaunchBindingTest\n[PASS] testCompanionsAreThePinnedImmutableMinimalProxies() (gas: 30786)\n[PASS] testConstructorWorksWithoutCompanionOrManagerCode() (gas: 28455456)\n[PASS] testExactFeeAccountingWhenImdIsCurrencyOne() (gas: 57875204)\n[PASS] testExactFeeAccountingWhenImdIsCurrencyZero() (gas: 57874988)\n[PASS] testHookAndTokenHaveNoCommonAdminOrWithdrawalSurface() (gas: 533225)\n[PASS] testLiquidityFeesAndFullWithdrawalRemainAvailable() (gas: 753826)\n[PASS] testNativeAndCodelessPairsAreRefused() (gas: 16551002)\n[PASS] testNotedBuyOnFreshManagerSeededOnlyWithMarg() (gas: 56336153)\n[PASS] testOnlyTheSuppliedFactoryCanInitializeAndFailureDoesNotConsumeBinding() (gas: 16695231)\n[PASS] testPermissionsEnableOnlyTheFiveRequiredFlags() (gas: 14191)\n[PASS] testPoolCannotBeReadOrSwappedBeforeBinding() (gas: 16479531)\n[PASS] testPoolMustContainTheConstructorToken() (gas: 16482159)\n[PASS] testWrongFeeIsRefusedBeforeCorrectFeeBinds() (gas: 16665338)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 90.56ms (193.48ms CPU time)\n\nRan 28 tests for test/CompanionFailures.t.sol:JudgeFailuresTest\n[PASS] testAJudgedWeekCannotBeAbandoned() (gas: 1257630)\n[PASS] testAbandonNeedsALiveRequestPastItsDeadline() (gas: 1190393)\n[PASS] testAbandonTakesNothingAndTheRetryDrawsAgain() (gas: 1467522)\n[PASS] testAnswerAtTheExactExpiryStillCountsAndOneSecondLaterDoesNot() (gas: 1257046)\n[PASS] testAnswerForAWeekAlreadyJudgedIsRefused() (gas: 1320679)\n[PASS] testAnswerSignedByAnotherKeyIsRefused() (gas: 1069433)\n[PASS] testAnswerSignedForAnotherConsumerIsRefused() (gas: 3952788)\n[PASS] testConvertForfeitsWithAnEmptyPotIsANoOp() (gas: 236930)\n[PASS] testConvertNeverSellsMoreThanThePot() (gas: 236488)\n[PASS] testConvertSellsTheLargestHalvingThePoolAbsorbs() (gas: 275386)\n[PASS] testConvertTriesExactlyNineTranchesDownToOneTwoHundredFiftySixth() (gas: 363686)\n[PASS] testCurrentAndFutureWeeksCannotBeRequested() (gas: 128617)\n[PASS] testEligibleThesesAreCappedAtTheJudgedMaximum() (gas: 14217218)\n[PASS] testImplementationHasAPlaceholderSignerAndCannotBeConfigured() (gas: 2726709)\n[PASS] testInitRequiresEveryConfigurationValue() (gas: 2953442)\n[PASS] testIntakeReturningAnIdAlreadyPendingIsRefused() (gas: 1599187)\n[PASS] testJudgedOfFiltersWrongWeekShortFormAndChildlessIds() (gas: 1439829)\n[PASS] testJudgedWeekCannotBeRequestedAgainEvenAfterTheDeadline() (gas: 1242650)\n[PASS] testMalformedAnswerBytesAreRefused() (gas: 1067354)\n[PASS] testOnlyTheHeadOfThreeIsStoredAndTheTailNeverPromotes() (gas: 1221812)\n[PASS] testPayBeforeAnAnswerReverts() (gas: 1064318)\n[PASS] testPayIsPermissionlessAndOnce() (gas: 1438634)\n[PASS] testQuestionBodyNamesTheConsumerChainAndEligibleIdsOnly() (gas: 2516225)\n[PASS] testRepeatRequestBeforeTheDeadlineIsRefused() (gas: 1419149)\n[PASS] testRequestDrawsExactlyThePriceAndKeepsNothing() (gas: 1028228)\n[PASS] testWeekClosedStates() (gas: 1940695)\n[PASS] testWeekWithoutEligibleThesesCannotBeRequested() (gas: 244665)\n[PASS] testZeroAndExcessiveOraclePricesAreRefused() (gas: 1345941)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 93.24ms (30.02ms CPU time)\n\nRan 31 tests for test/Lifecycle.t.sol:LifecycleTest\n[PASS] testAttestedClassCannotBeSelfDeclared() (gas: 294181)\n[PASS] testCallbackSelectorPinned() (gas: 3383)\n[PASS] testCounterCallDuel() (gas: 3574228)\n[PASS] testCounterThesisEntersTheJudgedSet() (gas: 2619171)\n[PASS] testFakeVenueIsRefused() (gas: 382712)\n[PASS] testFlagsAndBinding() (gas: 56004)\n[PASS] testForfeitsAreImdAndNeedNoConversion() (gas: 860264)\n[PASS] testNoDataRefunds() (gas: 879778)\n[PASS] testNoteTooSmall() (gas: 1642643)\n[PASS] testNotedBuyTakesStampAndDeposit() (gas: 728512)\n[PASS] testNotedSellPaysOnePercentPlusStamp() (gas: 987443)\n[PASS] testObservationsMustSpanAnHour() (gas: 1382961)\n[PASS] testPlainBuyTakesNothing() (gas: 211534)\n[PASS] testQuietSellPaysThreePercent() (gas: 295286)\n[PASS] testQuietThesisPoolSweeps() (gas: 300148)\n[PASS] testRetract() (gas: 865757)\n[PASS] testRightCallReturnsDeposit() (gas: 1616318)\n[PASS] testScoreIsReputationAndAccrualsSplitSeventyThirty() (gas: 2873294)\n[PASS] testSealedBuyMustKeepItsPositionFromTheSeal() (gas: 2161817)\n[PASS] testSealedNoteRevealsAgainstTheSealBaseline() (gas: 1767999)\n[PASS] testSellingEarlyBreaksTheCall() (gas: 1671033)\n[PASS] testThesisParentChild() (gas: 1339191)\n[PASS] testThesisWithoutChildForfeits() (gas: 805132)\n[PASS] testTreasuryDrip() (gas: 320725)\n[PASS] testTwoBlockPumpObserveUnwindSettlesWrong() (gas: 1685550)\n[PASS] testUnansweredWeekCanBeRetried() (gas: 2328397)\n[PASS] testUnrevealedSealIsNotAFreeOptionAndLapses() (gas: 1353385)\n[PASS] testUpOnlyIsRefused() (gas: 291808)\n[PASS] testWeeklyThesisJudging() (gas: 3667556)\n[PASS] testWriterRefundCappedAtStamp() (gas: 1587968)\n[PASS] testWrongCallForfeitsWithKeeperReward() (gas: 1504323)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 93.13ms (27.70ms CPU time)\n\nRan 3 tests for test/Implementations.t.sol:ImplementationsTest\n[PASS] testClonesInitializeOnceOnlyFromTheirHook() (gas: 4551335)\n[PASS] testFactoryDeploysAllFourWithoutArgumentsOrExternalDependencies() (gas: 34608585)\nLogs:\n  four implementation CREATE2 deployments (gas): 8829579\n\n[PASS] testImplementationsRejectInitialization() (gas: 81376)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 96.56ms (83.75ms CPU time)\n\nRan 8 tests for test/PriceHistory.t.sol:PriceHistoryTest\n[PASS] testBaselineRequiresMatureFreshHistory() (gas: 188472)\n[PASS] testEmptyVenueAndHubCannotBeCheckpointedObservedOrPriced() (gas: 284549)\n[PASS] testFuzzV4BaselineIsNeverFavourableToTheCall(int24,bool) (runs: 256, μ: 105911, ~: 106118)\nLogs:\n  Bound result 1\n\n[PASS] testHubBaselineUsesOppositeExtremeFromSettlement() (gas: 180334)\n[PASS] testLiveCheckpointCannotEraseHonestExtremesOrRestartTheClock() (gas: 224282)\n[PASS] testV2BaselineIgnoresSameBlockReservesDumpAndPumpBothOrientations() (gas: 467543)\n[PASS] testV3BaselineIgnoresSameBlockTickChangesBothOrientations() (gas: 418025)\n[PASS] testV3BaselineWeightsElapsedTime() (gas: 371037)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 110.06ms (110.01ms CPU time)\n\nRan 9 tests for test/CompanionFailures.t.sol:TreasuryFailuresTest\n[PASS] testDripFailsWhenTheHookCannotTakeTheFunds() (gas: 673929)\n[PASS] testDripIsPermissionlessAndCompounds() (gas: 518661)\n[PASS] testDripOfDustRoundsToZeroAndReverts() (gas: 258318)\n[PASS] testDripWithNothingHeldReverts() (gas: 54033)\n[PASS] testInitOnlyByTheNamedHookAndOnlyOnce() (gas: 623926)\n[PASS] testInitRefusesTheZeroHook() (gas: 556415)\n[PASS] testNoWithdrawOrAdminSurface() (gas: 274868)\n[PASS] testSecondDripOnTheSameDayRevertsAndTheNextDayWorks() (gas: 372660)\n[PASS] testTreasuryRefusesEth() (gas: 71164)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 110.49ms (1.95ms CPU time)\n\nRan 7 tests for test/JudgeOracle.t.sol:JudgeOracleTest\n[PASS] testEmptySignedRankingIsAnExecutableNoWinnerResult() (gas: 248153)\n[PASS] testFiveIdsWithEoaSignatureFitStipend() (gas: 554052)\n[PASS] testFullRankingWithEoaSignatureFitsStipend() (gas: 633672)\n[PASS] testProtocolDigestSignatureAndSelectorConformanceOnClone() (gas: 3322442)\n[PASS] testRejectedAnswersDoNotConsumeThePendingRequest() (gas: 892875)\n[PASS] testRequestedHeadIsFilteredAndDeduplicatedWithoutPromotingTheTail() (gas: 250679)\n[PASS] testTimeoutRetryInvalidatesOldIntakeRequest() (gas: 523953)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 112.65ms (4.66ms CPU time)\n\nRan 31 tests for test/PricerProperties.t.sol:PricerPropertiesTest\n[PASS] testDifficultyAnchors() (gas: 56436)\n[PASS] testDifficultyRefusesAZeroHorizon() (gas: 10063)\n[PASS] testDifficultyTiersStepExactlyAtTheThresholds() (gas: 79314)\n[PASS] testEmptyPoolsAreRefusedOnBothLegs() (gas: 161813)\n[PASS] testEthQuoteIsOnlyPriceableOnMainnet() (gas: 40894)\n[PASS] testFromSqrtRefusesAnEmptyOrUnpriceableReading() (gas: 53891)\n[PASS] testFromSqrtZeroThresholdIsSharpInBothOrientations() (gas: 1024182)\n[PASS] testFuzzAppendingAnObservationNeverHelpsTheCall(uint256[16],uint256[16],uint8) (runs: 1000, μ: 129210, ~: 114063)\nLogs:\n  Bound result 10\n  Bound result 999999999999999999999000000005\n  Bound result 999999999999999999999000050001\n  Bound result 999999999999999999999000020238\n  Bound result 999999999999999999999000021601\n  Bound result 25000000000000000000000000\n  Bound result 999999999999999999999000016385\n  Bound result 4288775753\n  Bound result 999999999999999999999000000092\n  Bound result 999999999999999999999000002049\n  Bound result 1782909587\n  Bound result 999999999999999999999000023011\n  Bound result 999999999999999999999000015001\n  Bound result 999999999999999999999000011002\n  Bound result 999999999999999999999000007953\n  Bound result 999999999999999999999000012346\n  Bound result 1000000000000000\n  Bound result 999999999999999999999000024372\n  Bound result 999999999999999999999000012733\n  Bound result 999999999999999999999000034814\n  Bound result 999999999999999999999000017794\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36904, ~: 36935)\nLogs:\n  Bound result 78236\n  Bound result 123773\n  Bound result 1\n  Bound result 210091042758787889962559685200\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141478, ~: 141832)\nLogs:\n  Bound result 1237940039285380274899124227\n  Bound result 1266425243283455344312395966334\n  Bound result 15697\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36755, ~: 36900)\nLogs:\n  Bound result 957725\n  Bound result 6\n  Bound result 5\n  Bound result 642801212284001685019519547450\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23097, ~: 21542)\nLogs:\n  Bound result 176674969205840157784387275105742853601145504678\n  Bound result 1461446703485210103287273052112074005593420983564\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39511, ~: 38625)\nLogs:\n  Bound result 378581698433549959598807007197484421450\n  Bound result 618407677285421539099152632733669\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16239, ~: 14392)\nLogs:\n  Bound result 14\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 53971, ~: 51987)\nLogs:\n  Bound result 18038\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36414, ~: 36366)\nLogs:\n  Bound result 5743\n  Bound result 1\n  Bound result 40\n  Bound result 196015682269412\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18880, ~: 16421)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21342, ~: 21299)\nLogs:\n  Bound result 286637877479420393860948568672\n  Bound result 3877663959985091824471\n  Bound result 1203\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 63377, ~: 58502)\nLogs:\n  Bound result 2667\n  Bound result 9\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 98463, ~: 84883)\nLogs:\n  Bound result 6\n  Bound result 4202047189\n  Bound result 350000000000000000\n  Bound result 5000\n  Bound result 296858534827628530496329220095\n  Bound result 806583589928461891782872549115\n  Bound result 640564039457584007913129639836\n  Bound result 7776000\n  Bound result 16777216\n  Bound result 1666\n  Bound result 48\n  Bound result 18936\n  Bound result 34660\n\n[PASS] testObserveRefusesUnknownVenuesAndUnpriceableQuotes() (gas: 150448)\n[PASS] testPostPriceRefusesAnEmptyWindow() (gas: 15317)\n[PASS] testPostPriceWhoseProductRoundsToZeroIsRefused() (gas: 293627)\n[PASS] testSellDifficultyRefusesAZeroTarget() (gas: 9518)\n[PASS] testSettlementRefusesAnEmptyOrUnspannedSeries() (gas: 39083)\n[PASS] testSqrtIsExactOnEveryHorizonDifficultyUses() (gas: 903275)\n[PASS] testSqrtPins() (gas: 123131)\n[PASS] testTwapRefusesTimeRunningBackwards() (gas: 9132)\n[PASS] testV2TwapAndSpotOfADustRatioAreRefused() (gas: 220677)\n[PASS] testV3TwapRefusesAMeanTickOutsideTheRange() (gas: 27255)\n[PASS] testV4SeriesWithADustExtremeIsRefusedNotSettledAtZero() (gas: 33519)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 112.80ms (1.17s CPU time)\n\nRan 27 tests for test/HookBoundaries.t.sol:HookBoundariesTest\n[PASS] testAfterSwapRejectsZeroOrWrongSignedOutput() (gas: 120803)\n[PASS] testCallCannotBeAChildOfItsOwnCallOrAClosedThesis() (gas: 2916709)\n[PASS] testChildAtTheSevenDayDeadlineCanReleaseTheThesis() (gas: 1462670)\n[PASS] testChildlessThesisForfeitureBoundaryAndKeeperPayment() (gas: 839179)\n[PASS] testEmptyCallAndThesisTextAreRejectedAtomically() (gas: 841392)\n[PASS] testEveryEnabledCallbackRejectsAStranger() (gas: 130699)\n[PASS] testExactOutputPlainBuyHasNoHookDelta() (gas: 54500)\n[PASS] testExactOutputQuietSellsAndNotedTradesAreRejected() (gas: 120229)\n[PASS] testFactoryCannotBindASecondPool() (gas: 73476)\n[PASS] testForeignPoolRejectedByBothSwapCallbacks() (gas: 85772)\n[PASS] testForgedNoteAndExemptionAreRejected() (gas: 153377)\n[PASS] testFuzzBondRoundTripReturnsOnlyTheBond(uint256) (runs: 1000, μ: 837372, ~: 837384)\nLogs:\n  Bound result 9750000000000021811\n\n[PASS] testFuzzNotedInputLeavesExactlyQuarterImdForThePool(uint256) (runs: 1000, μ: 58968, ~: 58980)\nLogs:\n  Bound result 9750000001201516888\n\n[PASS] testHorizonEdgesAndTargetEdges() (gas: 2706228)\n[PASS] testManagerCannotInventAnUnlockOutsideAnActiveOperation() (gas: 43843)\n[PASS] testMissingParentAndSameSideCounterAreRejectedAtomically() (gas: 2530964)\n[PASS] testNoDataBondCannotBeStolenOrClaimedTwice() (gas: 900381)\n[PASS] testObservationAndSettlementWindowExactEdges() (gas: 1471837)\n[PASS] testOnlyJudgeCanDrawOrPayAndZeroFundingIsRefused() (gas: 79352)\n[PASS] testRefundRequiresNextDayAuthorAndSingleUse() (gas: 841030)\n[PASS] testRetractAtHorizonIsTooLateAndBeforeItIsFinal() (gas: 1342496)\n[PASS] testSealMaximumAgeUsesSealedPriceDespiteExpiredPostingCheckpoint() (gas: 1100692)\n[PASS] testSealMinimumAgeIsInclusiveAndFailedRevealPreservesCommitment() (gas: 1550633)\n[PASS] testSealRejectsZeroHashAndDuplicateWithoutTakingAnotherStamp() (gas: 469389)\n[PASS] testSweepBoundaryMovesClaimsWithoutWithdrawingThem() (gas: 307915)\n[PASS] testTextLimitIsInclusiveForBothForms() (gas: 2003559)\n[PASS] testUnknownNotesFailEveryLifecycleEntry() (gas: 163991)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 115.97ms (158.68ms CPU time)\n\nRan 1 test for test/RouterInvariant.t.sol:RouterInvariantTest\n[PASS]\nRouterInvariantTest invariants:\n[PASS] invariant_bindingsPinned\n[PASS] invariant_everyNoteCameThroughTheRouter\n[PASS] invariant_managerBacksTheHooksClaims\n[PASS] invariant_routerKeepsNothing\n RouterInvariantTest invariants (runs: 48, calls: 1920, reverts: 3)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| RouterHandler | advance        | 228   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 212   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 442   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 204   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 203   | 3       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 218   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 207   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 206   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 959\n  Bound result 1\n  Bound result 1\n  Bound result 23379\n  Bound result 0\n  Bound result 412169798\n  Bound result 2\n  Bound result 181\n  Bound result 1022\n  Bound result 2\n  Bound result 2000000000000000000\n  Bound result 50100\n  Bound result 71\n  Bound result 0\n  Bound result 18302\n  Bound result 4996\n  Bound result 70\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 12663\n  Bound result 1\n  Bound result 1\n  Bound result 1024\n  Bound result 50028\n  Bound result 13\n  Bound result 0\n  Bound result 1454\n  Bound result 50061\n  Bound result 93\n  Bound result 765\n  Bound result 0\n  Bound result 2846\n  Bound result 49\n  Bound result 60\n  Bound result 2\n  Bound result 7790\n  Bound result 0\n  Bound result 1884\n  Bound result 58194\n  Bound result 6\n  Bound result 2\n  Bound result 1000000000\n  Bound result 0\n  Bound result 8086\n  Bound result 923\n  Bound result 58\n  Bound result 3878\n  Bound result 1\n  Bound result 62899200\n  Bound result 58248\n  Bound result 15\n  Bound result 0\n  Bound result 2548\n  Bound result 0\n  Bound result 2592000\n  Bound result 49991\n  Bound result 8\n  Bound result 1\n  Bound result 55\n  Bound result 25872\n  Bound result 46\n  Bound result 512\n  Bound result 2\n  Bound result 3943\n  Bound result 1\n  Bound result 2\n  Bound result 18000\n  Bound result 29904\n  Bound result 21\n  Bound result 17041\n  Bound result 0\n  Bound result 2\n  Bound result 4704\n  Bound result 2\n  Bound result 100000000000000000\n  Bound result 0\n  Bound result 19023\n  Bound result 53601\n  Bound result 0\n  Bound result 0\n  Bound result 1708029994300388038728\n  Bound result 50223\n  Bound result 50\n  Bound result 1\n  Bound result 2000000000000000000000\n  Bound result 256\n  Bound result 10\n  Bound result 1145\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 784247067953537247501\n  Bound result 1700\n  Bound result 30\n  Bound result 5625\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 485.10ms (474.38ms CPU time)\n\nRan 1 test for test/TreasuryInvariant.t.sol:TreasuryInvariantTest\n[PASS]\nTreasuryInvariantTest invariants:\n[PASS] invariant_balanceIsGiftsMinusDrips\n[PASS] invariant_dripNeverExceedsTwoPercent\n[PASS] invariant_holdsNoEth\n[PASS] invariant_hookHoldsExactlyTheDrips\n[PASS] invariant_hookIsPinned\n[PASS] invariant_lastDripDayMatchesTheLastSuccessfulDrip\n TreasuryInvariantTest invariants (runs: 256, calls: 12288, reverts: 0)\n\n╭-----------------+-----------+-------+---------+----------╮\n| Contract        | Selector  | Calls | Reverts | Discards |\n+==========================================================+\n| TreasuryHandler | advance   | 2488  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2519  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2416  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2392  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2473  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000000000\n  Bound result 5323913282232647682\n  Bound result 8584\n  Bound result 6308436550849232967\n  Bound result 6180\n  Bound result 1378\n  Bound result 6272\n  Bound result 9000\n  Bound result 150216027670530386275778\n  Bound result 72\n  Bound result 3395723176\n  Bound result 229773\n  Bound result 5208\n  Bound result 997\n  Bound result 127322\n  Bound result 127965\n  Bound result 1147\n  Bound result 200000000000000000\n  Bound result 8192\n  Bound result 1390\n  Bound result 7776000\n  Bound result 4220473\n  Bound result 369577045151698991304131\n  Bound result 10000000000000000000\n  Bound result 2220\n  Bound result 128\n  Bound result 4422\n  Bound result 3700\n  Bound result 2419200\n  Bound result 6283019655932542975\n  Bound result 507037891745082864\n  Bound result 6046\n  Bound result 12345\n  Bound result 127\n  Bound result 56659\n  Bound result 50\n  Bound result 1287378063346242585\n  Bound result 120\n  Bound result 9402\n  Bound result 3897\n  Bound result 191436\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.29s (1.28s CPU time)\n\nRan 2 tests for test/HookAccountingInvariant.t.sol:HookAccountingInvariantTest\n[PASS] invariant_everyImdClaimHasExactlyOneObligation() (runs: 128, calls: 10240, reverts: 0)\n\n╭-----------------------+-------------------+-------+---------+----------╮\n| Contract              | Selector          | Calls | Reverts | Discards |\n+========================================================================+\n| HookAccountingHandler | abandonJudging    | 500   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | advance           | 509   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | answerJudging     | 542   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | child             | 499   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimDeposit      | 517   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimRefund       | 523   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | fund              | 539   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | giftAndDrip       | 455   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | notedSell         | 513   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | observeSeries     | 540   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | payJudging        | 520   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | post              | 1039  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | requestJudging    | 532   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | retract           | 464   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | seal              | 511   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | settle            | 515   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | sweep             | 536   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | trade             | 491   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | unauthorizedClaim | 495   | 0       | 0        |\n╰-----------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 3000000000000000000\n  Bound result 3\n  Bound result 10000000000000000000\n  Bound result 99999999999999999966\n  Bound result 1\n  Bound result 9750046795971003309\n  Bound result 3720000000000000001\n  Bound result 2\n  Bound result 6\n  Bound result 6\n  Bound result 6\n  Bound result 3\n  Bound result 5543\n  Bound result 4\n  Bound result 5\n  Bound result 9750000000000007948\n  Bound result 12\n  Bound result 2\n  Bound result 6\n  Bound result 6\n  Bound result 4\n  Bound result 6\n  Bound result 4\n  Bound result 9900000000000000001\n  Bound result 9750000000000005489\n  Bound result 99999000000000000008048\n  Bound result 5\n  Bound result 2\n  Bound result 33505108406330732859665\n  Bound result 2748\n  Bound result 5\n  Bound result 83326366284629063278\n  Bound result 19564728518505578419\n  Bound result 99999000000000000002828\n  Bound result 131764\n  Bound result 7\n  Bound result 124783\n  Bound result 6\n  Bound result 8\n  Bound result 40417\n  Bound result 1010\n  Bound result 1706\n  Bound result 1\n  Bound result 5\n  Bound result 6\n  Bound result 3\n  Bound result 177650\n  Bound result 1\n  Bound result 999999999999897436\n  Bound result 787234894189135586\n  Bound result 698068152370464659\n  Bound result 5499999999999999898\n  Bound result 3\n  Bound result 99999000000000000003795\n  Bound result 9750000000000001528\n  Bound result 9750000000166773743\n  Bound result 15\n  Bound result 323021\n  Bound result 3591\n  Bound result 4\n  Bound result 9750000000000009312\n  Bound result 12\n\n[PASS] testAccountingHandlerExercisesPayoutsForfeitsSealsDripsAndSweeps() (gas: 5243210)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 3000000000000000000\n  Bound result 3\n  Bound result 10000000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 4\n  Bound result 3\n  Bound result 4000000000000000000\n  Bound result 5\n  Bound result 50000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.05s (7.02s CPU time)\n\nRan 20 test suites in 7.05s (9.92s CPU time): 228 tests passed, 0 failed, 1 skipped (229 total tests)\n","passed":true},{"durationMs":126,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Marginalia.approve(address,uint256)\",\"Marginalia.transfer(address,uint256)\",\"Marginalia.transferFrom(address,address,uint256)\",\"MarginaliaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"MarginaliaHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"MarginaliaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"MarginaliaHook.claimDeposit(bytes32)\",\"MarginaliaHook.claimRefund(bytes32)\",\"MarginaliaHook.drawForJudging(uint32,uint256,bool)\",\"MarginaliaHook.fundPot(uint256)\",\"MarginaliaHook.observe(bytes32)\",\"MarginaliaHook.payJudged(uint32,bytes32[3])\",\"MarginaliaHook.retract(bytes32,string)\",\"MarginaliaHook.seal(address,(uint8,bytes32,address,bool),bytes32)\",\"MarginaliaHook.settle(bytes32)\",\"MarginaliaHook.settleThesis(bytes32)\",\"MarginaliaHook.sweep(uint8,uint32)\",\"MarginaliaHook.unlockCallback(bytes)\",\"MarginaliaJudge.abandonRequest(uint32)\",\"MarginaliaJudge.convertForfeits()\",\"MarginaliaJudge.init(address,address,bytes32,address)\",\"MarginaliaJudge.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaJudge.payJudged(uint32)\",\"MarginaliaJudge.requestJudging(uint32)\",\"MarginaliaRouter.checkpointVenue((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address))\",\"MarginaliaRouter.init(address,address)\",\"MarginaliaRouter.note((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.sellWithNote((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.uniswapV3SwapCallback(int256,int256,bytes)\",\"MarginaliaRouter.unlockCallback(bytes)\",\"MarginaliaTreasury.drip()\",\"MarginaliaTreasury.init(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":335,\"README.md\":192,\"SPEC.md\":282,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":82,\"helper/server.js\":90,\"helper/src/app.js\":203,\"jobs/launch-1-hook.json\":43,\"jobs/launch-2-contracts.json\":38,\"jobs/launch-A-implementations.json\":47,\"jobs/launch-A2-implementations.json\":99,\"jobs/launch-B-hook.json\":36,\"jobs/launch-hook-v3.json\":43,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":924,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPricer.sol\":305,\"src/MarginaliaRouter.sol\":446,\"src/MarginaliaTreasury.sol\":53,\"src/MarginaliaTypes.sol\":127,\"src/OracleAttestation.sol\":221,\"src/interfaces/IIntake.sol\":15,\"src/interfaces/ILaunchFactory.sol\":49,\"test/ADVERSARIAL_COVERAGE.md\":45,\"test/AuditFindings.t.sol\":156,\"test/CompanionFailures.t.sol\":941,\"test/HoldRule.t.sol\":259,\"test/HookAccountingInvariant.t.sol\":656,\"test/HookBoundaries.t.sol\":475,\"test/Implementations.t.sol\":96,\"test/JudgeOracle.t.sol\":270,\"test/LaunchAuditFindings.t.sol\":230,\"test/LaunchBinding.t.sol\":305,\"test/Lifecycle.t.sol\":696,\"test/PriceHistory.t.sol\":233,\"test/Pricer.t.sol\":88,\"test/PricerProperties.t.sol\":569,\"test/RevisionFindings.t.sol\":319,\"test/Round3Findings.t.sol\":218,\"test/RouterInvariant.t.sol\":248,\"test/TreasuryInvariant.t.sol\":167,\"test/fork/MainnetLaunch.t.sol\":378,\"test/helpers/Fixture.sol\":285,\"test/mocks/MockERC20.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d3db90f9129d27ad728f2ad5d3d456bba17375dd56bcdffc2b5371349ff4891c","verifiedTreeHash":"c0d385542d6da783d3ce0e81f33cf0b9017fd8ab","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":167594,"exitCode":0,"name":"build","output":"Compiling 114 files with Solc 0.8.26\nSolc 0.8.26 finished in 167.29s\nCompiler run successful with warnings:\nWarning (2519): This declaration shadows an existing declaration.\n   --> src/MarginaliaHook.sol:808:9:\n    |\n808 |         uint256 pool = thesisPool[w];\n    |         ^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> src/MarginaliaHook.sol:97:5:\n   |\n97 |     PoolKey private pool;\n   |     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n   --> src/MarginaliaHook.sol:296:5:\n    |\n296 |     function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata data)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n   --> test/helpers/Fixture.sol:114:5:\n    |\n114 |     function priceOf(bytes32, address) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  --> test/fork/MainnetLaunch.t.sol:78:5:\n   |\n78 |     function _mine(bytes memory hookCode) internal view returns (bytes32 salt) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/MarginaliaTreasury.sol:51:9\n   │\n51 │         emit Dripped(day, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/MarginaliaTreasury.sol:43:22\n   │\n43 │         uint32 day = uint32(block.timestamp / 1 days);\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n   ╭▸ src/MarginaliaJudge.sol:96:17\n   │\n96 │             try hook.sellPotMarg(marg) returns (uint256 out) {\n   │                 ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:114:47\n    │\n114 │         for (uint256 i = 0; i < all.length && n < MAX_JUDGED; ++i) {\n    │                                               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-events-access-control]: `jobHash` is changed without an event but is used for access control\n    ╭▸ src/MarginaliaRouter.sol:303:16\n    │\n303 │         delete jobHash;\n    │                ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[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/MarginaliaJudge.sol:115:35\n    │\n115 │             (,,, bool hasChild) = hook.noteMeta(all[i]);\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:170:15\n    │\n170 │             ++n;\n    │               ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:174:33\n    │\n174 │             out[i - 1] = bytes1(uint8(48 + v % 10));\n    │                                 ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' 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/MarginaliaHook.sol:82:38\n   │\n82 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:186:52\n    │\n186 │         return eligibleTheses(week).length == 0 || block.timestamp >= (uint256(week) + 1) * 7 days + 28 days;\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/MarginaliaJudge.sol:194:32\n    │\n194 │         if (judgedSet[week] || block.timestamp < requestedAt[week] + ANSWER_DEADLINE) {\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:214:9\n    │\n214 │         hook.drawForJudging(day, price, retry);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestOf` is updated\n    ╭▸ src/MarginaliaJudge.sol:217:21\n    │\n217 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n218 │ ┃             action, body, IIntake.Callback(address(this), this.onOracleResult.selector), imd, price\n219 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaJudge.sol:206:41\n    │\n206 │         if (judgedSet[day] || (retry && block.timestamp < requestedAt[day] + ANSWER_DEADLINE)) {\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/MarginaliaJudge.sol:225:9\n    │\n225 │         emit Requested(day, requestId, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaJudge.sol:223:28\n    │\n223 │         requestedAt[day] = uint64(block.timestamp);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaRouter.sol:251:13\n    │\n251 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:252:41\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:252:49\n    │\n252 │         if (amountIn == 0 || amountIn > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/MarginaliaRouter.sol:338:9\n    │\n338 │         emit Noted(job.payer, job.sellMarg, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:320:18\n    │\n320 │                 -int256(job.amountIn),\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/MarginaliaRouter.sol:328:25\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:328:33\n    │\n328 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:329:28\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:329:36\n    │\n329 │         uint256 received = uint256(uint128(outputDelta));\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/MarginaliaJudge.sol:255:9\n    │\n255 │ ┏         emit Judged(\n256 │ ┃             day,\n257 │ ┃             [\n258 │ ┃                 count > 0 ? ranked[0] : bytes32(0),\n    ‡ ┃\n262 │ ┃         );\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/MarginaliaRouter.sol:373:9\n    │\n373 │         emit XTraded(payer, X_V4, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:355:18\n    │\n355 │                 -int256(x.amountIn),\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/MarginaliaRouter.sol:363:25\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:363:33\n    │\n363 │         uint256 spent = uint256(uint128(-inputDelta));\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/MarginaliaRouter.sol:364:20\n    │\n364 │         received = uint256(uint128(outputDelta));\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:276:17\n    │\n276 │             if (dup) continue;\n    │                 ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaJudge.sol:269:50\n    │\n269 │         for (uint256 i = 0; i < ranked.length && kept < 3; ++i) {\n    │                                                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:364:28\n    │\n364 │         received = uint256(uint128(outputDelta));\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaJudge.sol:270:77\n    │\n270 │             (address author, uint32 noteWeek, bool thesis, bool hasChild) = hook.noteMeta(ranked[i]);\n    │                                                                             ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:403:9\n    │\n403 │         emit XTraded(payer, X_V3, xIn, xOut, spent, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:394:13\n    │\n394 │             int256(x.amountIn),\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/MarginaliaRouter.sol:399:25\n    │\n399 │         uint256 spent = uint256(zeroForOne ? a0 : a1);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaJudge.sol:288:9\n    │\n288 │         hook.payJudged(day, top);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaRouter.sol:409:78\n    │\n409 │         if (amount0Delta > 0) IERC20(pool.token0()).safeTransfer(msg.sender, uint256(amount0Delta));\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/MarginaliaRouter.sol:410:78\n    │\n410 │         if (amount1Delta > 0) IERC20(pool.token1()).safeTransfer(msg.sender, uint256(amount1Delta));\n    │                                                                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaRouter.sol:438:9\n    │\n438 │         emit XTraded(payer, X_V2, xIn, xOut, actualIn, received);\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/MarginaliaRouter.sol:426:37\n    │\n426 │         (uint112 r0, uint112 r1,) = pair.getReserves();\n    │                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:309:49\n    │\n309 │                 specifiedTake = STAMP + _bondOf(uint256(-params.amountSpecified));\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:386:9\n    │\n386 │         emit Accrued(day, amount);\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/MarginaliaHook.sol:464:17\n    │\n464 │                 emit Revealed(id, hash);\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/MarginaliaHook.sol:483:9\n    │\n483 │         emit NotePosted(id, author, p.x, class, p.side, p.targetBps, p.horizonDays, p.parentId, p.text);\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/MarginaliaHook.sol:345:13\n    │\n345 │             emit SwapFee(true, author, poolImd, 0, STAMP);\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/MarginaliaHook.sol:358:13\n    │\n358 │             emit SwapFee(false, author, poolImd, fee - STAMP, STAMP);\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/MarginaliaHook.sol:369:9\n    │\n369 │         emit SwapFee(false, tx.origin, poolImd, quietFee, 0);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:332:33\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:41\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:63\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:332:71\n    │\n332 │         uint256 poolImd = buy ? uint256(uint128(-imdDelta)) : uint256(uint128(imdDelta));\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/MarginaliaHook.sol:337:36\n    │\n337 │             uint256 bond = _bondOf(uint256(-params.amountSpecified));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:339:31\n    │\n339 │             uint256 margOut = uint256(uint128(margDelta));\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/MarginaliaHook.sol:339:39\n    │\n339 │             uint256 margOut = uint256(uint128(margDelta));\n    │                                       ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:446:17\n    │\n446 │             if (weekTheses[_week()].length >= MAX_WEEK_THESES) revert InvalidNote();\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/MarginaliaHook.sol:458:26\n    │\n458 │             if (bound && age < SEAL_MIN) revert TooEarly(); // the head start is the key holders', not the public's\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/MarginaliaHook.sol:459:26\n    │\n459 │             if (bound && age <= SEAL_MAX) {\n    │                          ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:439:22\n    │\n439 │         n.postedAt = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:518:13\n    │\n518 │         if (block.timestamp < end) revert TooEarly();\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/MarginaliaHook.sol:519:13\n    │\n519 │         if (block.timestamp > end + SETTLE_WINDOW) revert TooLate();\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/MarginaliaHook.sol:532:9\n    │\n532 │         emit Observed(id, xRead, balance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:524:27\n    │\n524 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:524:52\n    │\n524 │             T.Observation(uint64(block.timestamp), uint64(block.number), xRead, quoteRead, balance);\n    │                                                    ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:540:13\n    │\n540 │             x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.balanceOf.selector, who));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MarginaliaHook.sol:626:35\n    │\n626 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │                                   ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:577:13\n    │\n577 │         if (block.timestamp <= end + SETTLE_WINDOW) revert TooEarly();\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/MarginaliaHook.sol:687:13\n    │\n687 │             emit ThesisReleased(n.parentId);\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/MarginaliaHook.sol:626:9\n    │\n626 │         emit Settled(id, outcome, settlePrice, scoreDelta, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:609:26\n    │\n609 │             scoreDelta = int256(_difficulty(n));\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/MarginaliaHook.sol:614:27\n    │\n614 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:616:27\n    │\n616 │             scoreDelta = -int256(_difficulty(n));\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/MarginaliaHook.sol:620:27\n    │\n620 │             scoreDelta = -int256(_difficulty(n));\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:634:13\n    │\n634 │         if (block.timestamp >= horizonEnd(id)) revert TooLate();\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/MarginaliaHook.sol:644:9\n    │\n644 │         emit Retracted(id, text);\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/MarginaliaHook.sol:645:9\n    │\n645 │         emit Settled(id, T.Status.Retracted, 0, scoreDelta, address(0));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:638:30\n    │\n638 │         int256 scoreDelta = -int256(_difficulty(n) / 2);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:653:13\n    │\n653 │         if (block.timestamp <= uint256(n.postedAt) + THESIS_GRACE) revert TooEarly();\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/MarginaliaHook.sol:656:9\n    │\n656 │         emit ThesisForfeited(id);\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/MarginaliaHook.sol:670:9\n    │\n670 │         emit DepositClaimed(id, n.author, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/MarginaliaHook.sol:700:13\n    │\n700 │             n.x.staticcall{gas: BALANCE_READ_GAS}(abi.encodeWithSelector(IERC20.totalSupply.selector));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:709:16\n    │\n709 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:713:16\n    │\n713 │         return uint32(block.timestamp / 7 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:733:9\n    │\n733 │         emit PotFunded(_today(), amount, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `seals` is updated\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:766:25\n    │\n766 │         if ((at != 0 && block.timestamp - at <= SEAL_MAX) || x == address(0) || hash == bytes32(0)) {\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/MarginaliaHook.sol:780:9\n    │\n780 │         emit Sealed(hash, msg.sender, x, venue.ref);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:774:13\n    │\n774 │             uint64(block.timestamp),\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:800:27\n    │\n800 │         return (n.author, uint32(uint256(n.postedAt) / 7 days), n.targetBps == 0, n.children > 0);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `thesisPool` is updated\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/MarginaliaHook.sol:874:28\n    │\n874 │         bytes memory out = poolManager.unlock(data);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaHook.sol:822:9\n    │\n822 │         emit JudgedPaid(w, paidAmounts);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaHook.sol:875:39\n    │\n875 │         if (unlockHash != bytes32(0)) revert InvalidUnlock();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:829:13\n    │\n829 │         if (n.day >= _today()) revert TooEarly();\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/MarginaliaHook.sol:839:9\n    │\n839 │         emit RefundClaimed(id, msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:837:30\n    │\n837 │         notesPerDay[n.day] = uint32(count - 1);\n    │                              ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaHook.sol:848:17\n    │\n848 │             if (block.timestamp < (uint256(epoch) + 1) * 1 days + SWEEP_AFTER) revert TooEarly();\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/MarginaliaHook.sol:852:17\n    │\n852 │             if (block.timestamp < (uint256(epoch) + 1) * 7 days + SWEEP_AFTER) revert TooEarly();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaHook.sol:885:40\n    │\n885 │             address currency = address(uint160(extra));\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[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaHook.sol:894:13\n    │\n894 │             poolManager.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/MarginaliaPricer.sol:85:13\n   │\n85 │             n += 1;\n   │             ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:120:33\n    │\n120 │         if (w.startedAt == 0 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:34\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:121:59\n    │\n121 │             return T.PriceWindow(uint64(block.timestamp), uint64(block.number), x, x, x, q, q);\n    │                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPricer.sol:142:20\n    │\n142 │                 || block.timestamp < uint256(w.startedAt) + POST_MIN_SPAN\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/MarginaliaPricer.sol:143:20\n    │\n143 │                 || block.timestamp > uint256(w.startedAt) + POST_MAX_AGE\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:149:69\n    │\n149 │             x = twap(v.kind, v.xIsToken0, w.xStart, w.startedAt, x, uint64(block.timestamp));\n    │                                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:168:55\n    │\n168 │         else if (v.kind == T.VenueKind.UniV3) xRead = uint256(_v3Cumulative(ref));\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/MarginaliaPricer.sol:213:28\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:213:41\n    │\n213 │             int256 delta = int256(c2) - int256(c1);\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/MarginaliaPricer.sol:214:35\n    │\n214 │             int256 mean = delta / int256(dt);\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/MarginaliaPricer.sol:215:38\n    │\n215 │             if (delta < 0 && delta % int256(dt) != 0) mean -= 1; // round toward negative infinity, as v3 does\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/MarginaliaPricer.sol:217:57\n    │\n217 │             return fromSqrt(TickMath.getSqrtPriceAtTick(int24(mean)), xIsToken0);\n    │                                                         ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' 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/MarginaliaPricer.sol:241:37\n    │\n241 │             (uint160 sqrtP,,,,,,) = IUniswapV3PoolOracle(ref).slot0();\n    │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:245:41\n    │\n245 │             (uint112 r0, uint112 r1,) = IUniswapV2PairOracle(ref).getReserves();\n    │                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/MarginaliaPricer.sol:269:33\n    │\n269 │         (int56[] memory cum,) = IUniswapV3PoolOracle(pool).observe(ago);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPricer.sol:279:24\n    │\n279 │         uint32 nowTs = uint32(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/AuditFindings.t.sol:19:30\n   │\n19 │         uint256 startBlock = block.number;\n   │                              ━━━━━━━━━━━━\n   ‡\n23 │             vm.roll(startBlock + 25 * (i + 1));\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/AuditFindings.t.sol:20:27\n   │\n20 │         uint256 startTs = block.timestamp;\n   │                           ━━━━━━━━━━━━━━━\n   ‡\n24 │             vm.warp(startTs + 31 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:18:9\n    │\n 18 │         vm.warp(hook.horizonEnd(id));\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/AuditFindings.t.sol:65:9\n    │\n 65 │         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/AuditFindings.t.sol:65:17\n   │\n65 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:148:9\n    │\n148 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:149:30\n    │\n149 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n153 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:150:27\n    │\n150 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n154 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:176:9\n    │\n176 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:177:30\n    │\n177 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n181 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:178:27\n    │\n178 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n182 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:203:9\n    │\n203 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:204:30\n    │\n204 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n208 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:205:27\n    │\n205 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n209 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:302:9\n    │\n302 │         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/Lifecycle.t.sol:302:17\n    │\n302 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:357:9\n    │\n357 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:358:30\n    │\n358 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n363 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:359:27\n    │\n359 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n364 │             vm.warp(startTs + 30 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:421:9\n    │\n421 │         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/Lifecycle.t.sol:421:17\n    │\n421 │         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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:488:9\n    │\n488 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:489:30\n    │\n489 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n492 │         vm.roll(startBlock + 25);\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/Lifecycle.t.sol:490:27\n    │\n490 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n493 │         vm.warp(startTs + 30 minutes);\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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:512:9\n    │\n512 │         vm.warp(hook.horizonEnd(id));\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/Lifecycle.t.sol:513:30\n    │\n513 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n517 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:514:27\n    │\n514 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n518 │             vm.warp(startTs + 10 minutes * (i + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:554:9\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:538:49\n    │\n538 │         router.note(rebuttal, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/Lifecycle.t.sol:554:17\n    │\n554 │         vm.warp(block.timestamp + hook.THESIS_GRACE() + 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Lifecycle.t.sol:583:9\n    │\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:575:49\n    │\n575 │         router.note(sameSide, key, 10 ether, 1, block.timestamp + 1);\n    │                                                 ━━━━━━━━━━━━━━━\n    ‡\n583 │         vm.warp(hook.horizonEnd(a));\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/Lifecycle.t.sol:584:30\n    │\n584 │         uint256 startBlock = block.number;\n    │                              ━━━━━━━━━━━━\n    ‡\n589 │             vm.roll(startBlock + 25 * (i + 1));\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/Lifecycle.t.sol:585:27\n    │\n585 │         uint256 startTs = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n590 │             vm.warp(startTs + 30 minutes * (i + 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/Lifecycle.t.sol:629:22\n    │\n629 │         assertEq(at, block.timestamp);\n    │                      ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:634:42\n    │\n634 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:638:17\n    │\n638 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:653:17\n    │\n653 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:657:42\n    │\n657 │         router.note(p, key, 10 ether, 1, block.timestamp + 1);\n    │                                          ━━━━━━━━━━━━━━━\n    ‡\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:663:17\n    │\n663 │         vm.warp(block.timestamp + hook.SEAL_MIN());\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/Lifecycle.t.sol:679:17\n    │\n679 │         vm.warp(block.timestamp + hook.SEAL_MAX() + 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/Lifecycle.t.sol:682:17\n    │\n682 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:199:17\n    │\n199 │         vm.warp(block.timestamp + 1 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/helpers/Fixture.sol:266:50\n    │\n266 │         received = router.note(p, key, imdIn, 1, block.timestamp + 1);\n    │                                                  ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:262:9\n    │\n262 │         vm.warp((uint256(w) + 1) * 7 days + 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/Round3Findings.t.sol:67:17\n   │\n67 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":1331,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/MainnetLaunch.t.sol:MainnetLaunchTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 570.96µs (0.00ns CPU time)\n\nRan 9 tests for test/CompanionFailures.t.sol:TreasuryFailuresTest\n[PASS] testDripFailsWhenTheHookCannotTakeTheFunds() (gas: 673929)\n[PASS] testDripIsPermissionlessAndCompounds() (gas: 518661)\n[PASS] testDripOfDustRoundsToZeroAndReverts() (gas: 258318)\n[PASS] testDripWithNothingHeldReverts() (gas: 54033)\n[PASS] testInitOnlyByTheNamedHookAndOnlyOnce() (gas: 623926)\n[PASS] testInitRefusesTheZeroHook() (gas: 556415)\n[PASS] testNoWithdrawOrAdminSurface() (gas: 274868)\n[PASS] testSecondDripOnTheSameDayRevertsAndTheNextDayWorks() (gas: 372660)\n[PASS] testTreasuryRefusesEth() (gas: 71164)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 3.62ms (2.10ms CPU time)\n\nRan 8 tests for test/LaunchAuditFindings.t.sol:LaunchAuditFindingsTest\n[PASS] testAHugeSupplyBooksTierOneInsteadOfOverflowing() (gas: 2453892)\n[PASS] testALapsedSealCanBeSealedAgain() (gas: 695400)\n[PASS] testARetractedNoteLeavesTheDaysRefundSplit() (gas: 1381349)\n[PASS] testARetractionAfterTheRefundClaimDoesNotDoubleCount() (gas: 1357517)\n[PASS] testARevertingTotalSupplyDoesNotBlockARetraction() (gas: 1931368)\n[PASS] testARevertingTotalSupplyStillSettlesWrongAndPaysTheKeeper() (gas: 2547256)\n[PASS] testAStrangersSealNeitherBlocksNorPricesTheAuthorsNote() (gas: 2515168)\n[PASS] testAnAuthorsSealOnAnotherVenueDoesNotPriceTheNote() (gas: 2233321)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 20.04ms (7.19ms CPU time)\n\nRan 6 tests for test/AuditFindings.t.sol:AuditFindingsTest\n[PASS] testEmptyV4ObservationIsRefused() (gas: 918187)\n[PASS] testExpiredBaselineRejectsPostWithoutTakingFunds() (gas: 601043)\n[PASS] testHeadOfThreeFitsIntakeStipendAndAFullRankingIsRetried() (gas: 2078898)\n[PASS] testSameBlockDumpPostUnwindDoesNotWinBuy() (gas: 1815075)\n[PASS] testSameBlockPumpPostUnwindDoesNotWinSell() (gas: 1684045)\n[PASS] testUnpayableRankingRollsTheWholePoolForward() (gas: 2352594)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 22.94ms (7.11ms CPU time)\n\nRan 14 tests for test/CompanionFailures.t.sol:RouterFailuresTest\n[PASS] testExpiredDeadlineTakesNothing() (gas: 667396)\n[PASS] testExpiredWindowRefusesPostsUntilAFreshCheckpointMatures() (gas: 1754059)\n[PASS] testInitRequiresAManagerWithCode() (gas: 4169863)\n[PASS] testSlippageFloorRefundsEverything() (gas: 639186)\n[PASS] testStrangersCannotEnterTheCallbacks() (gas: 133302)\n[PASS] testTradeAndNoteRefusesNoTradeZeroTradeAndNativeInput() (gas: 290621)\n[PASS] testTradedNoteMustBeAboutTheTokenTraded() (gas: 979819)\n[PASS] testTradedV4LegUnderAForeignHookOrEmptyPoolIsRefused() (gas: 396049)\n[PASS] testUnapprovedOrUnfundedAuthorIsRefused() (gas: 224201)\n[PASS] testV4VenueUnderAForeignHookIsRefused() (gas: 69737)\n[PASS] testV4VenueWithoutLiquidityIsRefused() (gas: 134939)\n[PASS] testVenueFieldsAreDerivedFromThePoolNotTheCaller() (gas: 48532)\n[PASS] testVenueKindNoneIsRefusedForAPricedCall() (gas: 116203)\n[PASS] testZeroAndOversizedAmountsAreRefused() (gas: 138629)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 24.64ms (9.62ms CPU time)\n\nRan 12 tests for test/HoldRule.t.sol:HoldRuleTest\n[PASS] testABreachIsNeverReplacedByANonBreachInsideTheGap() (gas: 1646626)\n[PASS] testABreachReplacesANonBreachInsideTheGap() (gas: 1656886)\n[PASS] testABuyCallWithAnUnreadableBalanceIsVoidSold() (gas: 1477672)\n[PASS] testASellAuthorMayDumpTheirWholeRemainingBalance() (gas: 1615102)\n[PASS] testASellAuthorWhoBuysBackTheirWholePostBalanceIsStillRight() (gas: 1710689)\n[PASS] testASellCallWithAnUnreadableBalanceStillSettlesOnPrice() (gas: 1502871)\n[PASS] testASellCallsBalanceIsNeverAnAdverseReading() (gas: 1362393)\n[PASS] testAWrongSellCallForfeitsWhateverTheBalanceDid() (gas: 1419422)\n[PASS] testAnEqualReadingInsideTheGapIsRefused() (gas: 1030985)\n[PASS] testAtTheCapAHigherReadingCannotLiftABuyCallsMinimum() (gas: 3896632)\n[PASS] testAtTheCapOnlyAMoreAdverseReadingGetsIn() (gas: 4142871)\n[PASS] testBuyCallHasNoToleranceDownwards() (gas: 1563716)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 29.35ms (24.07ms CPU time)\n\nRan 8 tests for test/PriceHistory.t.sol:PriceHistoryTest\n[PASS] testBaselineRequiresMatureFreshHistory() (gas: 188472)\n[PASS] testEmptyVenueAndHubCannotBeCheckpointedObservedOrPriced() (gas: 284549)\n[PASS] testFuzzV4BaselineIsNeverFavourableToTheCall(int24,bool) (runs: 256, μ: 106064, ~: 106151)\nLogs:\n  Bound result 13445\n\n[PASS] testHubBaselineUsesOppositeExtremeFromSettlement() (gas: 180334)\n[PASS] testLiveCheckpointCannotEraseHonestExtremesOrRestartTheClock() (gas: 224282)\n[PASS] testV2BaselineIgnoresSameBlockReservesDumpAndPumpBothOrientations() (gas: 467543)\n[PASS] testV3BaselineIgnoresSameBlockTickChangesBothOrientations() (gas: 418025)\n[PASS] testV3BaselineWeightsElapsedTime() (gas: 371037)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 38.71ms (38.02ms CPU time)\n\nRan 10 tests for test/Round3Findings.t.sol:Round3FindingsTest\n[PASS] testABuyCallStillBreaksWhenTheAuthorSells() (gas: 1662303)\n[PASS] testAGiftOfAnySizeDoesNotVoidACorrectSellCall() (gas: 1576984)\n[PASS] testAGiftWorthTheDepositDoesNotVoidACorrectSellCall() (gas: 1656237)\n[PASS] testALaunchPoolCallScoresTheSameWay() (gas: 1410703)\n[PASS] testASelfPricedVenueBooksReputationOnlyAndNoPoolPaysForIt() (gas: 3000040)\n[PASS] testAWrongCallOnAnotherVenueStillForfeitsAndBooksANegativeScore() (gas: 2699621)\n[PASS] testAWrongSellCallStillForfeits() (gas: 1388782)\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 256, μ: 23324, ~: 21078)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1944177)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204541)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 52.31ms (37.69ms CPU time)\n\nRan 7 tests for test/JudgeOracle.t.sol:JudgeOracleTest\n[PASS] testEmptySignedRankingIsAnExecutableNoWinnerResult() (gas: 248153)\n[PASS] testFiveIdsWithEoaSignatureFitStipend() (gas: 554052)\n[PASS] testFullRankingWithEoaSignatureFitsStipend() (gas: 633672)\n[PASS] testProtocolDigestSignatureAndSelectorConformanceOnClone() (gas: 3322442)\n[PASS] testRejectedAnswersDoNotConsumeThePendingRequest() (gas: 892875)\n[PASS] testRequestedHeadIsFilteredAndDeduplicatedWithoutPromotingTheTail() (gas: 250679)\n[PASS] testTimeoutRetryInvalidatesOldIntakeRequest() (gas: 523953)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 56.79ms (5.92ms CPU time)\n\nRan 31 tests for test/Lifecycle.t.sol:LifecycleTest\n[PASS] testAttestedClassCannotBeSelfDeclared() (gas: 294181)\n[PASS] testCallbackSelectorPinned() (gas: 3383)\n[PASS] testCounterCallDuel() (gas: 3574228)\n[PASS] testCounterThesisEntersTheJudgedSet() (gas: 2619171)\n[PASS] testFakeVenueIsRefused() (gas: 382712)\n[PASS] testFlagsAndBinding() (gas: 56004)\n[PASS] testForfeitsAreImdAndNeedNoConversion() (gas: 860264)\n[PASS] testNoDataRefunds() (gas: 879778)\n[PASS] testNoteTooSmall() (gas: 1642643)\n[PASS] testNotedBuyTakesStampAndDeposit() (gas: 728512)\n[PASS] testNotedSellPaysOnePercentPlusStamp() (gas: 987443)\n[PASS] testObservationsMustSpanAnHour() (gas: 1382961)\n[PASS] testPlainBuyTakesNothing() (gas: 211534)\n[PASS] testQuietSellPaysThreePercent() (gas: 295286)\n[PASS] testQuietThesisPoolSweeps() (gas: 300148)\n[PASS] testRetract() (gas: 865757)\n[PASS] testRightCallReturnsDeposit() (gas: 1616318)\n[PASS] testScoreIsReputationAndAccrualsSplitSeventyThirty() (gas: 2873294)\n[PASS] testSealedBuyMustKeepItsPositionFromTheSeal() (gas: 2161817)\n[PASS] testSealedNoteRevealsAgainstTheSealBaseline() (gas: 1767999)\n[PASS] testSellingEarlyBreaksTheCall() (gas: 1671033)\n[PASS] testThesisParentChild() (gas: 1339191)\n[PASS] testThesisWithoutChildForfeits() (gas: 805132)\n[PASS] testTreasuryDrip() (gas: 320725)\n[PASS] testTwoBlockPumpObserveUnwindSettlesWrong() (gas: 1685550)\n[PASS] testUnansweredWeekCanBeRetried() (gas: 2328397)\n[PASS] testUnrevealedSealIsNotAFreeOptionAndLapses() (gas: 1353385)\n[PASS] testUpOnlyIsRefused() (gas: 291808)\n[PASS] testWeeklyThesisJudging() (gas: 3667556)\n[PASS] testWriterRefundCappedAtStamp() (gas: 1587968)\n[PASS] testWrongCallForfeitsWithKeeperReward() (gas: 1504323)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 65.33ms (44.26ms CPU time)\n\nRan 28 tests for test/CompanionFailures.t.sol:JudgeFailuresTest\n[PASS] testAJudgedWeekCannotBeAbandoned() (gas: 1257630)\n[PASS] testAbandonNeedsALiveRequestPastItsDeadline() (gas: 1190393)\n[PASS] testAbandonTakesNothingAndTheRetryDrawsAgain() (gas: 1467522)\n[PASS] testAnswerAtTheExactExpiryStillCountsAndOneSecondLaterDoesNot() (gas: 1257046)\n[PASS] testAnswerForAWeekAlreadyJudgedIsRefused() (gas: 1320679)\n[PASS] testAnswerSignedByAnotherKeyIsRefused() (gas: 1069433)\n[PASS] testAnswerSignedForAnotherConsumerIsRefused() (gas: 3952788)\n[PASS] testConvertForfeitsWithAnEmptyPotIsANoOp() (gas: 236930)\n[PASS] testConvertNeverSellsMoreThanThePot() (gas: 236488)\n[PASS] testConvertSellsTheLargestHalvingThePoolAbsorbs() (gas: 275386)\n[PASS] testConvertTriesExactlyNineTranchesDownToOneTwoHundredFiftySixth() (gas: 363686)\n[PASS] testCurrentAndFutureWeeksCannotBeRequested() (gas: 128617)\n[PASS] testEligibleThesesAreCappedAtTheJudgedMaximum() (gas: 14217218)\n[PASS] testImplementationHasAPlaceholderSignerAndCannotBeConfigured() (gas: 2726709)\n[PASS] testInitRequiresEveryConfigurationValue() (gas: 2953442)\n[PASS] testIntakeReturningAnIdAlreadyPendingIsRefused() (gas: 1599187)\n[PASS] testJudgedOfFiltersWrongWeekShortFormAndChildlessIds() (gas: 1439829)\n[PASS] testJudgedWeekCannotBeRequestedAgainEvenAfterTheDeadline() (gas: 1242650)\n[PASS] testMalformedAnswerBytesAreRefused() (gas: 1067354)\n[PASS] testOnlyTheHeadOfThreeIsStoredAndTheTailNeverPromotes() (gas: 1221812)\n[PASS] testPayBeforeAnAnswerReverts() (gas: 1064318)\n[PASS] testPayIsPermissionlessAndOnce() (gas: 1438634)\n[PASS] testQuestionBodyNamesTheConsumerChainAndEligibleIdsOnly() (gas: 2516225)\n[PASS] testRepeatRequestBeforeTheDeadlineIsRefused() (gas: 1419149)\n[PASS] testRequestDrawsExactlyThePriceAndKeepsNothing() (gas: 1028228)\n[PASS] testWeekClosedStates() (gas: 1940695)\n[PASS] testWeekWithoutEligibleThesesCannotBeRequested() (gas: 244665)\n[PASS] testZeroAndExcessiveOraclePricesAreRefused() (gas: 1345941)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 74.70ms (33.00ms CPU time)\n\nRan 10 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testABuyBackNoLongerVoidsASellCallItSettlesOnPrice() (gas: 1592379)\n[PASS] testADustPricedV4VenueCannotBePostedOn() (gas: 1573375)\n[PASS] testARevertingBalanceOfVoidsTheCallAsSoldNotAsNoData() (gas: 2584779)\n[PASS] testAStrangersDustTransferDoesNotVoidASellCall() (gas: 1557285)\n[PASS] testAnAttestationAboutAnotherChainIsRefused() (gas: 2211392)\n[PASS] testAnEmptyCanonicalV3PoolIsRefusedAsAVenue() (gas: 567739)\n[PASS] testHonestObserverOverwritesAPumpObserveUnwindInTheNextBlock() (gas: 3639225)\n[PASS] testPricerRefusesAPriceThatRoundsToZeroInBothOrientations() (gas: 58734)\n[PASS] testSweepNeedsTheStaleRequestAbandonedAndALateAnswerIsThenRefused() (gas: 2347244)\n[PASS] testTheHundredAndTwentyFirstThesisOfAWeekIsRefusedBeforePayment() (gas: 50466529)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 75.72ms (61.82ms CPU time)\n\nRan 3 tests for test/Implementations.t.sol:ImplementationsTest\n[PASS] testClonesInitializeOnceOnlyFromTheirHook() (gas: 4551335)\n[PASS] testFactoryDeploysAllFourWithoutArgumentsOrExternalDependencies() (gas: 34608585)\nLogs:\n  four implementation CREATE2 deployments (gas): 8829579\n\n[PASS] testImplementationsRejectInitialization() (gas: 81376)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 81.86ms (61.68ms CPU time)\n\nRan 7 tests for test/Pricer.t.sol:PricerTest\n[PASS] testQuoteLegIsAdverseEvenUnderAV3Twap() (gas: 28455)\n[PASS] testTwapRefusesZeroSpanAndV4() (gas: 17708)\n[PASS] testV2TwapFromWrappingCumulative() (gas: 9503)\n[PASS] testV3TwapOfAConstantTickIsThatTick() (gas: 15459)\n[PASS] testV3TwapRoundsNegativeMeansDown() (gas: 14848)\n[PASS] testV3TwapWeightsByTime() (gas: 14715)\n[PASS] testV4SettlesOnTheAdverseExtreme() (gas: 26636)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 81.98ms (440.22µs CPU time)\n\nRan 31 tests for test/PricerProperties.t.sol:PricerPropertiesTest\n[PASS] testDifficultyAnchors() (gas: 56436)\n[PASS] testDifficultyRefusesAZeroHorizon() (gas: 10063)\n[PASS] testDifficultyTiersStepExactlyAtTheThresholds() (gas: 79314)\n[PASS] testEmptyPoolsAreRefusedOnBothLegs() (gas: 161813)\n[PASS] testEthQuoteIsOnlyPriceableOnMainnet() (gas: 40894)\n[PASS] testFromSqrtRefusesAnEmptyOrUnpriceableReading() (gas: 53891)\n[PASS] testFromSqrtZeroThresholdIsSharpInBothOrientations() (gas: 1024182)\n[PASS] testFuzzAppendingAnObservationNeverHelpsTheCall(uint256[16],uint256[16],uint8) (runs: 1000, μ: 132388, ~: 116130)\nLogs:\n  Bound result 6\n  Bound result 833257304096488271895104681391\n  Bound result 779446977975926379883186223314\n  Bound result 846525563230603556285191166271\n  Bound result 758530324516272497980983292385\n  Bound result 545626747916123961004747221223\n  Bound result 1220245520240389091733900938\n  Bound result 1000000002\n  Bound result 999999999999999999999999999999\n  Bound result 669118207104711779972472387735\n  Bound result 127785363262608247795257309\n  Bound result 568975033363254524632788554129\n  Bound result 895720595670219944597849211987\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36866, ~: 36834)\nLogs:\n  Bound result 9990923\n  Bound result 22080\n  Bound result 48\n  Bound result 35091945559\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141543, ~: 141883)\nLogs:\n  Bound result 1266412660188944021221804083676\n  Bound result 237684487542793012780631851008\n  Bound result 24576\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36725, ~: 36871)\nLogs:\n  Bound result 990923\n  Bound result 64\n  Bound result 48\n  Bound result 35091945559\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23183, ~: 21445)\nLogs:\n  Bound result 1461446703485210103287273052107014382464290017505\n  Bound result 1461446703485210103287273052103989628710152072565\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39508, ~: 38617)\nLogs:\n  Bound result 40439\n  Bound result 60315685960279\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16404, ~: 14794)\nLogs:\n  Bound result 131\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 53802, ~: 51987)\nLogs:\n  Bound result 16782\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36434, ~: 36410)\nLogs:\n  Bound result 3867\n  Bound result 90\n  Bound result 75\n  Bound result 8418\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 19230, ~: 17271)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21360, ~: 21299)\nLogs:\n  Bound result 5192296858534827628530496329220095\n  Bound result 5192296858534827628530496329220095\n  Bound result 1245\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 64550, ~: 61360)\nLogs:\n  Bound result 9969\n  Bound result 3\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 99292, ~: 91525)\nLogs:\n  Bound result 16\n  Bound result 3266167182\n  Bound result 48879\n  Bound result 17716\n  Bound result 18943\n  Bound result 12830\n  Bound result 7000\n  Bound result 1800000000\n  Bound result 55\n  Bound result 23890\n  Bound result 20735\n  Bound result 50000000000000000000000000\n  Bound result 12\n  Bound result 999999999999999999999999999999\n  Bound result 2419200\n  Bound result 20538\n  Bound result 565664426117466910078421933505\n  Bound result 1072\n  Bound result 1000000000000000000000000000000\n  Bound result 21412\n  Bound result 6318\n  Bound result 1000000000000000000000000000000\n  Bound result 377032989948697243942600083930\n  Bound result 10000000\n  Bound result 333643643352876860038887505921\n  Bound result 5000000000000000000000000\n  Bound result 3\n  Bound result 719206528\n  Bound result 4617\n  Bound result 7000\n  Bound result 9860\n  Bound result 113\n  Bound result 1\n\n[PASS] testObserveRefusesUnknownVenuesAndUnpriceableQuotes() (gas: 150448)\n[PASS] testPostPriceRefusesAnEmptyWindow() (gas: 15317)\n[PASS] testPostPriceWhoseProductRoundsToZeroIsRefused() (gas: 293627)\n[PASS] testSellDifficultyRefusesAZeroTarget() (gas: 9518)\n[PASS] testSettlementRefusesAnEmptyOrUnspannedSeries() (gas: 39083)\n[PASS] testSqrtIsExactOnEveryHorizonDifficultyUses() (gas: 903275)\n[PASS] testSqrtPins() (gas: 123131)\n[PASS] testTwapRefusesTimeRunningBackwards() (gas: 9132)\n[PASS] testV2TwapAndSpotOfADustRatioAreRefused() (gas: 220677)\n[PASS] testV3TwapRefusesAMeanTickOutsideTheRange() (gas: 27255)\n[PASS] testV4SeriesWithADustExtremeIsRefusedNotSettledAtZero() (gas: 33519)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 99.70ms (857.51ms CPU time)\n\nRan 1 test for test/RouterInvariant.t.sol:RouterInvariantTest\n[PASS]\nRouterInvariantTest invariants:\n[PASS] invariant_bindingsPinned\n[PASS] invariant_everyNoteCameThroughTheRouter\n[PASS] invariant_managerBacksTheHooksClaims\n[PASS] invariant_routerKeepsNothing\n RouterInvariantTest invariants (runs: 48, calls: 1920, reverts: 2)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| RouterHandler | advance        | 224   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 202   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 434   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 222   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 211   | 2       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 222   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 194   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 211   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 175\n  Bound result 1\n  Bound result 97\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 1203\n  Bound result 52828\n  Bound result 20\n  Bound result 2\n  Bound result 256\n  Bound result 4201\n  Bound result 242\n  Bound result 2\n  Bound result 3376814322\n  Bound result 1\n  Bound result 1967\n  Bound result 7132\n  Bound result 17\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 7762\n  Bound result 0\n  Bound result 9064\n  Bound result 50026\n  Bound result 6\n  Bound result 1\n  Bound result 830098549\n  Bound result 8192\n  Bound result 2\n  Bound result 0\n  Bound result 301291982502822352442\n  Bound result 41811\n  Bound result 1\n  Bound result 0\n  Bound result 13080\n  Bound result 0\n  Bound result 119\n  Bound result 2\n  Bound result 48\n  Bound result 53193\n  Bound result 97\n  Bound result 2\n  Bound result 481\n  Bound result 54772\n  Bound result 30\n  Bound result 0\n  Bound result 244\n  Bound result 0\n  Bound result 656805679988414885970\n  Bound result 5963\n  Bound result 8\n  Bound result 2\n  Bound result 13857\n  Bound result 52401\n  Bound result 19\n  Bound result 0\n  Bound result 1\n  Bound result 34206757835872338314\n  Bound result 0\n  Bound result 1\n  Bound result 288\n  Bound result 52990\n  Bound result 10\n  Bound result 0\n  Bound result 0\n  Bound result 999001\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 54904650524054341235246\n  Bound result 3171656386909677579104\n  Bound result 2\n  Bound result 0\n  Bound result 506154428405244755968\n  Bound result 53557\n  Bound result 49\n  Bound result 0\n  Bound result 9000000000000000000\n  Bound result 37031\n  Bound result 61\n  Bound result 1\n  Bound result 15\n  Bound result 3196\n  Bound result 0\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 570.32ms (555.88ms CPU time)\n\nRan 1 test for test/TreasuryInvariant.t.sol:TreasuryInvariantTest\n[PASS]\nTreasuryInvariantTest invariants:\n[PASS] invariant_balanceIsGiftsMinusDrips\n[PASS] invariant_dripNeverExceedsTwoPercent\n[PASS] invariant_holdsNoEth\n[PASS] invariant_hookHoldsExactlyTheDrips\n[PASS] invariant_hookIsPinned\n[PASS] invariant_lastDripDayMatchesTheLastSuccessfulDrip\n TreasuryInvariantTest invariants (runs: 256, calls: 12288, reverts: 0)\n\n╭-----------------+-----------+-------+---------+----------╮\n| Contract        | Selector  | Calls | Reverts | Discards |\n+==========================================================+\n| TreasuryHandler | advance   | 2439  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2443  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2407  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2499  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2500  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 5219\n  Bound result 120470\n  Bound result 25193248116\n  Bound result 181650\n  Bound result 119\n  Bound result 1024\n  Bound result 752439625496620962700595\n  Bound result 1999\n  Bound result 2419200\n  Bound result 7285877318534838428\n  Bound result 96176\n  Bound result 259199\n  Bound result 223040\n  Bound result 3117\n  Bound result 9397\n  Bound result 111402\n  Bound result 9348\n  Bound result 7346\n  Bound result 3796062199450743023\n  Bound result 259200\n  Bound result 2089076379\n  Bound result 1461501637330902918203684832716283019655932542975\n  Bound result 111856\n  Bound result 60000\n  Bound result 5817661807806360357\n  Bound result 807\n  Bound result 201291\n  Bound result 54537\n  Bound result 1928028033\n  Bound result 9934\n  Bound result 12345\n  Bound result 153783\n  Bound result 659918\n  Bound result 7808\n  Bound result 5644\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.18s (1.18s CPU time)\n\nRan 17 test suites in 1.18s (2.48s CPU time): 186 tests passed, 0 failed, 1 skipped (187 total tests)\n","passed":true},{"durationMs":124,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Marginalia.approve(address,uint256)\",\"Marginalia.transfer(address,uint256)\",\"Marginalia.transferFrom(address,address,uint256)\",\"MarginaliaHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"MarginaliaHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"MarginaliaHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"MarginaliaHook.claimDeposit(bytes32)\",\"MarginaliaHook.claimRefund(bytes32)\",\"MarginaliaHook.drawForJudging(uint32,uint256,bool)\",\"MarginaliaHook.fundPot(uint256)\",\"MarginaliaHook.observe(bytes32)\",\"MarginaliaHook.payJudged(uint32,bytes32[3])\",\"MarginaliaHook.retract(bytes32,string)\",\"MarginaliaHook.seal(address,(uint8,bytes32,address,bool),bytes32)\",\"MarginaliaHook.settle(bytes32)\",\"MarginaliaHook.settleThesis(bytes32)\",\"MarginaliaHook.sweep(uint8,uint32)\",\"MarginaliaHook.unlockCallback(bytes)\",\"MarginaliaJudge.abandonRequest(uint32)\",\"MarginaliaJudge.convertForfeits()\",\"MarginaliaJudge.init(address,address,bytes32,address)\",\"MarginaliaJudge.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaJudge.payJudged(uint32)\",\"MarginaliaJudge.requestJudging(uint32)\",\"MarginaliaRouter.checkpointVenue((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address))\",\"MarginaliaRouter.init(address,address)\",\"MarginaliaRouter.note((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.sellWithNote((address,(uint8,bytes32,address,bool),uint8,uint32,uint16,bytes32,uint8,string),(address,address,uint24,int24,address),uint256,uint256,uint256)\",\"MarginaliaRouter.uniswapV3SwapCallback(int256,int256,bytes)\",\"MarginaliaRouter.unlockCallback(bytes)\",\"MarginaliaTreasury.drip()\",\"MarginaliaTreasury.init(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":335,\"README.md\":192,\"SPEC.md\":282,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":82,\"helper/server.js\":90,\"helper/src/app.js\":203,\"jobs/launch-1-hook.json\":43,\"jobs/launch-2-contracts.json\":38,\"jobs/launch-A-implementations.json\":47,\"jobs/launch-A2-implementations.json\":99,\"jobs/launch-B-hook.json\":36,\"jobs/launch-hook-v3.json\":43,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":924,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPricer.sol\":305,\"src/MarginaliaRouter.sol\":446,\"src/MarginaliaTreasury.sol\":53,\"src/MarginaliaTypes.sol\":127,\"src/OracleAttestation.sol\":221,\"src/interfaces/IIntake.sol\":15,\"src/interfaces/ILaunchFactory.sol\":49,\"test/AuditFindings.t.sol\":156,\"test/CompanionFailures.t.sol\":941,\"test/HoldRule.t.sol\":259,\"test/Implementations.t.sol\":96,\"test/JudgeOracle.t.sol\":270,\"test/LaunchAuditFindings.t.sol\":230,\"test/Lifecycle.t.sol\":696,\"test/PriceHistory.t.sol\":233,\"test/Pricer.t.sol\":88,\"test/PricerProperties.t.sol\":569,\"test/RevisionFindings.t.sol\":319,\"test/Round3Findings.t.sol\":218,\"test/RouterInvariant.t.sol\":248,\"test/TreasuryInvariant.t.sol\":167,\"test/fork/MainnetLaunch.t.sol\":378,\"test/helpers/Fixture.sol\":285,\"test/mocks/MockERC20.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":12184,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/MarginaliaPricer.sol:205: MarginaliaPricer.twap(MarginaliaTypes.VenueKind,bool,uint256,uint64,uint256,uint64) (src/MarginaliaPricer.sol#205-229) uses a weak PRNG: \"delta < 0 && delta % int256(dt) != 0 (src/MarginaliaPricer.sol#215)\"\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:414: Reentrancy in MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:414: Reentrancy in MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:377: Reentrancy in MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:377: Reentrancy in MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:414: Reentrancy in MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439):\n[high/medium] reentrancy-balance at src/MarginaliaRouter.sol:287: Reentrancy in MarginaliaRouter._pull(address,uint256) (src/MarginaliaRouter.sol#287-292):\n[high/high] uninitialized-state at src/MarginaliaHook.sol:514: MarginaliaHook.observations (src/MarginaliaHook.sol#104) is never initialized. It is used in:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:295: MarginaliaPricer.fromSqrt(uint160,bool) (src/MarginaliaPricer.sol#295-304) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:377: MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaHook.sol:868: MarginaliaHook._unlock(uint8,address,uint256,uint256) (src/MarginaliaHook.sol#868-877) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaHook.sol:549: MarginaliaHook._broken(MarginaliaTypes.Note,uint256) (src/MarginaliaHook.sol#549-552) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:414: MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:299: MarginaliaRouter.unlockCallback(bytes) (src/MarginaliaRouter.sol#299-340) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:294: MarginaliaRouter._checkSubject(MarginaliaRouter.Job) (src/MarginaliaRouter.sol#294-297) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:295: MarginaliaPricer.fromSqrt(uint160,bool) (src/MarginaliaPricer.sol#295-304) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:176: MarginaliaPricer.settlePrice(MarginaliaTypes.Venue,bool,MarginaliaTypes.Observation[]) (src/MarginaliaPricer.sol#176-201) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:287: MarginaliaRouter._pull(address,uint256) (src/MarginaliaRouter.sol#287-292) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:205: MarginaliaPricer.twap(MarginaliaTypes.VenueKind,bool,uint256,uint64,uint256,uint64) (src/MarginaliaPricer.sol#205-229) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaTreasury.sol:42: MarginaliaTreasury.drip() (src/MarginaliaTreasury.sol#42-52) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaTreasury.sol:42: MarginaliaTreasury.drip() (src/MarginaliaTreasury.sol#42-52) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:414: MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:135: MarginaliaPricer.postPrice(IPoolManager,MarginaliaTypes.Venue,address,bool,MarginaliaTypes.PriceWindow) (src/MarginaliaPricer.sol#135-155) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaRouter.sol:242: MarginaliaRouter._run(bool,uint256,uint256,uint256,MarginaliaRouter.XTrade,MarginaliaTypes.NoteParams,PoolKey) (src/MarginaliaRouter.sol#242-284) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/MarginaliaPricer.sol:295: MarginaliaPricer.fromSqrt(uint160,bool) (src/MarginaliaPricer.sol#295-304) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/MarginaliaHook.sol:573: Reentrancy in MarginaliaHook.settle(bytes32) (src/MarginaliaHook.sol#573-627):\n[medium/medium] reentrancy-no-eth at src/MarginaliaHook.sol:804: Reentrancy in MarginaliaHook.payJudged(uint32,bytes32[3]) (src/MarginaliaHook.sol#804-823):\n[medium/medium] reentrancy-no-eth at src/MarginaliaJudge.sol:203: Reentrancy in MarginaliaJudge.requestJudging(uint32) (src/MarginaliaJudge.sol#203-226):\n[medium/medium] reentrancy-no-eth at src/MarginaliaHook.sol:630: Reentrancy in MarginaliaHook.retract(bytes32,string) (src/MarginaliaHook.sol#630-646):\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:179: MarginaliaRouter.sellWithNote(MarginaliaTypes.NoteParams,PoolKey,uint256,uint256,uint256).noX (src/MarginaliaRouter.sol#179) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:127: MarginaliaJudge.questionBody(uint32).allow (src/MarginaliaJudge.sol#127) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaHook.sol:581: MarginaliaHook.settle(bytes32).settlePrice (src/MarginaliaHook.sol#581) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:166: MarginaliaRouter.note(MarginaliaTypes.NoteParams,PoolKey,uint256,uint256,uint256).noX (src/MarginaliaRouter.sol#166) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:257: MarginaliaRouter._run(bool,uint256,uint256,uint256,MarginaliaRouter.XTrade,MarginaliaTypes.NoteParams,PoolKey).job (src/MarginaliaRouter.sol#257) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:113: MarginaliaJudge.eligibleTheses(uint32).n (src/MarginaliaJudge.sol#113) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:205: MarginaliaRouter.validateVenue(MarginaliaTypes.NoteParams,PoolKey).t1 (src/MarginaliaRouter.sol#205) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:272: MarginaliaJudge.judgedOf(uint32).dup (src/MarginaliaJudge.sol#272) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:268: MarginaliaJudge.judgedOf(uint32).kept (src/MarginaliaJudge.sol#268) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaHook.sol:811: MarginaliaHook.payJudged(uint32,bytes32[3]).paidAmounts (src/MarginaliaHook.sol#811) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaJudge.sol:168: MarginaliaJudge._dec(uint256).n (src/MarginaliaJudge.sol#168) is a local variable never initialized\n[medium/medium] uninitialized-local at src/MarginaliaRouter.sol:204: MarginaliaRouter.validateVenue(MarginaliaTypes.NoteParams,PoolKey).t0 (src/MarginaliaRouter.sol#204) is a local variable never initialized\n[medium/medium] unused-return at src/MarginaliaPricer.sol:255: MarginaliaPricer._quoteSpot(IPoolManager,address,address) (src/MarginaliaPricer.sol#255-264) ignores return value by (sqrtP,None,None,None) = manager.getSlot0(PoolId.wrap(HUB_POOL_ID)) (src/MarginaliaPricer.sol#260)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:233: MarginaliaPricer._spotInQuote(IPoolManager,MarginaliaTypes.Venue) (src/MarginaliaPricer.sol#233-252) ignores return value by (r0,r1,None) = IUniswapV2PairOracle(ref).getReserves() (src/MarginaliaPricer.sol#245)\n[medium/medium] unused-return at src/MarginaliaHook.sol:291: MarginaliaHook.margPriceInImd() (src/MarginaliaHook.sol#291-294) ignores return value by (sqrtP,None,None,None) = poolManager.getSlot0(poolId) (src/MarginaliaHook.sol#292)\n[medium/medium] unused-return at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) ignores return value by (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:233: MarginaliaPricer._spotInQuote(IPoolManager,MarginaliaTypes.Venue) (src/MarginaliaPricer.sol#233-252) ignores return value by (sqrtP_scope_0,None,None,None,None,None,None) = IUniswapV3PoolOracle(ref).slot0() (src/MarginaliaPricer.sol#241)\n[medium/medium] unused-return at src/MarginaliaRouter.sol:414: MarginaliaRouter._tradeV2(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#414-439) ignores return value by (r0,r1,None) = pair.getReserves() (src/MarginaliaRouter.sol#426)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:267: MarginaliaPricer._v3Cumulative(address) (src/MarginaliaPricer.sol#267-271) ignores return value by (cum,None) = IUniswapV3PoolOracle(pool).observe(ago) (src/MarginaliaPricer.sol#269)\n[medium/medium] unused-return at src/MarginaliaPricer.sol:233: MarginaliaPricer._spotInQuote(IPoolManager,MarginaliaTypes.Venue) (src/MarginaliaPricer.sol#233-252) ignores return value by (sqrtP,None,None,None) = manager.getSlot0(PoolId.wrap(v.ref)) (src/MarginaliaPricer.sol#237)\n[medium/medium] unused-return at src/MarginaliaHook.sol:879: MarginaliaHook.unlockCallback(bytes) (src/MarginaliaHook.sol#879-899) ignores return value by poolManager.settle() (src/MarginaliaHook.sol#894)\n[low/high] shadowing-local at src/MarginaliaHook.sol:808: MarginaliaHook.payJudged(uint32,bytes32[3]).pool (src/MarginaliaHook.sol#808) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.noteMeta(bytes32).week (src/MarginaliaJudge.sol#19) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.thesesOfWeek(uint32).week (src/MarginaliaJudge.sol#15) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.thesisPool(uint32).week (src/MarginaliaJudge.sol#12) shadows:\n[low/high] shadowing-local at src/MarginaliaJudge.sol:14: IHookJudge.drawForJudging(uint32,uint256,bool).week (src/MarginaliaJudge.sol#21) shadows:\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:266: MarginaliaJudge.judgedOf(uint32) (src/MarginaliaJudge.sol#266-279) has external calls inside a loop: (author,noteWeek,thesis,hasChild) = hook.noteMeta(ranked[i]) (src/MarginaliaJudge.sol#270)\n[low/medium] calls-loop at src/MarginaliaHook.sol:868: MarginaliaHook._unlock(uint8,address,uint256,uint256) (src/MarginaliaHook.sol#868-877) has external calls inside a loop: out = poolManager.unlock(data) (src/MarginaliaHook.sol#874)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:91: MarginaliaJudge.convertForfeits() (src/MarginaliaJudge.sol#91-106) has external calls inside a loop: out = hook.sellPotMarg(marg) (src/MarginaliaJudge.sol#96-100)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:266: MarginaliaJudge.judgedOf(uint32) (src/MarginaliaJudge.sol#266-279) has external calls inside a loop: (author,noteWeek,thesis,hasChild) = hook.noteMeta(ranked[i]) (src/MarginaliaJudge.sol#270)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] calls-loop at src/MarginaliaJudge.sol:110: MarginaliaJudge.eligibleTheses(uint32) (src/MarginaliaJudge.sol#110-122) has external calls inside a loop: (None,None,None,hasChild) = hook.noteMeta(all[i]) (src/MarginaliaJudge.sol#115)\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:673: Reentrancy in MarginaliaHook._forfeit(MarginaliaTypes.Note,address) (src/MarginaliaHook.sol#673-680):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:320: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#320-371):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:320: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#320-371):\n[low/medium] reentrancy-benign at src/MarginaliaRouter.sol:377: Reentrancy in MarginaliaRouter._tradeV3(address,MarginaliaRouter.XTrade) (src/MarginaliaRouter.sol#377-404):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:320: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#320-371):\n[low/medium] reentrancy-benign at src/MarginaliaHook.sol:736: Reentrancy in MarginaliaHook._fund(uint256) (src/MarginaliaHook.sol#736-740):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:673: Reentrancy in MarginaliaHook._forfeit(MarginaliaTypes.Note,address) (src/MarginaliaHook.sol#673-680):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:320: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#320-371):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:649: Reentrancy in MarginaliaHook.settleThesis(bytes32) (src/MarginaliaHook.sol#649-657):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:630: Reentrancy in MarginaliaHook.retract(bytes32,string) (src/MarginaliaHook.sol#630-646):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:573: Reentrancy in MarginaliaHook.settle(bytes32) (src/MarginaliaHook.sol#573-627):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:736: Reentrancy in MarginaliaHook._fund(uint256) (src/MarginaliaHook.sol#736-740):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:320: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#320-371):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:320: Reentrancy in MarginaliaHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/MarginaliaHook.sol#320-371):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:804: Reentrancy in MarginaliaHook.payJudged(uint32,bytes32[3]) (src/MarginaliaHook.sol#804-823):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:826: Reentrancy in MarginaliaHook.claimRefund(bytes32) (src/MarginaliaHook.sol#826-840):\n[low/medium] reentrancy-events at src/MarginaliaTreasury.sol:42: Reentrancy in MarginaliaTreasury.drip() (src/MarginaliaTreasury.sol#42-52):\n[low/medium] reentrancy-events at src/MarginaliaHook.sol:660: Reentrancy in MarginaliaHook.claimDeposit(bytes32) (src/MarginaliaHook.sol#660-671):\n[low/medium] return-bomb at src/MarginaliaHook.sol:538: MarginaliaHook._balanceOf(address,address) (src/MarginaliaHook.sol#538-543) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] timestamp at src/MarginaliaHook.sol:845: MarginaliaHook.sweep(uint8,uint32) (src/MarginaliaHook.sol#845-860) uses timestamp for comparisons\n[low/medium] timestamp at src/MarginaliaHook.sol:649: MarginaliaHook.settleThesis(bytes32) (src/MarginaliaHook.sol#649-657) uses timestamp for c","passed":true},{"durationMs":941,"exitCode":0,"name":"aderyn","output":"[high] eth-send-unchecked-address at src/MarginaliaHook.sol:730: ETH transferred without address checks (3 places)\n[high] reentrancy-state-change at src/MarginaliaHook.sol:221: Reentrancy: State change after external call (16 places)\n[high] storage-array-memory-edit at src/MarginaliaHook.sol:527: Storage Array Edited with Memory\n[high] unsafe-casting at src/MarginaliaHook.sol:885: Unsafe Casting of integers\n[low] costly-loop at src/MarginaliaHook.sol:813: Costly operations inside loop (2 places)\n[low] internal-function-used-once at src/HookFlags.sol:26: Internal Function Used Only Once (2 places)\n[low] large-numeric-literal at src/Marginalia.sol:10: Large Numeric Literal (17 places)\n[low] literal-instead-of-constant at src/MarginaliaHook.sol:352: Literal Instead of Constant (51 places)\n[low] local-variable-shadowing at src/MarginaliaHook.sol:808: Local Variable Shadows State Variable\n[low] require-revert-in-loop at src/MarginaliaHook.sol:813: Loop Contains `require`/`revert`\n[low] state-change-without-event at src/MarginaliaHook.sol:785: State Change Without Event (6 places)\n[low] state-no-address-check at src/MarginaliaRouter.sol:135: Address State Variable Set Without Checks\n[low] unchecked-return at src/MarginaliaHook.sol:669: Unchecked Return (6 places)\n[low] uninitialized-local-variable at src/MarginaliaJudge.sol:168: Uninitialized Local Variable (2 places)\n[low] unused-import at src/MarginaliaHook.sol:10: Unused Import\n[low] unused-public-function at src/MarginaliaHook.sol:291: Public Function Not Used Internally","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"f3c85d37898ef0c69cdba6c9a1b260b1c581d99f0185bf9eeed5b08a96004eef","verifiedTreeHash":"99a27c9909c8e187114a77dabae62d95e42ce95d","verifierVersion":"0.1.0+0e08a464"}]}