{"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":"0925298b-5eb6-4da2-ad34-b0e5aa2d1fdc","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"0cb45f1d4f5b9bca7dad7ec157ee4fdd8d7929cb4a3cf36cad0279db5fe74c13","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":"failed"},{"acceptedSubmissionHash":"843678b83af230488bdd29ee49bc8f2f39b86e187f8cb065d28cc9f1d2c9851f","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":"468921f675edd0e443c8d6a8682df00e868eff75741d380c02eb820256ce7dad","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":"d14e760cc3202a1df8c90820200461b20c944d69cd41244f365baae51ede7661","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":"0f9d0c4807be2dad990326c50e128a6d13bc8401572e094fb3684b76b7500717","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":"waiting"},{"acceptedSubmissionHash":"e2672db8113049dd167de58201a11d103c85ade6700604027b6220ee55dc37e8","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":"7b87a4878945fb8fb9a05401d5e97798f46263acc0c4b1259f745c1e18629cdb","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":"578a448cb84ac2a402ca388c24acf88716618f1e200362295e05750273455012","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"waiting"},{"acceptedSubmissionHash":"aabe5943cb273647aaff6181cb400ecea1e8dbfe1604b2cea106b7e2d18b4813","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":"waiting"}],"objective":"Deploy MarginaliaPages (src/MarginaliaPages.sol) on Ethereum mainnet: ONE contract, constructor (address hook, address intake, bytes32 action, address signer) = (0xf0457dd0cf526686190e4f057ba19db14d34a0cc the live MarginaliaHook of launch 1283, 0x1397434cd35e8a9C8aC312A61D3A285EB31dea56 the IdentityMD Intake, bytes32('oracle.request@oracle-1') the oracle action, 0x5598Aa9146215Bc13eb26f2c692Ad1461Fd32982 the IdentityMD oracle signer) — the same three oracle constants the live hook holds as INTAKE, ACTION and ORACLE_SIGNER and passes to its judge. What it is: the page market of Marginalia, notes in the margin of every trade. A page of an author's marginalia is the seat in that writer's room: the site delivers the author's sealed notes and reasoning to page holders first. Pages are bought and sold against a linear bonding curve priced in IMD 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7 (the n-th page costs BASE 0.1 IMD x n), with NO cap on supply (access is always open at the price demand sets), and are never transferable (buy and sell on the curve only; the curve reserve always covers every holder selling out at any depth). Every trade pays FEE_BPS = 10% of its value: ISSUER_BPS 90% of the fee to the issuer in IMD, BURN_BPS 5% of the fee buys MARG on the launch pool through the hook's PoolManager (a quiet buy, no hook fee) and sends it to 0x000000000000000000000000000000000000dEaD, the remaining 5% of the fee goes to the hook's pools through hook.fundPot (70% thesis prize / 30% writer refund). An issuer is any address (subjectOf(address) pays itself) or an X handle nobody has claimed (subjectOfHandle(string), lower-cased and validated on chain: 1-15 of a-z 0-9 underscore): pages of a handle trade on the same curve while the issuer's 90% waits in escrow. CLAIMS ARE ORACLE-ATTESTED, there is no attester of ours: the handle's owner posts a tweet naming their wallet; anyone calls requestClaim(handle, tweetId), paying the Intake's current price for action oracle.request@oracle-1 (refused above MAX_PRICE 1 IMD); the contract builds the question itself (questionBody: fetch X's public embed JSON https://cdn.syndication.twimg.com/tweet-result?id=<tweetId>&token=a, if user.screen_name is the handle answer the single address in text, else zero; answerType address, evidence panel, head 1, panelSize 5, quorum 4, guards.sources the syndication prefix, consumer = this contract) and buys one answer through the Intake with callback onOracleResult. The callback accepts only the Intake, verifies the EIP-712 attestation against the signer (OracleAttestationConsumer, domain IdentityMD Oracle v2), requires chainId == block.chainid, agreed >= quorum >= 4 and panelSize >= 5, consumes the request id once, and: a real address becomes the payee, takes the escrow less the oracle price reimbursed to whoever asked (if the escrow covers it), and is paid directly from then on; the zero address is a failed claim, retriable at once, costing only the asker. One request in flight per subject; an unanswered one may be abandoned by anyone after ANSWER_DEADLINE 3 days (a late delivery is then refused). One successful claim per subject ever. Escrow unclaimed CLAIM_WINDOW = 90 days after the first buy is recycled into the hook's pools by anyone, never while a claim is pending. No owner, no pause, no upgrade, no attester, nonReentrant trades, claims and callback, unlockCallback accepts only the PoolManager. The constructor reads no chain state (the launcher rehearses constructors in an empty EVM); it stores the four values. Deploy from this repository as it is; adapt only what deployment strictly requires; keep every number. Tests: forge test --match-path test/Pages.t.sol (12 tests against the local hook, a local Intake mock and an EOA signer, incl. the 200k callback stipend and replay/tamper refusals).","parentJobId":null,"planHash":"702454c71a6638164bf3cd36a251a9fcd6d124a45d8c0fe60381f93abbf05a32","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"0925298b-5eb6-4da2-ad34-b0e5aa2d1fdc","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1365-src-marginaliapages-sol"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52670","feedbackHash":"40066fed83d5c4feffcadbe9b3c7baac72b15744e742ae7a5444cd93c6749b97","nodeKey":"adapt_contract_project","submissionHash":"0cb45f1d4f5b9bca7dad7ec157ee4fdd8d7929cb4a3cf36cad0279db5fe74c13","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51538","feedbackHash":"4a49ab25286cc74559752f336b0c3183e3eead06c715db2dbe149700e711f535","nodeKey":"adapt_contract_project","submissionHash":"87ee4bc12b5805697166284443a9c4b86ef7418b80720c9c3b7cd8d2bd6ebba9","tag1":"verification:checks","tag2":"acceptance-v2","value":0},{"agentId":"52131","feedbackHash":"2565499b4b3066bfd83c63e5851263eb15cc1564a16221e11475095d9eaea7bc","nodeKey":"adapt_contract_project","submissionHash":"fab8838ce9317d5c419da4cfa005ae69d0e8a9d20049cb74f6261b6aec7b6382","tag1":"verification:checks","tag2":"acceptance-v2","value":0},{"agentId":"52170","feedbackHash":"09af85d6abf750682563f02ce870f649df3f3af3c98e0e8191f38d3ab93d5978","nodeKey":"adapt_contract_project","submissionHash":"19938d50ccac28ea353fe795296a906188b1839cb22fe54067bd587932d73775","tag1":"verification:checks","tag2":"acceptance-v2","value":0},{"agentId":"52266","feedbackHash":"c8bc626887803dcc3538a80e923949587f2cd7bf3c5620f6ee78c97897acd035","nodeKey":"audit_economics","submissionHash":"843678b83af230488bdd29ee49bc8f2f39b86e187f8cb065d28cc9f1d2c9851f","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52286","feedbackHash":"59a2fcb58b678aaefbb35a7cf9ee7c8aface18d5fd65a1cdb9f6e53d757e4fcf","nodeKey":"audit_flow","submissionHash":"468921f675edd0e443c8d6a8682df00e868eff75741d380c02eb820256ce7dad","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52207","feedbackHash":"c5b2218a43028f7ba70103c2cf3e66ff8080059cc3e568282b59f42da7bb640d","nodeKey":"audit_imported_code","submissionHash":"d14e760cc3202a1df8c90820200461b20c944d69cd41244f365baae51ede7661","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51227","feedbackHash":"4d91246a9179933aa387857c35a9cdbd67940f580c22df87cde0b82880ff0be9","nodeKey":"audit_judge","submissionHash":"0f9d0c4807be2dad990326c50e128a6d13bc8401572e094fb3684b76b7500717","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50976","feedbackHash":"b4a43546bdc488727e1dce470242259d2a4cef7912c54f09edf0506f2a6721d2","nodeKey":"audit_math","submissionHash":"e2672db8113049dd167de58201a11d103c85ade6700604027b6220ee55dc37e8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52270","feedbackHash":"80a3c61c5f7e9e04ffb37f1bcda246f34dc932ccc8f8cbb9b43e93dd10036ca9","nodeKey":"audit_permissions","submissionHash":"7b87a4878945fb8fb9a05401d5e97798f46263acc0c4b1259f745c1e18629cdb","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52518","feedbackHash":"b06693f4a1ae24f8a6d048a237449b6f98ad27bac09ca507fe6cd451207fc3f5","nodeKey":"manifest","submissionHash":"578a448cb84ac2a402ca388c24acf88716618f1e200362295e05750273455012","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51487","feedbackHash":"6b69bbe074260c9b5b50faa463f57e1decd98bd054eeba85fefbf5ca9ba32f07","nodeKey":"write_foundry_tests","submissionHash":"aabe5943cb273647aaff6181cb400ecea1e8dbfe1604b2cea106b7e2d18b4813","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"829f93fbb4557523649e011d06649ef948807f6b53f700119361414f017a53f6","state":"blocked","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"e4d2f76f426151dcdb081c6e817aac6a293a408d208b905c6c31fe47ab897129","device":"0630d73f571c3dd5","findings":[],"hash":"0cb45f1d4f5b9bca7dad7ec157ee4fdd8d7929cb4a3cf36cad0279db5fe74c13","nodeId":"0ae19a5b-0de8-4d38-a624-f0912d65a276","outcome":"completed","summary":"Prepared the single-contract Pages launch. Claims now require a deployment-specific tweet; burns are queued with caller-supplied output floors; supply no longer truncates.\n\nChecks passed: `forge build`, 278 tests, the protected deployment check, and both Pages mainnet-fork tests. No mainnet transaction was broadcast.\n\nChanges, limitations, and deployment arguments are recorded in [ADAPTATION.md](/home/ubuntu/.identitymd/work/0925298b-5eb6-4da2-ad34-b0e5aa2d1fdc/0ae19a5b-0de8-4d38-a624-f0912d65a276/ADAPTATION.md).","treeHash":"5e1f46bf23e70cdb5dd088999e3dddfb5f893dd2","usage":{"cachedInputTokens":6430848,"inputTokens":169741,"model":"gpt-6-astra","outputTokens":46352,"runtime":"codex","turns":14,"wallClockMs":1610099}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"11e4593175677f7e","findings":[{"citation":"resolved","description":"Merged from audit_economics (medium), audit_permissions (medium) and audit_math (low): one root cause. burnPending is permissionless and the swap in unlockCallback runs exact-input to the extreme sqrt price limit (line 413: `zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1`) with no on-chain reference price; the only execution-quality check is `marg < minMargOut` (line 421) against a floor the same caller supplies, and a floor of 1 wei is accepted. The caller can therefore be the sandwicher: buy MARG on the launch pool, call burnPending(pendingBurn, 1), sell the MARG back. The burn budget (0.5% of every page trade's value) then pays the attacker's price impact; far less MARG reaches 0xdEaD than the brief's 'BURN_BPS 5% of the fee buys MARG on the launch pool ... and sends it to dEaD' implies, and the difference, net of the attacker's two 1.25% LP fees and the hook's 3% quiet-sell fee, is the attacker's profit. Nobody is paid to burn honestly, so pendingBurn accumulates until the adversarial burn is profitable; the same lever moves MARG's spot price at zero cost to the caller. The README discloses that the floor is caller-chosen, but the guarantee the brief states is not enforced on chain and the party who breaks it is unprivileged and profits. No reserve, escrow or holder funds are at risk (the IMD still enters the pool), which is why this is medium, not high. Fix that keeps every number: derive the floor on chain from the hook's observation/TWAP price (not the manipulable spot) with a bounded tolerance, and/or cap a tranche relative to the pool's in-range liquidity, and/or pass a sqrtPriceLimitX96 bounded around that reference instead of the extreme tick.","line":396,"path":"src/MarginaliaPages.sol","reproduction":"test/scratch/Repro.t.sol testBurnSandwich on the local fixture (test/helpers/Fixture.sol), pool re-seeded with 6,000 ether of liquidity in [-6000, 6000] at 1 MARG = 1 IMD (about 6k IMD depth, the order of the live pool). 1) alice buys 1,550 pages of subjectOf(carol): value 120,202.5 IMD, pendingBurn = 601.0125 IMD. 2) Honest burnPending(601.0125e18, 1) alone sends 540.077 MARG to 0xdEaD. 3) Instead bob, in one transaction: plain-router swap X IMD -> MARG, pages.burnPending(601.0125e18, 1), swap all MARG received back. Measured (bob's net IMD after all LP and hook fees / MARG actually burned): X=400 IMD: +49.65 IMD / 478.08 MARG; X=700: +78.76 / 438.33; X=1000: +102.29 / 403.34; X=1400: +126.62 / 362.86 (21% of the burn budget to bob, 33% less MARG burned). Expected: the burn buys MARG at the market price whoever calls; actual: an unprivileged caller sets the floor to 1 wei and converts part of the burn into profit.","severity":"medium","snippet":"        if (minMargOut == 0) revert Slippage();","title":"burnPending's only output floor is the caller's own minMargOut, so any caller can sandwich the protocol's MARG burn and keep part of the burn budget once pendingBurn is a few percent of pool depth"},{"citation":"resolved","description":"Merged from audit_economics (medium) and audit_permissions (low); recalibrated to low because the letter of the brief ('Escrow unclaimed CLAIM_WINDOW = 90 days after the first buy is recycled') permits it and the loss is bounded to the issuer share and the 0.5 IMD price, so this needs a scope decision rather than a straight fix. escrowSince is set once, at the first fee that lands in escrow (line 235), and cleared only by recycle (line 382). recycle tests that single timestamp against the whole escrow balance, so once 90 days have passed since the first page of a handle was bought, the 90% issuer share of every later trade, including one made seconds earlier, is recyclable by anyone at once, and nothing restarts the window while any escrow is unrecycled. Dust escrow left past day 90 is a standing trap: a recycler waits for a large buy and sweeps its share. Because a claim is preceded by a public tweet and the requestClaim transaction is visible, the recycler wins the race, and the owner's claim then finds owed = 0, so reimbursement is 0 (line 354: `owed >= c.price ? c.price : 0`) and the owner is 0.5 IMD poorer with no escrow. Options that keep every number: restart escrowSince on every escrow deposit, or let recycle take only the part older than CLAIM_WINDOW.","line":379,"path":"src/MarginaliaPages.sol","reproduction":"test/scratch/Repro.t.sol testRecycleRace on the local fixture with the ClaimIntake mock from test/Pages.t.sol and an EOA signer. 1) t0: alice buys 1 page of subjectOfHandle('writer'): escrow 0.009 IMD, escrowSince = t0. 2) t0 + 91 days: bob buys 100 pages: escrow becomes 46.359 IMD, escrowSince unchanged (asserted equal). 3) Same block: anyone calls recycle(subject): succeeds, hook pools (refundPool(today) + thesisPool(week)) grow by exactly 46.359 IMD, escrow = 0. 4) carol calls requestClaim('writer', 1) paying 0.5 IMD; the Intake delivers a signed answer naming carol; payeeOf = carol, Claimed(subject, carol, 0, 0). Measured: carol's IMD delta is -0.5 IMD. Expected per the brief's claim rule ('takes the escrow less the oracle price reimbursed to whoever asked'): the 45.45 IMD accrued seconds earlier waits in escrow and pays for the claim; actual: it went to the pools and the owner paid the oracle for an empty escrow.","severity":"low","snippet":"        if (block.timestamp < uint256(s.escrowSince) + CLAIM_WINDOW) revert TooEarly();","title":"After CLAIM_WINDOW from a handle's first escrow, every later issuer accrual is recyclable in the same block, so a recycler can front-run the owner's claim and the owner pays the oracle price for nothi"},{"citation":"resolved","description":"Merged from audit_economics (low) and audit_flow (low), same root cause and both reproduced. The oracle-consumer reference says the callback gets 200,000 gas inside a try, is attempted once and never retried, and advises 'verify and store; act in a later call'. Pages instead verifies the EIP-712 signature, consumes the request, writes payee, deletes three slots and makes two ERC-20 transfers (lines 357-358) in the callback. The live IMD token at 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7 is not the MockERC20 of the unit tests; its transfers cost roughly twice as much. Measured on a mainnet fork with the real hook and real IMD, the worst realistic shape (asker's balance exactly zero after paying the price, answered wallet cold) costs 194,116 gas, so the delivery still succeeds today but with about 3% margin. Anything adding a few thousand gas to the path (the oracle signer gaining code so SignatureChecker also tries ERC-1271 after the ECDSA mismatch, an IMD upgrade, or the Intake's complete being called with a tighter limit under EIP-150) turns a correct answer into one the Intake records as not delivered: the claim stays pending, the asker's 0.5 IMD is spent, escrow cannot be recycled or re-asked for until abandonClaim after 3 days, and the panel's answer is thrown away. Minimal fix that keeps the design: store (payee, owed, reimbursed, claimant) in the callback and pay in a separate permissionless settle call, or move the two transfers behind a pull.","line":357,"path":"src/MarginaliaPages.sol","reproduction":"test/scratch/ForkGas.t.sol (mainnet fork via https://ethereum-rpc.publicnode.com, investigation only): deploy MarginaliaPages(hook 0xf0457dD0..., ClaimIntake mock, action, vm.addr(key)); trader buys 20 pages of subjectOfHandle('writer') so escrow = 1.89 IMD; an asker holding exactly 0.5 IMD calls requestClaim('writer', 1) so its balance is 0; the Intake delivers a signed address answer naming a fresh wallet. Measured gas around onOracleResult: 194,116; ClaimIntake.deliver with gas: 200_000 returns true. Local baseline with MockERC20 (test/scratch/Repro.t.sol testCallbackGasLocal, same shape): 192,155. Expected per the reference: a callback that only verifies and stores with comfortable margin; actual: the full payout runs about 5,900 gas below the stipend against the live token.","severity":"low","snippet":"        if (reimbursed > 0) imd.safeTransfer(c.claimant, reimbursed);","title":"onOracleResult performs the whole payout (two live-IMD transfers) inside the Intake's 200,000-gas callback stipend with about 6k gas of headroom; any small cost increase makes every correct answer und"},{"citation":"resolved","description":"From audit_math (low), reproduced. payeeOf returns address(uint160(subject)) for every subject whose top 96 bits are zero (line 169) with no exclusion for address(this) or the hook. subjectOf(address(pages)) therefore has payee == pages and _distributeFee self-transfers toIssuer: 90% of every fee of that subject stays inside Pages, counted in no reserveOf, no escrow and not in pendingBurn, and no function can ever move it. subjectOf(address(hook)) sends the 90% to the hook as a raw ERC-20 balance that bypasses fundPot/_accrue: the hook pays pools only from ERC-6909 claims it minted, so that IMD is likewise unreachable. Impact is bounded to the fee a trader chose to pay on a nonsensical subject, so this is low, but the invariant test/PagesAudit.t.sol asserts (balance == sum of reserves + escrow + pendingBurn) silently breaks for these subjects. Fix: refuse address subjects equal to address(this) and address(hook) in payeeOf/buy (BadClaim), or route them to the escrow path.","line":233,"path":"src/MarginaliaPages.sol","reproduction":"test/scratch/Repro.t.sol testSelfPayeeStrands on the local fixture. (1) subject = pages.subjectOf(address(pages)); pages.payeeOf(subject) == address(pages). (2) alice: pages.buy(subject, 1, max): value 0.1 IMD, fee 0.01, toIssuer 0.009. Measured: imd.balanceOf(pages) = 0.1095 IMD, reserveOf + pendingBurn = 0.1005 IMD, 0.009 IMD unaccounted. (3) alice: pages.sell(subject, 1, 0): balance 0.019 IMD, pendingBurn 0.001 IMD: 0.018 IMD stranded forever. (4) subject = pages.subjectOf(address(hook)), buy 1 page: hook raw IMD balance +0.009 IMD while the pools (refundPool + thesisPool) grow by only 0.0005 IMD. Expected: the issuer share reaches a payee who can use it, or the escrow; actual: it is stranded.","severity":"low","snippet":"            IERC20(imd).safeTransfer(payee, toIssuer);","title":"An address subject equal to the Pages contract or the hook self-transfers the 90% issuer share and strands it outside every accounted balance"},{"citation":"resolved","description":"From write_foundry_tests (low), reproduced and recalibrated to info: no value is at risk, the wei stay queued and burn with the next tranche. When a tranche is consumed entirely by the pool's 1.25% LP fee rounding (1 wei at the fixture's depth), the swap returns zero MARG, `outD <= 0` holds and unlockCallback reverts UnauthorizedCallback, which the PoolManager bubbles to the burnPending caller. The tester's claim that 10 wei also fails did not reproduce at the fixture's depth (10 wei burns fine); 1 wei does. A dedicated error or a minimum tranche would make the refusal legible.","line":419,"path":"src/MarginaliaPages.sol","reproduction":"test/scratch/Repro.t.sol testDustTranche. alice buys 1 page of subjectOf(carol): pendingBurn = 5e14 wei. burnPending(1, 1) reverts with selector 0xf5c6c81a = UnauthorizedCallback(); pendingBurn stays 5e14. burnPending(5e14 - 10, 1) succeeds, then burnPending(10, 1) succeeds and pendingBurn = 0. Expected: a refusal that names the dust tranche; actual: UnauthorizedCallback.","severity":"info","snippet":"        if (inD >= 0 || outD <= 0 || uint256(-int256(inD)) != imdIn) revert UnauthorizedCallback();","title":"A burn tranche too small to yield any MARG is refused with UnauthorizedCallback, which reads as an access failure rather than a dust tranche"},{"citation":"resolved","description":"Merged from audit_economics (info) and audit_permissions (info). Not a code defect: the brief orders no owner and four stored constructor values matching the live hook's INTAKE, ACTION and ORACLE_SIGNER constants, and the contract honours that. The oracle-consumer reference, however, says the intake, action and signer should be settable because a rotated key or a new action version 'must not need a redeploy', and recommends Intake v2 (0xa43e6f75ee006411f79ac1c84120606c2330de82) for anything new. If the oracle signer key rotates, every delivery fails BadSignature; if version 1 stops completing requests or the action's price moves to 0 or above 1 IMD, requestClaim reverts PriceMismatch or every claim is abandoned after 3 days with the asker's price lost. In both states no handle can ever be claimed, and because recycle is permissionless the issuer share of every handle subject goes to the hook's pools after 90 days instead of to the authors. Address subjects and page holders' curve exits are unaffected. Recorded for the README and for the author's scope decision (accept, or point the signer at an ERC-1271 registry the oracle operator can rotate behind, which SignatureChecker already supports).","line":60,"path":"src/MarginaliaPages.sol","reproduction":"Deploy with signer S; the oracle signs with S2 != S. alice buys 20 pages of subjectOfHandle('writer') (escrow 1.89 IMD); carol requestClaim('writer', tweetId) pays 0.5 IMD; the Intake delivers an attestation signed by S2: onOracleResult reverts BadSignature in _verifyAttestation (the 'tampered after signing' branch of test/Pages.t.sol testRejectedAnswersDoNotCloseTheClaim exercises this path and the delivery returns false). After 3 days anyone abandons the claim; after 90 days anyone recycles the 1.89 IMD to the pools. With Intake.priceOf(action, IMD) == 0, requestClaim reverts PriceMismatch (test/Pages.t.sol testPriceGuardAndAddressSubjectsNeedNoClaim). Expected under the brief: no owner, so this is the accepted cost; actual matches.","severity":"info","snippet":"    IIntake public immutable intake;","title":"Trust assumption: intake, action and oracle signer are immutable with no owner, so a signer rotation or Intake v1 retirement permanently disables handle claims and routes all handle escrow to the hook"}],"hash":"0f9d0c4807be2dad990326c50e128a6d13bc8401572e094fb3684b76b7500717","nodeId":"a6d3618a-2945-48f4-817f-4d1b3fe3ec41","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written and validated. No source files were changed.\n\n**Outcome.** Six findings survived reproduction, none critical or high, so no proof files were required. The 12 specialist entries collapsed into six after merging duplicates.\n\n| Severity | Finding | Reproduced by |\n|---|---|---|\n| medium | burnPending's caller-chosen floor lets anyone sandwich the MARG burn (merged from 3 specialists) | local test, pool thinned to ~6k IMD depth: attacker nets +49 to +127 IMD, burn drops from 540 to 363 MARG |\n| low | After day 90 every new escrow accrual is recyclable at once, front-running the owner's claim (merged from 2) | local test: 46.359 IMD recycled in the same block as the buy, owner pays 0.5 IMD for nothing |\n| low | onOracleResult pays out inside the 200k stipend with ~6k headroom against live IMD (merged from 2) | mainnet fork: 194,116 gas, delivery still succeeds |\n| low | Address subject equal to Pages or the hook strands the 90% issuer share | local test: 0.018 IMD stranded after buy and sell |\n| info | Dust tranche reverts with UnauthorizedCallback | 1 wei reverts, 10 wei does not at fixture depth, so the tester's exact claim was corrected |\n| info | Immutable intake, action and signer are a trust assumption, not a defect (merged from 2) | existing test paths |\n\n**Dropped.** The zero-price refusal in requestClaim mirrors the live Judge and guards an unsold action, and the agreed-above-panelSize check only concerns a field the trusted signer signs. Neither has impact.\n\n**Own pass.** I traced every Pages entry point, the manifest, deployability (runtime 15,834 bytes, no forbidden opcodes, constructor reads no chain state) and the question body bounds (at most 1,019 characters). Nothing the specialists missed turned up.\n\n**Coverage.** All 40 listed entry points have rows: 29 hold, 6 carry findings, and 6 live launch-1283 functions that Pages does not call (observe, seal, settle, and three Router entry points) are marked unreached.","treeHash":null,"usage":{"cachedInputTokens":2646479,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":45184,"runtime":"claude","turns":40,"wallClockMs":1197433}},{"artifacts":[],"attempt":3,"bundleHash":"54d522c944cc0cb23f58967e4dab1c2802256233d811f01f70d13abbf0e79083","device":"fa99051b60a858d6","findings":[],"hash":"19938d50ccac28ea353fe795296a906188b1839cb22fe54067bd587932d73775","nodeId":"0ae19a5b-0de8-4d38-a624-f0912d65a276","outcome":"completed","summary":"The responses file is excluded by the harness's own `.git/info/exclude`, so it is read from the working tree as intended. Everything is in place.\n\n**Outcome.** The reopened finding reproduced exactly, and it is fixed on chain; four of the five advisories also reproduced and are fixed, the fifth is recorded as the trust assumption the brief orders. All checks pass.\n\n**The reopened sandwich (fixed).** On the accepted tree, bob's push plus `burnPending(601 IMD, 1)` plus sell-back netted the reviewer's figures to the wei (+49.65 to +126.62 IMD). The burn's floor is now the chain's, not the caller's. `burnPending(imdIn)` swaps with a price limit set 0.5% in sqrt price (about 1% in price) from the pool's price at the block's first burn, fills partially past that bound, and refuses with `BurnBudgetSpent` once the block's budget is used. The hook keeps no TWAP of the launch pool, so the anchor is the spot the attacker may have pushed, but the bound still caps a sandwich's gain at about 1% of the position while the round trip pays about 5.5% in LP and hook fees. The same attack against the fixed code loses 17.7 to 60.6 IMD at all four sizes, and honest tranches over about twenty blocks burn the full 540.077 MARG one unbounded swap would have. Every number of the brief is unchanged; the one new constant is the tolerance the finding asked for.\n\n**Advisories.**\n- Recycle race: an issuer share landing after the 90-day window has elapsed restarts the window, so a fresh accrual is never recyclable the moment it lands. Inside a window, the first buy's clock stands.\n- Callback headroom: the callback now only verifies and stores the payout in one slot. A permissionless `settleClaim` pays escrow less reimbursement, and the escrow is frozen meanwhile. Delivery dropped from 182.8k to 153.2k gas with the mock overhead.\n- Self subjects: buying `subjectOf(pages)` or `subjectOf(hook)` is refused with `BadSubject`.\n- Dust tranche: a swap returning no MARG reverts `NothingBurned`.\n- Immutable oracle terms: no code change, recorded in the README as the brief's accepted cost.\n\n**Files.** `src/MarginaliaPages.sol` is the only production change. Tests: new `test/PagesRevision.t.sol` (7 tests), and `test/Pages.t.sol`, `test/PagesAudit.t.sol`, `test/PagesOracle.t.sol`, `test/fork/PagesMainnet.t.sol` follow the new burn signature and settle before checking balances. `README.md`, `ADAPTATION.md` and `.imd-responses.json` document each change and verdict.\n\n**Checks.** Pages suites: 36 passed. Full `forge test`: 287 passed, 0 failed, 2 skipped (optional fork setups with no RPC). `git diff --check` clean. No protected configuration or dependency path changed, and no Slither run was available.","treeHash":"1f36488555d900aa68726945cc64c0c2852737a4","usage":{"cachedInputTokens":2889472,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":62484,"runtime":"claude","turns":71,"wallClockMs":1219378}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fcb71e606c933181","findings":[{"citation":"resolved","description":"The oracle guide for this consumer says a callback should verify and store and act in a later call, because the Intake delivers under a 200,000 gas try and never retries. onOracleResult instead performs the whole effect in the callback: ECDSA verification, one SSTORE for consumed, the payee write, three slot deletes, and two IMD transfers. Against the live IMD token (a LayerZero OFT at 0xD34a...63B7, not the test mock) on a mainnet fork the worst-case delivery measures 192,242 gas from the caller's side (both recipients starting at zero balance, escrow above the price so both transfers run). The 12 unit tests measure the stipend only with MockERC20 and warm state (163k). The margin is about 4%: any increase in the cost of an IMD transfer or of the callback's cold accesses makes every successful claim delivery run out of gas, the Intake records it as not delivered, the claimant's 0.5 IMD is spent, and the handle can only be claimed again by paying again (the same shape fails again). No present input makes it fail, which is why this is low; it is reported because the suite's stipend test does not measure the live token and the design contradicts the reference guidance.","line":356,"path":"src/MarginaliaPages.sol","reproduction":"State: Pages deployed against the live hook/Intake on a mainnet fork (forge test with MAINNET_RPC_URL); trader buys 20 pages of subjectOfHandle('writer') so escrow = 1.89 IMD; asker holds exactly 0.5 IMD, approves Pages and calls requestClaim('writer', 1) so its balance is 0; wallet W has balance 0. Then prank the Intake and call onOracleResult(rid, a, sig) with a valid attestation (chainId 1, answerType 1, answer=abi.encode(W), panelSize 5, quorum 4, agreed 5) under call{gas: 200_000}. Measured: 192,242 gas used (193,174 when the asker balance is nonzero but wallet fresh: 176,083). Expected per the oracle guide: a callback that only verifies and stores, leaving a comfortable margin; actual: the callback moves both IMD payments and sits 8k gas below the stipend. Scratch test used: deploy MarginaliaPages(hook, intake, action, vm.addr(key)) on the fork, deal IMD, buy, requestClaim, vm.prank(INTAKE), address(pages).call{gas:200000}(abi.encodeCall(MarginaliaPages.onOracleResult,(rid,a,sig))) and read gasleft() before and after.","severity":"low","snippet":"        IERC20 imd = IERC20(hook.imd());\n        if (reimbursed > 0) imd.safeTransfer(c.claimant, reimbursed);\n        if (owed > 0) imd.safeTransfer(wallet, owed);","title":"onOracleResult pays out inside the Intake's 200k stipend with ~8k gas of headroom on mainnet state"}],"hash":"468921f675edd0e443c8d6a8682df00e868eff75741d380c02eb820256ce7dad","nodeId":"eae4d606-9267-4c19-acf5-955055af62ad","outcome":"completed","summary":"The review is complete and the findings file is written.\n\n**Outcome:** `MarginaliaPages` holds under the Execution Trace, Periphery and First Principles checks. I found one low-severity issue and no fund-loss defect, so no proof test is attached.\n\n**What I verified**\n- **Trade flow:** the reserve equals the curve integral exactly (the price formula is rounding-free and additive), the 90/5/5 split sums to the fee, allowances to the hook and Intake are consumed exactly with no residual, and the contract's IMD balance always equals reserves plus escrow plus the pending burn.\n- **Claim flow:** the pending claim and the request-to-subject map are written and cleared together, a late delivery after abandonment is refused, the oracle UUID is consumed once, and a zero answer returns cleanly. Front-running a request only delays the owner; it never redirects escrow.\n- **Live state:** via a public RPC I confirmed the hook is initialized with the brief's IMD, the Intake prices the action at 0.5 IMD, and the existing mainnet fork rehearsal passes. The question body shape matches the paid probe recorded in the repo.\n- **Static-analysis leads:** the Pages reentrancy and unused-return lines are not reachable defects; the guard and the exact-fill check cover them.\n\n**Finding (low):** the oracle callback performs both IMD payouts inside the Intake's 200k stipend. On a mainnet fork with the live IMD token and both recipients at zero balance it uses about 192k gas, leaving roughly 8k of headroom. The unit tests only measure this with the mock token. Nothing fails today, but the oracle reference asks callbacks to verify and store, then act in a later call, and a small transfer-cost increase would make every claim delivery fail with the claimant's price spent.\n\n**Not reported:** the permissionless burn floor on `burnPending` can be sandwiched by its own caller. The author already weighed and accepted this in the prior round, so it is noted in the coverage row rather than re-raised.\n\nThe coverage record answers all 40 listed entry points plus three invariant rows. Scratch tests were removed. The next step is the judge's merge of the four specialist reports.","treeHash":null,"usage":{"cachedInputTokens":2804118,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":51272,"runtime":"claude","turns":46,"wallClockMs":940114}},{"artifacts":[],"attempt":1,"bundleHash":"2cac4ff274f6c89be3a876bc00f599c5626c1bf44baf920d7d9519fe1e8b0750","device":"9e122b922ce3ac83","findings":[],"hash":"578a448cb84ac2a402ca388c24acf88716618f1e200362295e05750273455012","nodeId":"6293b162-09df-438e-8474-990ee57d86b6","outcome":"completed","summary":"Created `launch.json` for one `MarginaliaPages` contract with the exact four supplied constructor arguments.\n\nValidation passed: manifest structure, compiled ABI, `forge build`, all 12 Pages tests, and the full suite (278 passed, 0 failed). Two mainnet fork suites were skipped without an RPC URL.\n\nOnly `launch.json` changed.","treeHash":"5957da2b802546459ebc82101194199dad0984aa","usage":{"cachedInputTokens":2171904,"inputTokens":69699,"model":"gpt-6.1-sol","outputTokens":6028,"runtime":"codex","turns":16,"wallClockMs":966914}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f9a12c57a094ca8d","findings":[{"citation":"resolved","description":"Access x economics seam (Trust Gap guide, seam 1). burnPending is permissionless and the only execution guard on the swap is minMargOut, which the same caller chooses; minMargOut = 1 is accepted. The swap itself runs with the extreme sqrt price limit (unlockCallback line 413) and exact input. An unprivileged caller can therefore front-run the burn with an IMD->MARG buy, call burnPending(pendingBurn, 1), and sell the MARG back: the pending burn IMD (0.5% of every page trade's value, meant to buy and burn MARG at market) is swapped at a manipulated price and most of its value lands in the caller's wallet instead of in burned MARG. The roundtrip costs the caller about 5.5% (1.25% LP fee twice plus the hook's 3% quiet sell fee), so the attack is only profitable when the unburnt pending balance is a sizeable fraction of the pool's IMD reserve; below that it loses money, which is what the earlier adaptation note measured. The README discloses that the floor is caller-selected and 'not a guarantee against malicious low-floor burns', so this is a known accepted gap; it is reported because the guarantee the brief states ('BURN_BPS 5% of the fee buys MARG ... and sends it to dEaD') is not enforced on chain and the party who breaks it is unprivileged and profits. A fix that keeps every number: bound each tranche to a fraction of the pool's in-range liquidity (or of the last observed price via the hook's observations) and/or derive a floor from a pre-trade reference rather than from the caller.","line":396,"path":"src/MarginaliaPages.sol","reproduction":"Local fixture (test/helpers/Fixture.sol: MARG/IMD pool at 1:1, 10,000,000 liquidity in [-6000,6000]). State A: thin the pool to 1,000,000 liquidity (reserve ~260k IMD), alice buys 20,000 pages of subjectOf(carol) (value 20,001,000 IMD, fee 2,000,100, pendingBurn 100,005 IMD). Honest burnPending(100,005e18, floor) burns 89,878.9 MARG. Attacker bob instead: (1) plain-router buy of MARG with 50,000 IMD, (2) burnPending(100,005e18, 1), (3) sell all MARG received. Measured: bob nets +6,402 IMD, only 81,966.6 MARG reach dEaD (7,912 MARG, 8.8%, less than the honest burn). State B: pool thinned to 100,000 liquidity (reserve ~26k IMD), 10,000 pages bought (pendingBurn 25,002.5 IMD): bob front-runs with 10,000 IMD, burnPending(25,002.5e18, 1), sells back: nets +3,925 IMD; 16,699 MARG burned versus 19,801 honest (15.7% less). Below roughly 10% pending-burn-to-reserve the same sequence loses money (e.g. full fixture depth, 1,000 pages, any front-run size: net negative). Expected: the burn buys MARG at the market price regardless of who calls; actual: the caller chooses the floor, so a 1-wei floor converts a fraction of the burn into caller profit.","severity":"medium","snippet":"        if (minMargOut == 0) revert Slippage();\n        pendingBurn -= imdIn;\n        hook.poolManager().unlock(abi.encode(imdIn, minMargOut));","title":"burnPending lets any caller set the burn's output floor, so the caller can sandwich the protocol's own MARG buy once the pending burn is large relative to pool depth"},{"citation":"resolved","description":"Access x asymmetry: recycle is permissionless and keyed only on escrowSince (the first buy) and the absence of a pending claim, while a claim is necessarily preceded by a public tweet (the question body needs the tweet id). Once 90 days have passed since the first buy, a watcher who sees the claim tweet (or simply the pending transaction) can call recycle(subject) first. The owner's requestClaim then succeeds against a zero escrow: reimbursed = 0 because owed (0) < c.price, the owner has paid 0.5 IMD to the Intake and receives nothing, and the 90% issuer share of every earlier trade has gone to the hook's pools. The escrow itself going to the pools after 90 days is the brief's rule; the asymmetry is that the claim's cost is reimbursed only from the escrow and the recycle has no grace once a claim is being prepared, so the race is lost by the handle owner for the price of gas. Possible mitigations without changing a number: let a requestClaim within the same block as a recycle take priority is impossible, but recycle could be refused for a short grace after a subject's last buy, or the oracle price reimbursement could be drawn from the pools share instead of the escrow.","line":379,"path":"src/MarginaliaPages.sol","reproduction":"Fixture from test/Pages.t.sol. 1) alice: pages.buy(subjectOfHandle('quiet'), 20, max) at t0 -> escrow 1.89 IMD, escrowSince = t0. 2) warp to t0 + 90 days. Carol (handle owner) tweets the claim statement. 3) bob: pages.recycle(subject) -> succeeds, 1.89 IMD to hook.fundPot, escrow = 0. 4) carol: pages.requestClaim('quiet', tweetId) -> pays 0.5 IMD to the Intake. 5) Intake delivers a signed answer = carol: onOracleResult sets payee = carol, owed = 0, reimbursed = 0, emits Claimed(subject, carol, 0, 0). Expected (brief): 'takes the escrow less the oracle price reimbursed to whoever asked'; actual: carol is 0.5 IMD poorer and receives none of the 1.89 IMD her pages earned. With the same sequence but step 3 omitted, carol nets 1.39 IMD (testEscrowThenOracleAttestedClaim).","severity":"low","snippet":"        if (block.timestamp < uint256(s.escrowSince) + CLAIM_WINDOW) revert TooEarly();","title":"After CLAIM_WINDOW anyone can recycle a handle's escrow in front of the owner's visible claim, so the owner's requestClaim still costs the oracle price but pays and reimburses nothing"},{"citation":"resolved","description":"Trust assumption, not a code defect: the brief orders no owner and four stored constructor values, and the contract honours that. The oracle-consumer reference, however, says every protocol-facing value (intake, action, signer) must be settable because a new action version or rotated key 'must not need a redeploy', and that the brief's Intake 0x1397... is version 1, kept only for contracts already pointing at it. If the oracle signer key is rotated, every delivered attestation fails _verifyAttestation with BadSignature; if version 1 stops completing requests, every requestClaim spends 0.5 IMD and is abandoned after 3 days. In both states no handle can ever be claimed, and because recycle is permissionless, 100% of the issuer share of every handle subject goes to the hook's pools after 90 days instead of to the authors. Pages of address subjects are unaffected. Recorded so the author can decide the scope question (accept, or point the signer at an ERC-1271 registry address that the oracle operator can rotate behind, which SignatureChecker already supports).","line":126,"path":"src/MarginaliaPages.sol","reproduction":"Deploy with signer S. State: oracle operator signs with S2 != S. alice buys 20 pages of subjectOfHandle('writer') (escrow 1.89 IMD). carol requestClaim('writer', tweetId) pays 0.5 IMD; the Intake delivers an attestation signed by S2: onOracleResult reverts BadSignature (test pattern: testRejectedAnswersDoNotCloseTheClaim, 'tampered after signing' branch). After 3 days anyone abandons the claim; after 90 days anyone recycles 1.89 IMD to the pools. Expected by the brief's spirit: the handle owner can claim; actual: no path ever pays the handle owner and nothing on chain can repair it.","severity":"info","snippet":"        OracleAttestationConsumer(signer_)","title":"Oracle signer, Intake and action are immutable with no owner: a signer rotation or Intake v1 retirement permanently disables handle claims and routes all handle escrow to the pools"}],"hash":"7b87a4878945fb8fb9a05401d5e97798f46263acc0c4b1259f745c1e18629cdb","nodeId":"63c75fcf-faeb-4c59-98d6-b1b869f7a168","outcome":"completed","summary":"Review complete. The findings file is written at the repository root with three findings and a 42-row coverage record, and the one proof test fails on the current code as required.\n\n**Scope covered.** Access Control, Trust Gap and Asymmetry passes over every MarginaliaPages entry point, plus the two hook functions Pages calls into. The live hook, judge, router, treasury and token entry points are marked as holding only in the sense that nothing in Pages' permission model reaches them. I could not reach the live IMD token or Intake bytecode because the contributor RPC endpoint refused connections, so the 200k callback stipend is verified only against the mock token.\n\n**Findings**\n\n- **Medium, `burnPending` (line 396).** The swap's only execution guard is the caller's own `minMargOut`, and the price limit is the extreme tick. An unprivileged caller can buy MARG, burn the whole pending balance with a 1 wei floor, and sell back. On a pool with about 26k IMD in range and 25k IMD pending, the caller nets 3,925 IMD and 15.7% less MARG reaches the dead address. The roundtrip costs about 5.5% in fees, so it only pays once the pending burn is roughly a tenth of the pool's reserve or more. The README discloses the gap. A self-contained proof under `test/scratch/BurnSandwichProof.t.sol` is attached and fails today.\n- **Low, `recycle` (line 379).** After 90 days, anyone can recycle escrow ahead of the handle owner's claim, which is always preceded by a public tweet. The owner's claim then succeeds with zero escrow and no reimbursement, leaving them 0.5 IMD poorer. Reproduced against the fixture.\n- **Info, constructor (line 126).** Signer, Intake and action are immutable by the brief's own rule, but a signer rotation or Intake v1 retirement would permanently disable claims and route all handle escrow to the pools. Recorded as a trust assumption for the author's scope decision.\n\n**What held.** Buy and sell mirror each other exactly, the reserve invariant is integer-exact, the callback accepts only the Intake for a pending id and consumes the oracle UUID once, the unlock callback is bound to the PoolManager and a live guard, and transient approvals to the hook and Intake are fully consumed.","treeHash":null,"usage":{"cachedInputTokens":2623028,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":48746,"runtime":"claude","turns":34,"wallClockMs":1223705}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"644eb561f6d70a85","findings":[{"citation":"resolved","description":"Economic Security / Flow Gap (execution x periphery x first principles). The 5% burn share of every fee (BURN_BPS) is parked in pendingBurn and spent by burnPending, which anyone may call with any tranche size and any minMargOut >= 1. The only slippage protection is the caller's own floor, and in unlockCallback the swap runs to MIN_SQRT_PRICE+1 / MAX_SQRT_PRICE-1 with no on-chain price reference. The caller is therefore free to be the sandwicher: buy MARG, call burnPending(pendingBurn, 1), sell MARG back. The protocol then pays the pool's 1.25% LP fee and the full price impact out of the burn budget and burns far less MARG than it should; the difference, less the attacker's own LP fees (1.25% each leg) and the hook's 3% quiet-sell fee on the exit, is the attacker's profit. Nobody is paid to burn honestly (it costs gas and yields nothing), while the attacker is paid to burn adversarially, so pendingBurn will accumulate until the adversarial burn is profitable. Live state (mainnet, block ~26174333): the launch pool 0x436763bf...2f20 has liquidity 1.3479e24 at sqrtPriceX96 1.735e31 (tick 107787), i.e. an IMD virtual reserve of about 6,150 IMD. Break-even is pendingBurn > ~(1.25%+1.25%+3%)/2 of that depth = ~170 IMD, which is 0.5% of ~34,000 IMD of page trade value (e.g. 820 pages of one subject: priceOf(0,820) = 33,661 IMD). The same lever moves MARG's spot price at zero cost to the caller (the pump is paid by the burn budget), which is what every MARG call and thesis in the hook settles against; the pricer's observation TWAP dampens but does not remove a repeated, free pump. Proposed fix (keeps every number): derive the floor on chain instead of trusting the caller, e.g. require marg >= imdIn * 1e18 / twapPriceInImd * (10_000 - MAX_BURN_SLIPPAGE_BPS) / 10_000 using the hook's observation-based MARG price (not the manipulable spot), and/or cap a tranche at a small fraction of the pool's current liquidity; alternatively pass a sqrtPriceLimitX96 bounded around that reference instead of the extreme tick.","line":393,"path":"src/MarginaliaPages.sol","reproduction":"Local reproduction (test/scratch/BurnSandwich.t.sol, Fixture pool re-seeded with 6,000 ether of liquidity in [-6000, 6000] at 1 MARG = 1 IMD, i.e. ~6k IMD depth like the live pool). 1) alice buys 1,550 pages of subjectOf(carol): value 120,202.5 IMD, pendingBurn = 601.0125 IMD. 2) Honest burnPending(601.0125e18, 1) burns 540.08 MARG. 3) Attacker bob instead, in one transaction: swap 1,400 IMD -> MARG on the launch pool (plain router), call pages.burnPending(601.0125e18, 1), swap all the MARG back. Observed: bob's IMD balance rises by 126.62 IMD net of all LP and hook fees (profit = 21% of the burn budget); only 362.86 MARG reach 0xdEaD instead of 540.08. With X = 400 IMD the profit is 49.65 IMD; with pendingBurn = 1,199.57 IMD (2,190 pages) and X = 700 IMD the profit is 202.19 IMD and the burn shrinks from 989.27 to 809.21 MARG. With pendingBurn = 160.2 IMD (800 pages) every X loses money (-0.46 .. -12.16 IMD), confirming the ~3%-of-depth threshold. Expected per the brief: 'BURN_BPS 5% of the fee buys MARG on the launch pool ... and sends it to dEaD' at the market price the burn finds, not a price an unprivileged caller sets against it. Actual: the burn is an unbounded-slippage swap any caller can sandwich; the victim is the burn (MARG holders), the beneficiary is the caller.","severity":"medium","snippet":"    function burnPending(uint256 imdIn, uint256 minMargOut) external nonReentrant {\n        if (imdIn == 0) revert ZeroAmount();\n        if (imdIn > pendingBurn || imdIn > uint256(uint128(type(int128).max))) revert InsufficientBurn();\n        if (minMargOut == 0) revert Slippage();","title":"burnPending's MARG floor is caller-chosen, so anyone can sandwich the burn budget for profit once it exceeds ~3% of the pool's IMD depth"},{"citation":"resolved","description":"Invariant / Flow Gap (execution x first principles). escrowSince is set once, at the first fee that lands in escrow (line 235: `if (s.escrowSince == 0) s.escrowSince = uint64(block.timestamp);`), and only cleared by recycle. recycle (line 379) tests that single timestamp against the whole escrow balance. So once 90 days have passed since the first page of a handle was bought, the issuer share of every later trade, including one made seconds earlier, can be sent to the hook's pools by anyone in the same block, and nothing restarts the window while any escrow is unrecycled. Dust escrow left past day 90 is a standing trap: a recycler has no reason to clear 0.009 IMD, so they wait for a large buy and snipe its 90% share. The guarantee the brief states, 'pages of a handle trade on the same curve while the issuer's 90% waits in escrow' and 'the escrow pays for its own claim', no longer holds for any subject older than 90 days: the owner's only defence is to have a claim pending before each large buy, which they cannot know about. Because recycle needs no tweet and no oracle round-trip while the claim needs both (the tweet is public, the requestClaim tx is in the mempool), the owner reliably loses the race, and then reimbursement is 0 (line 354: `owed >= c.price ? c.price : 0` with owed = 0), so the claimant pays 0.5 IMD for a payee with no escrow. Who gains: the thesis and refund pools (indirectly the week's judged writers). Who loses: the handle owner, an identifiable victim. The letter of the brief ('CLAIM_WINDOW = 90 days after the first buy') permits this, so the fix needs a scope decision; two options that keep every number: (a) restart the 90-day clock on every accrual (escrowSince = block.timestamp on each escrow deposit), so recycle takes only escrow that has sat 90 days without a new trade; or (b) keep escrowSince per accrual epoch and let recycle take only the part older than CLAIM_WINDOW. Either way reimburse the claimant from escrow before any recycle that lands in the same block is not possible, so (a) is the simplest.","line":379,"path":"src/MarginaliaPages.sol","reproduction":"test/scratch/RecycleRace.t.sol against the local hook. 1) t0: alice buys 1 page of subjectOfHandle(\"writer\"): escrow 0.009 IMD, escrowSince = t0. 2) t0 + 91 days: bob buys 100 pages: value 505 IMD, fee 50.5, escrow += 45.45 -> 45.459 IMD. 3) Same block, before carol's requestClaim: any address calls recycle(subject): passes NothingToRecycle (escrow 45.459 > 0), ClaimPending (none), TooEarly (t0 + 91d >= t0 + 90d); 45.459 IMD go to hook.fundPot. 4) carol (the handle's owner) calls requestClaim(\"writer\", tweetId) paying 0.5 IMD; the panel answers carol; onOracleResult sets payee = carol with owed = 0, reimbursed = 0. Observed: pools +45.459 IMD, carol -0.5 IMD net, 0 escrow received. Expected: the 45.45 IMD accrued 0 seconds earlier waits in escrow for the owner's claim, which the escrow pays for.","severity":"medium","snippet":"        if (block.timestamp < uint256(s.escrowSince) + CLAIM_WINDOW) revert TooEarly();","title":"After CLAIM_WINDOW from the first buy, every later issuer accrual is recyclable immediately, and recycle front-runs the owner's requestClaim: the owner pays the oracle and gets nothing"},{"citation":"resolved","description":"Periphery / Flow Gap (execution x periphery). The oracle-consumer reference says the callback gets 200,000 gas inside a try, is attempted once and never retried, and advises 'verify and store; act in a later call'. Pages verifies, consumes, writes payee, and performs two ERC-20 transfers inside the callback. The live IMD token (0xD34a99Bc..., 23 KB of runtime, not a plain OpenZeppelin ERC-20) costs 57,358 gas for a transfer to a cold recipient and 35,755 to a warm one on a mainnet fork, roughly twice the MockERC20 the tests use. Measured on a fork with the real hook and real IMD, an EOA signer and a mock Intake: 177,116 gas when the asker still holds IMD and the wallet is cold; 194,205 gas when the asker's balance is exactly zero after paying the price (zero->nonzero SSTORE on reimbursement) and the wallet is cold. The 200k delivery still succeeds (ClaimIntake.deliver with gas: 200_000 returns true), so this is not a failure today, but the margin is ~6k gas (3%). Any state that adds a few thousand gas to the path turns a correct answer into a lost one: the oracle signer gaining code (SignatureChecker then also tries ERC-1271 after the ECDSA mismatch), an IMD token upgrade or a more expensive transfer branch, or the Intake granting slightly less than 200k after EIP-150's 63/64 rule when `complete` itself is called with a tight gas limit. When that happens the claim stays pending, the asker's 0.5 IMD is spent, the escrow cannot be recycled or re-asked for until abandonClaim after 3 days, and the panel's correct answer is thrown away. Minimal fix that keeps the design: store the answer (payee, owed, reimbursed, claimant) in the callback and pay out in a separate permissionless `settleClaim(subject)` call, or at least move the two transfers behind a `claimPayout` pull; the brief's 'paid directly from then on' is unaffected for later trades.","line":357,"path":"src/MarginaliaPages.sol","reproduction":"test/scratch/ForkProbe.t.sol (fork of mainnet via public RPC, investigation only): deploy MarginaliaPages(hook 0xf0457dD0..., mock ClaimIntake, action, vm.addr(key)); trader buys 20 pages of subjectOfHandle(\"writer\"); an asker funded with exactly 0.5 IMD calls requestClaim(\"writer\", 123); deliver a signed address answer naming a fresh wallet with zero IMD. Measured gas around the onOracleResult call: 194,205 (asker balance 0, wallet cold), 177,105 (asker balance 0.5 IMD, wallet cold), 172,305 (asker == wallet). Passing state today; failing state: any of the three additions above costing >= ~6,000 gas, e.g. an ERC-1271 signer, after which intake.deliver returns false, claims(subject) stays set, and only abandonClaim after ANSWER_DEADLINE clears it.","severity":"low","snippet":"        if (reimbursed > 0) imd.safeTransfer(c.claimant, reimbursed);\n        if (owed > 0) imd.safeTransfer(wallet, owed);","title":"onOracleResult acts inside the Intake's 200,000-gas stipend with ~6k headroom against the live IMD token; a delivery that runs out of gas strands the claim for 3 days and costs the asker the price"},{"citation":"resolved","description":"Economic Security, 'break dependencies'. The brief requires no owner and pins Intake v1 (0x1397...), action oracle.request@oracle-1 and the signer 0x5598..., matching the live hook's constants, so this is by design and not a defect to fix by adding an owner. The oracle-consumer reference, however, states that each of these 'is constructor input and owner-settable, never a constant' and that 'a new action version (oracle-2) or a moved price must not need a redeploy', and recommends Intake v2 (0xa43e...) for anything new. The economic consequence to record as a trust assumption: if the oracle plane rotates its signing key (every attestation then fails BadSignature), stops serving v1, retires the oracle-1 action (priceOf returns 0 -> PriceMismatch), or raises the price above MAX_PRICE 1 IMD, no handle can ever be claimed again; every handle's escrow then recycles into the hook's pools after 90 days and future issuer shares of handle pages go to the pools forever, while address subjects are unaffected. Holders of handle pages keep their curve exit. No code change is proposed within the brief; the README should state this dependency and that the live Judge shares it.","line":59,"path":"src/MarginaliaPages.sol","reproduction":"State: oracle signer rotated away from 0x5598Aa9146215Bc13eb26f2c692Ad1461Fd32982 (or Intake.priceOf(action, IMD) == 0). Call requestClaim(handle, tweetId): with price 0 it reverts PriceMismatch; with a rotated signer the request is paid (0.5 IMD) and every delivery reverts BadSignature in _verifyAttestation, so the claim is abandoned after 3 days and the asker's price is lost; recycle(subject) after CLAIM_WINDOW sends the escrow to hook.fundPot. Expected under the reference: a settable signer/intake/action; under the brief: no owner, so this is the accepted cost.","severity":"info","snippet":"    IMarginaliaHookPages public immutable hook;\n    IIntake public immutable intake;\n    bytes32 public immutable action;","title":"Trust assumption: intake, action and signer are immutable with no owner, so a signer rotation or retirement of Intake v1 / oracle-1 permanently disables handle claims and routes all handle escrow to t"}],"hash":"843678b83af230488bdd29ee49bc8f2f39b86e187f8cb065d28cc9f1d2c9851f","nodeId":"3931255c-7c88-450b-bef1-1718a9130a9e","outcome":"completed","summary":"The review is complete. The findings file holds four findings and a 43-row coverage record (all 40 listed entry points plus three invariants). No tracked file was changed; scratch tests live under test/scratch.\n\n**Findings**\n\n1. **Medium. The burn budget is sandwichable.** `burnPending` takes any tranche and any floor of 1 wei and swaps to the extreme tick with no on-chain price reference. Nobody is paid to burn honestly, so pendingBurn accumulates until an adversarial burn pays. On a pool re-seeded to the live depth of roughly 6k IMD, a 601 IMD budget sandwiched with 1,400 IMD nets the attacker 126.6 IMD after all LP and hook fees, and the burn drops from 540 to 363 MARG. Break-even is about 3% of pool depth, around 170 IMD of budget, or 34k IMD of page volume. The same lever pumps MARG spot for free, which the hook's calls and theses settle against.\n\n2. **Medium. Escrow accrued after day 90 is recyclable instantly and recycle front-runs the owner's claim.** The 90-day clock is set once at the first accrual. Reproduced: one page on day 0, a 100-page buy on day 91 adds 45.45 IMD of escrow, anyone recycles it in the same block, then the owner's claim lands, pays 0.5 IMD, and receives nothing with no reimbursement. This matches the brief's letter, so the fix needs a scope decision; restarting the clock on each accrual keeps every number.\n\n3. **Low. The claim callback acts inside the 200k stipend with thin headroom.** Against the live IMD token on a mainnet fork, the worst case measured 194,205 gas when the asker's balance is zero and the wallet is cold. It passes today. An ERC-1271 signer or a costlier IMD transfer would turn a correct answer into a lost one, stranding the claim three days and costing the asker the price.\n\n4. **Info. Immutable oracle constants with no owner.** A signer rotation or retirement of Intake v1 permanently disables handle claims and routes all handle escrow to the pools. This is the brief's design, recorded as a trust assumption.\n\n**What held**: curve math and reserve conservation, the fee split and rounding, slippage guards, the quiet burn swap taking no hook fee, claim replay and tamper refusals, abandon and recycle guards, and the live IMD token delivering full amounts with no recipient hooks.\n\n**Not reached in depth**: the hook's note, settlement and judging entry points, which Pages does not touch beyond funding the pools.","treeHash":null,"usage":{"cachedInputTokens":2035812,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":59532,"runtime":"claude","turns":35,"wallClockMs":1158616}},{"artifacts":[],"attempt":1,"bundleHash":"d2baf95b4f3582b9cb8bc3ed8ace4d221bb4d5d40cf4792ec55a122ccd4b6704","device":"b57ae3a96321a0e1","findings":[],"hash":"87ee4bc12b5805697166284443a9c4b86ef7418b80720c9c3b7cd8d2bd6ebba9","nodeId":"0ae19a5b-0de8-4d38-a624-f0912d65a276","outcome":"completed","summary":"Done. The revision is complete, verified, and answered in `.imd-responses.json`.\n\n**What I found**\n\nEvery finding reproduced except the trust-assumption note, which is not a defect. The medium finding reproduced with the reviewer's exact numbers on the pre-revision contract: a 1,000 IMD push before `burnPending(601.0125e18, 1)` cut the burn from 540.08 to 403.34 MARG and left the sandwicher up 102.29 IMD.\n\n**What changed, all in `src/MarginaliaPages.sol`, every number kept**\n\n- **Burn price bound (medium).** Pages now keeps its own tick-seconds accumulator of the launch pool, fed by a permissionless `observe()` and by every burn. The anchor always spans at least 30 minutes. A tranche swaps with a sqrt price limit 100 ticks (about 1%) beyond the lower of spot and that TWAP, fills only up to it, and leaves the rest pending. A spot already beyond the limit is refused before any swap. The 1% bound sits below the LP and hook fees a sandwicher pays, so sandwiching loses money whatever floor the caller passes. Tested on the reviewer's pool with pushes from 10 to 1,400 IMD, and separately with mainnet's orientation where IMD is currency0, since the default fixture has the opposite order.\n- **Aged escrow buckets (low).** Recycling pays out only the share that has itself waited 90 days. The first buy's share is still recyclable exactly 90 days after the first buy, but a share deposited seconds before cannot be swept ahead of the owner's claim.\n- **Store-then-settle callback (low).** The Intake callback only verifies and records the payee. A permissionless `settleClaim` pays the escrow and reimbursement. Cold-recipient delivery now measures 115,581 gas including the mock's overhead, asserted under 120,000.\n- **Self subjects (low)** are refused in `buy`, and a claim answer naming the market or hook fails like a zero answer.\n- **Dust tranche (info)** reverts with a named `NoFill` error.\n\n**Verification**\n\n- `forge build` passes. Runtime is 19,668 bytes, no forbidden opcodes, constructor unchanged.\n- `forge test --match-path 'test/Pages*.t.sol'`: 37 passed. Full suite without the fork tests: 287 passed, 0 failed.\n- ADAPTATION.md and README.md document each change, the operating steps for the first burn, and the accepted trust assumption.\n\n**Not done:** no mainnet fork run, since the fork suites skip without an RPC. The fork test was updated to observe and wait the window before burning.","treeHash":"0814907aa11c86b41fb08997804a051a5de9e9aa","usage":{"cachedInputTokens":3143697,"inputTokens":674,"model":"claude-fable-5-1","outputTokens":78952,"runtime":"claude","turns":32,"wallClockMs":1724391}},{"artifacts":[],"attempt":1,"bundleHash":"dcf3e43ef112a57f9796a6b19eb8c33f72ea70b7a0d5f69a69349b0d45c15ccf","device":"9e51ef2afd7c2af8","findings":[{"description":"burnPending lets the caller choose the tranche. When the tranche is below what the pool's 1.25% LP fee rounding leaves anything for (a few hundred wei), the swap returns zero MARG and unlockCallback reverts with UnauthorizedCallback, a name that suggests an access problem rather than a dust tranche. No value is at risk: the wei stay queued and are burned with the next fee. A dedicated error (or a minimum tranche) would make the refusal legible. The invariant handler in test/PagesInvariant.t.sol asserts this behaviour as it is today.","line":419,"path":"src/MarginaliaPages.sol","reproduction":"Buy one page of any subject (pendingBurn becomes 5e14 wei). Call burnPending(5e14 - 10, floor) so 10 wei remain, then call burnPending(10, 1). Expected: a refusal that says the tranche is dust, or the ten wei burned. Actual: the PoolManager bubbles UnauthorizedCallback() from unlockCallback because the swap output is zero; pendingBurn stays 10 wei.","severity":"low","title":"A burn tranche too small to yield any MARG is refused with UnauthorizedCallback, so a few wei can sit in pendingBurn until more fees accrue"},{"description":"The callback requires agreed >= quorum, quorum >= 4 and panelSize >= 5, but not agreed <= panelSize. An attestation with panelSize 5, quorum 4 and agreed 9 is accepted. Only the trusted oracle signer can produce such a message, so this is a consistency check that is missing, not an exploit; it is recorded here because it is a signed field the contract reads and does not bound.","line":336,"path":"src/MarginaliaPages.sol","reproduction":"Request a claim for any handle, then deliver from the Intake an attestation signed by the configured signer with panelSize = 5, quorum = 4, agreed = 9 and a nonzero address answer. Expected (strict reading of the brief's panel terms): BadAnswer. Actual: the claim succeeds and the address becomes the payee.","severity":"info","title":"onOracleResult accepts an attestation whose agreed count exceeds its panelSize"}],"hash":"aabe5943cb273647aaff6181cb400ecea1e8dbfe1604b2cea106b7e2d18b4813","nodeId":"8734f817-b327-4ca9-819c-8aa0a32ccfdd","outcome":"completed","summary":"The findings file is in place and intentionally excluded by the repository's own git exclude list, which is how the network collects it. Work is complete.\n\n## Summary\n\nThe accepted implementation of MarginaliaPages already had its 12 required tests in test/Pages.t.sol passing. What was missing against the acceptance criteria was an invariant suite over random call sequences for a contract that holds IMD, and coverage of the inputs the code did not obviously consider. I added two files under test/ and changed nothing else.\n\n**test/PagesInvariant.t.sol** drives the market against the real local PoolManager, hook and pool with a handler, four actors and six subjects: two address issuers, the zero address, and three handles including one with upper-case letters. The handler buys, sells, requests claims, delivers good, zero, tampered, thin, stale, wrong-chain and wrong-key answers, abandons, recycles, burns and warps time. It runs with fail-on-revert, so every refusal it provokes is asserted by exact error. Invariants checked after every call:\n\n- The market's IMD balance equals curve reserves plus escrow plus the burn queue, and equals everything paid in minus everything paid out.\n- Every reserve is the curve integral of its supply, so all holders can sell out at any depth, and every page is held by a trader.\n- Escrow, payee, pending claim and consumed oracle ids match the ledger. A payee never changes once set, and a claimed handle never has escrow or a pending claim.\n- The pools' share and recycled escrow land in the hook's IMD claims, and burned IMD reaches the dead address as MARG, never below the floors set.\n\n**test/PagesEdges.t.sol** holds 23 tests: constructor zero inputs, zero amounts, one wei of slippage either way, overflow reverting rather than wrapping, sell-fee split, selling out and restarting at BASE, independent curves, the zero-address subject, claims with no escrow, escrow exactly equal to and one wei short of the oracle price, the 1 IMD price cap boundary, every panel threshold at its boundary, upper-case requests, handle length and character limits, the escrow clock across a failed claim, a claimed handle being closed to all later paths, abandon at exactly the deadline, foreign-request and foreign-domain answers, a cold claim under the 200k stipend with the real hook, and the absence of any owner or pause surface. Two fuzz properties cover curve additivity and the exact cost of a round trip.\n\n**Results**\n\n| Check | Outcome |\n| --- | --- |\n| Full suite | 302 passed, 0 failed, 2 fork tests skipped without RPC |\n| Pages invariant campaign | 96 runs, 4608 calls, 0 reverts |\n| Scratch path check | every handler path reached, invariants hold after |\n\n**Findings** went to .imd-findings.json, both minor. A burn tranche too small to yield any MARG is refused with the misleading error UnauthorizedCallback, leaving a few wei queued until the next fee. The callback does not bound the signed agreed count by panelSize, which only the trusted signer could abuse. I found no defect that moves value or breaks a stated rule.","treeHash":"d38a982b8af5f96ef8273eb7374faeaf4bb763df","usage":{"cachedInputTokens":3274910,"inputTokens":770,"model":"claude-fable-5-1","outputTokens":71360,"runtime":"claude","turns":39,"wallClockMs":1925363}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f009de0ce52c7b3a","findings":[{"citation":"resolved","description":"requestClaim(handle, tweetId) is permissionless and the question it builds tells the panel to answer 'the single Ethereum address written in the text field' of whatever tweet the caller names, as long as user.screen_name is the handle. Nothing in the question requires the tweet to be a claim statement for this page market (no mention of Marginalia, the chain, or this contract's address; the 'consumer' field is signing metadata, not an instruction about the tweet's content). Crypto accounts tweet single addresses constantly: token contracts, donation wallets, an exchange deposit address, a scammer they are warning about. For any such tweet, a stranger calls requestClaim with that tweetId, the panel truthfully answers the address in it, and onOracleResult makes it the payee: the whole escrow is transferred there, every later trade's 90% issuer share goes there, and because 'one successful claim per subject ever' is enforced (AlreadyClaimed) the real owner can never correct it. The attacker's 0.5 IMD is reimbursed from the escrow whenever it holds at least the price, so the attack is free against every handle worth attacking. The repository's own probe (jobs/oracle-claim-probe.json) shows the concrete case: tweet 2109295512424009991 by @bddnewstoday names the MARG token contract 0xfa0efea559bde229031c2b0a219472316647759c and the panel answered it 5/5. requestClaim(\"bddnewstoday\", 2109295512424009991) therefore turns that handle's escrow and future fees into IMD sent to a token contract, unrecoverable. Fix: make the question refuse any tweet that is not an explicit claim naming this deployment, e.g. 'answer the address only if the text also contains the exact string <this contract's address> (or a fixed claim phrase plus the chain id); otherwise answer zero', so only a deliberate claim tweet by the handle's owner can set a payee. questionBody already prints address(this); put it in the instruction, not only in the consumer field.","line":256,"path":"src/MarginaliaPages.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {MarginaliaPages, IMarginaliaHookPages} from \"src/MarginaliaPages.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\n\n/// @notice The oracle question a claim asks must bind the tweet to THIS page market. As written, the panel is\n/// told to answer \"the single Ethereum address written in the text field\" of ANY tweet by the handle, so every\n/// handle that has ever tweeted one address (a token contract, a donation wallet, a scammer it warned about) can\n/// be claimed by anyone to that address, permanently, for the price of one oracle request that the escrow then\n/// reimburses. The fix is in the question text: the panel must be told to answer zero unless the tweet is a\n/// claim statement that names this contract (its address, as questionBody already prints it in the consumer\n/// field), so only a deliberate claim tweet can set a payee. This test fails while the question's instruction\n/// does not name the contract, and passes once it does.\ncontract PagesClaimBindingTest is Test {\n    MarginaliaPages pages;\n\n    function setUp() public {\n        pages = new MarginaliaPages(\n            IMarginaliaHookPages(address(0x1111)),\n            IIntake(address(0x2222)),\n            bytes32(\"oracle.request@oracle-1\"),\n            address(0x3333)\n        );\n    }\n\n    /// @dev The instruction the panel follows is the \"question\" string; everything after `\",\"chainId\"` is\n    /// metadata (consumer, guards) the panel does not read as a rule for the tweet's content.\n    function _question(string memory body) internal pure returns (string memory) {\n        bytes memory b = bytes(body);\n        bytes memory start = bytes('\"question\":\"');\n        bytes memory stop = bytes('\",\"chainId\"');\n        uint256 from = _indexOf(b, start, 0);\n        require(from != type(uint256).max, \"no question field\");\n        from += start.length;\n        uint256 to = _indexOf(b, stop, from);\n        require(to != type(uint256).max, \"no end of question\");\n        bytes memory q = new bytes(to - from);\n        for (uint256 i; i < q.length; ++i) {\n            q[i] = b[from + i];\n        }\n        return string(q);\n    }\n\n    function _indexOf(bytes memory hay, bytes memory needle, uint256 start) internal pure returns (uint256) {\n        if (needle.length > hay.length) return type(uint256).max;\n        for (uint256 i = start; i + needle.length <= hay.length; ++i) {\n            bool hit = true;\n            for (uint256 j; j < needle.length; ++j) {\n                if (hay[i + j] != needle[j]) {\n                    hit = false;\n                    break;\n                }\n            }\n            if (hit) return i;\n        }\n        return type(uint256).max;\n    }\n\n    /// @notice The probe tweet 2109295512424009991 by @bddnewstoday names the MARG token contract. With the\n    /// question as written the panel answers that contract address and the handle's escrow and every future\n    /// issuer fee go to a token contract forever. The question must require the tweet to name this contract.\n    function testClaimQuestionBindsTheTweetToThisContract() public view {\n        string memory body = pages.questionBody(\"bddnewstoday\", 2109295512424009991);\n        string memory question = _question(body);\n        bytes memory self = bytes(Strings.toHexString(address(pages)));\n        assertTrue(\n            _indexOf(bytes(question), self, 0) != type(uint256).max,\n            \"the panel's instruction does not require the tweet to name this page market, so any address the handle ever tweeted becomes its payee\"\n        );\n    }\n}","reproduction":"State: handle 'bddnewstoday' has pages bought (escrow >= 0.5 IMD) and is unclaimed. Input: anyone calls requestClaim(\"bddnewstoday\", 2109295512424009991) paying 0.5 IMD. The panel fetches the tweet, user.screen_name matches, the text contains exactly one address (the MARG token contract), so the attestation answers 0xfa0efea559bde229031c2b0a219472316647759c with agreed 5 >= quorum 4. onOracleResult sets subjects[subject].payee to the token contract, pays it the escrow less 0.5 IMD (the 0.5 IMD goes back to the attacker), and every later buy/sell of that subject pays its 90% issuer share to the token contract. Expected: only a tweet in which the handle deliberately claims its Marginalia page can set the payee. Actual: any single address the handle ever tweeted becomes the payee forever. test/scratch/PagesClaimBinding.t.sol fails on this code (the question's instruction never names this contract) and passes once the instruction requires the tweet to name it.","severity":"high","snippet":"                    \" then answer with the single Ethereum address written in the text field. If the document cannot be fetched, the handle differs, or the text names no address or more than one, answer 0x0000000000000000000000000000000000000000.\\\",\\\"chainId\\\":\"","title":"Claim question accepts any address the handle ever tweeted: anyone can permanently set a wrong payee and redirect the escrow and all future issuer fees"},{"citation":"resolved","description":"sell() calls _distributeFee, which calls _burnMarg for 0.5% of the value; unlockCallback performs an exact-input swap and then reverts with UnauthorizedCallback unless the pool consumed exactly imdIn and returned MARG (line 390), and the hook's afterSwap independently reverts PartialFill when the IMD delta is not negative. So the seller's payout, although fully covered by reserveOf[subject] (which fees never touch), is only reachable while the launch pool has liquidity in range for that amount. The hook does not lock the launch position ('no liquidity callbacks restrict seeding, withdrawals or LP fee claims', launch.json notes), so any LP, including the launch position's owner, can withdraw and every page holder is then locked out of their IMD until liquidity returns. The same path blocks a large sell whose burn exceeds what the pool can absorb at the unbounded price limit (the swap stops early, the delta is smaller than imdIn, UnauthorizedCallback), so a big holder must split sells or cannot exit. The promise 'the curve reserve always covers every holder selling out at any depth' therefore does not hold operationally. Buys are blocked in the same states, which is less harmful. Fix: never let the burn block the trade: if the swap cannot run (try/catch on poolManager.unlock, or a liquidity check) keep the burn's IMD in a pendingBurn balance that anyone can later burn with a permissionless call, and pay the seller from the reserve unconditionally. hook.fundPot has the same coupling (it also unlocks the PoolManager) but cannot fail for lack of liquidity.","line":232,"path":"src/MarginaliaPages.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 {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 {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Marginalia} from \"src/Marginalia.sol\";\nimport {MarginaliaHook} from \"src/MarginaliaHook.sol\";\nimport {MarginaliaRouter} from \"src/MarginaliaRouter.sol\";\nimport {MarginaliaTreasury} from \"src/MarginaliaTreasury.sol\";\nimport {MarginaliaJudge} from \"src/MarginaliaJudge.sol\";\nimport {MarginaliaPricer} from \"src/MarginaliaPricer.sol\";\nimport {MarginaliaImpls} from \"src/MarginaliaImpls.sol\";\nimport {HookFlags} from \"src/HookFlags.sol\";\nimport {MarginaliaPages, IMarginaliaHookPages} from \"src/MarginaliaPages.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofERC20 is ERC20 {\n    constructor() ERC20(\"Identity.md\", \"IMD\") {\n        _mint(msg.sender, 1_000_000_000 ether);\n    }\n}\n\ncontract ProofLiquidity is IUnlockCallback {\n    using SafeERC20 for IERC20;\n\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)).safeTransfer(address(manager), uint256(-int256(d)));\n            manager.settle();\n        } else if (d > 0) {\n            manager.take(c, address(this), uint256(uint128(d)));\n        }\n    }\n}\n\ncontract ProofIntake is IIntake {\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0.5 ether;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata, address, uint256)\n        external\n        payable\n        returns (bytes32)\n    {\n        return bytes32(uint256(1));\n    }\n}\n\n/// @notice \"The curve reserve always covers every holder selling out at any depth\" is only true while the launch\n/// pool can absorb the 0.5% MARG buy every trade makes: sell() reverts whenever that swap moves nothing, so the\n/// reserve is intact but unreachable. Here the pool's one position is withdrawn and alice, the only holder,\n/// cannot sell. A fix pays the seller from the reserve regardless of the burn (for example keeps the burn's IMD\n/// aside for a later permissionless burn when the swap cannot run), which is what this test then asserts.\ncontract PagesExitNeedsPoolTest is Test {\n    IPoolManager manager;\n    Marginalia token;\n    ProofERC20 imd;\n    MarginaliaHook hook;\n    PoolKey key;\n    ProofLiquidity liquidity;\n    MarginaliaPages pages;\n    address alice = makeAddr(\"alice\");\n    address carol = makeAddr(\"carol\");\n\n    function _deployHook(IPoolManager m, address t) internal returns (MarginaliaHook) {\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(m, t, address(this)));\n        bytes32 hash = keccak256(code);\n        for (uint256 i = 0; i < 300_000; ++i) {\n            bytes32 salt = bytes32(i);\n            address predicted =\n                address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, hash)))));\n            if (!HookFlags.matches(predicted, HookFlags.MARGINALIA)) continue;\n            address deployed;\n            assembly (\"memory-safe\") {\n                deployed := create2(0, add(code, 32), mload(code), salt)\n            }\n            require(deployed == predicted && deployed.code.length > 0, \"deployment failed\");\n            return MarginaliaHook(deployed);\n        }\n        revert(\"mining exhausted\");\n    }\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 ProofERC20();\n        hook = _deployHook(manager, address(token));\n        bool margIs0 = address(token) < address(imd);\n        (address c0, address c1) = margIs0 ? (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        liquidity = new ProofLiquidity(manager);\n        token.transfer(address(liquidity), 50_000_000 ether);\n        imd.transfer(address(liquidity), 50_000_000 ether);\n        liquidity.add(key, -6000, 6000, 10_000_000 ether);\n        pages = new MarginaliaPages(\n            IMarginaliaHookPages(address(hook)), new ProofIntake(), bytes32(\"oracle.request@oracle-1\"), address(0x5E7)\n        );\n        imd.transfer(alice, 1_000 ether);\n        vm.prank(alice);\n        imd.approve(address(pages), type(uint256).max);\n    }\n\n    function testHolderCanAlwaysSellOutEvenWhenThePoolIsEmpty() public {\n        bytes32 subject = pages.subjectOf(carol);\n        vm.prank(alice);\n        pages.buy(subject, 5, type(uint256).max);\n        assertEq(pages.pagesOf(subject, alice), 5);\n        (uint256 value, uint256 fee) = pages.sellPrice(subject, 5);\n        assertEq(pages.reserveOf(subject), value, \"the reserve covers alice selling out\");\n        // the launch pool's only position is withdrawn (any LP may do this; nothing in the hook prevents it)\n        liquidity.add(key, -6000, 6000, -10_000_000 ether);\n        uint256 before = imd.balanceOf(alice);\n        vm.prank(alice);\n        pages.sell(subject, 5, 0);\n        assertEq(imd.balanceOf(alice) - before, value - fee, \"alice is paid from the reserve\");\n        assertEq(pages.pagesOf(subject, alice), 0);\n    }\n}","reproduction":"State: alice holds 5 pages of subjectOf(carol) (reserve 1.5 IMD). The pool's only position is withdrawn by its LP (ProofLiquidity.add with a negative amount in the proof; on mainnet the launch position's owner or any LP). Input: alice calls sell(subject, 5, 0). Expected: alice receives 1.5 IMD minus the 0.15 IMD fee from the reserve, which holds exactly that. Actual: the call reverts (PoolManager WrappedError wrapping the hook's PartialFill, or UnauthorizedCallback at line 390 when the swap returns nothing); pagesOf and reserveOf are unchanged and no holder of any subject can sell while the pool is empty. test/scratch/PagesExitNeedsPool.t.sol fails on this code and passes once sell pays the seller regardless of the burn swap.","severity":"medium","snippet":"        if (toBurn > 0) _burnMarg(toBurn);","title":"Every trade, including every sell, requires a successful MARG buy on the launch pool: with no in-range liquidity (or a burn larger than the pool can absorb) sells revert and holders cannot reach the r"},{"citation":"resolved","description":"unlockCallback swaps the burn amount with the price limit at MIN_SQRT_PRICE+1 / MAX_SQRT_PRICE-1 and accepts any MARG output above zero (line 390). A searcher can front-run a large page trade with a MARG buy, let the Pages contract buy at the pushed price, and sell back: the trader is unaffected (they pay value + fee regardless) but the MARG actually burned shrinks to almost nothing and the difference is the searcher's profit. Deep trades make this worth doing: 1000 pages at supply 0 is 50,050 IMD of value, a 250 IMD market buy with no minimum output. Fix: bound the output with a minimum derived from the pool's current price before the swap (e.g. require marg >= imdIn * 1e18 / hook.margPriceInImd() * (1 - maxSlippage)), or accumulate burn IMD and let a keeper burn it with a caller-supplied minOut.","line":384,"path":"src/MarginaliaPages.sol","reproduction":"State: pool at 1 MARG = 1 IMD with the fixture's liquidity. Sequence in one block: (1) searcher buys MARG with 1,000,000 IMD through the pool, moving the price up; (2) alice calls buy(subjectOf(carol), 1000, type(uint256).max): unlockCallback swaps 250.25 IMD for MARG at the pushed price and the Burned event shows far less MARG than the ~247 MARG the same IMD bought before step 1; (3) searcher sells the MARG back for more IMD than it paid. Expected: a bounded burn (revert or deferral when the output is below a floor). Actual: any output above zero is accepted.","severity":"low","snippet":"                zeroForOne, -int256(imdIn), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1","title":"The MARG burn swap has no slippage bound: MEV sandwiches capture part of the burn on every trade"},{"citation":"resolved","description":"amount is a uint256 priced with priceOf(supply, amount) and credited to pagesOf[subject][msg.sender] in full, but supply is updated with uint64(amount), which wraps for amount >= 2^64. A buy of exactly 2^64 pages would leave supply unchanged while pagesOf grows by 2^64, breaking the supply/pagesOf/reserve relation sellPrice relies on. It is not reachable in practice (the price of 2^64 pages is about 1.7e55 IMD and the burn swap would have to absorb 5e-4 of it, so the trade reverts long before), so this is a robustness defect, not an exploit, but the cast is unchecked and should be: require(amount <= type(uint64).max) or use SafeCast.toUint64, in both buy and sell.","line":197,"path":"src/MarginaliaPages.sol","reproduction":"Input: buy(subject, 2^64, type(uint256).max) by a caller holding priceOf(0, 2^64) * 1.1 IMD (only possible with a mintable mock, test/scratch/Probe.t.sol::testBuyAmountTruncation). Expected: revert on the unrepresentable amount. Actual on this code: the IMD is pulled, supply stays 0 while pagesOf is 2^64; the trade then happens to revert inside the burn swap (UnauthorizedCallback) because the pool cannot absorb the burn, which is the only thing preventing the inconsistent state.","severity":"low","snippet":"        s.supply += uint64(amount);","title":"buy()/sell() silently truncate amount to uint64 when adding to supply while pagesOf and the price use the full uint256"},{"citation":"resolved","description":"The callback looks up the subject by the Intake's requestId argument, verifies the signature in this contract's domain, and consumes a.requestId (the oracle's UUID), but never checks that a.requestId belongs to that Intake request nor that a.questionHash is the hash of the question this contract built for that subject. Any attestation signed for this contract would be accepted as the answer to whichever pending request the Intake presents it with. With an honest Intake this is not exploitable (the Intake delivers each answer under the request it was bought for, and a request made directly on the Intake naming this contract as callback gets a requestId this contract does not know, so it is refused with UnknownRequest), and the question cannot be hash-pinned because its window is relative, which the Judge documents as the same limitation ('relies on Intake request routing without comparing questionHash'). Recorded so the adapter and the panel treat the Intake as a trusted component of the claim path; a cheap hardening is to store the Intake requestId in the Claim and require the Intake to deliver a.requestId equal to it if the live Intake uses the same id for both.","line":321,"path":"src/MarginaliaPages.sol","reproduction":"Not reproducible against an honest Intake; it is a trust statement. Setup that shows the missing check: two pending claims for subjects S1 and S2; an attestation signed for S1's question (answer W) delivered by the Intake under S2's requestId is accepted and sets S2's payee to W. Expected: refused because a.questionHash does not match S2's question. Actual: accepted.","severity":"info","snippet":"        _consume(a.requestId);","title":"onOracleResult trusts the Intake's routing entirely: the attestation's own requestId and questionHash are never compared with the request being answered"},{"citation":"resolved","description":"Read in full: src/MarginaliaPages.sol, src/OracleAttestation.sol, src/interfaces/IIntake.sol, src/Marginalia.sol, test/Pages.t.sol, test/helpers/Fixture.sol. Read for the paths Pages depends on: src/MarginaliaHook.sol (beforeSwap/afterSwap for a quiet buy, fundPot/_fund and the ACT_FUND unlock branch, getPoolKey) and src/MarginaliaJudge.sol (requestJudging/onOracleResult, the pattern Pages copies). Not read: MarginaliaRouter, MarginaliaTreasury, MarginaliaPricer, MarginaliaTypes, HookFlags, MarginaliaImpls (not on any Pages path), and the live Intake's and IMD token's source (only their on-chain reads). Checks run: forge test --match-path test/Pages.t.sol (12/12 pass); worst-case onOracleResult gas with fresh recipient balances is 145,817 under the 200k stipend (test/scratch/Probe.t.sol); the EIP-712 digest of the protocol's conformance vector and the callback selector match the protocol (test/scratch/Vector.t.sol); runtime is 14,954 bytes with no DELEGATECALL/CALLCODE/SELFDESTRUCT under the protected opcode scan; the constructor makes no external call. Live reads over a public RPC on 2026-10-12: hook 0xf0457dd0...a0cc returns imd() = 0xD34a99Bc...63B7, token() = 0xfA0EfEa5...759c, poolManager() = 0x00000000...8A90, INTAKE() = 0x1397434c...ea56, ORACLE_SIGNER() = 0x5598Aa91...2982 (an EOA, no code), ACTION() = bytes32('oracle.request@oracle-1'), initialized() = true, getPoolKey() = (IMD, MARG, 12500, 60, hook); the Intake's priceOf(action, IMD) is 0.5 IMD, under MAX_PRICE. No Slither or Mythril run. For the manifest step: the bytes32 constructor argument is written as the static word 0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000, and the three addresses as static words (none is $owner).","line":119,"path":"src/MarginaliaPages.sol","reproduction":"Not a defect; the record of what was read and verified.","severity":"info","snippet":"    constructor(IMarginaliaHookPages hook_, IIntake intake_, bytes32 action_, address signer_)","title":"Review scope, launch checks and live-constant verification"}],"hash":"d14e760cc3202a1df8c90820200461b20c944d69cd41244f365baae51ede7661","nodeId":"03a154fc-6a24-43c1-afe0-245603ae6434","outcome":"completed","summary":"The review is complete. No tracked file was changed; the findings are in `.imd-findings.json` at the repository root, and the proof tests live under `test/scratch/`, which is ignored.\n\n**Outcome: one high, one medium, two low, two info findings on MarginaliaPages.** The local suite passes 12/12 and the launch-level checks (runtime size, forbidden opcodes, constructor purity, EIP-712 vector, callback selector, 200k stipend) all pass.\n\n**High: the claim question binds the tweet to nothing.** The panel is asked for \"the single Ethereum address written in the text field\" of any tweet by the handle. Any handle that ever tweeted one address (a token contract, a donation wallet, a scammer it warned about) can be claimed by a stranger to that address, permanently, with the oracle fee reimbursed from escrow. The repository's own probe is the concrete case: the tweet by @bddnewstoday names the MARG token contract, so `requestClaim(\"bddnewstoday\", 2109295512424009991)` sends that handle's escrow and all future issuer fees to a token contract forever. Proof: `test/scratch/PagesClaimBinding.t.sol` (fails now, passes once the question requires the tweet to name this contract).\n\n**Medium: every sell needs a successful MARG buy on the launch pool.** The burn swap must consume exactly its input and return MARG, and the hook's afterSwap reverts on a partial fill. With no in-range liquidity, or a burn larger than the pool absorbs, sells revert while the reserve sits untouched. Nothing locks the launch position. Proof: `test/scratch/PagesExitNeedsPool.t.sol`.\n\n**Low:** the burn swap has no slippage bound (sandwichable on deep trades), and `amount` is silently truncated to uint64 when updating supply (unreachable in practice, but unchecked).\n\n**Info:** the callback trusts the Intake's routing entirely (no `questionHash` or request-id binding, same documented limit as the Judge), plus the scope record.\n\n**Verified live over RPC:** the hook at 0xf0457dd0…a0cc reports the IMD token, MARG, the canonical PoolManager, the Intake, the EOA signer and the action bytes32 exactly as the brief states, its pool is initialized at fee 12500, and the Intake quotes 0.5 IMD, under `MAX_PRICE`.\n\n**Read in full:** MarginaliaPages, OracleAttestation, IIntake, Marginalia, Pages.t.sol, Fixture. **Read on the dependent paths only:** MarginaliaHook (quiet-buy swap callbacks, fundPot, ACT_FUND unlock, getPoolKey) and MarginaliaJudge (oracle request/callback). **Not read:** Router, Treasury, Pricer, Types, HookFlags, Impls, and the live Intake and IMD token sources. No Slither or Mythril was run.","treeHash":null,"usage":{"cachedInputTokens":1603245,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":53063,"runtime":"claude","turns":30,"wallClockMs":1418375}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"9b06782c7559b54c","findings":[{"citation":"resolved","description":"Boundary (sentinel-address branch, Boundary guide step 4): payeeOf(subject) returns address(uint160(subject)) for every subject whose top 96 bits are zero, with no exclusion for address(this), the hook, or any other contract that cannot act on IMD. subjectOf(address(pages)) therefore has payee == address(pages) and _distributeFee does IERC20(imd).safeTransfer(address(this), toIssuer): a self-transfer that leaves 90% of every fee of that subject inside Pages, counted in no reserveOf, no escrow and not in pendingBurn. No function can ever move it (there is no sweep, and the only outflows are the reserve, escrow and pendingBurn paths). subjectOf(address(hook)) sends the 90% to the hook as a raw ERC-20 balance, bypassing fundPot/_accrue: the hook pays pools only from ERC-6909 claims it minted, so that IMD is likewise unreachable (the live hook holds 0 raw IMD today). Impact is bounded to the fee the trader chose to pay on a nonsensical subject, so this is a low, but the invariant the existing fuzz test asserts (balance == sum reserves + escrow + pendingBurn) silently breaks for these subjects. Fix: in payeeOf (or buy/sell) refuse address subjects equal to address(this) and address(hook) (BadClaim), or route them to the escrow/recycle path.","line":233,"path":"src/MarginaliaPages.sol","reproduction":"Local fixture (test/helpers/Fixture.sol), fresh MarginaliaPages on the local hook. (1) subject = pages.subjectOf(address(pages)); pages.payeeOf(subject) == address(pages). (2) alice: pages.buy(subject, 1, max): value 0.1e18, fee 0.01e18, toIssuer 0.009e18, toBurn 0.0005e18, toPools 0.0005e18. Expected: contract IMD balance == reserveOf + escrow + pendingBurn (the invariant test/PagesAudit.t.sol asserts). Actual: imd.balanceOf(pages) = 0.1095e18, reserveOf+pendingBurn = 0.1005e18, 0.009e18 unaccounted. (3) alice: pages.sell(subject, 1, 0): reserve 0, pendingBurn 0.001e18, contract balance 0.019e18: 0.018e18 IMD stranded forever. Same call with subject = pages.subjectOf(address(hook)): hook raw IMD balance +0.009e18, pools (refundPool+thesisPool) only +0.0005e18. Verified with test/scratch/SelfPayee.t.sol (both tests pass on current code, i.e. the stranding happens).","severity":"low","snippet":"            IERC20(imd).safeTransfer(payee, toIssuer);","title":"Issuer share of an address subject that is the Pages contract or the hook is self-transferred and stranded outside every accounted balance"},{"citation":"resolved","description":"Boundary (caller-supplied parameter without an on-chain bound, Boundary guide step 2 item 10). The comment at lines 391-392 says 'The caller chooses a meaningful floor from an independent quote', but the function is permissionless, so the floor is chosen by whoever wants the burn to execute badly: a front-runner who first buys MARG with a large IMD amount, then calls burnPending(pendingBurn, 1), then sells back. The contract has margPriceInImd() on the hook and the pool's slot0 available but never checks the received MARG against them. Measured on the fixture pool (10M liquidity at 1:1, 1.25% LP fee, 3% quiet-sell hook fee), with 2,250.75 IMD pending: an honest burn receives 2,222.12 MARG; after a 2,000,000 IMD front-run it receives 1,549.65 MARG (30% less burned). At this depth the sandwicher loses 103,642 IMD to LP and hook fees, so the attack is pure griefing here; it becomes profitable only when the pending tranche is a few percent of pool depth, and pendingBurn accumulates without bound until someone burns it. Severity low: no reserve, escrow or holder funds are at risk (the IMD still enters the pool), only the amount of MARG actually burned. Fix: bound the output on chain, e.g. require marg >= imdIn * 1e18 / hook.margPriceInImd() * (10_000 - MAX_IMPACT_BPS) / 10_000 inside unlockCallback, and/or cap a tranche relative to pool liquidity.","line":396,"path":"src/MarginaliaPages.sol","reproduction":"Fixture pool; carol's address subject. (1) alice buys 3000 pages: pendingBurn = 2,250.75 IMD. (2) Snapshot: burnPending(2250.75e18, 1) alone burns 2,222.12 MARG (fair). Revert snapshot. (3) bob: plain.swap(key, IMD->MARG, 2_000_000e18) then burnPending(2250.75e18, 1) then plain.swap back: MARG burned = 1,549.65 (expected: close to 2,222; actual: 30% less), bob's IMD delta = -103,642 IMD (griefing cost at this depth). Numbers from test/scratch/BurnSandwich.t.sol logs.","severity":"low","snippet":"        if (minMargOut == 0) revert Slippage();","title":"burnPending's only execution-quality floor is the permissionless caller's minMargOut, so any caller may execute the burn at an arbitrary price (floor 1 wei)"},{"citation":"resolved","description":"Boundary (zero input). The brief says the asker pays 'the Intake's current price ... refused above MAX_PRICE 1 IMD'. The code also refuses price == 0. If the Intake ever prices oracle.request@oracle-1 at 0 for IMD (a promotion, or the action version retired and re-added free), no claim can be requested, escrows keep accumulating and are recycled into the hook's pools after 90 days, and the handle owners never get their share. Today the live Intake returns 0.5e18 for this action and IMD, so this is informational. A zero price needs no transferFrom and no approval; the branch could simply skip them.","line":306,"path":"src/MarginaliaPages.sol","reproduction":"test/Pages.t.sol testPriceGuardAndAddressSubjectsNeedNoClaim already shows it: intake.setPrice(0); carol: pages.requestClaim('pricey', 1) reverts PriceMismatch. Expected per brief: a claim at the Intake's current price (0); actual: refused.","severity":"info","snippet":"        if (price == 0 || price > MAX_PRICE) revert PriceMismatch();","title":"requestClaim refuses a zero Intake price, which the brief does not ask for: a free oracle action makes every handle permanently unclaimable"}],"hash":"e2672db8113049dd167de58201a11d103c85ade6700604027b6220ee55dc37e8","nodeId":"e9cbd83e-293f-4afa-b244-db130bf5964b","outcome":"completed","summary":"The review is complete. The findings file is written and validated, and no tracked files were changed.\n\n**Result: no critical, high or medium defect in the Pages math.** The bonding curve and fee splits are integer-exact: the n-th page price sum a(2s+a+1)/2 is always even, every trade value is a multiple of 0.1 IMD, so the 10% fee and its 90/5/5 split leave zero dust, and the reserve equals priceOf(0, supply) after any sequence of buys and sells. The oracle callback needs 157,579 gas in the worst cold case against an OpenZeppelin-style token, inside the 200k stipend, and the live IMD token's transfer cost matches that model. The live hook at the given address has the same bytecode length as this repository's hook, exposes fundPot and poolManager, and holds the Intake, action and signer constants the brief names, and the Intake prices the action at 0.5 IMD today.\n\nThree findings were recorded in `.imd-findings.json`, all reproduced locally:\n\n- **Low:** an address subject equal to the Pages contract or the hook sends the 90% issuer share to itself or to the hook's raw balance, where no function can ever reach it. Buying one page of the contract's own subject strands 0.009 IMD and breaks the balance invariant the existing fuzz test asserts.\n- **Low:** the burn's only price floor is the permissionless caller's own parameter. A front-run of 2,000,000 IMD cut the burned MARG by 30% in the fixture, though the attacker lost 103,642 IMD to fees at that depth, so it is griefing rather than profit today.\n- **Info:** a zero Intake price is refused although the brief only caps it at 1 IMD, which would make every handle unclaimable if the action were ever free.\n\nCoverage lists all 41 listed entry points plus three invariant rows. Every Pages entry point, the hook's fundPot, unlockCallback, beforeSwap and afterSwap paths that Pages exercises, and the token are traced. The remaining hook, judge, router and treasury functions are marked unreached as they lie outside the assigned area.","treeHash":null,"usage":{"cachedInputTokens":1770858,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":48820,"runtime":"claude","turns":34,"wallClockMs":1133462}},{"artifacts":[],"attempt":2,"bundleHash":"5996c5baea82036842f146013aa37549d3acb74f56d16245ac7ab7fea700de53","device":"de319b702da6aa2e","findings":[],"hash":"fab8838ce9317d5c419da4cfa005ae69d0e8a9d20049cb74f6261b6aec7b6382","nodeId":"0ae19a5b-0de8-4d38-a624-f0912d65a276","outcome":"completed","summary":"I've fixed the reopened burn-sandwich finding, three of the five advisory findings, and answered all six in `.imd-responses.json`. `forge build` passes, and `forge test` gives 285 passed, 0 failed and 2 skipped (the two optional fork suites, which skip without an RPC URL). Nothing is committed.\n\n**Burn sandwich (b28cbca9, medium): reproduced and fixed.** On the reviewer's pool the old code gave the attacker exactly the reported profits: +49.65, +78.76, +102.29 and +126.62 IMD for attacks of 400, 700, 1,000 and 1,400 IMD.\n- **The fix:** `burnPending` now runs at most one burn per block. Its swap stops where MARG's price is 1% (`MAX_BURN_IMPACT_BPS`) above where it started, instead of having no limit. If the band is reached first, the leftover IMD stays queued for a later block.\n- **Why it works:** a sandwich can now gain at most about 1% on its own volume, but pays two 1.25% pool fees plus the hook's 3% sell fee. The same four attacks now lose 17.68, 30.72, 43.62 and 60.60 IMD. A scratch fuzz of 3,000 runs (attacks of 1 to 2,000 IMD, three pool shapes) found no profitable sandwich.\n- **What I ruled out:** my first version let the band restart within a block. My own test showed an attacker could profit (+49.3 IMD) by selling into the burn and triggering it again, so the rule is strictly one burn per block.\n- **What's left:** someone who controls several blocks in a row could stack several 1% bands. Someone can also spend a block's single burn on a tiny amount, which delays the burn but cannot divert the IMD. Both are written up in the README.\n- **Every existing number is unchanged.** The 1% limit is a new constant.\n\n**Advisory findings:**\n- **Claim callback gas (f2228aa4): fixed.** The oracle callback now only checks and records the answer, with no token transfers: 105,843 gas against the 200,000 limit. A new function anyone can call, `settleClaim(subject)`, pays out the escrow minus the refunded oracle price, with the same amounts as before. From the moment the answer lands, trades pay the new payee directly and the escrow can't be recycled. This means a successful claim now takes a second transaction to pay out. Four existing tests now call `settleClaim` before checking balances, with unchanged amounts.\n- **Market/hook as subject (8a9e9350): fixed.** If the subject's address is the Pages contract or the hook, its 90% issuer share now goes into escrow and is later recycled to the pools, instead of being stuck. An oracle answer naming either counts as a failed claim.\n- **Dust burn (e209caca): fixed.** A burn too small to buy any MARG now fails with its own `BurnTooSmall` error instead of the misleading `UnauthorizedCallback`.\n- **Recycle race (0680ae89): disputed, no code change.** It reproduces, but the brief sets the rule: escrow becomes recyclable 90 days after the first buy. The README now tells handle owners to claim early.\n- **Fixed oracle settings (8681a890): disputed as a defect, no code change.** It's accurate, but the brief requires the four stored values and no owner. The consequences of a signer key change or retired oracle action are now in the README.\n\n**Other checks:**\n- **Launch check:** the launch's own deployment check (copied from the task's read-only inputs) passes against the new bytecode with the four constructor arguments. The deployed code is 16,944 bytes, under the 24,576 limit, and has no forbidden opcodes.\n- **Mainnet fork:** the fork tests passed 2/2 against the live hook, IMD and Intake via `https://ethereum-rpc.publicnode.com`. The local RPC used in the first round was no longer running.\n\nThe source change is all in `src/MarginaliaPages.sol`, with the new tests in `test/PagesReview.t.sol`. `ADAPTATION.md` and `README.md` describe the changes.","treeHash":"d3981e86bdcfb6ec87a4cc10efbe607706ace350","usage":{"cachedInputTokens":7432975,"inputTokens":104,"model":"claude-opus-5-5","outputTokens":70105,"runtime":"claude","turns":55,"wallClockMs":2122524}}],"verification":[{"checks":[{"durationMs":279611,"exitCode":0,"name":"build","output":"Compiling 124 files with Solc 0.8.26\nSolc 0.8.26 finished in 279.32s\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[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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaPages.sol:158:17\n    │\n158 │                 revert BadHandle();\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/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-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:244:13\n    │\n244 │             hook.fundPot(toPools);\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:206:9\n    │\n206 │         emit Trade(subject, msg.sender, true, amount, value, fee, s.supply);\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/MarginaliaPages.sol:221:9\n    │\n221 │         emit Trade(subject, msg.sender, false, amount, value, fee, s.supply);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:235:53\n    │\n235 │             if (s.escrowSince == 0) s.escrowSince = 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/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[reentrancy-no-eth]: external call can be reentered before `claims` is updated\n    ╭▸ src/MarginaliaPages.sol:309:21\n    │\n309 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n310 │ ┃             action,\n311 │ ┃             bytes(questionBody(normalized, tweetId)),\n312 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n313 │ ┃             imd,\n314 │ ┃             price\n315 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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/MarginaliaPages.sol:320:9\n    │\n320 │         emit ClaimRequested(subject, requestId, msg.sender, tweetId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:318:63\n    │\n318 │         claims[subject] = Claim(requestId, msg.sender, price, 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/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-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:346:13\n    │\n346 │             emit ClaimFailed(subject, requestId);\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/MarginaliaPages.sol:359:9\n    │\n359 │         emit Claimed(subject, wallet, owed, reimbursed);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPages.sol:367:13\n    │\n367 │         if (block.timestamp < uint256(c.requestedAt) + ANSWER_DEADLINE) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:384:9\n    │\n384 │         hook.fundPot(amount);\n    │         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPages.sol:379:13\n    │\n379 │         if (block.timestamp < uint256(s.escrowSince) + CLAIM_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/MarginaliaPages.sol:385:9\n    │\n385 │         emit Recycled(subject, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:398:9\n    │\n398 │         hook.poolManager().unlock(abi.encode(imdIn, minMargOut));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:395:44\n    │\n395 │         if (imdIn > pendingBurn || imdIn > uint256(uint128(type(int128).max))) revert InsufficientBurn();\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/MarginaliaPages.sol:395:52\n    │\n395 │         if (imdIn > pendingBurn || imdIn > uint256(uint128(type(int128).max))) revert InsufficientBurn();\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/MarginaliaPages.sol:398:9\n    │\n398 │         hook.poolManager().unlock(abi.encode(imdIn, minMargOut));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\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[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:428:9\n    │\n428 │         emit Burned(imdIn, marg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:412:18\n    │\n412 │                 -int256(imdIn),\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/MarginaliaPages.sol:419:38\n    │\n419 │         if (inD >= 0 || outD <= 0 || uint256(-int256(inD)) != imdIn) revert UnauthorizedCallback();\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/MarginaliaPages.sol:420:24\n    │\n420 │         uint256 marg = uint256(uint128(outD));\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/MarginaliaPages.sol:420:32\n    │\n420 │         uint256 marg = uint256(uint128(outD));\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/MarginaliaPages.sol:426:9\n    │\n426 │         manager.settle();\n    │         ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/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[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[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[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[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":8136,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/PagesMainnet.t.sol:PagesMainnetTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 705.28µs (0.00ns 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 923.77µ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 9.99ms (4.04ms 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 17.49ms (9.60ms CPU time)\n\nRan 1 test for test/PagesDeployment.t.sol:PagesDeploymentTest\n[PASS] testFactoryDeploysOnlyPagesWithoutExistingChainState() (gas: 12065711)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 18.23ms (18.09ms 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 19.44ms (11.62ms 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 21.44ms (665.11µs CPU time)\n\nRan 12 tests for test/Pages.t.sol:PagesTest\n[PASS] testAbandonAfterDeadlineAndRecycleWaitsForPendingClaims() (gas: 2662900)\n[PASS] testBogusClaimCostsOnlyTheClaimantAndIsRetriable() (gas: 2411734)\n[PASS] testBuyPaysTheIssuerQueuesBoundedBurnAndFundsThePools() (gas: 668941)\n[PASS] testCurveIsLinear() (gas: 37344)\n[PASS] testEscrowThenOracleAttestedClaim() (gas: 3935373)\n[PASS] testHandleIsLowerCasedAndValidated() (gas: 63979)\n[PASS] testOnlyThePoolManagerMayCallBack() (gas: 37561)\n[PASS] testPriceGuardAndAddressSubjectsNeedNoClaim() (gas: 170731)\n[PASS] testRejectedAnswersDoNotCloseTheClaim() (gas: 2377793)\n[PASS] testSellReturnsTheCurveLessFeeAndPagesAreNotTransferable() (gas: 782680)\n[PASS] testSlippageAndNoCap() (gas: 615462)\n[PASS] testSmallEscrowIsPaidWithoutReimbursement() (gas: 1888094)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 43.89ms (9.28ms 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 47.43ms (29.35ms 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, μ: 22518, ~: 20080)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1945010)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204563)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 47.40ms (36.37ms 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 83.91ms (83.43ms 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 92.98ms (82.39ms 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 101.82ms (56.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 101.88ms (7.58ms 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 112.32ms (7.56ms 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 112.40ms (187.40ms CPU time)\n\nRan 6 tests for test/PagesOracle.t.sol:PagesOracleTest\n[PASS] testAbandonBoundaryInvalidatesOldRoutingAndAllowsRetry() (gas: 667767)\n[PASS] testAnswersForUnrequestedIdsAndOtherConsumersAreRefused() (gas: 3878569)\n[PASS] testColdCallbackPaysTwoFreshBalancesUnderStipendWithDistinctIds() (gas: 282027)\nLogs:\n  delivery gas including mock Intake overhead: 203394\n\n[PASS] testDigestMatchesProtocolVector() (gas: 14297)\n[PASS] testProtocolSignatureVerifiesUnchanged() (gas: 86052)\n[PASS] testSignedUuidCannotReplayAgainstAnotherPendingIntakeId() (gas: 742292)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 112.45ms (1.77ms 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, μ: 838159, ~: 838176)\nLogs:\n  Bound result 250000000000000001\n\n[PASS] testFuzzNotedInputLeavesExactlyQuarterImdForThePool(uint256) (runs: 1000, μ: 58952, ~: 58968)\nLogs:\n  Bound result 250000000000000000\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 120.34ms (219.18ms 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, ~: 106118)\nLogs:\n  Bound result 126\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 130.91ms (22.88ms 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 147.05ms (1.77ms 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 147.23ms (46.04ms CPU time)\n\nRan 10 tests for test/PagesAudit.t.sol:PagesAuditTest\n[PASS] testAbandonCannotReenterATrade() (gas: 2386917)\n[PASS] testBurnCannotSpendReserveOrEscrowAndRejectsZeroFloor() (gas: 705180)\n[PASS] testBurnFailureKeepsFundsAndCanResumeAfterLiquidityReturns() (gas: 1433838)\n[PASS] testBurnUsesCallerFloorAndManipulatedPriceCannotBlockTrading() (gas: 1017958)\n[PASS] testClaimInstructionChangesAcrossDeploymentsAndChains() (gas: 143720)\n[PASS] testClaimInstructionRequiresThisDeploymentAndChain() (gas: 3476847)\n[PASS] testEveryHolderCanExitAfterAllLiquidityIsWithdrawn() (gas: 1331251)\n[PASS] testFuzzReserveCoversAllHoldersWithQueuedBurns(uint16,uint16,uint16) (runs: 256, μ: 1219766, ~: 1257765)\nLogs:\n  Bound result 538\n  Bound result 788\n  Bound result 125\n\n[PASS] testPartialFillBurnRollsBackAndSmallerTranchesWork() (gas: 1297340)\n[PASS] testSupplyAndBalancesDoNotTruncateAboveUint64() (gas: 709869)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 147.12ms (141.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, μ: 130274, ~: 114658)\nLogs:\n  Bound result 16\n  Bound result 55613496089736688059\n  Bound result 264464191761863364130556460149\n  Bound result 966899090549794557\n  Bound result 851482182690440310177734957821\n  Bound result 333122696851384976005972299073\n  Bound result 649469263348983895549412\n  Bound result 647690298290650732698916240820\n  Bound result 29633376231344588896252309336\n  Bound result 160581219811887313314\n  Bound result 249680645377327\n  Bound result 21120665568091046\n  Bound result 1000000002\n  Bound result 106328323999074610728254\n  Bound result 840150811820758320542681639280\n  Bound result 389885335291734633067138516095\n  Bound result 999999999999999999999116437743\n  Bound result 664585839013950695257979097524\n  Bound result 14916610829\n  Bound result 102308102838493022371240261901\n  Bound result 120566026434478511969518850153\n  Bound result 797962289540374902419107465904\n  Bound result 281836751954644188618634494820\n  Bound result 999999999999999999999000001844\n  Bound result 49291105447986568407392977423\n  Bound result 164613033719334311245207057841\n  Bound result 36084860899551454245511\n  Bound result 169142291684465350023123776349\n  Bound result 172800416859096867448794154432\n  Bound result 999999999999999999999000000044\n  Bound result 999999999999999999999999999998\n  Bound result 503957353327339085977208561235\n  Bound result 946958530943013882311065913382\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36909, ~: 36938)\nLogs:\n  Bound result 115275\n  Bound result 11002\n  Bound result 41\n  Bound result 2400630265122203703687383\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141536, ~: 141885)\nLogs:\n  Bound result 687247697784139853184544418216\n  Bound result 1266412660322236585699451273204\n  Bound result 14213\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36752, ~: 36897)\nLogs:\n  Bound result 989119\n  Bound result 12\n  Bound result 2\n  Bound result 40393601615777331857018981\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23255, ~: 21542)\nLogs:\n  Bound result 1461446703485210103287273052103988822378723976689\n  Bound result 39614081257132168796771975168\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39606, ~: 38884)\nLogs:\n  Bound result 3085662557869407456901501805330143530183\n  Bound result 3675335185387145398576662629718278298157\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16165, ~: 14502)\nLogs:\n  Bound result 178\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 53890, ~: 51987)\nLogs:\n  Bound result 5332\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36415, ~: 36397)\nLogs:\n  Bound result 118\n  Bound result 5292\n  Bound result 2\n  Bound result 40393601615777331857018981\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18886, ~: 16591)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21367, ~: 21299)\nLogs:\n  Bound result 5048\n  Bound result 12296\n  Bound result 6864\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 63495, ~: 60538)\nLogs:\n  Bound result 6000\n  Bound result 3\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 100777, ~: 91838)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 1218626021010801080364452\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 147.18ms (1.12s 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        | 209   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 218   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 440   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 210   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 209   | 3       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 205   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 212   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 217   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1620\n  Bound result 1\n  Bound result 2000000000000000000000\n  Bound result 4096\n  Bound result 90\n  Bound result 1\n  Bound result 0\n  Bound result 1152921504606846975\n  Bound result 59139\n  Bound result 5\n  Bound result 0\n  Bound result 1269\n  Bound result 1\n  Bound result 50000000000000000000\n  Bound result 4973\n  Bound result 1\n  Bound result 1\n  Bound result 1261\n  Bound result 0\n  Bound result 37708281716\n  Bound result 3876\n  Bound result 29\n  Bound result 1\n  Bound result 0\n  Bound result 30000000000000000000\n  Bound result 8838\n  Bound result 40\n  Bound result 5000000000000000000000\n  Bound result 0\n  Bound result 112305878086378464\n  Bound result 0\n  Bound result 0\n  Bound result 11000\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 6449\n  Bound result 9000\n  Bound result 76\n  Bound result 0\n  Bound result 100000000000000000000\n  Bound result 33081\n  Bound result 79\n  Bound result 0\n  Bound result 13555\n  Bound result 55001\n  Bound result 16\n  Bound result 3\n  Bound result 0\n  Bound result 1\n  Bound result 15655\n  Bound result 2\n  Bound result 228\n  Bound result 2\n  Bound result 3183\n  Bound result 20149\n  Bound result 91\n  Bound result 1\n  Bound result 1000000000000000\n  Bound result 50257\n  Bound result 10\n  Bound result 0\n  Bound result 600\n  Bound result 2\n  Bound result 2\n  Bound result 2001\n  Bound result 2\n  Bound result 117300739\n  Bound result 3008\n  Bound result 0\n  Bound result 2975\n  Bound result 1\n  Bound result 10938\n  Bound result 1\n  Bound result 6745\n  Bound result 1548\n  Bound result 0\n  Bound result 155\n  Bound result 14566\n  Bound result 35\n  Bound result 0\n  Bound result 200180672591497932024\n  Bound result 50109\n  Bound result 0\n  Bound result 1\n  Bound result 7585\n  Bound result 50013\n  Bound result 43\n  Bound result 0\n  Bound result 212\n  Bound result 58569\n  Bound result 49\n  Bound result 0\n  Bound result 53\n  Bound result 1000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 531.58ms (523.37ms 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   | 2540  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2430  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2394  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2437  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2487  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 281\n  Bound result 67487\n  Bound result 13\n  Bound result 999999999999999999999999\n  Bound result 1666\n  Bound result 400000\n  Bound result 6000\n  Bound result 3167\n  Bound result 6931\n  Bound result 320\n  Bound result 384\n  Bound result 6142\n  Bound result 8745248984154165900885334782585\n  Bound result 6750\n  Bound result 1\n  Bound result 70\n  Bound result 1\n  Bound result 5698\n  Bound result 22685814125989351599235923974\n  Bound result 4030169805507390064\n  Bound result 976\n  Bound result 112838726185\n  Bound result 84077\n  Bound result 500000000000000001\n  Bound result 80780\n  Bound result 5400\n  Bound result 100000000000000000\n  Bound result 4000000000000000000\n  Bound result 6269\n  Bound result 3883923840\n  Bound result 122\n  Bound result 4831923615514126184\n  Bound result 489\n  Bound result 57468047504936032020328\n  Bound result 1238\n  Bound result 4000000000000000000\n  Bound result 5424\n  Bound result 40\n  Bound result 14373\n  Bound result 124\n  Bound result 1373611828468743159329371216018226462812469038028\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.35s (1.35s 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    | 508   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | advance           | 532   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | answerJudging     | 537   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | child             | 526   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimDeposit      | 538   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimRefund       | 509   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | fund              | 478   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | giftAndDrip       | 501   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | notedSell         | 528   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | observeSeries     | 493   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | payJudging        | 499   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | post              | 958   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | requestJudging    | 519   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | retract           | 564   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | seal              | 497   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | settle            | 508   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | sweep             | 513   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | trade             | 526   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | unauthorizedClaim | 506   | 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 3\n  Bound result 99999000000000000000282\n  Bound result 2\n  Bound result 99999000000000000020781\n  Bound result 98000000000000010754\n  Bound result 98000000000000000011\n  Bound result 152933\n  Bound result 19999999999999999980\n  Bound result 1\n  Bound result 1\n  Bound result 98000000000000156244\n  Bound result 8\n  Bound result 5\n  Bound result 6\n  Bound result 98\n  Bound result 1\n  Bound result 8\n  Bound result 99999000000000000000245\n  Bound result 98000000000000002401\n  Bound result 5\n  Bound result 98000000000000000958\n  Bound result 2\n  Bound result 611\n  Bound result 99999000000000000004726\n  Bound result 10\n  Bound result 7\n  Bound result 98000000000000006233\n  Bound result 1\n  Bound result 99999000000000000007567\n  Bound result 6\n  Bound result 99999000000000000018368\n  Bound result 98000000000008565803\n  Bound result 9750000000000007262\n  Bound result 5\n  Bound result 6\n  Bound result 99999000000000000000016\n  Bound result 3865423022304439599\n  Bound result 1\n  Bound result 3\n  Bound result 49999999999999999980\n  Bound result 13\n  Bound result 9\n  Bound result 12\n  Bound result 15\n  Bound result 98000000000000237144\n  Bound result 99999000000000000017501\n  Bound result 7\n  Bound result 12\n  Bound result 16\n  Bound result 16\n  Bound result 9750000000000022579\n  Bound result 12\n  Bound result 89582616721757000017\n  Bound result 15\n  Bound result 13\n  Bound result 7231\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.97s (7.97s CPU time)\n\nRan 26 test suites in 7.98s (11.64s CPU time): 278 tests passed, 0 failed, 2 skipped (280 total tests)\n","passed":true},{"durationMs":171,"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)\",\"MarginaliaPages.abandonClaim(bytes32)\",\"MarginaliaPages.burnPending(uint256,uint256)\",\"MarginaliaPages.buy(bytes32,uint256,uint256)\",\"MarginaliaPages.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaPages.recycle(bytes32)\",\"MarginaliaPages.requestClaim(string,uint256)\",\"MarginaliaPages.sell(bytes32,uint256,uint256)\",\"MarginaliaPages.unlockCallback(bytes)\",\"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\":11,\"ADAPTATION.md\":583,\"README.md\":268,\"SPEC.md\":286,\"app/app.js\":286,\"app/index.html\":126,\"app/style.css\":57,\"brand/banner-ledger-1500x500.png\":5801,\"brand/pfp-manicule-400.png\":1390,\"brand/pfp-manicule-800.png\":5292,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":94,\"helper/server.js\":90,\"helper/src/app.js\":257,\"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\":98,\"jobs/launch-C-pages.json\":34,\"jobs/launch-hook-v3.json\":43,\"jobs/oracle-claim-probe.json\":34,\"jobs/site-A-swarm.json\":27,\"keeper/.env.example\":27,\"keeper/.nvmrc\":1,\"keeper/.railwayignore\":3,\"keeper/README.md\":24,\"keeper/abi/erc20.json\":1,\"keeper/abi/factory.json\":1,\"keeper/abi/hook.json\":1,\"keeper/abi/judge.json\":1,\"keeper/abi/router.json\":1,\"keeper/package-lock.json\":222,\"keeper/package.json\":16,\"keeper/railway.json\":11,\"keeper/src/chain.js\":104,\"keeper/src/config.js\":53,\"keeper/src/db.js\":76,\"keeper/src/index.js\":89,\"keeper/src/sync.js\":90,\"keeper/src/tasks.js\":194,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":975,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPages.sol\":431,\"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/Pages.t.sol\":418,\"test/PagesAudit.t.sol\":300,\"test/PagesDeployment.t.sol\":61,\"test/PagesOracle.t.sol\":166,\"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/fork/PagesMainnet.t.sol\":79,\"test/helpers/Fixture.sol\":285,\"test/mocks/MockERC20.sol\":13},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":13559,"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/MarginaliaPages.sol:294: Reentrancy in MarginaliaPages.requestClaim(string,uint256) (src/MarginaliaPages.sol#294-321):\n[medium/medium] reentrancy-no-eth at src/MarginaliaPages.sol:196: Reentrancy in MarginaliaPages.buy(bytes32,uint256,uint256) (src/MarginaliaPages.sol#196-207):\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/MarginaliaPages.sol:401: MarginaliaPages.unlockCallback(bytes) (src/MarginaliaPages.sol#401-430) ignores return value by manager.settle() (src/MarginaliaPages.sol#426)\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[medium/medium] unused-return at src/MarginaliaPages.sol:393: MarginaliaPages.burnPending(uint256,uint256) (src/MarginaliaPages.sol#393-399) ignores return value by hook.poolManager().unlock(abi.encode(imdIn,minMargOut)) (src/MarginaliaPages.sol#398)\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/MarginaliaPages.sol:225: Reentrancy in MarginaliaPages._distributeFee(bytes32,MarginaliaPages.Subject,uint256) (src/MarginaliaPages.sol#225-246):\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/MarginaliaPages.sol:196: Reentrancy in MarginaliaPages.buy(bytes32,uint256,uint256) (src/MarginaliaPages.sol#196-207):\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-benign at src/MarginaliaPages.sol:294: Reentrancy in MarginaliaPages.requestClaim(string,uint256) (src/MarginaliaPages.sol#294-321):\n[low/medium] reentrancy-events at src/MarginaliaPages.sol:401: Reentrancy in MarginaliaPages.unlockCallback(bytes) (src/MarginaliaPages.sol#401-430):\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/","passed":true},{"durationMs":937,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/MarginaliaPages.sol:146: `abi.encodePacked()` Hash Collision (2 places)\n[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 (19 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 (3 places)\n[low] large-numeric-literal at src/Marginalia.sol:10: Large Numeric Literal (21 places)\n[low] literal-instead-of-constant at src/MarginaliaHook.sol:355: Literal Instead of Constant (56 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` (2 places)\n[low] state-change-without-event at src/MarginaliaHook.sol:835: State Change Without Event (7 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 (8 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 (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0cb45f1d4f5b9bca7dad7ec157ee4fdd8d7929cb4a3cf36cad0279db5fe74c13","verifiedTreeHash":"5e1f46bf23e70cdb5dd088999e3dddfb5f893dd2","verifierVersion":"0.1.0+fb8278c5"},{"checks":[],"detail":"checkout_base: fatal: reference is not a tree: 774273c50dff47cdb46d5512d350d3d1ef33bd34\n","evaluation":"checks","profile":"foundry","status":"error","submissionHash":"19938d50ccac28ea353fe795296a906188b1839cb22fe54067bd587932d73775","verifiedTreeHash":null,"verifierVersion":"0.1.0+fb8278c5"},{"checks":[{"durationMs":254602,"exitCode":0,"name":"build","output":"Compiling 124 files with Solc 0.8.26\nSolc 0.8.26 finished in 254.37s\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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaPages.sol:158:17\n    │\n158 │                 revert BadHandle();\n    │                 ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:244:13\n    │\n244 │             hook.fundPot(toPools);\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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/MarginaliaPages.sol:206:9\n    │\n206 │         emit Trade(subject, msg.sender, true, amount, value, fee, s.supply);\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/MarginaliaPages.sol:221:9\n    │\n221 │         emit Trade(subject, msg.sender, false, amount, value, fee, s.supply);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:235:53\n    │\n235 │             if (s.escrowSince == 0) s.escrowSince = 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-no-eth]: external call can be reentered before `claims` is updated\n    ╭▸ src/MarginaliaPages.sol:309:21\n    │\n309 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n310 │ ┃             action,\n311 │ ┃             bytes(questionBody(normalized, tweetId)),\n312 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n313 │ ┃             imd,\n314 │ ┃             price\n315 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:320:9\n    │\n320 │         emit ClaimRequested(subject, requestId, msg.sender, tweetId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:318:63\n    │\n318 │         claims[subject] = Claim(requestId, msg.sender, price, 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/MarginaliaPages.sol:346:13\n    │\n346 │             emit ClaimFailed(subject, requestId);\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/MarginaliaPages.sol:359:9\n    │\n359 │         emit Claimed(subject, wallet, owed, reimbursed);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPages.sol:367:13\n    │\n367 │         if (block.timestamp < uint256(c.requestedAt) + ANSWER_DEADLINE) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:384:9\n    │\n384 │         hook.fundPot(amount);\n    │         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPages.sol:379:13\n    │\n379 │         if (block.timestamp < uint256(s.escrowSince) + CLAIM_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/MarginaliaPages.sol:385:9\n    │\n385 │         emit Recycled(subject, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:398:9\n    │\n398 │         hook.poolManager().unlock(abi.encode(imdIn, minMargOut));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:395:44\n    │\n395 │         if (imdIn > pendingBurn || imdIn > uint256(uint128(type(int128).max))) revert InsufficientBurn();\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/MarginaliaPages.sol:395:52\n    │\n395 │         if (imdIn > pendingBurn || imdIn > uint256(uint128(type(int128).max))) revert InsufficientBurn();\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/MarginaliaPages.sol:398:9\n    │\n398 │         hook.poolManager().unlock(abi.encode(imdIn, minMargOut));\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/MarginaliaPages.sol:428:9\n    │\n428 │         emit Burned(imdIn, marg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:412:18\n    │\n412 │                 -int256(imdIn),\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/MarginaliaPages.sol:419:38\n    │\n419 │         if (inD >= 0 || outD <= 0 || uint256(-int256(inD)) != imdIn) revert UnauthorizedCallback();\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/MarginaliaPages.sol:420:24\n    │\n420 │         uint256 marg = uint256(uint128(outD));\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/MarginaliaPages.sol:420:32\n    │\n420 │         uint256 marg = uint256(uint128(outD));\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/MarginaliaPages.sol:426:9\n    │\n426 │         manager.settle();\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: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[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: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[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[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/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/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":7162,"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 529.05µs (0.00ns CPU time)\n\nRan 1 test for test/fork/PagesMainnet.t.sol:PagesMainnetTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 715.54µ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.59ms (1.89ms CPU time)\n\nRan 6 tests for test/PagesOracle.t.sol:PagesOracleTest\n[PASS] testAbandonBoundaryInvalidatesOldRoutingAndAllowsRetry() (gas: 667767)\n[PASS] testAnswersForUnrequestedIdsAndOtherConsumersAreRefused() (gas: 3878569)\n[PASS] testColdCallbackPaysTwoFreshBalancesUnderStipendWithDistinctIds() (gas: 282027)\nLogs:\n  delivery gas including mock Intake overhead: 203394\n\n[PASS] testDigestMatchesProtocolVector() (gas: 14297)\n[PASS] testProtocolSignatureVerifiesUnchanged() (gas: 86052)\n[PASS] testSignedUuidCannotReplayAgainstAnotherPendingIntakeId() (gas: 742292)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 7.43ms (4.33ms 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 15.39ms (14.37ms 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 18.73ms (6.26ms 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 20.65ms (8.40ms 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 21.97ms (4.34ms CPU time)\n\nRan 1 test for test/PagesDeployment.t.sol:PagesDeploymentTest\n[PASS] testFactoryDeploysOnlyPagesWithoutExistingChainState() (gas: 12065711)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 28.29ms (28.06ms 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 28.92ms (12.29ms 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, μ: 21863, ~: 20080)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1945010)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204563)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 35.72ms (36.71ms 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 57.15ms (58.07ms 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 61.63ms (56.97ms 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 96.97ms (28.89ms CPU time)\n\nRan 10 tests for test/PagesAudit.t.sol:PagesAuditTest\n[PASS] testAbandonCannotReenterATrade() (gas: 2386917)\n[PASS] testBurnCannotSpendReserveOrEscrowAndRejectsZeroFloor() (gas: 705180)\n[PASS] testBurnFailureKeepsFundsAndCanResumeAfterLiquidityReturns() (gas: 1433838)\n[PASS] testBurnUsesCallerFloorAndManipulatedPriceCannotBlockTrading() (gas: 1017958)\n[PASS] testClaimInstructionChangesAcrossDeploymentsAndChains() (gas: 143720)\n[PASS] testClaimInstructionRequiresThisDeploymentAndChain() (gas: 3476847)\n[PASS] testEveryHolderCanExitAfterAllLiquidityIsWithdrawn() (gas: 1331251)\n[PASS] testFuzzReserveCoversAllHoldersWithQueuedBurns(uint16,uint16,uint16) (runs: 256, μ: 1209989, ~: 1258082)\nLogs:\n  Bound result 2\n  Bound result 5\n  Bound result 0\n\n[PASS] testPartialFillBurnRollsBackAndSmallerTranchesWork() (gas: 1297340)\n[PASS] testSupplyAndBalancesDoNotTruncateAboveUint64() (gas: 709869)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 104.56ms (96.90ms 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, μ: 105971, ~: 106113)\nLogs:\n  Bound result -11438\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 116.26ms (119.56ms 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 117.70ms (152.79ms 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 117.82ms (36.28ms 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 121.05ms (78.91ms CPU time)\n\nRan 12 tests for test/Pages.t.sol:PagesTest\n[PASS] testAbandonAfterDeadlineAndRecycleWaitsForPendingClaims() (gas: 2662900)\n[PASS] testBogusClaimCostsOnlyTheClaimantAndIsRetriable() (gas: 2411734)\n[PASS] testBuyPaysTheIssuerQueuesBoundedBurnAndFundsThePools() (gas: 668941)\n[PASS] testCurveIsLinear() (gas: 37344)\n[PASS] testEscrowThenOracleAttestedClaim() (gas: 3935373)\n[PASS] testHandleIsLowerCasedAndValidated() (gas: 63979)\n[PASS] testOnlyThePoolManagerMayCallBack() (gas: 37561)\n[PASS] testPriceGuardAndAddressSubjectsNeedNoClaim() (gas: 170731)\n[PASS] testRejectedAnswersDoNotCloseTheClaim() (gas: 2377793)\n[PASS] testSellReturnsTheCurveLessFeeAndPagesAreNotTransferable() (gas: 782680)\n[PASS] testSlippageAndNoCap() (gas: 615462)\n[PASS] testSmallEscrowIsPaidWithoutReimbursement() (gas: 1888094)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 121.14ms (10.75ms 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 121.25ms (510.88µs 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, μ: 838166, ~: 838176)\nLogs:\n  Bound result 9750000000000000086\n\n[PASS] testFuzzNotedInputLeavesExactlyQuarterImdForThePool(uint256) (runs: 1000, μ: 58959, ~: 58968)\nLogs:\n  Bound result 9750000000000000319\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 126.84ms (215.37ms 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, μ: 128124, ~: 101845)\nLogs:\n  Bound result 4\n  Bound result 147530491195717072705658862629\n  Bound result 266089656772766543552057192539\n  Bound result 413567450346554648772191154736\n  Bound result 956970646055824511486275032660\n  Bound result 884718792784862078\n  Bound result 770300264960786895806654727512\n  Bound result 252274625570527139677059352229\n  Bound result 999999999999999999999000000202\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36927, ~: 36996)\nLogs:\n  Bound result 9992003\n  Bound result 11000\n  Bound result 1\n  Bound result 552691790224321108210492048537\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141443, ~: 141832)\nLogs:\n  Bound result 830729559070812284840438075833\n  Bound result 290472660253308476603606068057\n  Bound result 12009\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36741, ~: 36876)\nLogs:\n  Bound result 13320\n  Bound result 1\n  Bound result 20\n  Bound result 28800\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23251, ~: 21542)\nLogs:\n  Bound result 100000000000000000001\n  Bound result 1461446703485210103287273052103988822378723975094\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39551, ~: 39004)\nLogs:\n  Bound result 5557425729203426461259519600097268560812\n  Bound result 1917088554149\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16091, ~: 14429)\nLogs:\n  Bound result 165\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 53743, ~: 51987)\nLogs:\n  Bound result 997\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36415, ~: 36404)\nLogs:\n  Bound result 4320\n  Bound result 1000\n  Bound result 20\n  Bound result 28800\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18681, ~: 16761)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21346, ~: 21299)\nLogs:\n  Bound result 5192296858534827628530496329220095\n  Bound result 5192296858534827628530496329220095\n  Bound result 4659\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 62735, ~: 58038)\nLogs:\n  Bound result 61396\n  Bound result 16\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 100233, ~: 91671)\nLogs:\n  Bound result 1\n  Bound result 662692669726061643139652125654\n  Bound result 252\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 126.85ms (1.20s 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        | 241   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 205   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 418   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 211   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 195   | 3       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 217   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 212   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 221   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 1374255301884990083034\n  Bound result 53585\n  Bound result 44\n  Bound result 2\n  Bound result 252\n  Bound result 49601\n  Bound result 12\n  Bound result 0\n  Bound result 0\n  Bound result 1470548450400182098972\n  Bound result 57787\n  Bound result 11\n  Bound result 2\n  Bound result 8192\n  Bound result 50056\n  Bound result 4\n  Bound result 1\n  Bound result 13079\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 13\n  Bound result 2\n  Bound result 75000000000000000000\n  Bound result 2\n  Bound result 9954\n  Bound result 2\n  Bound result 500000000000000000000\n  Bound result 2\n  Bound result 10000\n  Bound result 56193\n  Bound result 86\n  Bound result 1\n  Bound result 14100\n  Bound result 0\n  Bound result 1390054571271235490\n  Bound result 31956\n  Bound result 13\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 600\n  Bound result 50016\n  Bound result 24\n  Bound result 1\n  Bound result 0\n  Bound result 23937420551000397919735\n  Bound result 2\n  Bound result 400000\n  Bound result 13923\n  Bound result 26\n  Bound result 4872\n  Bound result 1\n  Bound result 43563350896162705710252\n  Bound result 120\n  Bound result 1\n  Bound result 2109295512424009991\n  Bound result 2\n  Bound result 0\n  Bound result 125\n  Bound result 77\n  Bound result 4\n  Bound result 0\n  Bound result 1540\n  Bound result 2\n  Bound result 7656\n  Bound result 4767\n  Bound result 48\n  Bound result 2\n  Bound result 40470119486054760199303\n  Bound result 1860\n  Bound result 1\n  Bound result 900\n  Bound result 54184\n  Bound result 3\n  Bound result 3368671859121715175794\n  Bound result 1\n  Bound result 0\n  Bound result 16436\n  Bound result 2\n  Bound result 1\n  Bound result 10000\n  Bound result 2\n  Bound result 654082465424432199891\n  Bound result 7\n  Bound result 5\n  Bound result 1\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 466.22ms (450.63ms 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   | 2418  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2410  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2448  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2461  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2551  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 856\n  Bound result 868\n  Bound result 16777216\n  Bound result 168658\n  Bound result 2307\n  Bound result 15\n  Bound result 9285380274899124224\n  Bound result 6090\n  Bound result 8936\n  Bound result 103969\n  Bound result 5780\n  Bound result 64\n  Bound result 5707\n  Bound result 1000000000000000000000000\n  Bound result 500000000000000000000\n  Bound result 172558\n  Bound result 600\n  Bound result 10\n  Bound result 5009\n  Bound result 2903807060280344574\n  Bound result 9379\n  Bound result 1829332848658377190\n  Bound result 8\n  Bound result 5270\n  Bound result 240\n  Bound result 10000000000000000000000000\n  Bound result 2748\n  Bound result 7035\n  Bound result 108118959529514860835200\n  Bound result 2755\n  Bound result 8294\n  Bound result 757\n  Bound result 255\n  Bound result 3450829853099908082\n  Bound result 1945371970366175622662\n  Bound result 12517\n  Bound result 1450945\n  Bound result 259199\n  Bound result 6455\n  Bound result 3241218212765563463\n  Bound result 826074470\n  Bound result 49811\n  Bound result 887220\n  Bound result 6931\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.06s (1.05s 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    | 494   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | advance           | 483   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | answerJudging     | 476   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | child             | 526   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimDeposit      | 534   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimRefund       | 482   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | fund              | 538   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | giftAndDrip       | 520   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | notedSell         | 532   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | observeSeries     | 487   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | payJudging        | 516   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | post              | 1010  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | requestJudging    | 513   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | retract           | 516   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | seal              | 534   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | settle            | 513   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | sweep             | 517   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | trade             | 552   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | unauthorizedClaim | 497   | 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 259200\n  Bound result 2\n  Bound result 4\n  Bound result 60480000\n  Bound result 176307\n  Bound result 2\n  Bound result 2499999999999999990\n  Bound result 420000\n  Bound result 9750000004294988131\n  Bound result 36762445033683717132\n  Bound result 9750000000000005972\n  Bound result 7\n  Bound result 156081\n  Bound result 2\n  Bound result 1\n  Bound result 3\n  Bound result 98000000000000000065\n  Bound result 3\n  Bound result 6\n  Bound result 12285\n  Bound result 3\n  Bound result 8\n  Bound result 99999999999999999950\n  Bound result 15581\n  Bound result 9750000000000000095\n  Bound result 98000000000000023234\n  Bound result 7\n  Bound result 9750000000000019936\n  Bound result 8\n  Bound result 32\n  Bound result 2\n  Bound result 1234547799\n  Bound result 2\n  Bound result 9750000000000008372\n  Bound result 8423\n  Bound result 100000000000000000000000\n  Bound result 4\n  Bound result 4027\n  Bound result 16905\n  Bound result 7\n  Bound result 63999999999999998868\n  Bound result 4\n  Bound result 7739467576259600406\n  Bound result 10\n  Bound result 821\n  Bound result 99999000000000000015373\n  Bound result 98000000000000020718\n  Bound result 16628\n  Bound result 99999000000000000100001\n  Bound result 9750000000000000012\n  Bound result 24441864674355041054\n  Bound result 9750000000000015804\n  Bound result 997\n  Bound result 20207\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.05s (7.05s CPU time)\n\nRan 26 test suites in 7.05s (10.04s CPU time): 278 tests passed, 0 failed, 2 skipped (280 total tests)\n","passed":true},{"durationMs":179,"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)\",\"MarginaliaPages.abandonClaim(bytes32)\",\"MarginaliaPages.burnPending(uint256,uint256)\",\"MarginaliaPages.buy(bytes32,uint256,uint256)\",\"MarginaliaPages.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaPages.recycle(bytes32)\",\"MarginaliaPages.requestClaim(string,uint256)\",\"MarginaliaPages.sell(bytes32,uint256,uint256)\",\"MarginaliaPages.unlockCallback(bytes)\",\"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\":11,\"ADAPTATION.md\":583,\"README.md\":268,\"SPEC.md\":286,\"app/app.js\":286,\"app/index.html\":126,\"app/style.css\":57,\"brand/banner-ledger-1500x500.png\":5801,\"brand/pfp-manicule-400.png\":1390,\"brand/pfp-manicule-800.png\":5292,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":94,\"helper/server.js\":90,\"helper/src/app.js\":257,\"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\":98,\"jobs/launch-C-pages.json\":34,\"jobs/launch-hook-v3.json\":43,\"jobs/oracle-claim-probe.json\":34,\"jobs/site-A-swarm.json\":27,\"keeper/.env.example\":27,\"keeper/.nvmrc\":1,\"keeper/.railwayignore\":3,\"keeper/README.md\":24,\"keeper/abi/erc20.json\":1,\"keeper/abi/factory.json\":1,\"keeper/abi/hook.json\":1,\"keeper/abi/judge.json\":1,\"keeper/abi/router.json\":1,\"keeper/package-lock.json\":222,\"keeper/package.json\":16,\"keeper/railway.json\":11,\"keeper/src/chain.js\":104,\"keeper/src/config.js\":53,\"keeper/src/db.js\":76,\"keeper/src/index.js\":89,\"keeper/src/sync.js\":90,\"keeper/src/tasks.js\":194,\"launch.json\":15,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":975,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPages.sol\":431,\"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/Pages.t.sol\":418,\"test/PagesAudit.t.sol\":300,\"test/PagesDeployment.t.sol\":61,\"test/PagesOracle.t.sol\":166,\"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/fork/PagesMainnet.t.sol\":79,\"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":"578a448cb84ac2a402ca388c24acf88716618f1e200362295e05750273455012","verifiedTreeHash":"5957da2b802546459ebc82101194199dad0984aa","verifierVersion":"0.1.0+fb8278c5"},{"checks":[],"detail":"checkout_base: fatal: reference is not a tree: 774273c50dff47cdb46d5512d350d3d1ef33bd34\n","evaluation":"checks","profile":"foundry","status":"error","submissionHash":"87ee4bc12b5805697166284443a9c4b86ef7418b80720c9c3b7cd8d2bd6ebba9","verifiedTreeHash":null,"verifierVersion":"0.1.0+fb8278c5"},{"checks":[{"durationMs":311939,"exitCode":0,"name":"build","output":"Compiling 126 files with Solc 0.8.26\nSolc 0.8.26 finished in 311.69s\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[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[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[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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/MarginaliaPages.sol:158:17\n    │\n158 │                 revert BadHandle();\n    │                 ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\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[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-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:244:13\n    │\n244 │             hook.fundPot(toPools);\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:206:9\n    │\n206 │         emit Trade(subject, msg.sender, true, amount, value, fee, s.supply);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\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[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-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:221:9\n    │\n221 │         emit Trade(subject, msg.sender, false, amount, value, fee, s.supply);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:235:53\n    │\n235 │             if (s.escrowSince == 0) s.escrowSince = 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-no-eth]: external call can be reentered before `claims` is updated\n    ╭▸ src/MarginaliaPages.sol:309:21\n    │\n309 │           requestId = intake.request(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n310 │ ┃             action,\n311 │ ┃             bytes(questionBody(normalized, tweetId)),\n312 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n313 │ ┃             imd,\n314 │ ┃             price\n315 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:320:9\n    │\n320 │         emit ClaimRequested(subject, requestId, msg.sender, tweetId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:318:63\n    │\n318 │         claims[subject] = Claim(requestId, msg.sender, price, 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/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[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MarginaliaPages.sol:346:13\n    │\n346 │             emit ClaimFailed(subject, requestId);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\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/MarginaliaPages.sol:359:9\n    │\n359 │         emit Claimed(subject, wallet, owed, reimbursed);\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPages.sol:367:13\n    │\n367 │         if (block.timestamp < uint256(c.requestedAt) + ANSWER_DEADLINE) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\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-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/MarginaliaPages.sol:384:9\n    │\n384 │         hook.fundPot(amount);\n    │         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MarginaliaPages.sol:379:13\n    │\n379 │         if (block.timestamp < uint256(s.escrowSince) + CLAIM_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/MarginaliaPages.sol:385:9\n    │\n385 │         emit Recycled(subject, 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/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/MarginaliaPages.sol:398:9\n    │\n398 │         hook.poolManager().unlock(abi.encode(imdIn, minMargOut));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:395:44\n    │\n395 │         if (imdIn > pendingBurn || imdIn > uint256(uint128(type(int128).max))) revert InsufficientBurn();\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/MarginaliaPages.sol:395:52\n    │\n395 │         if (imdIn > pendingBurn || imdIn > uint256(uint128(type(int128).max))) revert InsufficientBurn();\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/MarginaliaPages.sol:398:9\n    │\n398 │         hook.poolManager().unlock(abi.encode(imdIn, minMargOut));\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/MarginaliaPages.sol:428:9\n    │\n428 │         emit Burned(imdIn, marg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MarginaliaPages.sol:412:18\n    │\n412 │                 -int256(imdIn),\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/MarginaliaPages.sol:419:38\n    │\n419 │         if (inD >= 0 || outD <= 0 || uint256(-int256(inD)) != imdIn) revert UnauthorizedCallback();\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/MarginaliaPages.sol:420:24\n    │\n420 │         uint256 marg = uint256(uint128(outD));\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/MarginaliaPages.sol:420:32\n    │\n420 │         uint256 marg = uint256(uint128(outD));\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/MarginaliaPages.sol:426:9\n    │\n426 │         manager.settle();\n    │         ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\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":7233,"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 574.79µ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 717.10µs (502.63µs CPU time)\n\nRan 6 tests for test/PagesOracle.t.sol:PagesOracleTest\n[PASS] testAbandonBoundaryInvalidatesOldRoutingAndAllowsRetry() (gas: 667767)\n[PASS] testAnswersForUnrequestedIdsAndOtherConsumersAreRefused() (gas: 3878569)\n[PASS] testColdCallbackPaysTwoFreshBalancesUnderStipendWithDistinctIds() (gas: 282027)\nLogs:\n  delivery gas including mock Intake overhead: 203394\n\n[PASS] testDigestMatchesProtocolVector() (gas: 14297)\n[PASS] testProtocolSignatureVerifiesUnchanged() (gas: 86052)\n[PASS] testSignedUuidCannotReplayAgainstAnotherPendingIntakeId() (gas: 742292)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 3.97ms (2.28ms CPU time)\n\nRan 1 test for test/fork/PagesMainnet.t.sol:PagesMainnetTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 3.41ms (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 7.45ms (6.16ms 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 12.94ms (7.27ms 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 18.04ms (6.69ms CPU time)\n\nRan 1 test for test/PagesDeployment.t.sol:PagesDeploymentTest\n[PASS] testFactoryDeploysOnlyPagesWithoutExistingChainState() (gas: 12065711)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 21.69ms (21.49ms 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.28ms (17.33ms 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 25.51ms (8.86ms 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, μ: 22599, ~: 20165)\n[PASS] testRetractingACallOnAnotherVenueBooksHalfAWrong() (gas: 1945010)\n[PASS] testSqrtFloorsSmallInputs() (gas: 9204563)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 27.45ms (22.25ms 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, μ: 105881, ~: 106088)\nLogs:\n  Bound result 2357\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 35.90ms (35.57ms 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 43.95ms (28.60ms 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 74.56ms (71.56ms 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 80.45ms (47.73ms CPU time)\n\nRan 23 tests for test/PagesEdges.t.sol:PagesEdgesTest\n[PASS] testAnyoneMayAbandonExactlyAtTheDeadlineAndTheAskerIsNotRefunded() (gas: 1554511)\n[PASS] testCallbackFromTheIntakeForAnotherConsumersRequestIsRefused() (gas: 2067158)\n[PASS] testClaimWithoutAnyEscrowSetsThePayeeAndLaterFeesGoDirect() (gas: 1953936)\n[PASS] testClaimedHandleIsClosedToEveryLaterClaimPath() (gas: 2036441)\n[PASS] testColdClaimAgainstTheRealHookFitsTheStipend() (gas: 2043457)\n[PASS] testConstructorRefusesEveryZeroInput() (gas: 9484)\n[PASS] testEscrowClockSurvivesAFailedClaimAndRecyclingTakesLaterFeesToo() (gas: 2524382)\n[PASS] testEscrowExactlyThePriceReimbursesAndPaysTheOwnerNothing() (gas: 1968517)\n[PASS] testEscrowOneWeiShortOfThePriceGoesWhollyToTheOwner() (gas: 1941381)\n[PASS] testFuzzCurveIsAdditiveAndEachPageCostsBaseTimesItsIndex(uint64,uint32,uint32) (runs: 1000, μ: 53890, ~: 54000)\nLogs:\n  Bound result 154395475549\n  Bound result 57713\n  Bound result 12208\n\n[PASS] testFuzzRoundTripAloneAlwaysLosesExactlyTheFees(uint16,uint16) (runs: 300, μ: 752223, ~: 765559)\nLogs:\n  Bound result 136\n  Bound result 1\n\n[PASS] testHandleLengthAndCharacterBoundaries() (gas: 127757)\n[PASS] testLargerPanelsAndQuorumsAreAccepted() (gas: 1516354)\n[PASS] testPanelThresholdsAtTheirBoundaries() (gas: 2293529)\n[PASS] testPriceBoundaryAcceptsExactlyOneImdAndRefusesOneWeiMore() (gas: 1544510)\n[PASS] testPriceOverflowRevertsInsteadOfWrapping() (gas: 66025)\n[PASS] testSellFeeIsSplitExactlyLikeABuyFee() (gas: 590581)\n[PASS] testSellingOutEmptiesTheCurveAndTheNextPageCostsBaseAgain() (gas: 774758)\n[PASS] testStrangersCannotCallTheCallbacksOrMoveValue() (gas: 1953324)\n[PASS] testSubjectsAreIndependentCurves() (gas: 992964)\n[PASS] testUpperCaseRequestClaimsTheLowerCaseSubjectAndAsksAboutTheLowerCaseHandle() (gas: 2018607)\n[PASS] testZeroAddressIssuerEscrowsAndCanOnlyBeRecycled() (gas: 879408)\n[PASS] testZeroAmountsAndOneWeiOfSlippageAreRefused() (gas: 668374)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 120.11ms (112.32ms 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 126.62ms (89.43ms 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 128.26ms (45.76ms CPU time)\n\nRan 12 tests for test/Pages.t.sol:PagesTest\n[PASS] testAbandonAfterDeadlineAndRecycleWaitsForPendingClaims() (gas: 2662900)\n[PASS] testBogusClaimCostsOnlyTheClaimantAndIsRetriable() (gas: 2411734)\n[PASS] testBuyPaysTheIssuerQueuesBoundedBurnAndFundsThePools() (gas: 668941)\n[PASS] testCurveIsLinear() (gas: 37344)\n[PASS] testEscrowThenOracleAttestedClaim() (gas: 3935373)\n[PASS] testHandleIsLowerCasedAndValidated() (gas: 63979)\n[PASS] testOnlyThePoolManagerMayCallBack() (gas: 37561)\n[PASS] testPriceGuardAndAddressSubjectsNeedNoClaim() (gas: 170731)\n[PASS] testRejectedAnswersDoNotCloseTheClaim() (gas: 2377793)\n[PASS] testSellReturnsTheCurveLessFeeAndPagesAreNotTransferable() (gas: 782680)\n[PASS] testSlippageAndNoCap() (gas: 615462)\n[PASS] testSmallEscrowIsPaidWithoutReimbursement() (gas: 1888094)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 128.73ms (12.26ms CPU time)\n\nRan 10 tests for test/PagesAudit.t.sol:PagesAuditTest\n[PASS] testAbandonCannotReenterATrade() (gas: 2386917)\n[PASS] testBurnCannotSpendReserveOrEscrowAndRejectsZeroFloor() (gas: 705180)\n[PASS] testBurnFailureKeepsFundsAndCanResumeAfterLiquidityReturns() (gas: 1433838)\n[PASS] testBurnUsesCallerFloorAndManipulatedPriceCannotBlockTrading() (gas: 1017958)\n[PASS] testClaimInstructionChangesAcrossDeploymentsAndChains() (gas: 143720)\n[PASS] testClaimInstructionRequiresThisDeploymentAndChain() (gas: 3476847)\n[PASS] testEveryHolderCanExitAfterAllLiquidityIsWithdrawn() (gas: 1331251)\n[PASS] testFuzzReserveCoversAllHoldersWithQueuedBurns(uint16,uint16,uint16) (runs: 256, μ: 1224305, ~: 1257740)\nLogs:\n  Bound result 1000\n  Bound result 309\n  Bound result 991\n\n[PASS] testPartialFillBurnRollsBackAndSmallerTranchesWork() (gas: 1297340)\n[PASS] testSupplyAndBalancesDoNotTruncateAboveUint64() (gas: 709869)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 128.84ms (112.33ms 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 131.30ms (164.84ms 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 131.81ms (1.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, μ: 131524, ~: 115292)\nLogs:\n  Bound result 14\n  Bound result 514264337593623178497920771838\n  Bound result 999999999999999999999000007720\n  Bound result 999999999999999999999000005957\n  Bound result 999999999999999999999000012273\n  Bound result 999999999999999999999000027038\n  Bound result 999999999999999999999000005555\n  Bound result 999999999999999999999000000836\n  Bound result 999999999999999999999000012472\n  Bound result 999999999999999999999000048880\n  Bound result 1099511627776\n  Bound result 999999999999999999999000031991\n  Bound result 907951651594334741017051742135\n  Bound result 999999999999999999999000000043\n  Bound result 999999999999999999999000023270\n  Bound result 999999999999999999999000003933\n  Bound result 2000000000000000000\n  Bound result 999999999999999999999000004380\n  Bound result 999999999999999999999000000009\n  Bound result 999999999999999999999000024236\n  Bound result 999999999999999999999000012501\n  Bound result 30000000000000000\n  Bound result 999999999999999999999000011540\n  Bound result 999999999999999999999000400001\n  Bound result 296858534827628535688329214903\n  Bound result 999999999999999999999000000261\n  Bound result 999999999999999999999000013126\n  Bound result 999999999999999999999000005478\n  Bound result 1064470260\n\n[PASS] testFuzzBuyDifficultyGrowsWithTheTarget(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36956, ~: 37007)\nLogs:\n  Bound result 9990190\n  Bound result 9989114\n  Bound result 2\n  Bound result 36821092777097356904638331009\n\n[PASS] testFuzzCheckpointKeepsStartAndWidensExtremes(uint160,uint160,uint256) (runs: 512, μ: 141503, ~: 141834)\nLogs:\n  Bound result 1266412668511742066691298552465\n  Bound result 1266412660308741483763937064508\n  Bound result 28796\n\n[PASS] testFuzzDifficultyFallsWithTheHorizon(uint32,uint16,uint16,uint256) (runs: 1000, μ: 36765, ~: 36900)\nLogs:\n  Bound result 989056\n  Bound result 68\n  Bound result 18\n  Bound result 20000000000000000000000\n\n[PASS] testFuzzFromSqrtIsMonotoneAndInverts(uint160,uint160) (runs: 1000, μ: 23271, ~: 21504)\nLogs:\n  Bound result 54933845692814916411780612294197277208572629\n  Bound result 1461446703485210103287273052103988822378724066398\n\n[PASS] testFuzzLog2IsBracketedAndMonotone(uint256,uint256) (runs: 1000, μ: 39478, ~: 38688)\nLogs:\n  Bound result 18430668395868694329365346742799910720\n  Bound result 701440855140002305260163596112033265194\n\n[PASS] testFuzzLog2IsExactAtPowersOfTwo(uint8) (runs: 512, μ: 16347, ~: 14648)\nLogs:\n  Bound result 172\n\n[PASS] testFuzzPostPriceWindowBoundaries(uint256,bool) (runs: 512, μ: 53833, ~: 51987)\nLogs:\n  Bound result 27490\n\n[PASS] testFuzzSellDifficultyGrowsAsTheTargetFalls(uint32,uint32,uint16,uint256) (runs: 1000, μ: 36425, ~: 36409)\nLogs:\n  Bound result 55\n  Bound result 1024\n  Bound result 18\n  Bound result 20000000000000000000000\n\n[PASS] testFuzzSqrtIsTheIntegerFloor(uint256) (runs: 1000, μ: 18617, ~: 16591)\n[PASS] testFuzzV2TwapOfAConstantRatioIsThatRatio(uint112,uint112,uint32,bool) (runs: 512, μ: 21367, ~: 21299)\nLogs:\n  Bound result 5192296858534827628530496329220093\n  Bound result 12772840593649592110673591\n  Bound result 229\n\n[PASS] testFuzzV3SettlementIgnoresMiddleReadings(int24,uint256[16],uint8,bool) (runs: 512, μ: 63628, ~: 60476)\nLogs:\n  Bound result 18200\n  Bound result 8\n\n[PASS] testFuzzV4SettlesOnTheExtremeOfEveryObservation(uint256[16],uint256[16],uint8) (runs: 1000, μ: 101145, ~: 91975)\nLogs:\n  Bound result 11\n  Bound result 100\n  Bound result 1000000000000000000000000000000\n  Bound result 150000000000000000\n  Bound result 16098\n  Bound result 16432\n  Bound result 1730\n  Bound result 79228162514264337593543950336\n  Bound result 4379\n  Bound result 25000000000000000000000000\n  Bound result 25\n  Bound result 3409\n  Bound result 7121\n  Bound result 864000\n  Bound result 23269\n  Bound result 3595\n  Bound result 1000000000000000000000000\n  Bound result 11000\n  Bound result 5555\n  Bound result 1300000000000000000\n  Bound result 7591\n  Bound result 999999999999999999999999999999\n  Bound result 22654\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 131.75ms (1.21s 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, μ: 838169, ~: 838176)\nLogs:\n  Bound result 9750000000000000859\n\n[PASS] testFuzzNotedInputLeavesExactlyQuarterImdForThePool(uint256) (runs: 1000, μ: 58962, ~: 58968)\nLogs:\n  Bound result 5107948921360346381\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 131.82ms (182.34ms 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        | 232   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | checkpoint     | 234   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteBuy        | 384   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | noteSell       | 237   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainBuy       | 224   | 2       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | plainSell      | 210   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | strayCallbacks | 191   | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| RouterHandler | thesis         | 208   | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 70\n  Bound result 0\n  Bound result 1\n  Bound result 48832021167430040737722\n  Bound result 1\n  Bound result 1\n  Bound result 1341\n  Bound result 3567\n  Bound result 6\n  Bound result 0\n  Bound result 1\n  Bound result 1184796774\n  Bound result 0\n  Bound result 0\n  Bound result 4096\n  Bound result 50013\n  Bound result 45\n  Bound result 0\n  Bound result 112\n  Bound result 12439\n  Bound result 23\n  Bound result 1\n  Bound result 1\n  Bound result 1733703501335536934730\n  Bound result 2\n  Bound result 23148\n  Bound result 16448\n  Bound result 0\n  Bound result 4325465634695161230826\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 1972971872141599964102\n  Bound result 7149\n  Bound result 15\n  Bound result 1\n  Bound result 0\n  Bound result 6931\n  Bound result 2\n  Bound result 2000000000000000000000\n  Bound result 50033\n  Bound result 7\n  Bound result 2\n  Bound result 12462\n  Bound result 2764\n  Bound result 1\n  Bound result 1\n  Bound result 904\n  Bound result 1\n  Bound result 2\n  Bound result 34827629454932861907436\n  Bound result 1\n  Bound result 385\n  Bound result 50071\n  Bound result 2\n  Bound result 1\n  Bound result 1020836872769517884543\n  Bound result 4467\n  Bound result 89\n  Bound result 3589\n  Bound result 2\n  Bound result 832792102268038764140\n  Bound result 4997\n  Bound result 30\n  Bound result 5217\n  Bound result 4079\n  Bound result 1000000000000\n  Bound result 0\n  Bound result 0\n  Bound result 12415\n  Bound result 13967\n  Bound result 98\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3083\n  Bound result 55577\n  Bound result 11\n  Bound result 0\n  Bound result 500000000000000000000\n  Bound result 334\n  Bound result 0\n  Bound result 500000000000000000000\n  Bound result 0\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 498.29ms (484.91ms 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   | 2470  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | drip      | 2401  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | gift      | 2454  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | initAgain | 2464  | 0       | 0        |\n|-----------------+-----------+-------+---------+----------|\n| TreasuryHandler | sendEth   | 2499  | 0       | 0        |\n╰-----------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 1490\n  Bound result 150362\n  Bound result 81257132168796771935554\n  Bound result 205\n  Bound result 224838\n  Bound result 13181092222551990251\n  Bound result 1345\n  Bound result 6737\n  Bound result 2074101769\n  Bound result 6000\n  Bound result 1800003600\n  Bound result 10000000000000000000\n  Bound result 3182973417968015266\n  Bound result 517440284\n  Bound result 1\n  Bound result 3124842406\n  Bound result 259199\n  Bound result 1046363172\n  Bound result 1040\n  Bound result 88042\n  Bound result 1000000000000\n  Bound result 23291559431389482\n  Bound result 203399661\n  Bound result 8461891782872549115\n  Bound result 3806\n  Bound result 2542\n  Bound result 123754\n  Bound result 1714\n  Bound result 1666\n  Bound result 210446\n  Bound result 8351\n  Bound result 80\n  Bound result 309254644812393708\n  Bound result 59600000000000000000\n  Bound result 300\n  Bound result 6191\n  Bound result 10000000000000000000\n  Bound result 242\n  Bound result 15\n  Bound result 1218686167626409700561913727245687294636522415155\n  Bound result 2144\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.08s (1.08s CPU time)\n\nRan 1 test for test/PagesInvariant.t.sol:PagesInvariantTest\n[PASS]\nPagesInvariantTest invariants:\n[PASS] invariant_claimsAreFinal\n[PASS] invariant_conservation\n[PASS] invariant_feesReachPoolsAndDead\n[PASS] invariant_marketHoldsExactlyWhatItOwes\n[PASS] invariant_reserveCoversEveryHolder\n PagesInvariantTest invariants (runs: 96, calls: 4608, reverts: 0)\n\n╭--------------+--------------+-------+---------+----------╮\n| Contract     | Selector     | Calls | Reverts | Discards |\n+==========================================================+\n| PagesHandler | abandon      | 574   | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| PagesHandler | answer       | 594   | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| PagesHandler | burn         | 559   | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| PagesHandler | buy          | 600   | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| PagesHandler | recycle      | 554   | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| PagesHandler | requestClaim | 558   | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| PagesHandler | sell         | 564   | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| PagesHandler | warp         | 605   | 0       | 0        |\n╰--------------+--------------+-------+---------+----------╯\n\nLogs:\n  Bound result 23748\n  Bound result 40\n  Bound result 306070\n  Bound result 39\n  Bound result 462061283478691461\n  Bound result 22178\n  Bound result 337937720568138789\n  Bound result 379694\n  Bound result 6\n  Bound result 445546\n  Bound result 993705\n  Bound result 1982064\n  Bound result 39\n  Bound result 517499996953169751\n  Bound result 34\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.41s (5.40s 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    | 513   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | advance           | 510   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | answerJudging     | 522   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | child             | 572   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimDeposit      | 508   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | claimRefund       | 463   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | fund              | 520   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | giftAndDrip       | 485   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | notedSell         | 498   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | observeSeries     | 496   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | payJudging        | 537   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | post              | 1027  | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | requestJudging    | 539   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | retract           | 516   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | seal              | 533   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | settle            | 510   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | sweep             | 458   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | trade             | 527   | 0       | 0        |\n|-----------------------+-------------------+-------+---------+----------|\n| HookAccountingHandler | unauthorizedClaim | 506   | 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 4\n  Bound result 2\n  Bound result 4\n  Bound result 3\n  Bound result 1\n  Bound result 4\n  Bound result 99999999999999999969\n  Bound result 2\n  Bound result 4\n  Bound result 3\n  Bound result 3\n  Bound result 40000\n  Bound result 99999000000000000006220\n  Bound result 83269986535294967434317\n  Bound result 338421\n  Bound result 2\n  Bound result 7776000\n  Bound result 4\n  Bound result 113735\n  Bound result 4\n  Bound result 78687401120522810512205\n  Bound result 9750000000000000026\n  Bound result 5\n  Bound result 2\n  Bound result 1\n  Bound result 2163258443\n  Bound result 3\n  Bound result 19774\n  Bound result 9750000000000020152\n  Bound result 99999000000000000008194\n  Bound result 9750000000000000740\n  Bound result 99999000000000000000010\n  Bound result 7\n  Bound result 3\n  Bound result 98000000000000002983\n  Bound result 1048576\n  Bound result 18143\n  Bound result 8\n  Bound result 7\n  Bound result 11675\n  Bound result 11000000000000000000\n  Bound result 2\n  Bound result 999\n  Bound result 8\n  Bound result 1\n  Bound result 7619943654654645805\n  Bound result 1\n  Bound result 6\n  Bound result 86124583988652836764\n  Bound result 5\n  Bound result 1\n  Bound result 4\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.10s (7.10s CPU time)\n\nRan 28 test suites in 7.11s (15.63s CPU time): 302 tests passed, 0 failed, 2 skipped (304 total tests)\n","passed":true},{"durationMs":166,"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)\",\"MarginaliaPages.abandonClaim(bytes32)\",\"MarginaliaPages.burnPending(uint256,uint256)\",\"MarginaliaPages.buy(bytes32,uint256,uint256)\",\"MarginaliaPages.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"MarginaliaPages.recycle(bytes32)\",\"MarginaliaPages.requestClaim(string,uint256)\",\"MarginaliaPages.sell(bytes32,uint256,uint256)\",\"MarginaliaPages.unlockCallback(bytes)\",\"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\":11,\"ADAPTATION.md\":583,\"README.md\":268,\"SPEC.md\":286,\"app/app.js\":286,\"app/index.html\":126,\"app/style.css\":57,\"brand/banner-ledger-1500x500.png\":5801,\"brand/pfp-manicule-400.png\":1390,\"brand/pfp-manicule-800.png\":5292,\"dependencies.json\":28,\"foundry.toml\":21,\"helper/.gitignore\":3,\"helper/package-lock.json\":737,\"helper/package.json\":20,\"helper/public/index.html\":94,\"helper/server.js\":90,\"helper/src/app.js\":257,\"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\":98,\"jobs/launch-C-pages.json\":34,\"jobs/launch-hook-v3.json\":43,\"jobs/oracle-claim-probe.json\":34,\"jobs/site-A-swarm.json\":27,\"keeper/.env.example\":27,\"keeper/.nvmrc\":1,\"keeper/.railwayignore\":3,\"keeper/README.md\":24,\"keeper/abi/erc20.json\":1,\"keeper/abi/factory.json\":1,\"keeper/abi/hook.json\":1,\"keeper/abi/judge.json\":1,\"keeper/abi/router.json\":1,\"keeper/package-lock.json\":222,\"keeper/package.json\":16,\"keeper/railway.json\":11,\"keeper/src/chain.js\":104,\"keeper/src/config.js\":53,\"keeper/src/db.js\":76,\"keeper/src/index.js\":89,\"keeper/src/sync.js\":90,\"keeper/src/tasks.js\":194,\"remappings.txt\":4,\"src/HookFlags.sol\":33,\"src/Marginalia.sol\":12,\"src/MarginaliaHook.sol\":975,\"src/MarginaliaImpls.sol\":15,\"src/MarginaliaJudge.sol\":290,\"src/MarginaliaPages.sol\":431,\"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/Pages.t.sol\":418,\"test/PagesAudit.t.sol\":300,\"test/PagesDeployment.t.sol\":61,\"test/PagesEdges.t.sol\":568,\"test/PagesInvariant.t.sol\":598,\"test/PagesOracle.t.sol\":166,\"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/fork/PagesMainnet.t.sol\":79,\"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":"aabe5943cb273647aaff6181cb400ecea1e8dbfe1604b2cea106b7e2d18b4813","verifiedTreeHash":"d38a982b8af5f96ef8273eb7374faeaf4bb763df","verifierVersion":"0.1.0+fb8278c5"},{"checks":[],"detail":"checkout_base: fatal: reference is not a tree: 774273c50dff47cdb46d5512d350d3d1ef33bd34\n","evaluation":"checks","profile":"foundry","status":"error","submissionHash":"fab8838ce9317d5c419da4cfa005ae69d0e8a9d20049cb74f6261b6aec7b6382","verifiedTreeHash":null,"verifierVersion":"0.1.0+fb8278c5"}]}