{"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":"251040a3-bb92-4aa0-b0a7-7cabf335c514","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"117191b4e831acbac93fb4b50663ea1f09b232c9be62bd5918192d406daf35a9","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"141aab2dcf23285a7103cc088d5f9bca786fbca46bfe2725964bfb34a2cdbedf","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"53d4ce13636a6a1d9aa4d9f897a9604dad112e10f584c598ec37eb0af0c7fc65","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"a5869253ee5a2b8ca1af74633d5390da745465cad5612a066a198cb63c40daef","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"338249e95208a585f18d4029376b2827fb0b19d9c9f4017e08929d45bbfc08b1","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"e09b659867e619fca91cde08d7057b2eb0e1c26993e9aa1bb5b80a88deddd876","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"efa2c60d32ef1fcc13ec81a61f7300d6a657aeff245fd823877c39a837049f91","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"0cb3a9804d8caee3f077058fa97645a6f81b64ac9703b44c0d6dddd001b8dfc7","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Build Verdict: parimutuel prediction markets settled by IMD oracle answers bought and delivered on chain through IMD's Intake. Three contracts with Foundry tests and an independent review; then deploy on Sepolia (chain 11155111) in the order VerdictBurnVault, VerdictOracle, VerdictMarkets. A website follows in a separate job.\n\nIMD facts: Intake.request(bytes32 action, bytes body, (address target, bytes4 selector) callback, address asset, uint256 amount) returns (bytes32 requestId) pulls amount after an approve, later calls target with selector ++ abi.encode(bytes32 intakeRequestId, OracleAttestation a, bytes signature) once, with 200,000 gas, inside a try. No refunds. Attestation: EIP-712 domain {name \"IdentityMD Oracle\", version \"2\", block.chainid, verifyingContract = the consumer}, struct OracleAttestation(bytes32 requestId,uint256 chainId,bytes32 questionHash,uint8 answerType,bytes answer,uint256 figure,uint64 fromBlock,uint64 toBlock,bytes32 blockHash,bytes32 panelJobId,uint16 panelSize,uint16 quorum,uint16 agreed,uint64 issuedAt,uint64 expiresAt) in that order, bytes answer hashed with keccak256; callback selector 0x510379c7; answerType 0 bool, 3 uint256, 4 address[], 5 bytes32[]; answer = abi.encode(value).\n\n1. VerdictBurnVault: no functions at all (no owner, receive, fallback or transfer path). IMD sent to it never leaves.\n\n2. VerdictOracle(address intake, address asset, address signer, bytes32 actionId, uint256 price, address owner, uint256 configDelay); configDelay <= 30 days.\n- request(bytes body) returns (bytes32 intakeRequestId): anyone; pulls price from the caller, forceApprove, Intake.request with callback (this, onOracleResult); records pending[id] = {bodyHash, intake, signer} as they are now.\n- onOracleResult: only from that request's recorded intake, only a pending id (then cleared); verifies the signature against that request's recorded signer; stores results[a.requestId] = {attHash: keccak256(abi.encode(a)), bodyHash} once; sets lastDelivered[bodyHash] = block.timestamp; emits Answered. Under 150,000 gas.\n- answerOf(a) view: bodyHash when attHash matches, else zero. lastDelivered(bodyHash) view.\n- Owner settings (intake, asset, signer, actionId, price) change only by propose then accept after configDelay; Ownable2Step; no other power; holds no funds.\n\n3. VerdictMarkets(address oracle, address collateral, address treasury, address burnSink, address guardian, uint16 creatorFeeBps, uint16 burnFeeBps, uint16 treasuryFeeBps, uint256 maxPoolPerMarket): no owner, no upgrade, immutable; reverts if fees total > 500 bps or the cap is 0. Collateral is IMD; credit the balance actually received.\n- Guardian: pause/unpause createMarket and bet only; add/remove allowlisted creators; switch the allowlist off for good; hand over the role; renounce only while unpaused. Never moves funds or outcomes.\n- createMarket(Params p, bytes body, bytes escalationBody, string uri, uint256 agentId): allowlisted creators while the allowlist is on. Stores bodyHash = keccak256(body) and escalationBodyHash (zero when escalationBody is empty) and emits both bodies in full in MarketCreated, so anyone can resolve. Params: questionHash, answerType (0, 3, 4, 5), dataChainId, fromBlock, toBlock, minPanelSize (>= 5), minAgreed, closeAt, answerFrom, answerUntil, disputeWindow (1 hour to 3 days), voidAfter, bounds, keys, bounty (>= 2x oracle price, pulled from the creator). closeAt <= answerFrom < answerUntil < voidAfter.\n- Outcomes 2 to 8: bool 0 false, 1 true; uint256 bounds.length + 1 buckets from strictly ascending bounds, bucket i holds bounds[i-1] <= x < bounds[i]; lists keys.length + 1, winner = first list element (address as bytes32(uint256(uint160(a)))), last = none of the keys.\n- bet(id, outcome, amount, agentId): before closeAt, not paused, pool within maxPoolPerMarket.\n- resolve(id, bytes body): anyone, only between answerFrom and answerUntil, only while the market has no provisional outcome; keccak256(body) == bodyHash; pays the oracle price from the bounty. A second primary ask only after 24 hours with no answer delivered for bodyHash.\n- escalate(id, bytes body): anyone, only while a primary provisional outcome exists, inside its dispute window, before answerUntil, once per market; keccak256(body) == escalationBodyHash; paid from the bounty; extends the current window to end no earlier than 24 hours from now so the answer can arrive. At most 2 paid asks per market.\n- propose(id, OracleAttestation a): answerOf(a) must equal bodyHash (first proposal, market open) or escalationBodyHash (only while a primary provisional outcome exists, inside its window, panelSize at least twice the current one; replaces it once and restarts the window once). questionHash, answerType, dataChainId, fromBlock, toBlock must match; panelSize >= minPanelSize; agreed >= minAgreed and agreed >= quorum; answerFrom <= issuedAt <= answerUntil.\n- finalize(id): once the current window ends, whatever voidAfter is; outcome fixed; fees from the whole pool to creator, burnSink and treasury by bps; unspent bounty to the creator.\n- claim(id): stake * (pool - fees) / winningPool; the last winning claim takes the exact remainder, so no dust is stranded.\n- voidMarket(id): only when voidAfter has passed with no provisional outcome, or the winning outcome has no stake: full refunds, no fees, unspent bounty to the creator.\n- ReentrancyGuard, checks-effects-interactions, events for every state change, getters.\n\nTests must show: struct hash, domain and selector match; callback under 150,000 gas via a mock Intake; wrong signer, other domain, wrong intake or unknown id store nothing; no requestId stored twice; an intake or signer rotation does not strand an in-flight request; invariant: per market, payouts + refunds + fees + oracle spend + returned bounty == deposits, with no dust left; a late escalation cannot push a decided market into void and finalize always stays reachable; an escalation answer cannot be the first proposal; asks after answerUntil revert; paused blocks only bet and createMarket; renounce while paused reverts; pool cap, allowlist, ask limit, fee cap and configDelay cap hold.\n\nSepolia only. GitHub publication is approved. Contracts only: no token, no pool, no proxy. Constructor arguments: VerdictBurnVault(); VerdictOracle(0x1397434cd35e8a9c8ac312a61d3a285eb31dea56, 0x44a1cd38474fb1748400e7deb5f8d786cce3f89a, 0x5598aa9146215bc13eb26f2c692ad1461fd32982, 0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000, 500000000000000000, $owner, 0); VerdictMarkets($contract:VerdictOracle, 0x44a1cd38474fb1748400e7deb5f8d786cce3f89a, $owner, $contract:VerdictBurnVault, $owner, 100, 50, 50, 500000000000000000000). The owner is 0x397dacb1ee8e9a8ce5196988958f56bde0a0a312. Solidity 0.8.24 or later, OpenZeppelin v5.","parentJobId":null,"planHash":"c648b5a996142b40d3ded41da961f175c1f8056577c14433aadcaccbf317ef56","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"251040a3-bb92-4aa0-b0a7-7cabf335c514","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1277-build-verdict-parimutuel-prediction"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51225","feedbackHash":"4f331ab0a855e32f545895fd18f1c5fd9bf6132a3d7aa55a4108560ae4ec1a4b","nodeKey":"audit_economics","submissionHash":"117191b4e831acbac93fb4b50663ea1f09b232c9be62bd5918192d406daf35a9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52223","feedbackHash":"38e35ed1419b3dff40698d8861dd12d870a05fd5f74091418e030eba445a81ce","nodeKey":"audit_flow","submissionHash":"141aab2dcf23285a7103cc088d5f9bca786fbca46bfe2725964bfb34a2cdbedf","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51216","feedbackHash":"3f44fa929315182770f5d7008bdee31b89900f549c2027cd00f63657647362fd","nodeKey":"audit_judge","submissionHash":"f82aaf504823c498d1cc37c59d1ade7da863edd03fd8338c9804e67fe1c2fc96","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52170","feedbackHash":"c4c90368775610f26cfdcd4c53b4a91d38b9891af94b66e94b076ebbcdf6aa56","nodeKey":"audit_judge","submissionHash":"53d4ce13636a6a1d9aa4d9f897a9604dad112e10f584c598ec37eb0af0c7fc65","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52162","feedbackHash":"c2c263d2933ba98d3cf849dff657ea922760206514526e5eee46fa970c34de58","nodeKey":"audit_math","submissionHash":"a5869253ee5a2b8ca1af74633d5390da745465cad5612a066a198cb63c40daef","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52396","feedbackHash":"bd62523316897cf46def8ea79380a871cdcac9d4bf51bea609d1977c2ca2b904","nodeKey":"audit_permissions","submissionHash":"338249e95208a585f18d4029376b2827fb0b19d9c9f4017e08929d45bbfc08b1","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52277","feedbackHash":"39634283789b25b0c0c06a63f5ebf6bbe9c8a3fab2e26cb47a1a04d9369cab7a","nodeKey":"build_contract_project","submissionHash":"e09b659867e619fca91cde08d7057b2eb0e1c26993e9aa1bb5b80a88deddd876","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52184","feedbackHash":"8c21a4ee0b9790c8ace9c761525d524214d828982f2132a14bce8e15d8012e34","nodeKey":"build_contract_project","submissionHash":"680cd8c12c0b806fd3c5d144766ed44d386430f1245e886413a1868f7243ddc1","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52430","feedbackHash":"c73c838956ac16a39ac36433b315ed0c661402c68229eee82009d9b6204250c5","nodeKey":"manifest","submissionHash":"03d961aed3f897d9d8a0ad75a2ae20003a6f52953a884581621031f12f4e0de3","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52274","feedbackHash":"6c9804fc789990471b7e4ed839d9219e160192cffdefe3796aadd51c8ed031cb","nodeKey":"manifest","submissionHash":"efa2c60d32ef1fcc13ec81a61f7300d6a657aeff245fd823877c39a837049f91","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52022","feedbackHash":"077d29a55bf657025444b38c4c2a2064f8570aa2ac97860fc453725b3f6e9b86","nodeKey":"write_foundry_tests","submissionHash":"a88654d4d8406a181bd2d9afaa36aa2f3662cd2ed1417ec52dfd59fa8a0c5ff3","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52276","feedbackHash":"8faadce00c737cd953f4d2a77af8afd9723f764f54edd8fcc9265b5c3a502bb5","nodeKey":"write_foundry_tests","submissionHash":"0cb3a9804d8caee3f077058fa97645a6f81b64ac9703b44c0d6dddd001b8dfc7","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"6dbde05d5f2759a25a402336813e488e90559307b1c086dc64d658dce1fc0393","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"55a5d7429ce83a03e8174e2daf4425104477e1f94774f9c7db23cda4996a2387","device":"49727037ad0b5bf2","findings":[],"hash":"03d961aed3f897d9d8a0ad75a2ae20003a6f52953a884581621031f12f4e0de3","nodeId":"9b74446b-623f-466d-9852-bab81354466f","outcome":"completed","summary":"Created [launch.json](/root/.identitymd/work/251040a3-bb92-4aa0-b0a7-7cabf335c514/9b74446b-623f-466d-9852-bab81354466f/launch.json) with the approved deployment order and exact constructor arguments.\n\nValidation passed against the manifest requirements and compiled ABIs. `forge build` succeeded with existing lint warnings; `forge test` passed all 81 tests.\n\nOnly `launch.json` changed.","treeHash":"b4eea4b9990ca59ba16c33b06d4e2d08a36203e3","usage":{"cachedInputTokens":421376,"inputTokens":33582,"model":"gpt-6-astra","outputTokens":3771,"runtime":"codex","turns":3,"wallClockMs":138290}},{"artifacts":[],"attempt":1,"bundleHash":"d8dcecbfd4b116696a44228a6a161ef461017a914492b30b67a9f6a0f2d73164","device":"41822d343cdb63ba","findings":[],"hash":"0cb3a9804d8caee3f077058fa97645a6f81b64ac9703b44c0d6dddd001b8dfc7","nodeId":"b02865ce-1c19-4c48-90ce-fe310c9d4ed6","outcome":"completed","summary":"Completed the test revision within `test/`.\n\n- Fixed stale fuzz and invariant inputs.\n- Added request-linkage, retry-order, and late-escalation regressions.\n- Expanded random accounting tests to include independently purchased answers.\n\n`forge build` and `forge test` pass: 121 tests, zero failures. No contracts or configuration changed.","treeHash":"01b4591904143d4e8ab75527bca4503ec33d22af","usage":{"cachedInputTokens":2607346,"inputTokens":139901,"model":"gpt-6.1-sol","outputTokens":9125,"runtime":"codex","turns":7,"wallClockMs":272885}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4dd74fd7c315da80","findings":[{"citation":"resolved","description":"propose() applies the same issuedAt bound (answerFrom <= issuedAt <= answerUntil) to a replacement as to the first proposal, while escalate() (src/VerdictMarkets.sol:300, m.disputeEnds = Math.max(m.disputeEnds, block.timestamp + 24 hours)) extends the dispute window past answerUntil 'so the answer can arrive'. The oracle issues an answer minutes after the ask, so any escalation asked within the oracle's latency of answerUntil produces an attestation with issuedAt > answerUntil that propose() rejects with InvalidAttestation, even though it arrives inside the window escalate() just extended. Flow-gap seam (execution x periphery x first principles): each step succeeds, the creator's bounty is spent (oracleSpend becomes 2 x price), the window is extended, the answer is stored in VerdictOracle, yet it can never replace the primary and the market finalizes on the disputed outcome. It is also exploitable deliberately: a first proposal is accepted until voidAfter, so whoever holds an early-delivered primary answer that favours them withholds propose() until shortly before or after answerUntil; escalate() then either reverts OutsideWindow or buys an unusable answer, and no sponsor can produce a timely escalation attestation either (every attestation issued from then on has issuedAt > answerUntil). The bounty-funded escalation the brief requires ('extends the current window ... so the answer can arrive') is therefore a guarantee the contract cannot keep whenever the primary proposal lands late in the ask window. Loss: the side that would win under the corrected answer loses the pool minus fees to the other side; the creator loses 0.5 IMD for an escalation that can never take effect. Suggested minimal fix (needs a scope decision because it loosens the brief's literal rule): for replacements bound issuedAt by the dispute deadline in force (a.issuedAt <= m.disputeEnds and a.issuedAt >= the primary proposal time) instead of answerUntil, and/or require the first proposal to be made before answerUntil minus a minimum escalation lead time.","line":324,"path":"src/VerdictMarkets.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {VerdictOracle} from \"src/VerdictOracle.sol\";\nimport {VerdictMarkets} from \"src/VerdictMarkets.sol\";\nimport {VerdictBurnVault} from \"src/VerdictBurnVault.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofIMD is ERC20 {\n    constructor() ERC20(\"Test IMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\ncontract ProofIntake is IIntake {\n    uint256 public nonce;\n    mapping(bytes32 => Callback) public callbacks;\n\n    function request(bytes32, bytes calldata, Callback calldata callback, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        IERC20(asset).transferFrom(msg.sender, address(this), amount);\n        id = keccak256(abi.encode(address(this), ++nonce));\n        callbacks[id] = callback;\n    }\n\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata signature)\n        external\n        returns (bool ok)\n    {\n        Callback memory cb = callbacks[id];\n        (ok,) = cb.target.call{gas: 200_000}(abi.encodeWithSelector(cb.selector, id, a, signature));\n    }\n}\n\n/// @dev Finding: an escalation asked shortly before answerUntil yields an answer issued after answerUntil,\n/// which propose() rejects, so the paid escalation can never replace the primary outcome.\ncontract EscalationTimingProof is Test {\n    uint256 internal constant SIGNER_KEY = 0x123456;\n    uint256 internal constant PRICE = 0.5 ether;\n    bytes32 internal constant QUESTION = keccak256(\"precisely defined question\");\n    address internal creator = makeAddr(\"creator\");\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n    ProofIMD internal token;\n    ProofIntake internal intake;\n    VerdictOracle internal oracle;\n    VerdictMarkets internal markets;\n    bytes internal body = '{\"v\":1,\"question\":\"primary\"}';\n    bytes internal escalationBody = '{\"v\":1,\"question\":\"primary\",\"panelSize\":10}';\n    uint256 internal attNonce;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.chainId(11155111);\n        token = new ProofIMD();\n        intake = new ProofIntake();\n        oracle = new VerdictOracle(\n            address(intake), address(token), vm.addr(SIGNER_KEY), bytes32(\"oracle.request@oracle-1\"), PRICE, address(this), 0\n        );\n        VerdictBurnVault burn = new VerdictBurnVault();\n        markets = new VerdictMarkets(\n            address(oracle), address(token), makeAddr(\"treasury\"), address(burn), address(this), 100, 50, 50, 500 ether\n        );\n        markets.setCreatorAllowed(creator, true);\n        address[3] memory users = [creator, alice, bob];\n        for (uint256 i; i < users.length; i++) {\n            token.mint(users[i], 1_000 ether);\n            vm.prank(users[i]);\n            token.approve(address(markets), type(uint256).max);\n        }\n    }\n\n    function params() internal view returns (VerdictMarkets.Params memory p) {\n        p.questionHash = QUESTION;\n        p.answerType = 0;\n        p.dataChainId = 1;\n        p.fromBlock = 100;\n        p.toBlock = 200;\n        p.minPanelSize = 5;\n        p.minAgreed = 4;\n        p.closeAt = uint64(block.timestamp + 1 hours);\n        p.answerFrom = p.closeAt;\n        p.answerUntil = p.answerFrom + 4 days;\n        p.disputeWindow = 1 days;\n        p.voidAfter = p.answerUntil + 1 hours;\n        p.bounty = 2 * PRICE;\n    }\n\n    function attestation(VerdictMarkets.Params memory p, bytes memory answer, uint16 panel, uint64 issuedAt)\n        internal\n        returns (OracleAttestation.Attestation memory a)\n    {\n        a.requestId = keccak256(abi.encode(\"oracle request\", ++attNonce));\n        a.chainId = p.dataChainId;\n        a.questionHash = p.questionHash;\n        a.answerType = p.answerType;\n        a.answer = answer;\n        a.fromBlock = p.fromBlock;\n        a.toBlock = p.toBlock;\n        a.blockHash = keccak256(\"closing block\");\n        a.panelJobId = keccak256(abi.encode(\"panel\", attNonce));\n        a.panelSize = panel;\n        a.quorum = 4;\n        a.agreed = panel;\n        a.issuedAt = issuedAt;\n        a.expiresAt = issuedAt + 7 days;\n    }\n\n    function deliver(bytes32 requestId, OracleAttestation.Attestation memory a) internal {\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(SIGNER_KEY, oracle.attestationDigest(a));\n        assertTrue(intake.deliver(requestId, a, abi.encodePacked(r, s, v)), \"callback failed\");\n    }\n\n    /// Escalation asked 10 minutes before answerUntil; the oracle answers 15 minutes later (issuedAt is\n    /// answerUntil + 5 minutes), inside the 24 hour window escalate() extended. The replacement should be\n    /// accepted; today propose() reverts InvalidAttestation and the market finalizes on the disputed outcome.\n    function test_escalationAnswerIssuedInsideExtendedWindowReplacesPrimary() public {\n        VerdictMarkets.Params memory p = params();\n        vm.prank(creator);\n        uint256 id = markets.createMarket(p, body, escalationBody, \"\", 0);\n        vm.prank(alice);\n        markets.bet(id, 1, 100 ether, 0);\n        vm.prank(bob);\n        markets.bet(id, 0, 100 ether, 0);\n\n        // Primary answer \"true\" issued and delivered early in the ask window.\n        vm.warp(p.answerFrom);\n        bytes32 primaryId = markets.resolve(id, body);\n        OracleAttestation.Attestation memory primary = attestation(p, abi.encode(true), 5, uint64(block.timestamp));\n        deliver(primaryId, primary);\n\n        // Alice (winner under \"true\") proposes it 10 minutes before answerUntil.\n        vm.warp(p.answerUntil - 10 minutes);\n        vm.prank(alice);\n        markets.propose(id, primary);\n\n        // Bob escalates at once, still before answerUntil; the window is extended by 24 hours \"so the answer can arrive\".\n        vm.prank(bob);\n        bytes32 escalationId = markets.escalate(id, escalationBody);\n        assertEq(markets.getMarket(id).disputeEnds, block.timestamp + 24 hours);\n        assertEq(markets.getMarket(id).oracleSpend, 2 * PRICE);\n\n        // The oracle answers 15 minutes later with the larger panel: \"false\".\n        vm.warp(block.timestamp + 15 minutes);\n        OracleAttestation.Attestation memory escalation =\n            attestation(p, abi.encode(false), 10, uint64(block.timestamp));\n        deliver(escalationId, escalation);\n        assertEq(oracle.answerOf(escalation), keccak256(escalationBody));\n        assertLt(block.timestamp, markets.getMarket(id).disputeEnds);\n\n        // Expected: the paid escalation answer replaces the primary outcome inside the extended window.\n        vm.prank(bob);\n        markets.propose(id, escalation);\n        VerdictMarkets.Market memory m = markets.getMarket(id);\n        assertTrue(m.escalated, \"escalation answer must be usable inside the window it extended\");\n        assertEq(m.outcome, 0);\n    }\n}","reproduction":"Market with answerFrom = closeAt = T, answerUntil = T + 4 days, disputeWindow = 1 day; alice bets 100 IMD on outcome 1, bob 100 IMD on 0. At T resolve(id, body) is asked and the oracle delivers 'true' (issuedAt = T). At answerUntil - 10 minutes alice proposes it (Provisional, outcome 1). Bob immediately calls escalate(id, escalationBody): succeeds, disputeEnds = now + 24h, oracleSpend = 1 IMD. 15 minutes later the oracle delivers the escalation attestation (panelSize 10, answer false, issuedAt = answerUntil + 5 minutes); VerdictOracle stores it (answerOf == escalationBodyHash). bob calls propose(id, escalation) while block.timestamp < disputeEnds. Expected: replacement accepted (escalated = true, outcome 0). Actual: revert InvalidAttestation() from the issuedAt > answerUntil branch; after disputeEnds finalize() pays alice 196 IMD. Variant: alice proposes at answerUntil + 1 instead; escalate() reverts OutsideWindow and every sponsored escalation attestation is likewise rejected. Run: forge test --match-path test/scratch/EscalationTiming.t.sol (fails on current code with InvalidAttestation).","severity":"medium","snippet":"                || a.issuedAt < p.answerFrom || a.issuedAt > p.answerUntil","title":"Escalation answers issued after answerUntil are unproposable, so a late primary proposal or a late escalate() defeats the paid dispute path"},{"citation":"resolved","description":"propose() accepts any attestation VerdictOracle has stored for the matching body hash regardless of which request produced it, and the first accepted proposal is final for the primary (the first accepted replacement is final for the escalation). VerdictOracle.request(body) is permissionless and costs only the oracle price, so any party can re-run the exact same body as often as they like and present whichever delivered answer favours them. This is the Economic Security guide's 'choose which provider fulfills a pending request' pattern. Concrete economics: pool cap 500 IMD; a bettor losing 250 IMD pays 0.5 IMD per extra panel run of the same question; whenever the panel's answer varies for the question (ambiguous wording, chain-evidence splits, disagreeing re-runs) each roll is a lottery ticket for the whole pool and the market's own paid answer is silently superseded. The same holds for escalation: an escalation attestation fetched in advance (before any primary exists) can be proposed in the same block as the primary, which sets escalated = true, restarts the window once and makes escalate() revert WrongState, so honest parties get no dispute at all. Precondition: the oracle must produce at least two differing valid attestations for the same body; with a perfectly deterministic honest panel the race is harmless, which is why this is medium rather than high. The contract gives no preference to its own paid request and offers no deterministic tie-break, so under disagreement the outcome is decided by mempool ordering and by who spends 0.5 IMD more. Suggested fix preserving the brief: have VerdictOracle record which intake request produced each result (e.g. intakeRequestOf[a.requestId]) so Markets can prefer its own asks (accept sponsored answers only after a grace period or only when no own-ask answer exists), and/or settle conflicts by a signed metric (highest agreed/panelSize) instead of first arrival.","line":318,"path":"src/VerdictMarkets.sol","reproduction":"Primary: market with alice 100 IMD on 1 and bob 100 IMD on 0; at answerFrom the market's own resolve() ask is delivered 'true' (panel 5). bob calls oracle.request(body) paying 0.5 IMD and a second valid attestation for the same body is delivered 'false' (panel 5). bob calls propose(id, rolled): accepted, outcome = 0; the market's own 'true' answer can no longer be proposed (propose now takes the replacement path and reverts InvalidAttestation because panelSize 5 < 2*5). Escalation: bob first calls oracle.request(escalationBody) and a 'false' attestation with panel 10 is delivered; the market's primary 'true' (panel 5) is delivered and proposed; in the same block bob calls propose(id, rolled): escalated = true, outcome = 0, escalate() reverts WrongState; after disputeEnds finalize() and bob's claim returns 196 IMD. Both sequences pass on current code: forge test --match-path test/scratch/AnswerSelection.t.sol (test_firstProposerPicksAmongConflictingValidPrimaryAnswers, test_prefetchedEscalationAnswerLocksOutcomeAndClosesEscalate).","severity":"medium","snippet":"        if (oracle.answerOf(a) != expected) revert UnauthenticatedAnswer();","title":"First proposer chooses among conflicting valid answers: a 0.5 IMD re-roll per attempt lets a bettor select the primary outcome or lock it with a pre-fetched escalation answer"},{"citation":"resolved","description":"resolve() gates the second primary ask on VerdictOracle.lastDelivered(bodyHash), which the oracle sets for every signature-valid delivery, including attestations Markets will reject at propose() (the protocol reference says the panel may sign agreed < quorum for chain evidence; the market requires agreed >= quorum and agreed >= minAgreed). Once such an answer lands, lastDelivered >= lastPrimaryAsk stays true forever (lastPrimaryAsk only moves on a successful resolve), so the retry the brief allows after 24 hours with no usable answer is unreachable, the second half of the bounty idles until void/finalize, and resolution depends on a volunteer paying 0.5 IMD through VerdictOracle.request. Bettor principal is not at risk (voidAfter refunds), so severity is low: liveness and a wasted creator bounty under a specific oracle output. Suggested fix: gate the retry on an answer Markets actually accepted, e.g. a per-market flag set by a successful propose, or allow resolve again when the delivered attestation for this market was rejected.","line":285,"path":"src/VerdictMarkets.sol","reproduction":"Market with minAgreed 4; at answerFrom resolve(id, body) is asked; the oracle delivers an attestation with panelSize 5, quorum 4, agreed 3 (signature valid, stored, lastDelivered set). propose(id, a) reverts InvalidAttestation. 3 days later resolve(id, body) reverts AnswerAlreadyDelivered although no usable answer exists; bountyRemaining stays 0.5 IMD until voidMarket returns it after voidAfter. Passes on current code: forge test --match-path test/scratch/AnswerSelection.t.sol --match-test test_rejectedDeliveredAnswerBlocksRetryForever.","severity":"low","snippet":"            if (oracle.lastDelivered(m.bodyHash) >= m.lastPrimaryAsk) revert AnswerAlreadyDelivered();","title":"A delivered answer the market cannot use (agreed < quorum, agreed < minAgreed, late issuedAt) permanently blocks the bounty-funded primary retry"},{"citation":"resolved","description":"Trust assumption, not a bypass: the brief fixes configDelay to 0 and the owner (0x397dacb1ee8e9a8ce5196988958f56bde0a0a312, also treasury and guardian) can proposeConfig then acceptConfig in one block. A rotated signer key held by the owner signs any attestation in VerdictOracle's domain; with a rotated intake address under the owner's control, onOracleResult accepts it for any request made after the rotation, so a sponsored request for a market's body yields an owner-authored answer that propose() accepts. In-flight requests keep their recorded intake and signer (verified in the suite). Bettors therefore trust the oracle owner as much as the IMD panel for every market whose asks happen after a rotation, and the same owner receives the treasury fee. Document it for bettors or raise configDelay for the launch; nothing to fix in code.","line":78,"path":"src/VerdictOracle.sol","reproduction":"Owner calls proposeConfig({intake: ownerIntake, asset: IMD, signer: ownerKey, actionId, price}) and acceptConfig() in the same block (configDelay 0). Owner calls request(body) for an open market, then ownerIntake calls onOracleResult with an attestation signed by ownerKey: stored. Owner calls propose(id, a) and the market settles on the owner's answer.","severity":"info","snippet":"        if (configDelay_ > 30 days) revert InvalidConfig();","title":"Launch configDelay = 0 lets the oracle owner rotate the signer and intake instantly, which is full control over every market asked after the rotation"}],"hash":"117191b4e831acbac93fb4b50663ea1f09b232c9be62bd5918192d406daf35a9","nodeId":"6e9ad1cb-d176-4439-aea0-2672fda5fab5","outcome":"completed","summary":"Review complete. The findings file is written and validated, and the working tree has no stray files (`git status --porcelain` is empty; `test/scratch/` and `.imd-findings.json` are ignored by the repo's own rules).\n\n**What I covered.** All three contracts and the full suite (81 tests passing on this tree), traced against the Pashov Economic Security, Invariant and Flow Gap guides. The core accounting holds: per-market conservation, bounty isolation, exact oracle spend, received-amount crediting, the dust-free last claim, fee and pool caps, pause scope, and the void/finalize boundary all behaved as the brief requires. All 22 entry points have a coverage row, plus five invariant and economic rows.\n\n**Findings written to `.imd-findings.json`:**\n\n1. **Medium, with a failing proof test.** A replacement proposal is bound by `issuedAt <= answerUntil`, but `escalate()` extends the dispute window 24 hours \"so the answer can arrive\". Any escalation asked within oracle latency of `answerUntil` buys an answer `propose()` rejects with `InvalidAttestation`. A party holding a favourable primary answer can exploit this by withholding the first proposal until near or after `answerUntil`, which makes the dispute path unusable. The proof at `test/scratch/EscalationTiming.t.sol` fails on the current code.\n2. **Medium.** The first proposer picks among conflicting valid answers. Anyone can re-run the same body through `VerdictOracle.request` for 0.5 IMD and propose whichever answer favours them, or pre-fetch an escalation answer to lock the outcome in the same block as the primary. Precondition is oracle answer variance, so it is medium rather than high.\n3. **Low.** A delivered but unusable answer (for example `agreed < quorum`) sets `lastDelivered`, which blocks the bounty-funded primary retry forever.\n4. **Info.** With `configDelay = 0`, the oracle owner can rotate signer and intake instantly and author outcomes for any market asked after the rotation. Trust assumption to document, not a code fix.\n\n**Not reached in depth.** The IMD Intake's live behaviour on Sepolia (pairing of request ids, panel-size fidelity in attestations) was assumed per the reference, not verified against a live contract.","treeHash":null,"usage":{"cachedInputTokens":1882439,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":55396,"runtime":"claude","turns":35,"wallClockMs":811530}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f20ec62b0213db3f","findings":[{"citation":"resolved","description":"propose() accepts any attestation whose answerOf() equals the market's bodyHash (or escalationBodyHash for the replacement). VerdictOracle.request(bytes) is open to anyone for 0.5 IMD, and every delivered answer is stored under its own a.requestId, so several contradicting answers for the same body can coexist in results[] and all pass this check. Nothing ties a proposal to the market's own paid asks (resolve/escalate), and nothing prefers the market's answer over a sponsor's. For a question the panel answers non-deterministically (evidence 'panel', subjective wording), a bettor on side X pays 0.5 IMD per extra sample until one says X, proposes it, and can in the same transaction propose a sponsored 2x-panel escalation answer saying X: the replacement sets escalated=true, so no further replacement or escalate() is possible, the dispute window only delays finalize, and the other side's stake is paid to X. This follows the brief's wording ('anyone can resolve', 'answerOf(a) must equal bodyHash'), so it is a design-level risk rather than a deviation from the brief, but it is the control-flow property that decides who gets the pool and the independent review does not mention it. Possible mitigations that keep 'anyone can resolve': only accept a.requestId values whose intake request was made by the market (record the oracle's intakeRequestId per ask and have VerdictOracle expose results keyed by it), or forbid a replacement in the same block as the primary and require the replacement's agreed share to exceed the primary's. Either changes the agreed design and needs a scope decision.","line":318,"path":"src/VerdictMarkets.sol","reproduction":"Market id=1 from TestBase (bool, minPanelSize 5, minAgreed 4). alice bets 100 IMD on 1, bob bets 100 IMD on 0. At answerFrom bob calls oracle.request(body) twice (r1, r2) and oracle.request(escalationBody) once (r3). Mock intake delivers attestation A1 (answer=true, panel 5) for r1, A2 (answer=false, panel 5) for r2 and A3 (answer=false, panel 10) for r3; all three are stored and oracle.answerOf(A1)==oracle.answerOf(A2)==keccak256(body), oracle.answerOf(A3)==keccak256(escalationBody). bob calls markets.propose(1, A2) then markets.propose(1, A3) in the same block. Expected: the market's own resolve() answer, or at least a single answer per body, decides. Actual: outcome=0, escalated=true, propose(1, A1) reverts EscalationUnavailable, escalate() reverts WrongState, finalize() at disputeEnds pays bob 196 IMD of the 200 IMD pool (2% fees). The market never called resolve(). Reproduced in test/scratch/Leads.t.sol test_lead1_sponsorPicksAmongContradictingAnswers (passes on the current code, i.e. the sequence is accepted).","severity":"medium","snippet":"        if (oracle.answerOf(a) != expected) revert UnauthenticatedAnswer();","title":"Outcome is set by whichever stored oracle answer for the body hash is proposed first; sponsors can sample the panel repeatedly and pick, and a pre-fetched escalation answer locks the pick in the same "},{"citation":"resolved","description":"resolve() permits the second primary ask only if VerdictOracle.lastDelivered(bodyHash) is older than the first ask. VerdictOracle.onOracleResult sets lastDelivered for every signature-valid delivery, including attestations that propose() rejects at lines 320-327: agreed < quorum (which the pinned protocol reference documents as a legitimate chain-evidence outcome when a panel splits and the deployer's rerun settles it), issuedAt > answerUntil, or a panelSize below minPanelSize. After such a delivery the retry path reverts AnswerAlreadyDelivered for the rest of the market's life, although no usable answer exists. The remaining bounty is returned at voidMarket, so no funds are lost, but the brief's retry ('a second primary ask only after 24 hours with no answer delivered') becomes dead for exactly the deliveries it was meant to recover from, and bettors wait until voidAfter for refunds. A fix that keeps the oracle unchanged is for resolve() to treat a delivered answer as consumed only if it would satisfy the market, e.g. have VerdictOracle also record lastDelivered keyed by (bodyHash, agreed>=quorum) or let resolve() accept a retry when the stored answer's requestId has not been proposed and a.agreed < a.quorum.","line":285,"path":"src/VerdictMarkets.sol","reproduction":"Market id=1 from TestBase. alice bets 10 IMD on 1. At answerFrom call markets.resolve(1, body) (asks=1, 0.5 IMD spent). Mock intake delivers a correctly signed attestation with panelSize 5, quorum 4, agreed 3 for that request: onOracleResult stores it and sets lastDelivered[bodyHash]=now. markets.propose(1, a) reverts InvalidAttestation (agreed < quorum). Warp +24h and call markets.resolve(1, body). Expected: the retry is allowed because no usable answer was delivered. Actual: revert AnswerAlreadyDelivered; asks stays 1; the only exit is voidMarket at voidAfter. Reproduced in test/scratch/Leads.t.sol test_lead2_unusableDeliveryBlocksRetry.","severity":"low","snippet":"            if (oracle.lastDelivered(m.bodyHash) >= m.lastPrimaryAsk) revert AnswerAlreadyDelivered();","title":"A delivered answer that propose() can never accept blocks the 24-hour primary retry, so the second paid ask is unreachable and the market can only void"},{"citation":"resolved","description":"escalate() gates on _askWindow (block.timestamp < answerUntil) and extends disputeEnds by 24 hours so the answer can arrive, but propose() rejects any attestation with issuedAt > answerUntil, for the replacement as well as the primary. The oracle answers minutes after the request, so every escalation asked inside that latency of answerUntil is paid (0.5 IMD of the creator's bounty, asks incremented) and its answer is guaranteed to be rejected; the primary outcome then finalizes after the extended window. The same boundary makes a late primary undisputable: propose() of a first outcome is allowed until voidAfter (line 314) while escalate() stops at answerUntil, so a stored primary answer delivered shortly before answerUntil can be held and proposed at answerUntil, after which neither escalate() nor a replacement (issuedAt would exceed answerUntil) is possible. Both follow the brief's literal windows, so this is a specification tension to decide rather than a code deviation. Minimal options: refuse escalate() when block.timestamp + a latency margin >= answerUntil, or bound the replacement's issuedAt by disputeEnds instead of answerUntil.","line":324,"path":"src/VerdictMarkets.sol","reproduction":"Params from TestBase with answerUntil = answerFrom + 2h, voidAfter = answerUntil + 1 day, disputeWindow 2h. alice bets 10 IMD on 1, bob 10 IMD on 0. Primary answer true proposed at answerFrom. Warp to answerUntil - 1 and call markets.escalate(1, escalationBody): accepted, oracleSpend becomes 1.0 IMD, disputeEnds = now + 24h. Five minutes later the mock intake delivers a valid escalation attestation (answer=false, panel 10, issuedAt = answerUntil + 299) and oracle.answerOf(a) == keccak256(escalationBody). markets.propose(1, a) reverts InvalidAttestation. finalize() at disputeEnds fixes outcome 1. Expected: an escalation the contract accepts and pays for can be answered; actual: it cannot. Reproduced in test/scratch/Leads.t.sol test_lead3_escalationNearAnswerUntilIsAlwaysWasted. The undisputable-late-primary half is shown by the existing tests test_proposeAfterAnswerUntilWithTimelyStoredAnswer (propose accepted at answerUntil+1) and test_escalationAskAtAnswerUntilRevertsEvenInsideDisputeWindow (escalate reverts at answerUntil).","severity":"low","snippet":"                || a.issuedAt < p.answerFrom || a.issuedAt > p.answerUntil","title":"Escalation is accepted until answerUntil-1 but its answer must be issued by answerUntil, so an escalation asked within oracle latency of answerUntil always spends the bounty for an unusable answer, wh"}],"hash":"141aab2dcf23285a7103cc088d5f9bca786fbca46bfe2725964bfb34a2cdbedf","nodeId":"e8cb8f75-9aba-4801-a596-0ab6cc2bd864","outcome":"completed","summary":"The review is complete. No tracked source files were changed; the findings file is excluded by the repository's own git exclude rules and the scratch test lives under the ignored `test/scratch/` directory.\n\n**Outcome.** The control flow of `VerdictMarkets`, `VerdictOracle` and the `OracleAttestation` periphery is sound in every path I traced. Three substantiated findings are recorded in `.imd-findings.json`, none critical or high, so no proof files were required. The existing 81 tests pass, the EIP-712 vector, domain and callback selector match the pinned protocol, and the cold callback measures well under the 150,000 gas bound.\n\n**Findings, most severe first.**\n- **Medium, answer selection.** `propose` accepts any stored oracle answer whose body hash matches, from anyone's sponsored request. A bettor can buy repeated samples of a non-deterministic panel for 0.5 IMD each, propose the favorable one, and in the same block propose a pre-fetched 2x-panel escalation answer that locks it. This matches the brief's wording, so I framed it as a design risk needing a scope decision, with two mitigations that keep \"anyone can resolve\".\n- **Low, dead retry.** A delivered attestation that `propose` can never accept, such as one with agreed below quorum, still sets the oracle's delivery timestamp, so the 24-hour primary retry reverts forever. No funds are lost, but the market can only void.\n- **Low, escalation boundary.** Escalation is accepted until one second before answerUntil, but the replacement must be issued by answerUntil, so an escalation inside the oracle's latency always spends the bounty for nothing. The same boundary makes a primary proposed at or after answerUntil undisputable.\n\n**Coverage.** All 22 listed entry points have rows, plus rows for the two brief invariants, the burn vault and the deployment arguments. Three rows point to findings and the rest hold. Each lead was reproduced in a scratch Foundry test before being reported.\n\n**Left unreached.** No live Sepolia Intake behavior was exercised; the mock models exact pulls and a single delivery attempt. Guardian renouncing while the allowlist is on freezes creation permanently, which the shipped review already documents, so I did not list it as a defect.","treeHash":null,"usage":{"cachedInputTokens":1556563,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":47564,"runtime":"claude","turns":32,"wallClockMs":778282}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f9a9196633a6ffa8","findings":[{"citation":"resolved","description":"Trust gap (access x economics x asymmetry). The market bounds its own oracle spend to 2 asks (resolve/escalate, AskLimit), but propose() binds an attestation to the market only through oracle.answerOf(a) == bodyHash. VerdictOracle.request(body) is callable by anyone with any body, and every delivered answer is stored under its own a.requestId with the same bodyHash. So any bettor can buy as many extra panels for the market's exact body (0.5 IMD each) as they like, keep the one whose answer favours their position, and propose it first; the market's own paid answer is simply never proposed. Because a market goes Open -> Provisional on the first propose, the losing side cannot counter with the market's own answer afterwards. The same holds for the replacement path: an attestation for escalationBodyHash bought directly at the oracle is accepted while m.escalationAsked is false and asks == 1, replacing the primary once and for good (m.escalated = true), so the one-shot dispute mechanism is consumed by whoever is first with a favourable 2x panel. With a 500 IMD pool cap and 0.5 IMD per extra panel, answer-shopping is profitable whenever repeated panels can diverge on the question (which the brief's escalation design itself presumes). The oracle-consumer reference's rule 'only a request id it created and has not settled' is satisfied at VerdictOracle level but not at the market level, where value moves. The brief's wording ('answerOf(a) must equal bodyHash') permits this, so a fix needs a scope decision: have VerdictOracle expose the intake request id an attestation answered (e.g. results[a.requestId].intakeRequestId) and have VerdictMarkets record the ids returned by its own resolve()/escalate() asks and require propose() to present an answer to one of them (escalation answers only after escalate()). The existing test test_externalSponsorCanDeliverPrimaryAndEscalation codifies the current behaviour as intended, so the tests do not catch it.","line":318,"path":"src/VerdictMarkets.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {VerdictOracle} from \"src/VerdictOracle.sol\";\nimport {VerdictMarkets} from \"src/VerdictMarkets.sol\";\nimport {VerdictBurnVault} from \"src/VerdictBurnVault.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ShopIMD is ERC20 {\n    constructor() ERC20(\"Test IMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\ncontract ShopIntake is IIntake {\n    using SafeERC20 for IERC20;\n\n    uint256 public nonce;\n    mapping(bytes32 => Callback) public callbacks;\n\n    function request(bytes32, bytes calldata, Callback calldata callback, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);\n        id = keccak256(abi.encode(address(this), ++nonce));\n        callbacks[id] = callback;\n    }\n\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata signature)\n        external\n        returns (bool ok)\n    {\n        Callback memory cb = callbacks[id];\n        (ok,) = cb.target.call{gas: 200_000}(abi.encodeWithSelector(cb.selector, id, a, signature));\n    }\n}\n\n/// @notice Whoever proposes first picks among every answer anyone ever bought for the body.\n/// The market's own paid answer (false) is discarded in favour of a sponsor-bought answer (true),\n/// and a sponsor-bought escalation answer replaces a primary without any escalate() call.\ncontract AnswerShoppingTest is Test {\n    uint256 internal constant SIGNER_KEY = 0x123456;\n    uint256 internal constant PRICE = 0.5 ether;\n\n    address internal creator = makeAddr(\"creator\");\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n    address internal treasury = makeAddr(\"treasury\");\n\n    ShopIMD internal token;\n    ShopIntake internal intake;\n    VerdictOracle internal oracle;\n    VerdictMarkets internal markets;\n    bytes internal body = '{\"v\":1,\"question\":\"primary\"}';\n    bytes internal escalationBody = '{\"v\":1,\"question\":\"primary\",\"panelSize\":10}';\n    uint256 internal attNonce;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.chainId(11155111);\n        token = new ShopIMD();\n        intake = new ShopIntake();\n        oracle = new VerdictOracle(\n            address(intake), address(token), vm.addr(SIGNER_KEY), bytes32(\"oracle.request@oracle-1\"), PRICE, address(this), 0\n        );\n        VerdictBurnVault burn = new VerdictBurnVault();\n        markets = new VerdictMarkets(\n            address(oracle), address(token), treasury, address(burn), address(this), 100, 50, 50, 500 ether\n        );\n        markets.setCreatorAllowed(creator, true);\n        address[4] memory users = [address(this), creator, alice, bob];\n        for (uint256 i; i < users.length; i++) {\n            token.mint(users[i], 1_000 ether);\n            vm.startPrank(users[i]);\n            token.approve(address(markets), type(uint256).max);\n            token.approve(address(oracle), type(uint256).max);\n            vm.stopPrank();\n        }\n    }\n\n    function params() internal view returns (VerdictMarkets.Params memory p) {\n        p.questionHash = keccak256(\"question\");\n        p.answerType = 0;\n        p.dataChainId = 1;\n        p.fromBlock = 100;\n        p.toBlock = 200;\n        p.minPanelSize = 5;\n        p.minAgreed = 4;\n        p.closeAt = uint64(block.timestamp + 1 hours);\n        p.answerFrom = p.closeAt;\n        p.answerUntil = p.answerFrom + 4 days;\n        p.disputeWindow = 1 days;\n        p.voidAfter = p.answerUntil + 1 hours;\n        p.bounty = 2 * PRICE;\n    }\n\n    function attestation(uint256 id, bytes memory answer, uint16 panel)\n        internal\n        returns (OracleAttestation.Attestation memory a)\n    {\n        VerdictMarkets.Params memory p = markets.getMarket(id).params;\n        a.requestId = keccak256(abi.encode(\"oracle request\", ++attNonce));\n        a.chainId = p.dataChainId;\n        a.questionHash = p.questionHash;\n        a.answerType = p.answerType;\n        a.answer = answer;\n        a.fromBlock = p.fromBlock;\n        a.toBlock = p.toBlock;\n        a.blockHash = keccak256(\"closing block\");\n        a.panelJobId = keccak256(abi.encode(\"panel\", attNonce));\n        a.panelSize = panel;\n        a.quorum = 4;\n        a.agreed = panel;\n        a.issuedAt = uint64(block.timestamp);\n        a.expiresAt = uint64(block.timestamp + 7 days);\n    }\n\n    function deliver(bytes32 rid, OracleAttestation.Attestation memory a) internal {\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(SIGNER_KEY, oracle.attestationDigest(a));\n        assertTrue(intake.deliver(rid, a, abi.encodePacked(r, s, v)), \"delivery failed\");\n    }\n\n    /// Market paid for one answer (false). Alice, who bet on true, buys her own answers directly\n    /// at the oracle until one says true and proposes it first. Expected: only an answer the market\n    /// paid for (one of its own asks) may be proposed. Actual: the sponsor-bought answer is accepted\n    /// and the market finalizes on it.\n    function test_firstProposerPicksAmongDivergentAnswers() public {\n        vm.prank(creator);\n        uint256 id = markets.createMarket(params(), body, escalationBody, \"ipfs://m\", 1);\n        vm.prank(alice);\n        markets.bet(id, 1, 100 ether, 0);\n        vm.prank(bob);\n        markets.bet(id, 0, 100 ether, 0);\n\n        vm.warp(markets.getMarket(id).params.answerFrom);\n        // The market's own paid ask answers \"false\".\n        bytes32 marketRid = markets.resolve(id, body);\n        OracleAttestation.Attestation memory marketAnswer = attestation(id, abi.encode(false), 5);\n        deliver(marketRid, marketAnswer);\n\n        // Alice buys a second panel for the same body; this one answers \"true\".\n        vm.prank(alice);\n        bytes32 aliceRid = oracle.request(body);\n        OracleAttestation.Attestation memory aliceAnswer = attestation(id, abi.encode(true), 5);\n        deliver(aliceRid, aliceAnswer);\n\n        // Expected: an answer the market did not pay for is refused.\n        vm.prank(alice);\n        vm.expectRevert(VerdictMarkets.UnauthenticatedAnswer.selector);\n        markets.propose(id, aliceAnswer);\n    }\n\n    /// A sponsor-bought escalation answer replaces the primary outcome although escalate() was\n    /// never called and the market never spent a second ask. Expected: replacement requires the\n    /// market's own escalation ask. Actual: accepted, escalated = true, asks still 1.\n    function test_replacementWithoutEscalationAsk() public {\n        vm.prank(creator);\n        uint256 id = markets.createMarket(params(), body, escalationBody, \"ipfs://m\", 1);\n        vm.prank(alice);\n        markets.bet(id, 1, 100 ether, 0);\n        vm.prank(bob);\n        markets.bet(id, 0, 100 ether, 0);\n\n        vm.warp(markets.getMarket(id).params.answerFrom);\n        bytes32 marketRid = markets.resolve(id, body);\n        OracleAttestation.Attestation memory primary = attestation(id, abi.encode(false), 5);\n        deliver(marketRid, primary);\n        markets.propose(id, primary);\n        assertEq(markets.getMarket(id).outcome, 0);\n\n        vm.prank(alice);\n        bytes32 aliceRid = oracle.request(escalationBody);\n        OracleAttestation.Attestation memory replacement = attestation(id, abi.encode(true), 10);\n        deliver(aliceRid, replacement);\n\n        vm.prank(alice);\n        vm.expectRevert(VerdictMarkets.UnauthenticatedAnswer.selector);\n        markets.propose(id, replacement);\n    }\n}","reproduction":"Market id=1 (bool, minPanelSize 5, minAgreed 4). Alice bets 100 IMD on outcome 1 (true), Bob bets 100 IMD on outcome 0 (false). At answerFrom anyone calls markets.resolve(1, body); the Intake delivers the market's answer a1 = false (stored, answerOf(a1) == bodyHash). Alice calls oracle.request(body) herself for 0.5 IMD; the Intake delivers a2 = true with a fresh a.requestId; answerOf(a2) == bodyHash too. Alice calls markets.propose(1, a2). Expected: UnauthenticatedAnswer (the market never paid for a2). Actual: accepted, status Provisional, outcome 1; after disputeWindow finalize() pays Alice ~196 IMD. Second sequence: after a legitimate primary (false) is proposed, Alice calls oracle.request(escalationBody) directly, gets a 10-member 'true' answer delivered and calls propose(1, a3) with no escalate() call. Expected: revert. Actual: outcome replaced, m.escalated = true, m.asks still 1, no further replacement possible. See test/scratch/AnswerShopping.t.sol (both tests fail on current code).","severity":"medium","snippet":"        if (oracle.answerOf(a) != expected) revert UnauthenticatedAnswer();","title":"propose() accepts any stored answer for the body, so the first proposer picks among unlimited third-party-bought answers and can replace a primary without any escalate() call"},{"citation":"resolved","description":"Asymmetry between the escalate() guard and the propose() guard. escalate() only requires block.timestamp < answerUntil (via _askWindow) and then extends disputeEnds to at least now + 24h 'so the answer can arrive'. But propose() rejects any attestation with a.issuedAt > p.answerUntil (line 324). An escalation asked within the oracle's answer latency (minutes) of answerUntil therefore produces an answer that is stored at the oracle but can never be proposed. Anyone, holding no IMD, can trigger this at zero cost: the creator's remaining bounty (0.5 IMD) is spent for nothing and finalize() is pushed back by up to 24h for every bettor. The paired guard is missing: escalate() should refuse when the window left before answerUntil is too short for the answer to be issuable (or the issuedAt bound for replacements should be relaxed to the extended window), otherwise the extension is pure delay.","line":300,"path":"src/VerdictMarkets.sol","reproduction":"Params: answerFrom = closeAt, answerUntil = answerFrom + 2h, disputeWindow = 1h, voidAfter = answerUntil + 1d, bounty 1 IMD. Primary answer (false) proposed at answerUntil - 30min, so disputeEnds = answerUntil + 30min. At answerUntil - 1s a third party with zero IMD calls escalate(id, escalationBody): succeeds, oracleSpend = 1 IMD, bountyRemaining = 0, disputeEnds = answerUntil - 1s + 24h. The escalation answer is issued 5 minutes later (issuedAt = answerUntil + 5min) and delivered; oracle.answerOf(a) == escalationBodyHash, yet propose(id, a) reverts InvalidAttestation. finalize() at the original disputeEnds (answerUntil + 30min) reverts OutsideWindow; it only succeeds at answerUntil + 24h - 1s, and the creator's returnedBounty is 0. Reproduced by test/scratch/LateEscalation.t.sol (passes, documenting the behaviour).","severity":"low","snippet":"        m.disputeEnds = Math.max(m.disputeEnds, block.timestamp + 24 hours);","title":"escalate() in the final minutes before answerUntil spends the bounty and extends the dispute window 24h although its answer can never be proposed"},{"citation":"resolved","description":"Access x economics. The brief grants the owner propose/accept over intake, asset, signer, actionId and price behind configDelay, and the Sepolia constructor sets configDelay = 0; the constructor only caps the delay at 30 days and accepts 0. acceptConfig() then succeeds in the same transaction as proposeConfig() (acceptAfter == block.timestamp). The owner (0x397d..., who is also guardian and treasury) can point intake at a contract they control and signer at their own key, call resolve() on any Open market (the 0.5 IMD ask now lands in their intake), deliver a self-signed attestation, propose it and finalize, having bet on the chosen side before closeAt. Markets pin in-flight requests to the old intake/signer, which protects answers already bought but not markets still waiting to be asked. This is the owner power the brief requested, not a bypass, so it is reported as a trust assumption with a reproduction; the mitigation that preserves the design is a non-zero configDelay at deployment (or a constructor minimum) so bettors can observe a pending rotation before it takes effect.","line":78,"path":"src/VerdictOracle.sol","reproduction":"Deploy VerdictOracle(..., owner, configDelay = 0) as in script/SepoliaParameters.sol. Market id=1: owner bets 10 IMD on outcome 1, Bob bets 100 IMD on outcome 0. At answerFrom, in one transaction the owner calls oracle.proposeConfig(Config(fakeIntake, IMD, ownerKeyAddress, action, 0.5e18)) then oracle.acceptConfig() (no revert because block.timestamp >= acceptAfter), then markets.resolve(1, body): 0.5 IMD of the creator's bounty is transferred to fakeIntake. fakeIntake calls onOracleResult with an attestation signed by the owner's key (answer = true): stored. markets.propose(1, a) succeeds; after disputeWindow finalize() and owner claim() returns 107.8 IMD for a 10 IMD stake. Reproduced by test/scratch/OwnerInstantConfig.t.sol (passes, documenting the behaviour).","severity":"low","snippet":"        if (configDelay_ > 30 days) revert InvalidConfig();","title":"Trust assumption: with the deployed configDelay = 0 the oracle owner can swap intake and signer in the same block and forge any open market's outcome"},{"citation":"resolved","description":"Asymmetry. renounceGuardian() refuses to leave the contract in a paused state nobody can undo, but it does not apply the same reasoning to the other guardian-only, otherwise-irreversible switch: allowlistOn. After renounce, guardian == address(0), so setCreatorAllowed() and disableAllowlist() are unreachable forever (onlyGuardian can never pass). If the allowlist is still on, createMarket() is restricted for good to whatever addresses were allowed at that moment; if none were, no market can ever be created again and the deployment is dead while still holding no funds at risk. The brief says renounce is allowed 'only while unpaused'; the same accidental-lock argument applies to renouncing with the allowlist on, and the prior review only documents it as an operational note.","line":225,"path":"src/VerdictMarkets.sol","reproduction":"Fresh deployment (allowlistOn = true, no allowed creators). Guardian calls renounceGuardian(): succeeds, guardian = 0. Any call to createMarket(...) reverts CreatorNotAllowed; setCreatorAllowed(x, true) and disableAllowlist() revert NotGuardian from every address including the former guardian. Expected: either revert (like the paused case) or require disableAllowlist() first; actual: permanent freeze of market creation.","severity":"low","snippet":"        if (paused) revert MustUnpause();","title":"renounceGuardian() while the allowlist is still on permanently freezes the creator set (no paired guard, unlike the pause check)"}],"hash":"338249e95208a585f18d4029376b2827fb0b19d9c9f4017e08929d45bbfc08b1","nodeId":"23bf35af-e360-4a72-9104-c7584415d226","outcome":"completed","summary":"The review is complete. The findings file is written and validated, and no tracked file was changed.\n\n**Outcome.** The permission model is sound in isolation: every guardian and owner path has the right guard, the callback authenticates intake, pending id and recorded signer, and two-step handovers behave. The defects sit at the seams between access, economics and asymmetry, which is my assigned area. I report one medium and three low findings in `.imd-findings.json`, each with a reproduction, plus a coverage row for all 22 entry points and three invariants.\n\n**Findings.**\n- **Medium, answer selection by the first proposer.** `propose` binds an attestation to a market only by body hash. Anyone can buy unlimited extra panels for the same body through the open oracle `request`, keep the favourable answer and propose it before the market's own paid answer. A directly bought escalation answer also replaces a primary without any `escalate` call, consuming the one-shot dispute. The attached proof test fails on current code with two scenarios. The fix needs a scope decision since the brief's wording permits this: have the oracle expose which intake request an answer settled and have markets accept only answers to their own asks.\n- **Low, late escalation is paid but unusable.** An escalation one second before `answerUntil` spends the creator's bounty and extends the window 24 hours, yet its answer fails the `issuedAt <= answerUntil` check and can never be proposed. Any address with no IMD can cause this delay.\n- **Low, trust assumption at configDelay 0.** The Sepolia argument lets the owner swap intake and signer in one block and forge any open market's outcome. Reported as the owner power the brief chose, with a reproduction, and a recommendation for a non-zero delay.\n- **Low, renounce with the allowlist on.** The pause guard on `renounceGuardian` has no counterpart for the allowlist, so renouncing freezes the creator set permanently.\n\n**Coverage.** All 22 entry points have rows. Seventeen hold, five point to the findings above, none unreached. Scratch tests under `test/scratch/` reproduce each finding and are not part of the tree. Slither and aderyn leads on reentrancy, strict equality and the uninitialised local were traced and found benign under the guards and the plain IMD token.","treeHash":null,"usage":{"cachedInputTokens":1308386,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":44193,"runtime":"claude","turns":27,"wallClockMs":739520}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fa99051b60a858d6","findings":[],"hash":"53d4ce13636a6a1d9aa4d9f897a9604dad112e10f584c598ec37eb0af0c7fc65","nodeId":"481c5b80-5437-44fe-a9fe-f8273392f09f","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds an empty findings list with a full coverage record. Nothing from the prior round remains open and no new defect reproduced.\n\n**Settlement of the earlier findings**\n\n- **Answer shopping in propose (medium): fixed.** Both attached proofs now pass. The oracle records which intake request each attestation answered, the market records its own paid ask ids, and propose accepts only answers to those asks. An escalation answer is accepted only after a paid escalate call. Regressions cover cross-market identical bodies and both paid primaries.\n- **Escalation answer issued after answerUntil (medium): fixed.** Both proofs pass. A replacement's issuance is now bounded by the escalation ask time and the extended dispute deadline. The primary-ask half stays as the brief's literal rule and is documented. Since delivered answers are public and anyone may propose, the losing side can propose early and escalate, so the withholding variant has no rational attacker.\n- **Unusable delivery blocks retry (low): author's dispute accepted.** The brief says a retry needs \"no answer delivered\". The cross-market interference part is fixed, since the retry now checks the market's own first request is still pending.\n- **Renounce while allowlist on (low): fixed** with a MustDisableAllowlist revert.\n- **bounds[0] == 0 (low): fixed**, rejected before the bounty is pulled.\n- **configDelay 0 (info): trust assumption**, now documented in the README and revision review.\n- **16,384-byte answer cap (info): kept and documented**, with the cold max-size callback still asserted under 150,000 gas.\n\n**Verification run**\n\n| Check | Result |\n| --- | --- |\n| Four attached proofs on revised code | 6 of 6 tests pass |\n| Full project suite | 121 passed, 0 failed |\n| Runtime sizes (Markets / Oracle / Vault) | 15,639 / 7,720 / 16 bytes |\n\nStatic-analysis leads were reviewed: the reentrancy lines are guarded by nonReentrant and call only the project's own oracle, the strict equality is a zero check on received amount, and the uninitialized local is guarded by an empty flag. The launch manifest matches the brief's constructor arguments and order. Scratch copies of the proofs were removed, so the tree is unchanged apart from the findings file.","treeHash":null,"usage":{"cachedInputTokens":625938,"inputTokens":194,"model":"claude-fable-5-1","outputTokens":16202,"runtime":"claude","turns":14,"wallClockMs":349435}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a13784fa5cb209c3","findings":[],"hash":"54678387de9e2ff4cb227154586af0840a39bbeb7580274b214b28f5d849d0f1","nodeId":"f4a5773b-e02d-40c8-86f7-66332cd4f147","outcome":"failed","summary":"the task produced no changes; the agent's last message was: The environment blocks every command with `bwrap: setting up uid map: Permission denied`, including `forge --version`.\n\nNo files were changed. I couldn’t reproduce the proofs, repair the contracts, write evidence-based finding responses, or run the required checks. The task remains incomplete; the worker’s sandbox needs repair before this revision can continue.","treeHash":null,"usage":{"cachedInputTokens":183936,"inputTokens":48459,"model":"gpt-6.1-sol","outputTokens":728,"runtime":"codex","turns":5,"wallClockMs":275480}},{"artifacts":[],"attempt":1,"bundleHash":"a079a345a65c1c3ad8e57d541591a04a04f9c2ec033af0b7a8305d031384decd","device":"2bb6789ad7b554e8","findings":[],"hash":"680cd8c12c0b806fd3c5d144766ed44d386430f1245e886413a1868f7243ddc1","nodeId":"f4a5773b-e02d-40c8-86f7-66332cd4f147","outcome":"completed","summary":"Implemented all three contracts, vendored dependencies, tests, documentation, and an independent automated review.\n\n`forge build`, `forge test` (**81 passing**), and `forge fmt --check` pass, including clean offline verification.\n\nSepolia deployment and publication remain pending with the launch service; no transactions were broadcast. Exact parameters and responsibilities are documented in `docs/DEPLOYMENT.md`.","treeHash":"ff389b1a497a527004161e62c0a2de36ee5799b5","usage":{"cachedInputTokens":2570624,"inputTokens":127117,"model":"gpt-6-astra","outputTokens":51116,"runtime":"codex","turns":10,"wallClockMs":1314537}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f9cb4fd544aa3c68","findings":[{"citation":"resolved","description":"Boundary x invariant seam. _askWindow lets resolve() and escalate() spend the oracle price right up to answerUntil - 1, but propose() (line 324: `|| a.issuedAt < p.answerFrom || a.issuedAt > p.answerUntil`) refuses every attestation whose issuedAt is past answerUntil. The oracle stamps issuedAt with its own clock when the panel settles, which is minutes after the request, so an ask placed inside the oracle's latency of answerUntil is guaranteed to produce an answer the market can never use. For resolve() this leaves the market to void at voidAfter with the creator's bounty short by the price; for escalate() it spends the price and delays finalization by up to 24 hours with zero chance of a replacement. The two rules are each as the brief states them, but together they make the last minutes of the ask window a pure loss. Either close asks a margin (e.g. the body's validForSeconds or a fixed 15 minutes) before answerUntil, or let propose accept issuedAt up to answerUntil + that margin.","line":409,"path":"src/VerdictMarkets.sol","reproduction":"Market with params(): answerFrom = closeAt, answerUntil = answerFrom + 4 days, voidAfter = answerUntil + 1 hours, bounty = 1 IMD, price 0.5 IMD. alice bets 1 IMD on 1, bob 1 IMD on 0. vm.warp(answerUntil - 1); markets.resolve(id, body) succeeds and oracleSpend == 0.5 IMD. vm.warp(answerUntil + 120); the intake delivers a valid signed attestation with issuedAt = answerUntil + 120; oracle.answerOf(a) == bodyHash. markets.propose(id, a) reverts InvalidAttestation. At voidAfter, voidMarket(id) returns only 0.5 IMD to the creator. Expected: an ask the contract accepts should be answerable, or the ask should be refused. Actual: the ask is accepted and the price is spent with no possible outcome. Reproduced in test/scratch/Probe.t.sol::test_askRightBeforeAnswerUntilIsWasted.","severity":"low","snippet":"        if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();","title":"Asks are accepted until answerUntil-1 although any answer stamped after answerUntil is unusable, so a late ask burns 0.5 IMD of the bounty for nothing"},{"citation":"resolved","description":"Boundary case in _validateParams. The ascending-order loop starts at i = 1, so nothing constrains bounds[0]. Bucket 0 is defined as x < bounds[0]; with bounds[0] == 0 no uint256 satisfies it, yet the market still advertises outcomes = bounds.length + 1 and bet() accepts stakes on outcome 0. Every IMD staked on outcome 0 is a guaranteed loss paid to the other buckets. A one-line check `p.bounds[0] == 0` -> InvalidParams closes it.","line":465,"path":"src/VerdictMarkets.sol","reproduction":"params() with answerType = 3, bounds = [0, 10]. createMarket succeeds and getMarket(id).outcomes == 3. alice bets 1 IMD on outcome 0 (accepted). At answerFrom resolve, deliver a signed attestation with answer = abi.encode(uint256(0)), propose: getMarket(id).outcome == 1 (value 0 lands in bucket 1 because 0 < 0 is false). No answer value can ever select outcome 0. Expected: createMarket rejects an empty bucket. Actual: an unwinnable outcome is offered for betting. Reproduced in test/scratch/Probe.t.sol::test_zeroLowerBoundUnreachableBucket.","severity":"low","snippet":"                if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();","title":"bounds[0] == 0 passes validation and creates a numeric bucket that can never win"},{"citation":"resolved","description":"Boundary x gas seam. onOracleResult reverts for any answer longer than MAX_ANSWER_BYTES (16,384). The intake attempts the callback once and never retries, so a signed, otherwise valid answer that is 16,416 bytes long (an address[] of more than ~510 entries, or bytes32[] of the same count) is dropped: pending stays set, nothing is stored, the 0.5 IMD is gone, and a market waiting on it voids. Measured cold-callback gas with a 16,384-byte answer is 98,483, far below the 200,000 stipend (and the brief's 150,000 target), so the cap is well below what the callback can actually afford. Either raise the cap to what the gas budget supports (a 32 KiB answer measures well under 150k) or truncate: VerdictMarkets only reads the first list element.","line":124,"path":"src/VerdictOracle.sol","reproduction":"oracle.request(body) -> id. Build an attestation with answerType 5 and answer = new bytes(16_416), signed by the configured signer for the oracle's domain. intake.deliver(id, a, sig, 200_000) returns ok = false after 17,720 gas (revert InvalidAttestation); oracle.pending(id) still set, oracle.answerOf(a) == 0. The same delivery with answer = new bytes(16_384) succeeds using 98,483 gas. Expected: an answer the gas budget can store is stored. Actual: it is refused and the request is permanently unanswered. Measured in test/scratch/Probe2.t.sol::test_gasScaling.","severity":"low","snippet":"        if (a.answer.length > MAX_ANSWER_BYTES || a.expiresAt < a.issuedAt) revert InvalidAttestation();","title":"Callback refuses answers over 16,384 bytes although the stipend affords twice that, so an oversize list answer loses the paid request"},{"citation":"resolved","description":"lastDelivered records that some attestation for the body reached the oracle; it says nothing about whether the market's propose() checks (minAgreed, minPanelSize, agreed >= quorum, issuedAt window) accept it. A delivered answer with agreed < minAgreed (a split panel settled by the deployer rerun) therefore both fails propose and permanently forbids the second primary ask, so the market voids with half the bounty unspent. This is what the brief literally specifies ('no answer delivered for bodyHash'), so it is reported for the author's awareness rather than as a defect; a retry rule keyed on 'no usable answer' would need the market to be told which attestation was delivered.","line":285,"path":"src/VerdictMarkets.sol","reproduction":"Market with minAgreed = 4. At answerFrom resolve(id, body). Same block, deliver a signed attestation with panelSize 5, quorum 4, agreed 3. propose(id, a) reverts InvalidAttestation. vm.warp(+24 hours); resolve(id, body) reverts AnswerAlreadyDelivered. Market can only void at voidAfter. Reproduced in test/scratch/Probe.t.sol::test_sameBlockDeliveryBlocksRetry.","severity":"info","snippet":"            if (oracle.lastDelivered(m.bodyHash) >= m.lastPrimaryAsk) revert AnswerAlreadyDelivered();","title":"Primary retry is blocked by any delivery for the body, including one the market cannot use"},{"citation":"resolved","description":"The renounce guard only covers the paused flag. If the guardian renounces while allowlistOn is true, no address can ever call setCreatorAllowed or disableAllowlist again, so the creator set is frozen at whatever it was; with no creators allowlisted (the state right after deployment) createMarket is permanently unreachable. This is a guardian self-inflicted state with no unprivileged trigger, so it is informational; the same reasoning that forbids renouncing while paused argues for also requiring the allowlist to be off (or non-empty) first.","line":225,"path":"src/VerdictMarkets.sol","reproduction":"Fresh deployment, no creator allowlisted. guardian calls renounceGuardian() -> succeeds, guardian() == 0, allowlistOn() == true. disableAllowlist() and setCreatorAllowed(x, true) now revert NotGuardian from every caller; createMarket reverts CreatorNotAllowed for everyone. Reproduced in test/scratch/Probe2.t.sol::test_renounceWhileAllowlistOnFreezesCreation.","severity":"info","snippet":"        if (paused) revert MustUnpause();","title":"renounceGuardian is allowed while the allowlist is still on, which can freeze market creation forever"}],"hash":"a5869253ee5a2b8ca1af74633d5390da745465cad5612a066a198cb63c40daef","nodeId":"d82d424f-8b70-4c32-b099-178350597d41","outcome":"completed","summary":"Review complete. The findings file is written and every snippet matches its source line.\n\n**Outcome: no critical, high or medium defects in the math, boundary or numerical-gap area.** The arithmetic in VerdictMarkets and VerdictOracle holds up under tracing and probing: fee floors by mulDiv sum to at most 5% of the pool, the last winning claim takes an exact remainder and I proved the remainder cannot underflow, the pool-cap subtraction cannot wrap, bounty checks guarantee two asks at the creation-time price, timestamps are consistent at every inclusive or exclusive edge, and the callback costs about 98k gas cold with a maximum-size answer. The existing 81-test suite passes, and my scratch probes under `test/scratch/` confirmed each edge I report.\n\n**Findings written to `.imd-findings.json`** (3 low, 2 info, each with a concrete reproduction):\n\n- **Low, late asks are wasted.** `resolve` and `escalate` accept an ask one second before `answerUntil`, but `propose` rejects any attestation stamped after it. The oracle answers minutes later, so such an ask spends 0.5 IMD with no usable result and the market voids.\n- **Low, empty first bucket.** A numeric market with `bounds[0] == 0` passes validation. Outcome 0 means x < 0, which nothing satisfies, yet bets on it are accepted and always lose.\n- **Low, answer size cap too tight.** The callback refuses answers over 16,384 bytes and the intake never retries, so a long list answer loses the paid request. Measured gas shows the cap could be roughly doubled within the 150k target.\n- **Info, retry blocked by unusable delivery.** Any delivery for the body blocks the second primary ask, even one the market cannot accept. This matches the brief literally, so it is noted rather than flagged.\n- **Info, renounce with allowlist on.** The guardian may renounce while the allowlist is still enabled, freezing creator onboarding forever. Admin self-inflicted, no unprivileged trigger.\n\n**Coverage:** all 22 listed entry points have a row, plus three invariant rows. Six are marked `finding` with the references above; the rest are `holds`. Nothing was left `unreached`.","treeHash":null,"usage":{"cachedInputTokens":1531848,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":45529,"runtime":"claude","turns":34,"wallClockMs":712683}},{"artifacts":[],"attempt":1,"bundleHash":"bc71457d8df88cd6de395251577a84df89b0d5f73d17e197529d4b8cdc81b4d1","device":"30739b66307c87c9","findings":[],"hash":"a88654d4d8406a181bd2d9afaa36aa2f3662cd2ed1417ec52dfd59fa8a0c5ff3","nodeId":"b02865ce-1c19-4c48-90ce-fe310c9d4ed6","outcome":"completed","summary":"Added 22 tests covering adversarial callbacks, payment rollback, settlement rounding, and stateful accounting invariants.\n\n`forge build` and `forge test` pass: **103 tests, 0 failures**. The new invariant passed 16,384 randomized calls.\n\nAll changes are under `test/`. No reproducible implementation defects were found.","treeHash":"5c1ff3145c18d3a666ac035056a6776072021804","usage":{"cachedInputTokens":4441856,"inputTokens":159337,"model":"gpt-6-astra","outputTokens":31347,"runtime":"codex","turns":10,"wallClockMs":1053014}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"29819a9ff9555c6f","findings":[],"hash":"b1fc720581678dc59c8e41afd532def693cfe1d92c86062b2316d3b694230182","nodeId":"9b74446b-623f-466d-9852-bab81354466f","outcome":"failed","summary":"the task produced no changes; the agent's last message was: The existing [launch.json](/home/identitymd7/.identitymd/work/251040a3-bb92-4aa0-b0a7-7cabf335c514/9b74446b-623f-466d-9852-bab81354466f/launch.json) already matches the approved brief and compiled constructor ABIs. No changes were needed.\n\nValidation passed: manifest constraints, `forge build`, and all 94 Foundry tests. The working tree is unchanged.","treeHash":null,"usage":{"cachedInputTokens":403328,"inputTokens":42385,"model":"gpt-6-astra","outputTokens":3147,"runtime":"codex","turns":4,"wallClockMs":184360}},{"artifacts":[],"attempt":1,"bundleHash":"00b05b1b844617189bc4693598efbe48c87735dd408505d316d19fe09a7c7761","device":"06c32862bedacb46","findings":[],"hash":"e09b659867e619fca91cde08d7057b2eb0e1c26993e9aa1bb5b80a88deddd876","nodeId":"f4a5773b-e02d-40c8-86f7-66332cd4f147","outcome":"completed","summary":"Implemented targeted fixes for request binding, late escalation answers, guardian renunciation, and numeric bounds.\n\nAll seven findings are answered in [.imd-responses.json](.imd-responses.json), including the preserved retry and primary-timing limits.\n\nValidation passed: 94 tests, all three supplied proof tests, independent revision review, and clean offline build/test/format checks.\n\nSepolia deployment remains with the launch service.","treeHash":"6b4979004169e8f878538df38896cd96d2f4a584","usage":{"cachedInputTokens":1924428,"inputTokens":121887,"model":"gpt-6.1-sol","outputTokens":14998,"runtime":"codex","turns":5,"wallClockMs":298319}},{"artifacts":[],"attempt":2,"bundleHash":"0747ecbcc0dd3a818f33aed775bb5956b4494d49a1b40274632fd9a45711a12c","device":"7d2db8d9021f8063","findings":[],"hash":"efa2c60d32ef1fcc13ec81a61f7300d6a657aeff245fd823877c39a837049f91","nodeId":"9b74446b-623f-466d-9852-bab81354466f","outcome":"completed","summary":"Updated `launch.json` notes to clarify guardian permissions and initial allowlist requirements. Approved constructor arguments and deployment order are preserved.\n\nValidation passed: manifest constraints, compiled constructor ABIs, `forge build`, and all 94 Foundry tests. Only `launch.json` changed.","treeHash":"6efc5072554eeedc21130f38c6bd959bc221b1e2","usage":{"cachedInputTokens":209027,"inputTokens":35109,"model":"gpt-6.1-sol","outputTokens":2340,"runtime":"codex","turns":3,"wallClockMs":62395}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fa2b7fcb5f53535a","findings":[{"citation":"resolved","description":"Merged from audit_flow (5f7d05b5), audit_permissions (ed995c2e) and audit_economics (188c1d51): same root cause. The only link between an attestation and a market is oracle.answerOf(a) == bodyHash (or escalationBodyHash). VerdictOracle.request(bytes) is open to anyone for the oracle price and every delivered answer is stored under its own a.requestId with the same bodyHash, so unlimited contradicting answers for one body can coexist and all pass line 318. Nothing ties a proposal to the asks the market itself paid for through resolve()/escalate() (OracleAsked ids are emitted but never recorded), nothing prefers the market's own answer, and the first accepted proposal is final for the primary (status Open -> Provisional) while the first accepted replacement is final for the escalation (escalated = true). Consequences: (1) a bettor on the losing side re-runs the market's exact body at 0.5 IMD per sample and proposes the first favourable answer; the market's own paid answer is never used. (2) An escalation-body answer bought directly at the oracle replaces a primary while escalationAsked is false and asks == 1, consuming the single replacement, so escalate() then reverts WrongState and honest parties get no dispute. (3) Both can be done in one block (primary + pre-fetched 2x-panel replacement), locking the pick. Precondition: the panel must be able to return different answers for the same body (subjective or 'panel' evidence questions, split chain-evidence reruns), which is exactly the case the escalation design exists for; with a deterministic panel the race is harmless, hence medium rather than high. Economics: pool cap 500 IMD against 0.5 IMD per sample. The brief's literal wording ('answerOf(a) must equal bodyHash') permits this, so the fix needs a scope decision; one that keeps 'anyone can resolve': record the intakeRequestId returned by each of the market's own asks, have VerdictOracle expose which intake request an a.requestId answered, and accept in propose() only answers to the market's own asks (escalation answers only after escalate()). The existing test test_externalSponsorCanDeliverPrimaryAndEscalation codifies the current behaviour, so the suite does not catch it.","line":318,"path":"src/VerdictMarkets.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {VerdictOracle} from \"src/VerdictOracle.sol\";\nimport {VerdictMarkets} from \"src/VerdictMarkets.sol\";\nimport {VerdictBurnVault} from \"src/VerdictBurnVault.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ShopIMD is ERC20 {\n    constructor() ERC20(\"Test IMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\ncontract ShopIntake is IIntake {\n    using SafeERC20 for IERC20;\n\n    uint256 public nonce;\n    mapping(bytes32 => Callback) public callbacks;\n\n    function request(bytes32, bytes calldata, Callback calldata callback, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);\n        id = keccak256(abi.encode(address(this), ++nonce));\n        callbacks[id] = callback;\n    }\n\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata signature)\n        external\n        returns (bool ok)\n    {\n        Callback memory cb = callbacks[id];\n        (ok,) = cb.target.call{gas: 200_000}(abi.encodeWithSelector(cb.selector, id, a, signature));\n    }\n}\n\n/// @notice Whoever proposes first picks among every answer anyone ever bought for the body.\n/// The market's own paid answer (false) is discarded in favour of a sponsor-bought answer (true),\n/// and a sponsor-bought escalation answer replaces a primary without any escalate() call.\ncontract AnswerShoppingTest is Test {\n    uint256 internal constant SIGNER_KEY = 0x123456;\n    uint256 internal constant PRICE = 0.5 ether;\n\n    address internal creator = makeAddr(\"creator\");\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n    address internal treasury = makeAddr(\"treasury\");\n\n    ShopIMD internal token;\n    ShopIntake internal intake;\n    VerdictOracle internal oracle;\n    VerdictMarkets internal markets;\n    bytes internal body = '{\"v\":1,\"question\":\"primary\"}';\n    bytes internal escalationBody = '{\"v\":1,\"question\":\"primary\",\"panelSize\":10}';\n    uint256 internal attNonce;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.chainId(11155111);\n        token = new ShopIMD();\n        intake = new ShopIntake();\n        oracle = new VerdictOracle(\n            address(intake), address(token), vm.addr(SIGNER_KEY), bytes32(\"oracle.request@oracle-1\"), PRICE, address(this), 0\n        );\n        VerdictBurnVault burn = new VerdictBurnVault();\n        markets = new VerdictMarkets(\n            address(oracle), address(token), treasury, address(burn), address(this), 100, 50, 50, 500 ether\n        );\n        markets.setCreatorAllowed(creator, true);\n        address[4] memory users = [address(this), creator, alice, bob];\n        for (uint256 i; i < users.length; i++) {\n            token.mint(users[i], 1_000 ether);\n            vm.startPrank(users[i]);\n            token.approve(address(markets), type(uint256).max);\n            token.approve(address(oracle), type(uint256).max);\n            vm.stopPrank();\n        }\n    }\n\n    function params() internal view returns (VerdictMarkets.Params memory p) {\n        p.questionHash = keccak256(\"question\");\n        p.answerType = 0;\n        p.dataChainId = 1;\n        p.fromBlock = 100;\n        p.toBlock = 200;\n        p.minPanelSize = 5;\n        p.minAgreed = 4;\n        p.closeAt = uint64(block.timestamp + 1 hours);\n        p.answerFrom = p.closeAt;\n        p.answerUntil = p.answerFrom + 4 days;\n        p.disputeWindow = 1 days;\n        p.voidAfter = p.answerUntil + 1 hours;\n        p.bounty = 2 * PRICE;\n    }\n\n    function attestation(uint256 id, bytes memory answer, uint16 panel)\n        internal\n        returns (OracleAttestation.Attestation memory a)\n    {\n        VerdictMarkets.Params memory p = markets.getMarket(id).params;\n        a.requestId = keccak256(abi.encode(\"oracle request\", ++attNonce));\n        a.chainId = p.dataChainId;\n        a.questionHash = p.questionHash;\n        a.answerType = p.answerType;\n        a.answer = answer;\n        a.fromBlock = p.fromBlock;\n        a.toBlock = p.toBlock;\n        a.blockHash = keccak256(\"closing block\");\n        a.panelJobId = keccak256(abi.encode(\"panel\", attNonce));\n        a.panelSize = panel;\n        a.quorum = 4;\n        a.agreed = panel;\n        a.issuedAt = uint64(block.timestamp);\n        a.expiresAt = uint64(block.timestamp + 7 days);\n    }\n\n    function deliver(bytes32 rid, OracleAttestation.Attestation memory a) internal {\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(SIGNER_KEY, oracle.attestationDigest(a));\n        assertTrue(intake.deliver(rid, a, abi.encodePacked(r, s, v)), \"delivery failed\");\n    }\n\n    /// Market paid for one answer (false). Alice, who bet on true, buys her own answers directly\n    /// at the oracle until one says true and proposes it first. Expected: only an answer the market\n    /// paid for (one of its own asks) may be proposed. Actual: the sponsor-bought answer is accepted\n    /// and the market finalizes on it.\n    function test_firstProposerPicksAmongDivergentAnswers() public {\n        vm.prank(creator);\n        uint256 id = markets.createMarket(params(), body, escalationBody, \"ipfs://m\", 1);\n        vm.prank(alice);\n        markets.bet(id, 1, 100 ether, 0);\n        vm.prank(bob);\n        markets.bet(id, 0, 100 ether, 0);\n\n        vm.warp(markets.getMarket(id).params.answerFrom);\n        // The market's own paid ask answers \"false\".\n        bytes32 marketRid = markets.resolve(id, body);\n        OracleAttestation.Attestation memory marketAnswer = attestation(id, abi.encode(false), 5);\n        deliver(marketRid, marketAnswer);\n\n        // Alice buys a second panel for the same body; this one answers \"true\".\n        vm.prank(alice);\n        bytes32 aliceRid = oracle.request(body);\n        OracleAttestation.Attestation memory aliceAnswer = attestation(id, abi.encode(true), 5);\n        deliver(aliceRid, aliceAnswer);\n\n        // Expected: an answer the market did not pay for is refused.\n        vm.prank(alice);\n        vm.expectRevert(VerdictMarkets.UnauthenticatedAnswer.selector);\n        markets.propose(id, aliceAnswer);\n    }\n\n    /// A sponsor-bought escalation answer replaces the primary outcome although escalate() was\n    /// never called and the market never spent a second ask. Expected: replacement requires the\n    /// market's own escalation ask. Actual: accepted, escalated = true, asks still 1.\n    function test_replacementWithoutEscalationAsk() public {\n        vm.prank(creator);\n        uint256 id = markets.createMarket(params(), body, escalationBody, \"ipfs://m\", 1);\n        vm.prank(alice);\n        markets.bet(id, 1, 100 ether, 0);\n        vm.prank(bob);\n        markets.bet(id, 0, 100 ether, 0);\n\n        vm.warp(markets.getMarket(id).params.answerFrom);\n        bytes32 marketRid = markets.resolve(id, body);\n        OracleAttestation.Attestation memory primary = attestation(id, abi.encode(false), 5);\n        deliver(marketRid, primary);\n        markets.propose(id, primary);\n        assertEq(markets.getMarket(id).outcome, 0);\n\n        vm.prank(alice);\n        bytes32 aliceRid = oracle.request(escalationBody);\n        OracleAttestation.Attestation memory replacement = attestation(id, abi.encode(true), 10);\n        deliver(aliceRid, replacement);\n\n        vm.prank(alice);\n        vm.expectRevert(VerdictMarkets.UnauthenticatedAnswer.selector);\n        markets.propose(id, replacement);\n    }\n}","reproduction":"Market id=1 (bool, minPanelSize 5, minAgreed 4, params as in TestBase). alice bets 100 IMD on outcome 1, bob bets 100 IMD on outcome 0. At answerFrom anyone calls markets.resolve(1, body); the intake delivers the market's answer a1 = false (stored, answerOf(a1) == keccak256(body)). alice calls oracle.request(body) for 0.5 IMD; the intake delivers a2 = true under a fresh a.requestId; answerOf(a2) == keccak256(body) too. alice calls markets.propose(1, a2). Expected: revert UnauthenticatedAnswer (the market never paid for a2). Actual: accepted, status Provisional, outcome 1; after disputeWindow finalize() pays alice 196 IMD of the 200 IMD pool. Second sequence: after the legitimate primary (false) is proposed, alice calls oracle.request(escalationBody) directly, a 10-member 'true' answer is delivered, and alice calls propose(1, a3) with no escalate() call. Expected: revert. Actual: outcome replaced, escalated = true, asks still 1, escalate() now reverts WrongState. Verified: forge test --match-path test/scratch/Proof_ed995c2e03dd.t.sol fails both tests on the current code with 'next call did not revert as expected'.","severity":"medium","snippet":"        if (oracle.answerOf(a) != expected) revert UnauthenticatedAnswer();","title":"propose() accepts any oracle answer stored for the body hash, so a bettor can buy extra panels and pick the outcome, and can replace a primary with a pre-bought escalation answer without any escalate("},{"citation":"resolved","description":"Merged from audit_economics (a2c470f3), audit_flow (e2531d6a), audit_permissions (fbd911bc) and audit_math (ecbb8095): one boundary mismatch. _askWindow (line 409) lets resolve() and escalate() spend the oracle price while block.timestamp < answerUntil, and escalate() (line 300) sets disputeEnds = max(disputeEnds, now + 24 hours) 'so the answer can arrive'. The oracle stamps issuedAt minutes after the ask, yet line 324 refuses issuedAt > answerUntil for replacements as well as first proposals. So every ask placed within the oracle's latency of answerUntil is paid from the creator's bounty for an attestation the market can never accept. For escalate() this is a zero-cost grief available to anyone holding no IMD: 0.5 IMD of the bounty is burnt, finalize() is pushed back up to 24 hours for all bettors, and the primary stands. For resolve() on an Open market it leaves the market to void at voidAfter with half the bounty spent. It is also usable deliberately: a first proposal is accepted until voidAfter (line 314) while escalate() stops at answerUntil, so whoever holds an early-delivered primary answer that favours them proposes it shortly before or after answerUntil; escalate() then either reverts OutsideWindow or buys an unusable answer, and no sponsor can produce a timely escalation attestation either because every attestation issued from then on has issuedAt > answerUntil. The bounty-funded dispute the brief requires is therefore not kept whenever the primary lands late in the ask window; the side that would win under the corrected answer loses the pool minus fees. Both rules follow the brief literally, so the fix needs a scope decision: bound a replacement's issuedAt by the dispute deadline in force (and at least the primary proposal time) instead of answerUntil, and/or refuse asks closer than a latency margin to answerUntil.","line":324,"path":"src/VerdictMarkets.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {VerdictOracle} from \"src/VerdictOracle.sol\";\nimport {VerdictMarkets} from \"src/VerdictMarkets.sol\";\nimport {VerdictBurnVault} from \"src/VerdictBurnVault.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofIMD is ERC20 {\n    constructor() ERC20(\"Test IMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\ncontract ProofIntake is IIntake {\n    uint256 public nonce;\n    mapping(bytes32 => Callback) public callbacks;\n\n    function request(bytes32, bytes calldata, Callback calldata callback, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        IERC20(asset).transferFrom(msg.sender, address(this), amount);\n        id = keccak256(abi.encode(address(this), ++nonce));\n        callbacks[id] = callback;\n    }\n\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata signature)\n        external\n        returns (bool ok)\n    {\n        Callback memory cb = callbacks[id];\n        (ok,) = cb.target.call{gas: 200_000}(abi.encodeWithSelector(cb.selector, id, a, signature));\n    }\n}\n\n/// @dev Finding: an escalation asked shortly before answerUntil yields an answer issued after answerUntil,\n/// which propose() rejects, so the paid escalation can never replace the primary outcome.\ncontract EscalationTimingProof is Test {\n    uint256 internal constant SIGNER_KEY = 0x123456;\n    uint256 internal constant PRICE = 0.5 ether;\n    bytes32 internal constant QUESTION = keccak256(\"precisely defined question\");\n    address internal creator = makeAddr(\"creator\");\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n    ProofIMD internal token;\n    ProofIntake internal intake;\n    VerdictOracle internal oracle;\n    VerdictMarkets internal markets;\n    bytes internal body = '{\"v\":1,\"question\":\"primary\"}';\n    bytes internal escalationBody = '{\"v\":1,\"question\":\"primary\",\"panelSize\":10}';\n    uint256 internal attNonce;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.chainId(11155111);\n        token = new ProofIMD();\n        intake = new ProofIntake();\n        oracle = new VerdictOracle(\n            address(intake), address(token), vm.addr(SIGNER_KEY), bytes32(\"oracle.request@oracle-1\"), PRICE, address(this), 0\n        );\n        VerdictBurnVault burn = new VerdictBurnVault();\n        markets = new VerdictMarkets(\n            address(oracle), address(token), makeAddr(\"treasury\"), address(burn), address(this), 100, 50, 50, 500 ether\n        );\n        markets.setCreatorAllowed(creator, true);\n        address[3] memory users = [creator, alice, bob];\n        for (uint256 i; i < users.length; i++) {\n            token.mint(users[i], 1_000 ether);\n            vm.prank(users[i]);\n            token.approve(address(markets), type(uint256).max);\n        }\n    }\n\n    function params() internal view returns (VerdictMarkets.Params memory p) {\n        p.questionHash = QUESTION;\n        p.answerType = 0;\n        p.dataChainId = 1;\n        p.fromBlock = 100;\n        p.toBlock = 200;\n        p.minPanelSize = 5;\n        p.minAgreed = 4;\n        p.closeAt = uint64(block.timestamp + 1 hours);\n        p.answerFrom = p.closeAt;\n        p.answerUntil = p.answerFrom + 4 days;\n        p.disputeWindow = 1 days;\n        p.voidAfter = p.answerUntil + 1 hours;\n        p.bounty = 2 * PRICE;\n    }\n\n    function attestation(VerdictMarkets.Params memory p, bytes memory answer, uint16 panel, uint64 issuedAt)\n        internal\n        returns (OracleAttestation.Attestation memory a)\n    {\n        a.requestId = keccak256(abi.encode(\"oracle request\", ++attNonce));\n        a.chainId = p.dataChainId;\n        a.questionHash = p.questionHash;\n        a.answerType = p.answerType;\n        a.answer = answer;\n        a.fromBlock = p.fromBlock;\n        a.toBlock = p.toBlock;\n        a.blockHash = keccak256(\"closing block\");\n        a.panelJobId = keccak256(abi.encode(\"panel\", attNonce));\n        a.panelSize = panel;\n        a.quorum = 4;\n        a.agreed = panel;\n        a.issuedAt = issuedAt;\n        a.expiresAt = issuedAt + 7 days;\n    }\n\n    function deliver(bytes32 requestId, OracleAttestation.Attestation memory a) internal {\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(SIGNER_KEY, oracle.attestationDigest(a));\n        assertTrue(intake.deliver(requestId, a, abi.encodePacked(r, s, v)), \"callback failed\");\n    }\n\n    /// Escalation asked 10 minutes before answerUntil; the oracle answers 15 minutes later (issuedAt is\n    /// answerUntil + 5 minutes), inside the 24 hour window escalate() extended. The replacement should be\n    /// accepted; today propose() reverts InvalidAttestation and the market finalizes on the disputed outcome.\n    function test_escalationAnswerIssuedInsideExtendedWindowReplacesPrimary() public {\n        VerdictMarkets.Params memory p = params();\n        vm.prank(creator);\n        uint256 id = markets.createMarket(p, body, escalationBody, \"\", 0);\n        vm.prank(alice);\n        markets.bet(id, 1, 100 ether, 0);\n        vm.prank(bob);\n        markets.bet(id, 0, 100 ether, 0);\n\n        // Primary answer \"true\" issued and delivered early in the ask window.\n        vm.warp(p.answerFrom);\n        bytes32 primaryId = markets.resolve(id, body);\n        OracleAttestation.Attestation memory primary = attestation(p, abi.encode(true), 5, uint64(block.timestamp));\n        deliver(primaryId, primary);\n\n        // Alice (winner under \"true\") proposes it 10 minutes before answerUntil.\n        vm.warp(p.answerUntil - 10 minutes);\n        vm.prank(alice);\n        markets.propose(id, primary);\n\n        // Bob escalates at once, still before answerUntil; the window is extended by 24 hours \"so the answer can arrive\".\n        vm.prank(bob);\n        bytes32 escalationId = markets.escalate(id, escalationBody);\n        assertEq(markets.getMarket(id).disputeEnds, block.timestamp + 24 hours);\n        assertEq(markets.getMarket(id).oracleSpend, 2 * PRICE);\n\n        // The oracle answers 15 minutes later with the larger panel: \"false\".\n        vm.warp(block.timestamp + 15 minutes);\n        OracleAttestation.Attestation memory escalation =\n            attestation(p, abi.encode(false), 10, uint64(block.timestamp));\n        deliver(escalationId, escalation);\n        assertEq(oracle.answerOf(escalation), keccak256(escalationBody));\n        assertLt(block.timestamp, markets.getMarket(id).disputeEnds);\n\n        // Expected: the paid escalation answer replaces the primary outcome inside the extended window.\n        vm.prank(bob);\n        markets.propose(id, escalation);\n        VerdictMarkets.Market memory m = markets.getMarket(id);\n        assertTrue(m.escalated, \"escalation answer must be usable inside the window it extended\");\n        assertEq(m.outcome, 0);\n    }\n}","reproduction":"Market with closeAt = answerFrom = T, answerUntil = T + 4 days, disputeWindow = 1 day, voidAfter = answerUntil + 1h, bounty 1 IMD; alice 100 IMD on 1, bob 100 IMD on 0. At T resolve(id, body); the oracle delivers 'true' (issuedAt = T). At answerUntil - 10 minutes alice proposes it (Provisional, outcome 1). bob immediately calls escalate(id, escalationBody): succeeds, disputeEnds = now + 24h, oracleSpend = 1 IMD, bountyRemaining = 0. 15 minutes later the oracle delivers the escalation attestation (panelSize 10, answer false, issuedAt = answerUntil + 5 minutes); oracle.answerOf(e) == keccak256(escalationBody) and block.timestamp < disputeEnds. bob calls propose(id, e). Expected: replacement accepted (escalated = true, outcome 0). Actual: revert InvalidAttestation from the issuedAt > answerUntil branch; finalize() at disputeEnds pays alice 196 IMD. Verified: forge test --match-path test/scratch/Proof_a2c470f37289.t.sol fails on the current code with InvalidAttestation(). Variants reproduced in test/scratch/Repro.t.sol: test_lateResolveWasted (resolve at answerUntil-1 accepted, oracleSpend 0.5 IMD, answer issued at answerUntil+120 rejected, voidMarket returns only 0.5 IMD) and test_lateEscalationGrief (third party with zero IMD escalates at answerUntil-1: bountyRemaining 0, disputeEnds = answerUntil - 1 + 24h, escalation answer rejected, finalize() at the original disputeEnds reverts OutsideWindow and only succeeds 24h later with the primary outcome).","severity":"medium","snippet":"                || a.issuedAt < p.answerFrom || a.issuedAt > p.answerUntil","title":"Asks are accepted until answerUntil-1 and escalate() extends the window 24h, but propose() rejects any attestation issued after answerUntil, so late asks are paid for answers that can never be used an"},{"citation":"resolved","description":"Merged from audit_flow (eaa7a8f6), audit_economics (27f32bfa) and audit_math (e1a93238). VerdictOracle.onOracleResult sets lastDelivered[bodyHash] for every signature-valid delivery, including attestations propose() rejects at lines 320-327 (the protocol reference documents agreed < quorum as a legitimate chain-evidence outcome). lastPrimaryAsk only moves on a successful resolve(), so once such a delivery lands the condition at line 285 is true for the rest of the market's life and the second paid ask the brief allows 'after 24 hours with no answer delivered' is unreachable. lastDelivered is also keyed globally by bodyHash, so any delivery for the same body bought for another market or by a sponsor blocks this market's retry as well. Bettor principal is not at risk (voidMarket refunds after voidAfter) and the unspent half of the bounty is returned, so the impact is liveness and a dead retry; resolution then depends on a volunteer paying through VerdictOracle.request. The behaviour matches the brief's literal wording, so a fix is a scope decision: gate the retry on an answer the market actually accepted (e.g. a per-market flag) or let VerdictOracle record whether the delivered attestation met agreed >= quorum.","line":285,"path":"src/VerdictMarkets.sol","reproduction":"Market id=1 with minAgreed 4. alice bets 10 IMD on 1. At answerFrom call markets.resolve(1, body) (asks = 1, 0.5 IMD spent, lastPrimaryAsk = now). The intake delivers a correctly signed attestation with panelSize 5, quorum 4, agreed 3: onOracleResult stores it and sets lastDelivered[bodyHash] = now; oracle.answerOf(a) == keccak256(body). markets.propose(1, a) reverts InvalidAttestation (agreed < quorum). vm.warp(+24 hours); markets.resolve(1, body). Expected: retry allowed because no usable answer exists. Actual: revert AnswerAlreadyDelivered; asks stays 1; the only exit is voidMarket at voidAfter. Verified in test/scratch/Repro.t.sol::test_unusableDeliveryBlocksRetry (passes on the current code, i.e. the sequence is as described).","severity":"low","snippet":"            if (oracle.lastDelivered(m.bodyHash) >= m.lastPrimaryAsk) revert AnswerAlreadyDelivered();","title":"A delivered answer the market cannot use (agreed < quorum, below minAgreed or minPanelSize, late issuedAt) permanently blocks the 24-hour primary retry"},{"citation":"resolved","description":"Merged from audit_permissions (cf9672a9) and audit_math (3ea7288b). renounceGuardian() refuses to leave the contract paused with nobody able to unpause, but applies no equivalent check to the other guardian-only irreversible switch, allowlistOn. After renounce guardian == address(0), so setCreatorAllowed() and disableAllowlist() can never pass onlyGuardian again. If the allowlist is still on, createMarket() is restricted for good to the addresses allowed at that moment; in the launch's initial state (allowlistOn = true, no creators) no market can ever be created and the deployment is dead. No funds are at risk and only the guardian can trigger it, so low. The paired guard (require !allowlistOn, or at least one allowed creator) preserves the brief's design.","line":225,"path":"src/VerdictMarkets.sol","reproduction":"Fresh VerdictMarkets deployment (allowlistOn = true, no allowed creators). Guardian calls renounceGuardian(): succeeds, guardian() == address(0), allowlistOn() == true. disableAllowlist() and setCreatorAllowed(x, true) revert NotGuardian from every caller including the former guardian; createMarket(...) reverts CreatorNotAllowed for everyone. Expected: revert like the paused case, or require disableAllowlist() first. Actual: permanent freeze of market creation. Verified in test/scratch/Repro.t.sol::test_renounceWhileAllowlistOnFreezes.","severity":"low","snippet":"        if (paused) revert MustUnpause();","title":"renounceGuardian() is allowed while the allowlist is still on, which freezes the creator set forever (empty right after deployment)"},{"citation":"resolved","description":"From audit_math (6b0a2609), reproduced. The strictly-ascending loop starts at i = 1, so bounds[0] is unconstrained. Bucket 0 is defined as x < bounds[0]; with bounds[0] == 0 no uint256 satisfies it, but the market still advertises outcomes = bounds.length + 1 and bet() accepts stakes on outcome 0. Every IMD staked on outcome 0 is a guaranteed loss paid to the other buckets. Bettors can read the bounds, so this is a creator-configured trap rather than a hidden theft; a one-line check (p.bounds[0] == 0 -> InvalidParams) closes it.","line":464,"path":"src/VerdictMarkets.sol","reproduction":"params() with answerType = 3, bounds = [0, 10]. createMarket succeeds and getMarket(id).outcomes == 3. alice bets 1 IMD on outcome 0 (accepted), bob 1 IMD on outcome 1. At answerFrom resolve, deliver a signed attestation with answer = abi.encode(uint256(0)), propose: getMarket(id).outcome == 1 (0 < 0 is false, so value 0 lands in bucket 1). No answer value selects outcome 0. Expected: createMarket rejects the empty bucket. Actual: an unwinnable outcome is offered for betting. Verified in test/scratch/Repro.t.sol::test_zeroLowerBoundUnreachableBucket.","severity":"low","snippet":"            for (uint256 i = 1; i < p.bounds.length; i++) {\n                if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();","title":"bounds[0] == 0 passes validation and creates a numeric bucket that no answer can ever select, yet bets on it are accepted"},{"citation":"resolved","description":"Merged from audit_permissions (13b6733d) and audit_economics (9d3397a2). The constructor only caps configDelay at 30 days and the manifest sets it to 0, so acceptAfter == block.timestamp and proposeConfig() + acceptConfig() succeed in the same transaction. The owner (0x397dacb1ee8e9a8ce5196988958f56bde0a0a312, also guardian and treasury) can point intake at a contract they control and signer at their own key, then any resolve()/escalate() on an Open or Provisional market lands at their intake and a self-signed attestation is stored and accepted by propose(). In-flight requests keep their recorded intake and signer (verified by the suite), so only markets asked after the rotation are affected. The owner can also force markets to void by changing asset (OracleAssetMismatch) or raising price above bountyRemaining (InsufficientBounty); bettors are refunded in those cases. This is the owner power the brief requested with the delay the brief fixed, not a bypass; it is reported so bettors are told, and a non-zero configDelay at deployment would let them observe a pending rotation.","line":78,"path":"src/VerdictOracle.sol","reproduction":"Deploy VerdictOracle(..., owner, configDelay = 0) as in launch.json. owner calls oracle.proposeConfig(Config(ownerIntake, IMD, ownerKey, action, 0.5e18)) then oracle.acceptConfig() in the same block: both succeed, intake() == ownerIntake, signer() == ownerKey (test/scratch/Repro.t.sol::test_instantRotation). Then on market id=1 where owner holds 10 IMD on outcome 1 and bob 100 IMD on 0: markets.resolve(1, body) pays 0.5 IMD to ownerIntake; ownerIntake calls onOracleResult with an attestation signed by ownerKey (answer true): stored; markets.propose(1, a) succeeds; after disputeWindow finalize() and owner's claim() return 107.8 IMD for the 10 IMD stake.","severity":"info","snippet":"        if (configDelay_ > 30 days) revert InvalidConfig();","title":"Trust assumption: with the launch's configDelay = 0 the oracle owner can rotate intake and signer in one block and author the answer for any market asked afterwards"},{"citation":"resolved","description":"From audit_math (0f3847d3), reproduced with my own gas measurement. The Intake attempts the callback once and never retries, so a signed, otherwise valid answer longer than MAX_ANSWER_BYTES (an address[] or bytes32[] of more than ~511 entries) is dropped: pending stays set, nothing is stored, the price is spent and a market waiting on it can only void. Measured cold delivery of a 16,384-byte answer costs 118,403 gas under the mock intake, so the cap sits below what the stipend allows but a 32 KiB answer would approach the brief's 150,000 target; the cap is therefore a defensible tradeoff and VerdictMarkets reads only the first list element anyway. Informational: document the limit for creators of list-type markets or truncate instead of reverting.","line":124,"path":"src/VerdictOracle.sol","reproduction":"oracle.request(body) -> id. Build an attestation with answerType 5 and answer = new bytes(16_416), signed by the configured signer for the oracle's domain. intake.deliver(id, a, sig, 200_000) returns ok = false after 17,772 gas (revert InvalidAttestation); oracle.pending(id) is still set and oracle.answerOf(a) == 0. The same delivery with answer = new bytes(16_384) succeeds using 118,403 gas. Verified in test/scratch/Repro.t.sol::test_oversizeAnswerRefused.","severity":"info","snippet":"        if (a.answer.length > MAX_ANSWER_BYTES || a.expiresAt < a.issuedAt) revert InvalidAttestation();","title":"Callback refuses answers over 16,384 bytes although the 200,000 gas stipend affords them, so an oversize list answer loses the paid request"}],"hash":"f82aaf504823c498d1cc37c59d1ade7da863edd03fd8338c9804e67fe1c2fc96","nodeId":"481c5b80-5437-44fe-a9fe-f8273392f09f","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds 7 findings and a 24-row coverage record. No files outside `test/scratch/` and the findings file were changed.\n\n**What I verified**\n\n- The existing suite passes in full: 103 tests across 12 suites, including the conformance vector, invariant suites and the 150,000 gas callback assertion.\n- Both specialist proofs fail on the current code for the stated reasons, so they are attached to the two medium findings.\n- Callback selector is `0x510379c7`, runtime sizes are well under the EIP-170 limit, constructors make no external calls, and the manifest has only schema keys with argument counts matching the constructors.\n- Every remaining specialist lead was reproduced in a scratch test before being kept. Snippets were checked byte for byte against the tree.\n\n**Findings kept, after merging duplicates across the four specialists**\n\n1. **Medium, answer shopping.** `propose()` accepts any oracle answer stored for the body hash, so a bettor can buy extra panels at 0.5 IMD each and pick the first favourable one, or replace a primary with a pre-bought escalation answer without any `escalate()` call. Three specialists reported this; proof attached.\n2. **Medium, ask and dispute timing.** Asks are accepted until one second before `answerUntil` and escalation extends the window 24 hours, but `propose()` rejects any attestation issued after `answerUntil`. Late asks burn bounty for unusable answers, anyone can delay finalization 24 hours for free, and a late primary becomes undisputable. Four specialists reported facets of this; proof attached.\n3. **Low, dead retry.** Any delivery for the body, including one the market cannot use, blocks the second primary ask forever. Three specialists reported it.\n4. **Low, guardian renounce.** Renouncing while the allowlist is still on freezes market creation permanently. Two specialists reported it.\n5. **Low, unwinnable bucket.** A zero lower bound passes validation and creates a bucket no answer can select while bets on it are accepted.\n6. **Info, trust assumption.** With the launch's `configDelay` of zero the oracle owner can rotate intake and signer in one block and author answers for markets asked afterwards. Documented as the requested owner power, not a bypass.\n7. **Info, answer size cap.** The callback refuses answers over 16 KiB although the stipend affords them. I measured 118,403 gas for a 16 KiB cold delivery, so the cap is a defensible tradeoff and I lowered it to informational.\n\nNothing critical or high was found. My own pass over the entry points the specialists marked as holding turned up no additional defects, so all four unanswered-by-finding entry point groups are recorded as `holds` with reasons.","treeHash":null,"usage":{"cachedInputTokens":1045771,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":36968,"runtime":"claude","turns":23,"wallClockMs":755696}}],"verification":[{"checks":[{"durationMs":32493,"exitCode":0,"name":"build","output":"Compiling 65 files with Solc 0.8.26\nSolc 0.8.26 finished in 32.37s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:70:9\n   │\n70 │         address intake_,\n   │         ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:71:9\n   │\n71 │         address asset_,\n   │         ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/VerdictOracle.sol:113:9\n    │\n113 │         emit Requested(intakeRequestId, bodyHash, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:101:13\n    │\n101 │         if (token.balanceOf(address(this)) != beforeBalance + cost) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:108:13\n    │\n108 │         if (token.balanceOf(address(this)) != beforeBalance) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:125:13\n    │\n125 │         if (block.timestamp > a.expiresAt) revert AttestationExpired(a.expiresAt);\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/VerdictOracle.sol:126:13\n    │\n126 │         if (a.issuedAt > block.timestamp + ISSUED_AT_TOLERANCE) revert AttestationNotYetValid(a.issuedAt);\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/VerdictOracle.sol:135:9\n    │\n135 │         emit Answered(a.requestId, intakeRequestId, p.bodyHash, attHash);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:144:66\n    │\n144 │     function proposeConfig(Config calldata c) external onlyOwner nonReentrant {\n    │                                                                  ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:152:48\n    │\n152 │     function acceptConfig() external onlyOwner nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:153:31\n    │\n153 │         if (!configPending || block.timestamp < acceptAfter) revert ConfigNotReady();\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/VerdictMarkets.sol:266:13\n    │\n266 │         if (block.timestamp >= m.params.closeAt) revert OutsideWindow();\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/VerdictMarkets.sol:284:17\n    │\n284 │             if (block.timestamp < m.lastPrimaryAsk + 24 hours) revert RetryNotReady();\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/VerdictMarkets.sol:295:13\n    │\n295 │         if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:301:9\n    │\n301 │         emit DisputeExtended(id, m.disputeEnds);\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/VerdictMarkets.sol:427:9\n    │\n427 │         emit OracleAsked(id, requestId, escalation, cost);\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/VerdictMarkets.sol:309:13\n    │\n309 │         if (block.timestamp < m.params.answerFrom) revert OutsideWindow();\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/VerdictMarkets.sol:312:17\n    │\n312 │             if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:314:20\n    │\n314 │         } else if (block.timestamp >= m.params.voidAfter) {\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/VerdictMarkets.sol:340:13\n    │\n340 │         if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:434:9\n    │\n434 │         emit BountyReturned(id, m.creator, bounty);\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/VerdictMarkets.sol:351:9\n    │\n351 │         emit Finalized(id, m.outcome, creatorFee, burnFee, treasuryFee);\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/VerdictMarkets.sol:360:17\n    │\n360 │             if (block.timestamp < m.params.voidAfter) revert OutsideWindow();\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/VerdictMarkets.sol:363:17\n    │\n363 │             if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:395:9\n    │\n395 │         emit Claimed(id, msg.sender, amount, refund);\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/VerdictMarkets.sol:409:13\n    │\n409 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\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/VerdictMarkets.sol:409:54\n    │\n409 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictMarkets.sol:426:13\n    │\n426 │         if (collateral.balanceOf(address(this)) != beforeBalance - cost) revert InexactOracleSpend();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictMarkets.sol:452:40\n    │\n452 │                 || p.minAgreed == 0 || p.closeAt <= block.timestamp || p.closeAt > p.answerFrom\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:465:53\n    │\n465 │                 if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();\n    │                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:472:82\n    │\n472 │                 if (p.answerType == 4 && uint256(p.keys[i]) > type(uint160).max) revert InvalidParams();\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:474:49\n    │\n474 │                     if (p.keys[i] == p.keys[j]) revert InvalidParams();\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:467:20\n    │\n467 │             return uint8(p.bounds.length + 1);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:477:20\n    │\n477 │             return uint8(p.keys.length + 1);\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/VerdictMarkets.sol:504:21\n    │\n504 │                 if (first == p.keys[i]) return i;\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:489:20\n    │\n489 │             return uint8(p.bounds.length);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:507:16\n    │\n507 │         return uint8(p.keys.length);\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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:17:9\n   │\n17 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:63:9\n   │\n63 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:78:9\n   │\n78 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:183:9\n    │\n183 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:198:9\n    │\n198 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictInvariant.t.sol:166:17\n    │\n166 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictMarkets.t.sol:46:9\n   │\n46 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:142:9\n    │\n142 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:154:9\n    │\n154 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:174:9\n    │\n174 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:176:17\n    │\n176 │         vm.warp(block.timestamp + 24 hours - 1);\n    │         ────────━━━━━━━━━━━━━━━──────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:179:17\n    │\n179 │         vm.warp(block.timestamp + 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/VerdictMarkets.t.sol:183:17\n    │\n183 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:195:9\n    │\n195 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:209:9\n    │\n209 │         vm.warp(p.answerUntil);\n    │         ────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:231:9\n    │\n231 │         vm.warp(p.answerUntil - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:249:9\n    │\n249 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:249:9\n    │\n249 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:276:9\n    │\n276 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:311:9\n    │\n311 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:166:9\n    │\n166 │         vm.warp(markets.getMarket(id).params.closeAt - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:265:9\n    │\n265 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:274:9\n    │\n274 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:307:9\n    │\n307 │         vm.warp(markets.getMarket(id).params.answerUntil + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:307:9\n    │\n307 │         vm.warp(markets.getMarket(id).params.answerUntil + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:332:9\n    │\n332 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:211:17\n    │\n211 │         vm.warp(block.timestamp + 2 days - 1);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:238:17\n    │\n238 │         vm.warp(block.timestamp + 1 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictOutcomes.t.sol:11:9\n   │\n11 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:130:9\n    │\n130 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes 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":1675,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 17 tests for test/VerdictOracle.t.sol:VerdictOracleTest\n[PASS] test_bodyLimitsAndExactPaymentRequired() (gas: 585988)\n[PASS] test_configDelayCapAndInvalidConfiguration() (gas: 9288)\n[PASS] test_consumedIntakeIdAndOracleIdCannotBeStoredTwice() (gas: 948524)\n[PASS] test_deliveredAnswerRemainsReadableAfterExpiry() (gas: 501860)\n[PASS] test_expiredFutureMalformedAndTamperedRejected() (gas: 766375)\n[PASS] test_falseAnswerStoredUnder150kGas() (gas: 553418)\nLogs:\n  cold callback gas: 103835\n\n[PASS] test_intakeAndSignerRotationPreservesInflightRequest() (gas: 2129782)\n[PASS] test_maxAnswerUnder150kGas() (gas: 587911)\nLogs:\n  maximum answer cold callback gas: 118403\n\n[PASS] test_replacingConfigProposalRestartsDelay() (gas: 283329)\n[PASS] test_requestPaysExactlyAndPinsConfiguration() (gas: 403437)\n[PASS] test_requestReentrancyFails() (gas: 486011)\n[PASS] test_reusedIntakeRequestIdRollsBackPayment() (gas: 545804)\n[PASS] test_timelockAndOwnable2Step() (gas: 558119)\n[PASS] test_wrongChainDomainStoresNothing() (gas: 417710)\n[PASS] test_wrongConsumerDomainStoresNothing() (gas: 422597)\n[PASS] test_wrongIntakeAndUnknownIdStoreNothing() (gas: 454073)\n[PASS] test_wrongSignerStoresNothingAndNoRefund() (gas: 521960)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 60.86ms (5.96ms CPU time)\n\nRan 6 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 177455)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 168291)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4480)\n[PASS] test_digestMatchesTheProtocol() (gas: 13408)\n[PASS] test_domainIsConsumerChainAndVersionTwo() (gas: 15739)\n[PASS] test_structHashMatchesIndependentEncoding() (gas: 251625)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 64.79ms (1.60ms CPU time)\n\nRan 15 tests for test/VerdictMarketsValidation.t.sol:VerdictMarketsValidationTest\n[PASS] test_allowlistRemovalAndPermanentDisable() (gas: 1276505)\n[PASS] test_attestationMustMatchEveryMarketFieldAndPanelRequirements() (gas: 6410189)\n[PASS] test_betZeroUnknownOutcomeAndCloseBoundary() (gas: 694664)\n[PASS] test_bodyHashAndBodySizeValidation() (gas: 707944)\n[PASS] test_bountyMustCoverTwoAsksAfterTransferFee() (gas: 235996)\n[PASS] test_creationEmitsBothFullBodies() (gas: 380289)\n[PASS] test_escalationRequiresDoubleCurrentPanelAndCorrectBody() (gas: 2747565)\n[PASS] test_feeCapAndPoolCapConstructor() (gas: 15564)\n[PASS] test_feeOnTransferCreditsOnlyActualBountyAndStakes() (gas: 1120818)\n[PASS] test_firstProposalAtVoidDeadlineCannotResurrectMarket() (gas: 1191129)\n[PASS] test_guardianHandoverIsTwoStepAndNoUnauthorizedPowers() (gas: 370210)\n[PASS] test_invalidTimesPanelsAndTypes() (gas: 614214)\n[PASS] test_minAgreedCanRequireMoreThanMinimumPanelSize() (gas: 1061340)\n[PASS] test_pauseBlocksOnlyEntryAndRenounceRequiresUnpaused() (gas: 3043898)\n[PASS] test_poolCapUsesReceivedBalanceAndFailedBetIsAtomic() (gas: 804428)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 73.84ms (12.95ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_burnVaultHasNoCallablePathOrEtherReceiver() (gas: 1013344)\n[PASS] test_exactSepoliaFactoryDeploymentWithoutDependencyCode() (gas: 18993281)\n[PASS] test_rehearsalRefusesOtherChains() (gas: 207095)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 75.05ms (25.51ms CPU time)\n\nRan 7 tests for test/VerdictOutcomes.t.sol:VerdictOutcomesTest\n[PASS] testFuzz_uintBucketDefinition(uint256) (runs: 512, μ: 1164740, ~: 1164813)\n[PASS] test_addressListUsesFirstElementOnlyAndCanonicalAddressKey() (gas: 4168549)\n[PASS] test_booleanOutcomes() (gas: 1957005)\n[PASS] test_bytes32ListUsesFirstElementOnlyAndEmptyMeansNone() (gas: 5127470)\n[PASS] test_malformedEncodedAnswerCannotSetOutcome() (gas: 1100041)\n[PASS] test_numericBucketsIncludeLowerBoundaryExcludeUpper() (gas: 6159611)\n[PASS] test_twoToEightOutcomesAndSortedUniqueDefinitions() (gas: 1747296)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 75.01ms (46.10ms CPU time)\n\nRan 20 tests for test/VerdictMarkets.t.sol:VerdictMarketsTest\n[PASS] testFuzz_terminalConservation(uint96,uint96,uint96,uint8,bool) (runs: 512, μ: 1824113, ~: 2092116)\nLogs:\n  Bound result 47429181105799519548\n  Bound result 3535056885925475\n  Bound result 126435\n\n[PASS] test_asksBeforeAnswerFromAndAtOrAfterAnswerUntilRevert() (gas: 541156)\n[PASS] test_assetRotationBlocksAsksButNotRefunds() (gas: 2064182)\n[PASS] test_emptyWinningBucketCannotVoidUntilDisputeEnds() (gas: 1682233)\n[PASS] test_escalationAnswerCannotBeFirstProposal() (gas: 1143220)\n[PASS] test_escalationAskAtAnswerUntilRevertsEvenInsideDisputeWindow() (gas: 1189332)\n[PASS] test_externalSponsorCanDeliverPrimaryAndEscalation() (gas: 2330353)\n[PASS] test_fullSettlementPaysWholePoolFeesAndExactRemainder() (gas: 2272210)\n[PASS] test_lateEscalationBeyondVoidAfterStillFinalizesWithoutAnswer() (gas: 2310756)\n[PASS] test_lateEscalationReplacementRestartsWindowOnceAndFinalizes() (gas: 2598787)\n[PASS] test_noEscalationBodyAndDuplicateEscalationAsk() (gas: 2474916)\n[PASS] test_priceIncreaseCannotSpendBettorsCollateral() (gas: 2106263)\n[PASS] test_primaryRetryBlockedAfterDeliveryEvenWithoutProposal() (gas: 1105575)\n[PASS] test_proposeAfterAnswerUntilWithTimelyStoredAnswer() (gas: 1346498)\n[PASS] test_provisionalWindowBoundariesAreStrict() (gas: 2173538)\n[PASS] test_secondPrimaryAskAfter24HoursAndMaximumTwoAsks() (gas: 1661739)\n[PASS] test_tokenReentrancyBlockedOnDepositAndClaim() (gas: 2041257)\n[PASS] test_voidNoAnswerRefundsEveryOutcomeAndUnspentBounty() (gas: 1677885)\n[PASS] test_wrongBodiesAndResolveAfterProposalRevertWithoutSpend() (gas: 1392674)\n[PASS] test_zeroAndUnknownClaimsAndUnfinishedClaimsRevert() (gas: 652251)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 75.48ms (78.60ms CPU time)\n\nRan 12 tests for test/IndependentReview.t.sol:IndependentReviewTest\n[PASS] testFuzzReviewActualTransfersConserveInAnyClaimOrder(uint96,uint96,uint96,uint8) (runs: 512, μ: 2490693, ~: 2490916)\nLogs:\n  Bound result 9089\n  Bound result 4973\n  Bound result 948\n\n[PASS] testReviewAgreementMinimumCanExceedMinimumPanel() (gas: 1599982)\n[PASS] testReviewDonationDoesNotAlterPayoutOrAccounting() (gas: 1704577)\n[PASS] testReviewEscalationCannotBeFirstProposalEvenWithLargePanel() (gas: 1142803)\n[PASS] testReviewEscalationCannotVoidAfterDeadline() (gas: 2135189)\n[PASS] testReviewFailedTokenTransferRollsBackClaim() (gas: 1821631)\n[PASS] testReviewLateReplacementPastVoidRemainsFinalizable() (gas: 2363827)\n[PASS] testReviewMaximumAnswerColdCallback() (gas: 1182306)\nLogs:\n  maximum answer cold callback gas: 118403\n\n[PASS] testReviewMixedMarketsCannotCrossSubsidizeClaims() (gas: 3060947)\n[PASS] testReviewNoWinnerIsVoidableAfterWindowPastVoidAfter() (gas: 1843037)\n[PASS] testReviewRotationPreservesOldCallerAndKey() (gas: 2201006)\n[PASS] testReviewSameAttestationCannotOverwriteDifferentRequest() (gas: 1368025)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 75.48ms (84.90ms CPU time)\n\nRan 1 test for test/VerdictInvariant.t.sol:VerdictInvariantTest\n[PASS] invariant_actualTokensMatchEveryMarketsAccounting() (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------------+-------+---------+----------╮\n| Contract       | Selector       | Calls | Reverts | Discards |\n+==============================================================+\n| VerdictHandler | advance        | 830   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | ask            | 783   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | askEscalation  | 804   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | collect        | 800   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | deliverPrimary | 810   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | enter          | 837   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | proposePrimary | 835   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | replaceOutcome | 857   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | settle         | 830   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | togglePause    | 806   | 0       | 0        |\n╰----------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 2611\n  Bound result 2789\n  Bound result 13871\n  Bound result 10000\n  Bound result 8766\n  Bound result 9876\n  Bound result 21421\n  Bound result 5143\n  Bound result 8\n  Bound result 101\n  Bound result 12487\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.60s (1.59s CPU time)\n\nRan 8 test suites in 1.60s (2.10s CPU time): 81 tests passed, 0 failed, 0 skipped (81 total tests)\n","passed":true},{"durationMs":50,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"VerdictMarkets.acceptGuardian()\",\"VerdictMarkets.bet(uint256,uint8,uint256,uint256)\",\"VerdictMarkets.claim(uint256)\",\"VerdictMarkets.createMarket((bytes32,uint8,uint256,uint64,uint64,uint16,uint16,uint64,uint64,uint64,uint32,uint64,uint256[],bytes32[],uint256),bytes,bytes,string,uint256)\",\"VerdictMarkets.disableAllowlist()\",\"VerdictMarkets.escalate(uint256,bytes)\",\"VerdictMarkets.finalize(uint256)\",\"VerdictMarkets.pause()\",\"VerdictMarkets.propose(uint256,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64))\",\"VerdictMarkets.renounceGuardian()\",\"VerdictMarkets.resolve(uint256,bytes)\",\"VerdictMarkets.setCreatorAllowed(address,bool)\",\"VerdictMarkets.transferGuardian(address)\",\"VerdictMarkets.unpause()\",\"VerdictMarkets.voidMarket(uint256)\",\"VerdictOracle.acceptConfig()\",\"VerdictOracle.acceptOwnership()\",\"VerdictOracle.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"VerdictOracle.proposeConfig((address,address,address,bytes32,uint256))\",\"VerdictOracle.renounceOwnership()\",\"VerdictOracle.request(bytes)\",\"VerdictOracle.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":14,\"LICENSE\":21,\"README.md\":94,\"docs/DEPLOYMENT.md\":58,\"docs/INDEPENDENT_REVIEW.md\":65,\"docs/VERIFICATION.md\":39,\"foundry.toml\":23,\"launch.json\":36,\"remappings.txt\":2,\"script/SepoliaParameters.sol\":24,\"src/OracleAttestation.sol\":221,\"src/VerdictBurnVault.sol\":5,\"src/VerdictMarkets.sol\":509,\"src/VerdictOracle.sol\":172,\"src/interfaces/IIntake.sol\":14,\"src/interfaces/IVerdictOracle.sol\":12,\"test/Deployment.t.sol\":102,\"test/IndependentReview.t.sol\":239,\"test/OracleConsumerConformance.t.sol\":162,\"test/TestBase.sol\":135,\"test/VerdictInvariant.t.sol\":215,\"test/VerdictMarkets.t.sol\":375,\"test/VerdictMarketsValidation.t.sol\":354,\"test/VerdictOracle.t.sol\":288,\"test/VerdictOutcomes.t.sol\":148,\"test/mocks/MockIMD.sol\":42,\"test/mocks/MockIntake.sol\":62},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"03d961aed3f897d9d8a0ad75a2ae20003a6f52953a884581621031f12f4e0de3","verifiedTreeHash":"b4eea4b9990ca59ba16c33b06d4e2d08a36203e3","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":59844,"exitCode":0,"name":"build","output":"Compiling 71 files with Solc 0.8.26\nSolc 0.8.26 finished in 59.70s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:71:9\n   │\n71 │         address intake_,\n   │         ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:72:9\n   │\n72 │         address asset_,\n   │         ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/VerdictOracle.sol:114:9\n    │\n114 │         emit Requested(intakeRequestId, bodyHash, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:102:13\n    │\n102 │         if (token.balanceOf(address(this)) != beforeBalance + cost) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:109:13\n    │\n109 │         if (token.balanceOf(address(this)) != beforeBalance) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:126:13\n    │\n126 │         if (block.timestamp > a.expiresAt) revert AttestationExpired(a.expiresAt);\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/VerdictOracle.sol:127:13\n    │\n127 │         if (a.issuedAt > block.timestamp + ISSUED_AT_TOLERANCE) revert AttestationNotYetValid(a.issuedAt);\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/VerdictOracle.sol:137:9\n    │\n137 │         emit Answered(a.requestId, intakeRequestId, p.bodyHash, attHash);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:150:66\n    │\n150 │     function proposeConfig(Config calldata c) external onlyOwner nonReentrant {\n    │                                                                  ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:158:48\n    │\n158 │     function acceptConfig() external onlyOwner nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:159:31\n    │\n159 │         if (!configPending || block.timestamp < acceptAfter) revert ConfigNotReady();\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/VerdictMarkets.sol:271:13\n    │\n271 │         if (block.timestamp >= m.params.closeAt) revert OutsideWindow();\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/VerdictMarkets.sol:289:17\n    │\n289 │             if (block.timestamp < m.lastPrimaryAsk + 24 hours) revert RetryNotReady();\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/VerdictMarkets.sol:300:13\n    │\n300 │         if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:307:9\n    │\n307 │         emit DisputeExtended(id, m.disputeEnds);\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/VerdictMarkets.sol:445:9\n    │\n445 │         emit OracleAsked(id, requestId, escalation, cost);\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/VerdictMarkets.sol:315:13\n    │\n315 │         if (block.timestamp < m.params.answerFrom) revert OutsideWindow();\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/VerdictMarkets.sol:318:17\n    │\n318 │             if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:320:20\n    │\n320 │         } else if (block.timestamp >= m.params.voidAfter) {\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/VerdictMarkets.sol:356:13\n    │\n356 │         if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:452:9\n    │\n452 │         emit BountyReturned(id, m.creator, bounty);\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/VerdictMarkets.sol:367:9\n    │\n367 │         emit Finalized(id, m.outcome, creatorFee, burnFee, treasuryFee);\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/VerdictMarkets.sol:376:17\n    │\n376 │             if (block.timestamp < m.params.voidAfter) revert OutsideWindow();\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/VerdictMarkets.sol:379:17\n    │\n379 │             if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:411:9\n    │\n411 │         emit Claimed(id, msg.sender, amount, refund);\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/VerdictMarkets.sol:425:13\n    │\n425 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\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/VerdictMarkets.sol:425:54\n    │\n425 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictMarkets.sol:442:13\n    │\n442 │         if (collateral.balanceOf(address(this)) != beforeBalance - cost) revert InexactOracleSpend();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictMarkets.sol:470:40\n    │\n470 │                 || p.minAgreed == 0 || p.closeAt <= block.timestamp || p.closeAt > p.answerFrom\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:484:53\n    │\n484 │                 if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();\n    │                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:491:82\n    │\n491 │                 if (p.answerType == 4 && uint256(p.keys[i]) > type(uint160).max) revert InvalidParams();\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:493:49\n    │\n493 │                     if (p.keys[i] == p.keys[j]) revert InvalidParams();\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:486:20\n    │\n486 │             return uint8(p.bounds.length + 1);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:496:20\n    │\n496 │             return uint8(p.keys.length + 1);\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/VerdictMarkets.sol:523:21\n    │\n523 │                 if (first == p.keys[i]) return i;\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:508:20\n    │\n508 │             return uint8(p.bounds.length);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:526:16\n    │\n526 │         return uint8(p.keys.length);\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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:17:9\n   │\n17 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:63:9\n   │\n63 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:78:9\n   │\n78 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:183:9\n    │\n183 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:198:9\n    │\n198 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:11:9\n   │\n11 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:26:9\n   │\n26 │         vm.warp(markets.getMarket(first).params.answerFrom);\n   │         ─────────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionIndependentReview.t.sol:39:9\n    │\n 39 │         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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionIndependentReview.t.sol:39:9\n    │\n 39 │         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/RevisionIndependentReview.t.sol:39:17\n   │\n39 │         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/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:51:9\n   │\n51 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:66:9\n   │\n66 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:11:9\n   │\n11 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:50:9\n   │\n50 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:80:9\n   │\n80 │         vm.warp(markets.getMarket(first).params.answerFrom);\n   │         ─────────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:88:9\n    │\n 88 │         vm.warp(block.timestamp + 24 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:88:9\n    │\n 88 │         vm.warp(block.timestamp + 24 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/RevisionRegression.t.sol:88:17\n   │\n88 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:101:9\n    │\n101 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:106:9\n    │\n106 │         vm.warp(until - 10 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:106:9\n    │\n106 │         vm.warp(until - 10 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:125:9\n    │\n125 │         vm.warp(block.timestamp + 1 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:125:9\n    │\n125 │         vm.warp(block.timestamp + 1 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/RevisionRegression.t.sol:125:17\n    │\n125 │         vm.warp(block.timestamp + 1 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:139:9\n    │\n139 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/RevisionRegression.t.sol:141:17\n    │\n141 │         vm.warp(block.timestamp + 24 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:210:9\n    │\n210 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:214:9\n    │\n214 │         vm.warp(p.answerUntil - bound(leadSeed, 1, 1 hours - 1));\n    │         ──────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:214:9\n    │\n214 │         vm.warp(p.answerUntil - bound(leadSeed, 1, 1 hours - 1));\n    │         ──────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/RevisionRegression.t.sol:219:31\n    │\n219 │         assertGe(extendedEnd, block.timestamp + 24 hours);\n    │                               ━━━━━━━━━━━━━━━\n220 │         vm.warp(p.answerUntil + bound(latencySeed, 1, extendedEnd - p.answerUntil - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:65:9\n    │\n 65 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:65:9\n    │\n 65 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:157:9\n    │\n157 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:164:9\n    │\n164 │         vm.warp(block.timestamp + 24 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:164:9\n    │\n164 │         vm.warp(block.timestamp + 24 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/VerdictAtomicity.t.sol:164:17\n    │\n164 │         vm.warp(block.timestamp + 24 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/VerdictInvariant.t.sol:164:17\n    │\n164 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictLifecycleInvariant.t.sol:458:17\n    │\n458 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictMarkets.t.sol:46:9\n   │\n46 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:142:9\n    │\n142 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:154:9\n    │\n154 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:182:9\n    │\n182 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:184:17\n    │\n184 │         vm.warp(block.timestamp + 24 hours - 1);\n    │         ────────━━━━━━━━━━━━━━━──────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:187:17\n    │\n187 │         vm.warp(block.timestamp + 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/VerdictMarkets.t.sol:191:17\n    │\n191 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:203:9\n    │\n203 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:217:9\n    │\n217 │         vm.warp(p.answerUntil);\n    │         ────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:239:9\n    │\n239 │         vm.warp(p.answerUntil - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:257:9\n    │\n257 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:257:9\n    │\n257 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:284:9\n    │\n284 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:319:9\n    │\n319 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:169:9\n    │\n169 │         vm.warp(markets.getMarket(id).params.closeAt - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:268:9\n    │\n268 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:277:9\n    │\n277 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:355:20\n    │\n355 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:355:20\n    │\n355 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:326:20\n    │\n326 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:326:20\n    │\n326 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:339:9\n    │\n339 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:211:17\n    │\n211 │         vm.warp(block.timestamp + 2 days - 1);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:238:17\n    │\n238 │         vm.warp(block.timestamp + 1 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictOutcomes.t.sol:11:9\n   │\n11 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:130:9\n    │\n130 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:177:9\n    │\n177 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:194:13\n    │\n194 │             vm.warp(p.answerFrom);\n    │             ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:204:13\n    │\n204 │             vm.warp(p.voidAfter);\n    │             ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:204:13\n    │\n204 │             vm.warp(p.voidAfter);\n    │             ──────────────────── `vm.warp` changes 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":36421,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 199666)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 190502)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4480)\n[PASS] test_digestMatchesTheProtocol() (gas: 13408)\n[PASS] test_domainIsConsumerChainAndVersionTwo() (gas: 15761)\n[PASS] test_structHashMatchesIndependentEncoding() (gas: 251625)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.09ms (1.21ms CPU time)\n\nRan 5 tests for test/RevisionIndependentReview.t.sol:RevisionIndependentReviewTest\n[PASS] test_documentedUnusableOwnDeliveryStillBlocksRetry() (gas: 1239144)\n[PASS] test_escalationRejectsIssuanceBeforeItsOwnAsk() (gas: 1960042)\n[PASS] test_identicalBodyOtherMarketAnswerCannotSetOutcome() (gas: 1896821)\n[PASS] test_independentSameBodyCannotBlockOwnRetry() (gas: 1696131)\n[PASS] test_primaryLateIssuanceRemainsOutsideBriefsExplicitRange() (gas: 1333342)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 5.46ms (4.42ms CPU time)\n\nRan 17 tests for test/VerdictOracle.t.sol:VerdictOracleTest\n[PASS] test_bodyLimitsAndExactPaymentRequired() (gas: 586164)\n[PASS] test_configDelayCapAndInvalidConfiguration() (gas: 9288)\n[PASS] test_consumedIntakeIdAndOracleIdCannotBeStoredTwice() (gas: 970867)\n[PASS] test_deliveredAnswerRemainsReadableAfterExpiry() (gas: 524115)\n[PASS] test_expiredFutureMalformedAndTamperedRejected() (gas: 766529)\n[PASS] test_falseAnswerStoredUnder150kGas() (gas: 575739)\nLogs:\n  cold callback gas: 126024\n\n[PASS] test_intakeAndSignerRotationPreservesInflightRequest() (gas: 2174415)\n[PASS] test_maxAnswerUnder150kGas() (gas: 610144)\nLogs:\n  maximum answer cold callback gas: 140592\n\n[PASS] test_replacingConfigProposalRestartsDelay() (gas: 283461)\n[PASS] test_requestPaysExactlyAndPinsConfiguration() (gas: 403481)\n[PASS] test_requestReentrancyFails() (gas: 486117)\n[PASS] test_reusedIntakeRequestIdRollsBackPayment() (gas: 545892)\n[PASS] test_timelockAndOwnable2Step() (gas: 558572)\n[PASS] test_wrongChainDomainStoresNothing() (gas: 417798)\n[PASS] test_wrongConsumerDomainStoresNothing() (gas: 422685)\n[PASS] test_wrongIntakeAndUnknownIdStoreNothing() (gas: 454227)\n[PASS] test_wrongSignerStoresNothingAndNoRefund() (gas: 522092)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 70.41ms (9.38ms CPU time)\n\nRan 15 tests for test/VerdictMarketsValidation.t.sol:VerdictMarketsValidationTest\n[PASS] test_allowlistRemovalAndPermanentDisable() (gas: 1276599)\n[PASS] test_attestationMustMatchEveryMarketFieldAndPanelRequirements() (gas: 5047338)\n[PASS] test_betZeroUnknownOutcomeAndCloseBoundary() (gas: 704338)\n[PASS] test_bodyHashAndBodySizeValidation() (gas: 717617)\n[PASS] test_bountyMustCoverTwoAsksAfterTransferFee() (gas: 236040)\n[PASS] test_creationEmitsBothFullBodies() (gas: 380282)\n[PASS] test_escalationRequiresDoubleCurrentPanelAndCorrectBody() (gas: 2769648)\n[PASS] test_feeCapAndPoolCapConstructor() (gas: 15564)\n[PASS] test_feeOnTransferCreditsOnlyActualBountyAndStakes() (gas: 1169280)\n[PASS] test_firstProposalAtVoidDeadlineCannotResurrectMarket() (gas: 1349349)\n[PASS] test_guardianHandoverIsTwoStepAndNoUnauthorizedPowers() (gas: 370210)\n[PASS] test_invalidTimesPanelsAndTypes() (gas: 614214)\n[PASS] test_minAgreedCanRequireMoreThanMinimumPanelSize() (gas: 1215513)\n[PASS] test_pauseBlocksOnlyEntryAndRenounceRequiresUnpaused() (gas: 3261673)\n[PASS] test_poolCapUsesReceivedBalanceAndFailedBetIsAtomic() (gas: 814102)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 80.58ms (11.57ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_burnVaultHasNoCallablePathOrEtherReceiver() (gas: 1013344)\n[PASS] test_exactSepoliaFactoryDeploymentWithoutDependencyCode() (gas: 19751923)\n[PASS] test_rehearsalRefusesOtherChains() (gas: 207095)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 104.30ms (42.38ms CPU time)\n\nRan 6 tests for test/VerdictOracleAdversarial.t.sol:VerdictOracleAdversarialTest\n[PASS] testFuzz_rotationsKeepFourInflightSnapshotsInAnyDeliveryOrder(uint256) (runs: 256, μ: 5459977, ~: 5459977)\n[PASS] test_contractSignerIsPinnedAndRevokedSignatureStoresNothing() (gas: 1500728)\n[PASS] test_everyAttestationFieldIsBoundBySignatureAndStoredHash() (gas: 2610090)\n[PASS] test_expiryAndClockToleranceAreInclusiveAtExactBoundary() (gas: 977218)\n[PASS] test_nonCanonicalAndTruncatedSignaturesCannotConsumePendingRequest() (gas: 829160)\n[PASS] test_pendingOwnerCannotAcceptConfigurationAndFormerOwnerLosesAccess() (gas: 434003)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 173.63ms (178.60ms CPU time)\n\nRan 7 tests for test/VerdictOutcomes.t.sol:VerdictOutcomesTest\n[PASS] testFuzz_uintBucketDefinition(uint256) (runs: 512, μ: 1319137, ~: 1319215)\n[PASS] test_addressListUsesFirstElementOnlyAndCanonicalAddressKey() (gas: 4785569)\n[PASS] test_booleanOutcomes() (gas: 2265435)\n[PASS] test_bytes32ListUsesFirstElementOnlyAndEmptyMeansNone() (gas: 5898834)\n[PASS] test_malformedEncodedAnswerCannotSetOutcome() (gas: 1263905)\n[PASS] test_numericBucketsIncludeLowerBoundaryExcludeUpper() (gas: 7086553)\n[PASS] test_twoToEightOutcomesAndSortedUniqueDefinitions() (gas: 1767352)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 208.00ms (220.97ms CPU time)\n\nRan 12 tests for test/IndependentReview.t.sol:IndependentReviewTest\n[PASS] testFuzzReviewActualTransfersConserveInAnyClaimOrder(uint96,uint96,uint96,uint8) (runs: 512, μ: 2589602, ~: 2589529)\nLogs:\n  Bound result 25\n  Bound result 764674956164893552\n  Bound result 8455096463\n\n[PASS] testReviewAgreementMinimumCanExceedMinimumPanel() (gas: 1679247)\n[PASS] testReviewDonationDoesNotAlterPayoutOrAccounting() (gas: 1793548)\n[PASS] testReviewEscalationCannotBeFirstProposalEvenWithLargePanel() (gas: 1194141)\n[PASS] testReviewEscalationCannotVoidAfterDeadline() (gas: 2268446)\n[PASS] testReviewFailedTokenTransferRollsBackClaim() (gas: 1920313)\n[PASS] testReviewLateReplacementPastVoidRemainsFinalizable() (gas: 2536759)\n[PASS] testReviewMaximumAnswerColdCallback() (gas: 1246333)\nLogs:\n  maximum answer cold callback gas: 140592\n\n[PASS] testReviewMixedMarketsCannotCrossSubsidizeClaims() (gas: 3179094)\n[PASS] testReviewNoWinnerIsVoidableAfterWindowPastVoidAfter() (gas: 1932008)\n[PASS] testReviewRotationPreservesOldCallerAndKey() (gas: 2280373)\n[PASS] testReviewSameAttestationCannotOverwriteDifferentRequest() (gas: 1409748)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 208.28ms (208.59ms CPU time)\n\nRan 7 tests for test/VerdictAtomicity.t.sol:VerdictAtomicityTest\n[PASS] testFuzz_failureAtAnyFinalizeRecipientRollsBackEarlierPayments(uint8,bool) (runs: 64, μ: 2335750, ~: 2334068)\n[PASS] test_failedBountyReturnDoesNotVoidMarketOrPreventLaterRefund() (gas: 1075296)\n[PASS] test_failedCallbackIsNotRefundedButMarketRetryAndSettlementRemainReachable() (gas: 2356715)\n[PASS] test_failedEscalationPaymentCannotExtendOrConsumeDisputeWindow() (gas: 2636232)\n[PASS] test_failedPrimaryPaymentRestoresBountyAskCountTimestampAndAllowances() (gas: 1702871)\n[PASS] test_failedRefundCanBeRetriedAndDoesNotConsumeAnotherUsersClaim() (gas: 1415551)\n[PASS] test_guardBlocksCrossMarketReentryFromAnOtherwiseEligibleClaimant() (gas: 4366686)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 208.21ms (153.97ms CPU time)\n\nRan 20 tests for test/VerdictMarkets.t.sol:VerdictMarketsTest\n[PASS] testFuzz_terminalConservation(uint96,uint96,uint96,uint8,bool) (runs: 512, μ: 1897761, ~: 2181091)\nLogs:\n  Bound result 40532585527296528876\n  Bound result 834233709\n  Bound result 6061174475659728935\n\n[PASS] test_asksBeforeAnswerFromAndAtOrAfterAnswerUntilRevert() (gas: 550863)\n[PASS] test_assetRotationBlocksAsksButNotRefunds() (gas: 2093333)\n[PASS] test_emptyWinningBucketCannotVoidUntilDisputeEnds() (gas: 1771204)\n[PASS] test_escalationAnswerCannotBeFirstProposal() (gas: 1194558)\n[PASS] test_escalationAskAtAnswerUntilRevertsEvenInsideDisputeWindow() (gas: 1258906)\n[PASS] test_externalSponsorCannotDeliverPrimaryOrEscalation() (gas: 3793707)\n[PASS] test_fullSettlementPaysWholePoolFeesAndExactRemainder() (gas: 2361182)\n[PASS] test_lateEscalationBeyondVoidAfterStillFinalizesWithoutAnswer() (gas: 2453724)\n[PASS] test_lateEscalationReplacementRestartsWindowOnceAndFinalizes() (gas: 2781443)\n[PASS] test_noEscalationBodyAndDuplicateEscalationAsk() (gas: 2658385)\n[PASS] test_priceIncreaseCannotSpendBettorsCollateral() (gas: 2227154)\n[PASS] test_primaryRetryBlockedAfterDeliveryEvenWithoutProposal() (gas: 1171348)\n[PASS] test_proposeAfterAnswerUntilWithTimelyStoredAnswer() (gas: 1435466)\n[PASS] test_provisionalWindowBoundariesAreStrict() (gas: 2284755)\n[PASS] test_secondPrimaryAskAfter24HoursAndMaximumTwoAsks() (gas: 1772213)\n[PASS] test_tokenReentrancyBlockedOnDepositAndClaim() (gas: 2125896)\n[PASS] test_voidNoAnswerRefundsEveryOutcomeAndUnspentBounty() (gas: 1729322)\n[PASS] test_wrongBodiesAndResolveAfterProposalRevertWithoutSpend() (gas: 1481642)\n[PASS] test_zeroAndUnknownClaimsAndUnfinishedClaimsRevert() (gas: 672266)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 208.28ms (162.77ms CPU time)\n\nRan 11 tests for test/RevisionRegression.t.sol:RevisionRegressionTest\n[PASS] testFuzz_eitherPaidPrimaryRequestCanProposeButCannotReplace(bool,bool) (runs: 256, μ: 2750034, ~: 2749028)\n[PASS] testFuzz_lateEscalationHasFiniteSettlementDeadline(uint32,uint32,uint32,bool) (runs: 256, μ: 2665811, ~: 2445966)\nLogs:\n  Bound result 255697\n  Bound result 51\n  Bound result 200000\n\n[PASS] test_escalationCannotUseAnswerIssuedBeforeItsAsk() (gas: 1961636)\n[PASS] test_identicalEscalationBodiesStillRequireEachMarketsOwnPaidAsk() (gas: 5164572)\n[PASS] test_lateEscalationIssuedAfterAnswerUntilSettlesCorrectedOutcome() (gas: 2766499)\n[PASS] test_otherMarketAnswerCannotSetOutcomeOrBlockRetry() (gas: 2572792)\n[PASS] test_oversizeAnswerRefused() (gas: 971465)\n[PASS] test_renounceRequiresAllowlistDisabledEvenWhenEmpty() (gas: 494213)\n[PASS] test_unusableDeliveryBlocksRetry() (gas: 1239244)\n[PASS] test_zeroBoundRejectedWithoutTakingBounty() (gas: 1549961)\n[PASS] test_zeroDelayAcceptsConfigInSameBlock() (gas: 271514)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 219.61ms (242.36ms CPU time)\n\nRan 7 tests for test/VerdictSettlementProperties.t.sol:VerdictSettlementPropertiesTest\n[PASS] testFuzz_feeSplitsAndRationalPayoutBoundsInEveryClaimOrder(uint256,uint16,uint16,uint16,uint8) (runs: 1000, μ: 2928102, ~: 2933160)\nLogs:\n  Bound result 473\n  Bound result 3\n  Bound result 9\n  Bound result 12384745934021834103\n  Bound result 84352517682536549558\n  Bound result 28224987918885338037\n  Bound result 61553264295711630507\n\n[PASS] testFuzz_numericOutcomeSatisfiesItsHalfOpenInterval(uint128,uint96,uint256,uint8) (runs: 1000, μ: 1363701, ~: 1356498)\nLogs:\n  Bound result 2\n  Bound result 3\n  Bound result 831\n\n[PASS] test_malformedListsCannotChangeAnAuthenticatedMarketsOutcome() (gas: 2835864)\n[PASS] test_oneWeiLastWinnerReceivesTheRoundingRemainder() (gas: 2241298)\n[PASS] test_oneWeiWinnerMayRoundToZeroButLastClaimStillDrainsExactly() (gas: 2512854)\n[PASS] test_payoutUsesFullPrecisionWhenIntermediateStakeTimesPoolOverflows256Bits() (gas: 2496146)\n[PASS] test_settlementEventsDescribeWholePoolFeesAndUnspentBounty() (gas: 1951288)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 219.73ms (427.09ms CPU time)\n\nRan 1 test for test/VerdictInvariant.t.sol:VerdictInvariantTest\n[PASS] invariant_actualTokensMatchEveryMarketsAccounting() (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------------+-------+---------+----------╮\n| Contract       | Selector       | Calls | Reverts | Discards |\n+==============================================================+\n| VerdictHandler | advance        | 806   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | ask            | 857   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | askEscalation  | 857   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | collect        | 798   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | deliverPrimary | 837   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | enter          | 804   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | proposePrimary | 777   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | replaceOutcome | 808   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | settle         | 805   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | togglePause    | 843   | 0       | 0        |\n╰----------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 7200\n  Bound result 11535025520838075367\n  Bound result 3081\n  Bound result 8204\n  Bound result 15138\n  Bound result 21599\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.92s (1.92s CPU time)\n\nRan 4 tests for test/VerdictLifecycleInvariant.t.sol:VerdictLifecycleInvariantTest\n[PASS] invariant_tokensStakesAndFinalityMatchIndependentLedger() (runs: 256, calls: 16384, reverts: 0)\n\n╭-------------------------+------------------------+-------+---------+----------╮\n| Contract                | Selector               | Calls | Reverts | Discards |\n+===============================================================================+\n| VerdictLifecycleHandler | advance                | 1293  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | askEscalation          | 1305  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | askPrimary             | 1280  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | collect                | 1212  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | deliverAnswer          | 1299  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | donate                 | 1232  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | openMarket             | 1259  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | probeBurn              | 1300  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | probeIndependentAnswer | 1211  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | probeTerminal          | 1253  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | settle                 | 1236  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | togglePause            | 1250  | 0       | 0        |\n|-------------------------+------------------------+-------+---------+----------|\n| VerdictLifecycleHandler | wager                  | 1254  | 0       | 0        |\n╰-------------------------+------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 1707710109\n  Bound result 700\n  Bound result 10991\n  Bound result 12365\n  Bound result 993\n  Bound result 50\n  Bound result 700\n  Bound result 54647071825257952\n  Bound result 96\n\n[PASS] test_handlerIndependentAnswersCannotBlockRetryOrShopOutcomes() (gas: 9872903)\nLogs:\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 21600\n  Bound result 21600\n  Bound result 21600\n  Bound result 21600\n\n[PASS] test_handlerReachesPrimaryEscalationFailureFinalizeAndRefundPaths() (gas: 16081579)\nLogs:\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 31\n  Bound result 17\n  Bound result 11\n\n[PASS] test_handlerUsesActualLateEscalationIssuanceAndStillDrains() (gas: 9503410)\nLogs:\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 36.33s (36.35s CPU time)\n\nRan 14 test suites in 36.33s (39.95s CPU time): 121 tests passed, 0 failed, 0 skipped (121 total tests)\n","passed":true},{"durationMs":58,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"VerdictMarkets.acceptGuardian()\",\"VerdictMarkets.bet(uint256,uint8,uint256,uint256)\",\"VerdictMarkets.claim(uint256)\",\"VerdictMarkets.createMarket((bytes32,uint8,uint256,uint64,uint64,uint16,uint16,uint64,uint64,uint64,uint32,uint64,uint256[],bytes32[],uint256),bytes,bytes,string,uint256)\",\"VerdictMarkets.disableAllowlist()\",\"VerdictMarkets.escalate(uint256,bytes)\",\"VerdictMarkets.finalize(uint256)\",\"VerdictMarkets.pause()\",\"VerdictMarkets.propose(uint256,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64))\",\"VerdictMarkets.renounceGuardian()\",\"VerdictMarkets.resolve(uint256,bytes)\",\"VerdictMarkets.setCreatorAllowed(address,bool)\",\"VerdictMarkets.transferGuardian(address)\",\"VerdictMarkets.unpause()\",\"VerdictMarkets.voidMarket(uint256)\",\"VerdictOracle.acceptConfig()\",\"VerdictOracle.acceptOwnership()\",\"VerdictOracle.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"VerdictOracle.proposeConfig((address,address,address,bytes32,uint256))\",\"VerdictOracle.renounceOwnership()\",\"VerdictOracle.request(bytes)\",\"VerdictOracle.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":14,\"LICENSE\":21,\"README.md\":100,\"docs/DEPLOYMENT.md\":58,\"docs/INDEPENDENT_REVIEW.md\":67,\"docs/REVISION_REVIEW.md\":41,\"docs/VERIFICATION.md\":41,\"foundry.toml\":23,\"remappings.txt\":2,\"script/SepoliaParameters.sol\":24,\"src/OracleAttestation.sol\":221,\"src/VerdictBurnVault.sol\":5,\"src/VerdictMarkets.sol\":528,\"src/VerdictOracle.sol\":178,\"src/interfaces/IIntake.sol\":14,\"src/interfaces/IVerdictOracle.sol\":14,\"test/Deployment.t.sol\":102,\"test/IndependentReview.t.sol\":239,\"test/OracleConsumerConformance.t.sol\":162,\"test/RevisionIndependentReview.t.sol\":77,\"test/RevisionRegression.t.sol\":245,\"test/TESTING.md\":87,\"test/TestBase.sol\":135,\"test/VerdictAtomicity.t.sol\":214,\"test/VerdictInvariant.t.sol\":213,\"test/VerdictLifecycleInvariant.t.sol\":580,\"test/VerdictMarkets.t.sol\":383,\"test/VerdictMarketsValidation.t.sol\":363,\"test/VerdictOracle.t.sol\":288,\"test/VerdictOracleAdversarial.t.sol\":228,\"test/VerdictOutcomes.t.sol\":148,\"test/VerdictSettlementProperties.t.sol\":227,\"test/mocks/MockIMD.sol\":42,\"test/mocks/MockIntake.sol\":62},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0cb3a9804d8caee3f077058fa97645a6f81b64ac9703b44c0d6dddd001b8dfc7","verifiedTreeHash":"01b4591904143d4e8ab75527bca4503ec33d22af","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":33842,"exitCode":0,"name":"build","output":"Compiling 65 files with Solc 0.8.26\nSolc 0.8.26 finished in 33.70s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:70:9\n   │\n70 │         address intake_,\n   │         ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:71:9\n   │\n71 │         address asset_,\n   │         ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/VerdictOracle.sol:113:9\n    │\n113 │         emit Requested(intakeRequestId, bodyHash, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:101:13\n    │\n101 │         if (token.balanceOf(address(this)) != beforeBalance + cost) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:108:13\n    │\n108 │         if (token.balanceOf(address(this)) != beforeBalance) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:125:13\n    │\n125 │         if (block.timestamp > a.expiresAt) revert AttestationExpired(a.expiresAt);\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/VerdictOracle.sol:126:13\n    │\n126 │         if (a.issuedAt > block.timestamp + ISSUED_AT_TOLERANCE) revert AttestationNotYetValid(a.issuedAt);\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/VerdictOracle.sol:135:9\n    │\n135 │         emit Answered(a.requestId, intakeRequestId, p.bodyHash, attHash);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:144:66\n    │\n144 │     function proposeConfig(Config calldata c) external onlyOwner nonReentrant {\n    │                                                                  ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:152:48\n    │\n152 │     function acceptConfig() external onlyOwner nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:153:31\n    │\n153 │         if (!configPending || block.timestamp < acceptAfter) revert ConfigNotReady();\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/VerdictMarkets.sol:266:13\n    │\n266 │         if (block.timestamp >= m.params.closeAt) revert OutsideWindow();\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/VerdictMarkets.sol:284:17\n    │\n284 │             if (block.timestamp < m.lastPrimaryAsk + 24 hours) revert RetryNotReady();\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/VerdictMarkets.sol:295:13\n    │\n295 │         if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:301:9\n    │\n301 │         emit DisputeExtended(id, m.disputeEnds);\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/VerdictMarkets.sol:427:9\n    │\n427 │         emit OracleAsked(id, requestId, escalation, cost);\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/VerdictMarkets.sol:309:13\n    │\n309 │         if (block.timestamp < m.params.answerFrom) revert OutsideWindow();\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/VerdictMarkets.sol:312:17\n    │\n312 │             if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:314:20\n    │\n314 │         } else if (block.timestamp >= m.params.voidAfter) {\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/VerdictMarkets.sol:340:13\n    │\n340 │         if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:434:9\n    │\n434 │         emit BountyReturned(id, m.creator, bounty);\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/VerdictMarkets.sol:351:9\n    │\n351 │         emit Finalized(id, m.outcome, creatorFee, burnFee, treasuryFee);\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/VerdictMarkets.sol:360:17\n    │\n360 │             if (block.timestamp < m.params.voidAfter) revert OutsideWindow();\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/VerdictMarkets.sol:363:17\n    │\n363 │             if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:395:9\n    │\n395 │         emit Claimed(id, msg.sender, amount, refund);\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/VerdictMarkets.sol:409:13\n    │\n409 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\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/VerdictMarkets.sol:409:54\n    │\n409 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictMarkets.sol:426:13\n    │\n426 │         if (collateral.balanceOf(address(this)) != beforeBalance - cost) revert InexactOracleSpend();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictMarkets.sol:452:40\n    │\n452 │                 || p.minAgreed == 0 || p.closeAt <= block.timestamp || p.closeAt > p.answerFrom\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:465:53\n    │\n465 │                 if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();\n    │                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:472:82\n    │\n472 │                 if (p.answerType == 4 && uint256(p.keys[i]) > type(uint160).max) revert InvalidParams();\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:474:49\n    │\n474 │                     if (p.keys[i] == p.keys[j]) revert InvalidParams();\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:467:20\n    │\n467 │             return uint8(p.bounds.length + 1);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:477:20\n    │\n477 │             return uint8(p.keys.length + 1);\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/VerdictMarkets.sol:504:21\n    │\n504 │                 if (first == p.keys[i]) return i;\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:489:20\n    │\n489 │             return uint8(p.bounds.length);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:507:16\n    │\n507 │         return uint8(p.keys.length);\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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:17:9\n   │\n17 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:63:9\n   │\n63 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:78:9\n   │\n78 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:183:9\n    │\n183 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:198:9\n    │\n198 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictInvariant.t.sol:166:17\n    │\n166 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictMarkets.t.sol:46:9\n   │\n46 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:142:9\n    │\n142 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:154:9\n    │\n154 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:174:9\n    │\n174 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:176:17\n    │\n176 │         vm.warp(block.timestamp + 24 hours - 1);\n    │         ────────━━━━━━━━━━━━━━━──────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:179:17\n    │\n179 │         vm.warp(block.timestamp + 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/VerdictMarkets.t.sol:183:17\n    │\n183 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:195:9\n    │\n195 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:209:9\n    │\n209 │         vm.warp(p.answerUntil);\n    │         ────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:231:9\n    │\n231 │         vm.warp(p.answerUntil - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:249:9\n    │\n249 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:249:9\n    │\n249 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:276:9\n    │\n276 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:311:9\n    │\n311 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:166:9\n    │\n166 │         vm.warp(markets.getMarket(id).params.closeAt - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:265:9\n    │\n265 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:274:9\n    │\n274 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:307:9\n    │\n307 │         vm.warp(markets.getMarket(id).params.answerUntil + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:307:9\n    │\n307 │         vm.warp(markets.getMarket(id).params.answerUntil + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:332:9\n    │\n332 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:211:17\n    │\n211 │         vm.warp(block.timestamp + 2 days - 1);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:238:17\n    │\n238 │         vm.warp(block.timestamp + 1 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictOutcomes.t.sol:11:9\n   │\n11 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:130:9\n    │\n130 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes 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":1702,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 177455)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 168291)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4480)\n[PASS] test_digestMatchesTheProtocol() (gas: 13408)\n[PASS] test_domainIsConsumerChainAndVersionTwo() (gas: 15739)\n[PASS] test_structHashMatchesIndependentEncoding() (gas: 251625)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 986.44µs (1.11ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_burnVaultHasNoCallablePathOrEtherReceiver() (gas: 1013344)\n[PASS] test_exactSepoliaFactoryDeploymentWithoutDependencyCode() (gas: 18993281)\n[PASS] test_rehearsalRefusesOtherChains() (gas: 207095)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 36.67ms (36.64ms CPU time)\n\nRan 7 tests for test/VerdictOutcomes.t.sol:VerdictOutcomesTest\n[PASS] testFuzz_uintBucketDefinition(uint256) (runs: 512, μ: 1164771, ~: 1164837)\n[PASS] test_addressListUsesFirstElementOnlyAndCanonicalAddressKey() (gas: 4168549)\n[PASS] test_booleanOutcomes() (gas: 1957005)\n[PASS] test_bytes32ListUsesFirstElementOnlyAndEmptyMeansNone() (gas: 5127470)\n[PASS] test_malformedEncodedAnswerCannotSetOutcome() (gas: 1100041)\n[PASS] test_numericBucketsIncludeLowerBoundaryExcludeUpper() (gas: 6159611)\n[PASS] test_twoToEightOutcomesAndSortedUniqueDefinitions() (gas: 1747296)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 49.29ms (50.00ms CPU time)\n\nRan 17 tests for test/VerdictOracle.t.sol:VerdictOracleTest\n[PASS] test_bodyLimitsAndExactPaymentRequired() (gas: 585988)\n[PASS] test_configDelayCapAndInvalidConfiguration() (gas: 9288)\n[PASS] test_consumedIntakeIdAndOracleIdCannotBeStoredTwice() (gas: 948524)\n[PASS] test_deliveredAnswerRemainsReadableAfterExpiry() (gas: 501860)\n[PASS] test_expiredFutureMalformedAndTamperedRejected() (gas: 766375)\n[PASS] test_falseAnswerStoredUnder150kGas() (gas: 553418)\nLogs:\n  cold callback gas: 103835\n\n[PASS] test_intakeAndSignerRotationPreservesInflightRequest() (gas: 2129782)\n[PASS] test_maxAnswerUnder150kGas() (gas: 587911)\nLogs:\n  maximum answer cold callback gas: 118403\n\n[PASS] test_replacingConfigProposalRestartsDelay() (gas: 283329)\n[PASS] test_requestPaysExactlyAndPinsConfiguration() (gas: 403437)\n[PASS] test_requestReentrancyFails() (gas: 486011)\n[PASS] test_reusedIntakeRequestIdRollsBackPayment() (gas: 545804)\n[PASS] test_timelockAndOwnable2Step() (gas: 558119)\n[PASS] test_wrongChainDomainStoresNothing() (gas: 417710)\n[PASS] test_wrongConsumerDomainStoresNothing() (gas: 422597)\n[PASS] test_wrongIntakeAndUnknownIdStoreNothing() (gas: 454073)\n[PASS] test_wrongSignerStoresNothingAndNoRefund() (gas: 521960)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 58.42ms (8.78ms CPU time)\n\nRan 15 tests for test/VerdictMarketsValidation.t.sol:VerdictMarketsValidationTest\n[PASS] test_allowlistRemovalAndPermanentDisable() (gas: 1276505)\n[PASS] test_attestationMustMatchEveryMarketFieldAndPanelRequirements() (gas: 6410189)\n[PASS] test_betZeroUnknownOutcomeAndCloseBoundary() (gas: 694664)\n[PASS] test_bodyHashAndBodySizeValidation() (gas: 707944)\n[PASS] test_bountyMustCoverTwoAsksAfterTransferFee() (gas: 235996)\n[PASS] test_creationEmitsBothFullBodies() (gas: 380289)\n[PASS] test_escalationRequiresDoubleCurrentPanelAndCorrectBody() (gas: 2747565)\n[PASS] test_feeCapAndPoolCapConstructor() (gas: 15564)\n[PASS] test_feeOnTransferCreditsOnlyActualBountyAndStakes() (gas: 1120818)\n[PASS] test_firstProposalAtVoidDeadlineCannotResurrectMarket() (gas: 1191129)\n[PASS] test_guardianHandoverIsTwoStepAndNoUnauthorizedPowers() (gas: 370210)\n[PASS] test_invalidTimesPanelsAndTypes() (gas: 614214)\n[PASS] test_minAgreedCanRequireMoreThanMinimumPanelSize() (gas: 1061340)\n[PASS] test_pauseBlocksOnlyEntryAndRenounceRequiresUnpaused() (gas: 3043898)\n[PASS] test_poolCapUsesReceivedBalanceAndFailedBetIsAtomic() (gas: 804428)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 67.10ms (15.39ms CPU time)\n\nRan 20 tests for test/VerdictMarkets.t.sol:VerdictMarketsTest\n[PASS] testFuzz_terminalConservation(uint96,uint96,uint96,uint8,bool) (runs: 512, μ: 1822076, ~: 2092116)\nLogs:\n  Bound result 750\n  Bound result 14264337593543950332\n  Bound result 8829\n\n[PASS] test_asksBeforeAnswerFromAndAtOrAfterAnswerUntilRevert() (gas: 541156)\n[PASS] test_assetRotationBlocksAsksButNotRefunds() (gas: 2064182)\n[PASS] test_emptyWinningBucketCannotVoidUntilDisputeEnds() (gas: 1682233)\n[PASS] test_escalationAnswerCannotBeFirstProposal() (gas: 1143220)\n[PASS] test_escalationAskAtAnswerUntilRevertsEvenInsideDisputeWindow() (gas: 1189332)\n[PASS] test_externalSponsorCanDeliverPrimaryAndEscalation() (gas: 2330353)\n[PASS] test_fullSettlementPaysWholePoolFeesAndExactRemainder() (gas: 2272210)\n[PASS] test_lateEscalationBeyondVoidAfterStillFinalizesWithoutAnswer() (gas: 2310756)\n[PASS] test_lateEscalationReplacementRestartsWindowOnceAndFinalizes() (gas: 2598787)\n[PASS] test_noEscalationBodyAndDuplicateEscalationAsk() (gas: 2474916)\n[PASS] test_priceIncreaseCannotSpendBettorsCollateral() (gas: 2106263)\n[PASS] test_primaryRetryBlockedAfterDeliveryEvenWithoutProposal() (gas: 1105575)\n[PASS] test_proposeAfterAnswerUntilWithTimelyStoredAnswer() (gas: 1346498)\n[PASS] test_provisionalWindowBoundariesAreStrict() (gas: 2173538)\n[PASS] test_secondPrimaryAskAfter24HoursAndMaximumTwoAsks() (gas: 1661739)\n[PASS] test_tokenReentrancyBlockedOnDepositAndClaim() (gas: 2041257)\n[PASS] test_voidNoAnswerRefundsEveryOutcomeAndUnspentBounty() (gas: 1677885)\n[PASS] test_wrongBodiesAndResolveAfterProposalRevertWithoutSpend() (gas: 1392674)\n[PASS] test_zeroAndUnknownClaimsAndUnfinishedClaimsRevert() (gas: 652251)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 83.29ms (75.28ms CPU time)\n\nRan 12 tests for test/IndependentReview.t.sol:IndependentReviewTest\n[PASS] testFuzzReviewActualTransfersConserveInAnyClaimOrder(uint96,uint96,uint96,uint8) (runs: 512, μ: 2490664, ~: 2490847)\nLogs:\n  Bound result 14264337593543950332\n  Bound result 5314093742326\n  Bound result 68123611842563858433\n\n[PASS] testReviewAgreementMinimumCanExceedMinimumPanel() (gas: 1599982)\n[PASS] testReviewDonationDoesNotAlterPayoutOrAccounting() (gas: 1704577)\n[PASS] testReviewEscalationCannotBeFirstProposalEvenWithLargePanel() (gas: 1142803)\n[PASS] testReviewEscalationCannotVoidAfterDeadline() (gas: 2135189)\n[PASS] testReviewFailedTokenTransferRollsBackClaim() (gas: 1821631)\n[PASS] testReviewLateReplacementPastVoidRemainsFinalizable() (gas: 2363827)\n[PASS] testReviewMaximumAnswerColdCallback() (gas: 1182306)\nLogs:\n  maximum answer cold callback gas: 118403\n\n[PASS] testReviewMixedMarketsCannotCrossSubsidizeClaims() (gas: 3060947)\n[PASS] testReviewNoWinnerIsVoidableAfterWindowPastVoidAfter() (gas: 1843037)\n[PASS] testReviewRotationPreservesOldCallerAndKey() (gas: 2201006)\n[PASS] testReviewSameAttestationCannotOverwriteDifferentRequest() (gas: 1368025)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 83.33ms (93.22ms CPU time)\n\nRan 1 test for test/VerdictInvariant.t.sol:VerdictInvariantTest\n[PASS] invariant_actualTokensMatchEveryMarketsAccounting() (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------------+-------+---------+----------╮\n| Contract       | Selector       | Calls | Reverts | Discards |\n+==============================================================+\n| VerdictHandler | advance        | 834   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | ask            | 828   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | askEscalation  | 849   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | collect        | 825   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | deliverPrimary | 842   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | enter          | 823   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | proposePrimary | 805   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | replaceOutcome | 762   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | settle         | 794   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | togglePause    | 830   | 0       | 0        |\n╰----------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 732\n  Bound result 7484\n  Bound result 14811\n  Bound result 12552\n  Bound result 1954\n  Bound result 19621\n  Bound result 3839\n  Bound result 6255\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.61s (1.61s CPU time)\n\nRan 8 test suites in 1.61s (1.99s CPU time): 81 tests passed, 0 failed, 0 skipped (81 total tests)\n","passed":true},{"durationMs":47,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"VerdictMarkets.acceptGuardian()\",\"VerdictMarkets.bet(uint256,uint8,uint256,uint256)\",\"VerdictMarkets.claim(uint256)\",\"VerdictMarkets.createMarket((bytes32,uint8,uint256,uint64,uint64,uint16,uint16,uint64,uint64,uint64,uint32,uint64,uint256[],bytes32[],uint256),bytes,bytes,string,uint256)\",\"VerdictMarkets.disableAllowlist()\",\"VerdictMarkets.escalate(uint256,bytes)\",\"VerdictMarkets.finalize(uint256)\",\"VerdictMarkets.pause()\",\"VerdictMarkets.propose(uint256,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64))\",\"VerdictMarkets.renounceGuardian()\",\"VerdictMarkets.resolve(uint256,bytes)\",\"VerdictMarkets.setCreatorAllowed(address,bool)\",\"VerdictMarkets.transferGuardian(address)\",\"VerdictMarkets.unpause()\",\"VerdictMarkets.voidMarket(uint256)\",\"VerdictOracle.acceptConfig()\",\"VerdictOracle.acceptOwnership()\",\"VerdictOracle.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"VerdictOracle.proposeConfig((address,address,address,bytes32,uint256))\",\"VerdictOracle.renounceOwnership()\",\"VerdictOracle.request(bytes)\",\"VerdictOracle.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":14,\"LICENSE\":21,\"README.md\":94,\"docs/DEPLOYMENT.md\":58,\"docs/INDEPENDENT_REVIEW.md\":65,\"docs/VERIFICATION.md\":39,\"foundry.toml\":23,\"remappings.txt\":2,\"script/SepoliaParameters.sol\":24,\"src/OracleAttestation.sol\":221,\"src/VerdictBurnVault.sol\":5,\"src/VerdictMarkets.sol\":509,\"src/VerdictOracle.sol\":172,\"src/interfaces/IIntake.sol\":14,\"src/interfaces/IVerdictOracle.sol\":12,\"test/Deployment.t.sol\":102,\"test/IndependentReview.t.sol\":239,\"test/OracleConsumerConformance.t.sol\":162,\"test/TestBase.sol\":135,\"test/VerdictInvariant.t.sol\":215,\"test/VerdictMarkets.t.sol\":375,\"test/VerdictMarketsValidation.t.sol\":354,\"test/VerdictOracle.t.sol\":288,\"test/VerdictOutcomes.t.sol\":148,\"test/mocks/MockIMD.sol\":42,\"test/mocks/MockIntake.sol\":62},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4536,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/VerdictMarkets.sol:412: Reentrancy in VerdictMarkets._ask(uint256,VerdictMarkets.Market,bytes,bool) (src/VerdictMarkets.sol#412-428):\n[high/medium] reentrancy-balance at src/VerdictOracle.sol:93: Reentrancy in VerdictOracle.request(bytes) (src/VerdictOracle.sol#93-114):\n[medium/high] incorrect-equality at src/VerdictMarkets.sol:437: VerdictMarkets._pull(address,uint256) (src/VerdictMarkets.sol#437-443) uses a dangerous strict equality:\n[medium/medium] uninitialized-local at src/VerdictMarkets.sol:491: VerdictMarkets._outcome(VerdictMarkets.Params,bytes).first (src/VerdictMarkets.sol#491) is a local variable never initialized\n[low/medium] missing-zero-check at src/VerdictOracle.sol:70: VerdictOracle.constructor(address,address,address,bytes32,uint256,address,uint256).intake_ (src/VerdictOracle.sol#70) lacks a zero-check on :\n[low/medium] missing-zero-check at src/VerdictOracle.sol:71: VerdictOracle.constructor(address,address,address,bytes32,uint256,address,uint256).asset_ (src/VerdictOracle.sol#71) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/VerdictOracle.sol:93: Reentrancy in VerdictOracle.request(bytes) (src/VerdictOracle.sol#93-114):\n[low/medium] timestamp at src/VerdictMarkets.sol:291: VerdictMarkets.escalate(uint256,bytes) (src/VerdictMarkets.sol#291-303) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:263: VerdictMarkets.bet(uint256,uint8,uint256,uint256) (src/VerdictMarkets.sol#263-275) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictOracle.sol:116: VerdictOracle.onOracleResult(bytes32,OracleAttestation.Attestation,bytes) (src/VerdictOracle.sol#116-136) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:357: VerdictMarkets.voidMarket(uint256) (src/VerdictMarkets.sol#357-372) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictOracle.sol:152: VerdictOracle.acceptConfig() (src/VerdictOracle.sol#152-164) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:408: VerdictMarkets._askWindow(VerdictMarkets.Market) (src/VerdictMarkets.sol#408-410) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:449: VerdictMarkets._validateParams(VerdictMarkets.Params) (src/VerdictMarkets.sol#449-480) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:337: VerdictMarkets.finalize(uint256) (src/VerdictMarkets.sol#337-355) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:277: VerdictMarkets.resolve(uint256,bytes) (src/VerdictMarkets.sol#277-289) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:305: VerdictMarkets.propose(uint256,OracleAttestation.Attestation) (src/VerdictMarkets.sol#305-335) uses timestamp for comparisons\n[low/medium] timestamp at src/OracleAttestation.sol:157: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/OracleAttestation.sol#157-165) uses timestamp for comparisons","passed":true},{"durationMs":555,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/VerdictMarkets.sol:245: Reentrancy: State change after external call (8 places)\n[low] centralization-risk at src/VerdictOracle.sol:14: Centralization Risk (3 places)\n[low] large-numeric-literal at src/VerdictMarkets.sol:343: Large Numeric Literal (3 places)\n[low] literal-instead-of-constant at src/VerdictMarkets.sol:241: Literal Instead of Constant (17 places)\n[low] local-variable-shadowing at src/VerdictOracle.sol:19: Local Variable Shadows State Variable (5 places)\n[low] non-reentrant-not-first at src/VerdictOracle.sol:144: `nonReentrant` is Not the First Modifier (2 places)\n[low] require-revert-in-loop at src/VerdictMarkets.sol:464: Loop Contains `require`/`revert` (3 places)\n[low] state-no-address-check at src/VerdictOracle.sol:82: Address State Variable Set Without Checks (2 places)\n[low] uninitialized-local-variable at src/VerdictMarkets.sol:471: Uninitialized Local Variable (4 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"680cd8c12c0b806fd3c5d144766ed44d386430f1245e886413a1868f7243ddc1","verifiedTreeHash":"ff389b1a497a527004161e62c0a2de36ee5799b5","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":49858,"exitCode":0,"name":"build","output":"Compiling 69 files with Solc 0.8.26\nSolc 0.8.26 finished in 49.72s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:71:9\n   │\n71 │         address asset_,\n   │         ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:70:9\n   │\n70 │         address intake_,\n   │         ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/VerdictOracle.sol:113:9\n    │\n113 │         emit Requested(intakeRequestId, bodyHash, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:101:13\n    │\n101 │         if (token.balanceOf(address(this)) != beforeBalance + cost) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:108:13\n    │\n108 │         if (token.balanceOf(address(this)) != beforeBalance) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:125:13\n    │\n125 │         if (block.timestamp > a.expiresAt) revert AttestationExpired(a.expiresAt);\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/VerdictOracle.sol:126:13\n    │\n126 │         if (a.issuedAt > block.timestamp + ISSUED_AT_TOLERANCE) revert AttestationNotYetValid(a.issuedAt);\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/VerdictOracle.sol:135:9\n    │\n135 │         emit Answered(a.requestId, intakeRequestId, p.bodyHash, attHash);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:144:66\n    │\n144 │     function proposeConfig(Config calldata c) external onlyOwner nonReentrant {\n    │                                                                  ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:152:48\n    │\n152 │     function acceptConfig() external onlyOwner nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:153:31\n    │\n153 │         if (!configPending || block.timestamp < acceptAfter) revert ConfigNotReady();\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/VerdictMarkets.sol:266:13\n    │\n266 │         if (block.timestamp >= m.params.closeAt) revert OutsideWindow();\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/VerdictMarkets.sol:284:17\n    │\n284 │             if (block.timestamp < m.lastPrimaryAsk + 24 hours) revert RetryNotReady();\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/VerdictMarkets.sol:295:13\n    │\n295 │         if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:301:9\n    │\n301 │         emit DisputeExtended(id, m.disputeEnds);\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/VerdictMarkets.sol:427:9\n    │\n427 │         emit OracleAsked(id, requestId, escalation, cost);\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/VerdictMarkets.sol:309:13\n    │\n309 │         if (block.timestamp < m.params.answerFrom) revert OutsideWindow();\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/VerdictMarkets.sol:312:17\n    │\n312 │             if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:314:20\n    │\n314 │         } else if (block.timestamp >= m.params.voidAfter) {\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/VerdictMarkets.sol:340:13\n    │\n340 │         if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:434:9\n    │\n434 │         emit BountyReturned(id, m.creator, bounty);\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/VerdictMarkets.sol:351:9\n    │\n351 │         emit Finalized(id, m.outcome, creatorFee, burnFee, treasuryFee);\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/VerdictMarkets.sol:360:17\n    │\n360 │             if (block.timestamp < m.params.voidAfter) revert OutsideWindow();\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/VerdictMarkets.sol:363:17\n    │\n363 │             if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:395:9\n    │\n395 │         emit Claimed(id, msg.sender, amount, refund);\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/VerdictMarkets.sol:409:13\n    │\n409 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\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/VerdictMarkets.sol:409:54\n    │\n409 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictMarkets.sol:426:13\n    │\n426 │         if (collateral.balanceOf(address(this)) != beforeBalance - cost) revert InexactOracleSpend();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictMarkets.sol:452:40\n    │\n452 │                 || p.minAgreed == 0 || p.closeAt <= block.timestamp || p.closeAt > p.answerFrom\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:465:53\n    │\n465 │                 if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();\n    │                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:472:82\n    │\n472 │                 if (p.answerType == 4 && uint256(p.keys[i]) > type(uint160).max) revert InvalidParams();\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:474:49\n    │\n474 │                     if (p.keys[i] == p.keys[j]) revert InvalidParams();\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:467:20\n    │\n467 │             return uint8(p.bounds.length + 1);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:477:20\n    │\n477 │             return uint8(p.keys.length + 1);\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/VerdictMarkets.sol:504:21\n    │\n504 │                 if (first == p.keys[i]) return i;\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:489:20\n    │\n489 │             return uint8(p.bounds.length);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:507:16\n    │\n507 │         return uint8(p.keys.length);\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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:17:9\n   │\n17 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:63:9\n   │\n63 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:78:9\n   │\n78 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:183:9\n    │\n183 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:198:9\n    │\n198 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:65:9\n    │\n 65 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:65:9\n    │\n 65 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:157:9\n    │\n157 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:164:9\n    │\n164 │         vm.warp(block.timestamp + 24 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictAtomicity.t.sol:164:9\n    │\n164 │         vm.warp(block.timestamp + 24 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/VerdictAtomicity.t.sol:164:17\n    │\n164 │         vm.warp(block.timestamp + 24 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictInvariant.t.sol:166:17\n    │\n166 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictLifecycleInvariant.t.sol:417:17\n    │\n417 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictMarkets.t.sol:46:9\n   │\n46 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:142:9\n    │\n142 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:154:9\n    │\n154 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:174:9\n    │\n174 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:176:17\n    │\n176 │         vm.warp(block.timestamp + 24 hours - 1);\n    │         ────────━━━━━━━━━━━━━━━──────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:179:17\n    │\n179 │         vm.warp(block.timestamp + 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/VerdictMarkets.t.sol:183:17\n    │\n183 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:195:9\n    │\n195 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:209:9\n    │\n209 │         vm.warp(p.answerUntil);\n    │         ────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:231:9\n    │\n231 │         vm.warp(p.answerUntil - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:249:9\n    │\n249 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:249:9\n    │\n249 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:276:9\n    │\n276 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:311:9\n    │\n311 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:166:9\n    │\n166 │         vm.warp(markets.getMarket(id).params.closeAt - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:265:9\n    │\n265 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:274:9\n    │\n274 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:307:9\n    │\n307 │         vm.warp(markets.getMarket(id).params.answerUntil + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:307:9\n    │\n307 │         vm.warp(markets.getMarket(id).params.answerUntil + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:332:9\n    │\n332 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:211:17\n    │\n211 │         vm.warp(block.timestamp + 2 days - 1);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:238:17\n    │\n238 │         vm.warp(block.timestamp + 1 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictOutcomes.t.sol:11:9\n   │\n11 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:130:9\n    │\n130 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:174:9\n    │\n174 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:191:13\n    │\n191 │             vm.warp(p.answerFrom);\n    │             ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:201:13\n    │\n201 │             vm.warp(p.voidAfter);\n    │             ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictSettlementProperties.t.sol:201:13\n    │\n201 │             vm.warp(p.voidAfter);\n    │             ──────────────────── `vm.warp` changes 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":34434,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 177455)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 168291)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4480)\n[PASS] test_digestMatchesTheProtocol() (gas: 13408)\n[PASS] test_domainIsConsumerChainAndVersionTwo() (gas: 15739)\n[PASS] test_structHashMatchesIndependentEncoding() (gas: 251625)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 941.60µs (1.11ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_burnVaultHasNoCallablePathOrEtherReceiver() (gas: 1013344)\n[PASS] test_exactSepoliaFactoryDeploymentWithoutDependencyCode() (gas: 18993281)\n[PASS] test_rehearsalRefusesOtherChains() (gas: 207095)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 112.64ms (93.40ms CPU time)\n\nRan 7 tests for test/VerdictOutcomes.t.sol:VerdictOutcomesTest\n[PASS] testFuzz_uintBucketDefinition(uint256) (runs: 512, μ: 1164736, ~: 1164837)\n[PASS] test_addressListUsesFirstElementOnlyAndCanonicalAddressKey() (gas: 4168549)\n[PASS] test_booleanOutcomes() (gas: 1957005)\n[PASS] test_bytes32ListUsesFirstElementOnlyAndEmptyMeansNone() (gas: 5127470)\n[PASS] test_malformedEncodedAnswerCannotSetOutcome() (gas: 1100041)\n[PASS] test_numericBucketsIncludeLowerBoundaryExcludeUpper() (gas: 6159611)\n[PASS] test_twoToEightOutcomesAndSortedUniqueDefinitions() (gas: 1747296)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 141.08ms (153.23ms CPU time)\n\nRan 20 tests for test/VerdictMarkets.t.sol:VerdictMarketsTest\n[PASS] testFuzz_terminalConservation(uint96,uint96,uint96,uint8,bool) (runs: 512, μ: 1859975, ~: 2092116)\nLogs:\n  Bound result 87322550\n  Bound result 183300758820500\n  Bound result 336815748276035148\n\n[PASS] test_asksBeforeAnswerFromAndAtOrAfterAnswerUntilRevert() (gas: 541156)\n[PASS] test_assetRotationBlocksAsksButNotRefunds() (gas: 2064182)\n[PASS] test_emptyWinningBucketCannotVoidUntilDisputeEnds() (gas: 1682233)\n[PASS] test_escalationAnswerCannotBeFirstProposal() (gas: 1143220)\n[PASS] test_escalationAskAtAnswerUntilRevertsEvenInsideDisputeWindow() (gas: 1189332)\n[PASS] test_externalSponsorCanDeliverPrimaryAndEscalation() (gas: 2330353)\n[PASS] test_fullSettlementPaysWholePoolFeesAndExactRemainder() (gas: 2272210)\n[PASS] test_lateEscalationBeyondVoidAfterStillFinalizesWithoutAnswer() (gas: 2310756)\n[PASS] test_lateEscalationReplacementRestartsWindowOnceAndFinalizes() (gas: 2598787)\n[PASS] test_noEscalationBodyAndDuplicateEscalationAsk() (gas: 2474916)\n[PASS] test_priceIncreaseCannotSpendBettorsCollateral() (gas: 2106263)\n[PASS] test_primaryRetryBlockedAfterDeliveryEvenWithoutProposal() (gas: 1105575)\n[PASS] test_proposeAfterAnswerUntilWithTimelyStoredAnswer() (gas: 1346498)\n[PASS] test_provisionalWindowBoundariesAreStrict() (gas: 2173538)\n[PASS] test_secondPrimaryAskAfter24HoursAndMaximumTwoAsks() (gas: 1661739)\n[PASS] test_tokenReentrancyBlockedOnDepositAndClaim() (gas: 2041257)\n[PASS] test_voidNoAnswerRefundsEveryOutcomeAndUnspentBounty() (gas: 1677885)\n[PASS] test_wrongBodiesAndResolveAfterProposalRevertWithoutSpend() (gas: 1392674)\n[PASS] test_zeroAndUnknownClaimsAndUnfinishedClaimsRevert() (gas: 652251)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 151.79ms (171.60ms CPU time)\n\nRan 12 tests for test/IndependentReview.t.sol:IndependentReviewTest\n[PASS] testFuzzReviewActualTransfersConserveInAnyClaimOrder(uint96,uint96,uint96,uint8) (runs: 512, μ: 2490682, ~: 2490835)\nLogs:\n  Bound result 14108\n  Bound result 11303\n  Bound result 7130\n\n[PASS] testReviewAgreementMinimumCanExceedMinimumPanel() (gas: 1599982)\n[PASS] testReviewDonationDoesNotAlterPayoutOrAccounting() (gas: 1704577)\n[PASS] testReviewEscalationCannotBeFirstProposalEvenWithLargePanel() (gas: 1142803)\n[PASS] testReviewEscalationCannotVoidAfterDeadline() (gas: 2135189)\n[PASS] testReviewFailedTokenTransferRollsBackClaim() (gas: 1821631)\n[PASS] testReviewLateReplacementPastVoidRemainsFinalizable() (gas: 2363827)\n[PASS] testReviewMaximumAnswerColdCallback() (gas: 1182306)\nLogs:\n  maximum answer cold callback gas: 118403\n\n[PASS] testReviewMixedMarketsCannotCrossSubsidizeClaims() (gas: 3060947)\n[PASS] testReviewNoWinnerIsVoidableAfterWindowPastVoidAfter() (gas: 1843037)\n[PASS] testReviewRotationPreservesOldCallerAndKey() (gas: 2201006)\n[PASS] testReviewSameAttestationCannotOverwriteDifferentRequest() (gas: 1368025)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 151.83ms (160.74ms CPU time)\n\nRan 15 tests for test/VerdictMarketsValidation.t.sol:VerdictMarketsValidationTest\n[PASS] test_allowlistRemovalAndPermanentDisable() (gas: 1276505)\n[PASS] test_attestationMustMatchEveryMarketFieldAndPanelRequirements() (gas: 6410189)\n[PASS] test_betZeroUnknownOutcomeAndCloseBoundary() (gas: 694664)\n[PASS] test_bodyHashAndBodySizeValidation() (gas: 707944)\n[PASS] test_bountyMustCoverTwoAsksAfterTransferFee() (gas: 235996)\n[PASS] test_creationEmitsBothFullBodies() (gas: 380289)\n[PASS] test_escalationRequiresDoubleCurrentPanelAndCorrectBody() (gas: 2747565)\n[PASS] test_feeCapAndPoolCapConstructor() (gas: 15564)\n[PASS] test_feeOnTransferCreditsOnlyActualBountyAndStakes() (gas: 1120818)\n[PASS] test_firstProposalAtVoidDeadlineCannotResurrectMarket() (gas: 1191129)\n[PASS] test_guardianHandoverIsTwoStepAndNoUnauthorizedPowers() (gas: 370210)\n[PASS] test_invalidTimesPanelsAndTypes() (gas: 614214)\n[PASS] test_minAgreedCanRequireMoreThanMinimumPanelSize() (gas: 1061340)\n[PASS] test_pauseBlocksOnlyEntryAndRenounceRequiresUnpaused() (gas: 3043898)\n[PASS] test_poolCapUsesReceivedBalanceAndFailedBetIsAtomic() (gas: 804428)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 197.90ms (19.63ms CPU time)\n\nRan 6 tests for test/VerdictOracleAdversarial.t.sol:VerdictOracleAdversarialTest\n[PASS] testFuzz_rotationsKeepFourInflightSnapshotsInAnyDeliveryOrder(uint256) (runs: 256, μ: 5370399, ~: 5370399)\n[PASS] test_contractSignerIsPinnedAndRevokedSignatureStoresNothing() (gas: 1478271)\n[PASS] test_everyAttestationFieldIsBoundBySignatureAndStoredHash() (gas: 2586185)\n[PASS] test_expiryAndClockToleranceAreInclusiveAtExactBoundary() (gas: 932730)\n[PASS] test_nonCanonicalAndTruncatedSignaturesCannotConsumePendingRequest() (gas: 806751)\n[PASS] test_pendingOwnerCannotAcceptConfigurationAndFormerOwnerLosesAccess() (gas: 433704)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 197.94ms (201.23ms CPU time)\n\nRan 7 tests for test/VerdictAtomicity.t.sol:VerdictAtomicityTest\n[PASS] testFuzz_failureAtAnyFinalizeRecipientRollsBackEarlierPayments(uint8,bool) (runs: 64, μ: 2226176, ~: 2224979)\n[PASS] test_failedBountyReturnDoesNotVoidMarketOrPreventLaterRefund() (gas: 1035823)\n[PASS] test_failedCallbackIsNotRefundedButMarketRetryAndSettlementRemainReachable() (gas: 2226717)\n[PASS] test_failedEscalationPaymentCannotExtendOrConsumeDisputeWindow() (gas: 2450956)\n[PASS] test_failedPrimaryPaymentRestoresBountyAskCountTimestampAndAllowances() (gas: 1641014)\n[PASS] test_failedRefundCanBeRetriedAndDoesNotConsumeAnotherUsersClaim() (gas: 1376078)\n[PASS] test_guardBlocksCrossMarketReentryFromAnOtherwiseEligibleClaimant() (gas: 4198353)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 210.15ms (59.71ms CPU time)\n\nRan 17 tests for test/VerdictOracle.t.sol:VerdictOracleTest\n[PASS] test_bodyLimitsAndExactPaymentRequired() (gas: 585988)\n[PASS] test_configDelayCapAndInvalidConfiguration() (gas: 9288)\n[PASS] test_consumedIntakeIdAndOracleIdCannotBeStoredTwice() (gas: 948524)\n[PASS] test_deliveredAnswerRemainsReadableAfterExpiry() (gas: 501860)\n[PASS] test_expiredFutureMalformedAndTamperedRejected() (gas: 766375)\n[PASS] test_falseAnswerStoredUnder150kGas() (gas: 553418)\nLogs:\n  cold callback gas: 103835\n\n[PASS] test_intakeAndSignerRotationPreservesInflightRequest() (gas: 2129782)\n[PASS] test_maxAnswerUnder150kGas() (gas: 587911)\nLogs:\n  maximum answer cold callback gas: 118403\n\n[PASS] test_replacingConfigProposalRestartsDelay() (gas: 283329)\n[PASS] test_requestPaysExactlyAndPinsConfiguration() (gas: 403437)\n[PASS] test_requestReentrancyFails() (gas: 486011)\n[PASS] test_reusedIntakeRequestIdRollsBackPayment() (gas: 545804)\n[PASS] test_timelockAndOwnable2Step() (gas: 558119)\n[PASS] test_wrongChainDomainStoresNothing() (gas: 417710)\n[PASS] test_wrongConsumerDomainStoresNothing() (gas: 422597)\n[PASS] test_wrongIntakeAndUnknownIdStoreNothing() (gas: 454073)\n[PASS] test_wrongSignerStoresNothingAndNoRefund() (gas: 521960)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 210.16ms (10.93ms CPU time)\n\nRan 7 tests for test/VerdictSettlementProperties.t.sol:VerdictSettlementPropertiesTest\n[PASS] testFuzz_feeSplitsAndRationalPayoutBoundsInEveryClaimOrder(uint256,uint16,uint16,uint16,uint8) (runs: 1000, μ: 2839252, ~: 2844162)\nLogs:\n  Bound result 494\n  Bound result 4\n  Bound result 1\n  Bound result 54089179139451691852\n  Bound result 77837551778584569782\n  Bound result 58040141650942839758\n  Bound result 1000000000000000000\n\n[PASS] testFuzz_numericOutcomeSatisfiesItsHalfOpenInterval(uint128,uint96,uint256,uint8) (runs: 1000, μ: 1293633, ~: 1284106)\nLogs:\n  Bound result 1\n  Bound result 30595\n\n[PASS] test_malformedListsCannotChangeAnAuthenticatedMarketsOutcome() (gas: 2656579)\n[PASS] test_oneWeiLastWinnerReceivesTheRoundingRemainder() (gas: 2152323)\n[PASS] test_oneWeiWinnerMayRoundToZeroButLastClaimStillDrainsExactly() (gas: 2384997)\n[PASS] test_payoutUsesFullPrecisionWhenIntermediateStakeTimesPoolOverflows256Bits() (gas: 2407171)\n[PASS] test_settlementEventsDescribeWholePoolFeesAndUnspentBounty() (gas: 1862317)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 210.27ms (423.76ms CPU time)\n\nRan 1 test for test/VerdictInvariant.t.sol:VerdictInvariantTest\n[PASS] invariant_actualTokensMatchEveryMarketsAccounting() (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------------+-------+---------+----------╮\n| Contract       | Selector       | Calls | Reverts | Discards |\n+==============================================================+\n| VerdictHandler | advance        | 828   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | ask            | 807   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | askEscalation  | 868   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | collect        | 824   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | deliverPrimary | 796   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | enter          | 805   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | proposePrimary | 784   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | replaceOutcome | 808   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | settle         | 834   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | togglePause    | 838   | 0       | 0        |\n╰----------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 18729\n  Bound result 18296\n  Bound result 1438\n  Bound result 0\n  Bound result 12361\n  Bound result 13003\n  Bound result 9876\n  Bound result 2\n  Bound result 15135\n  Bound result 7710\n  Bound result 4478\n  Bound result 1\n  Bound result 2\n  Bound result 202\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.61s (1.60s CPU time)\n\nRan 2 tests for test/VerdictLifecycleInvariant.t.sol:VerdictLifecycleInvariantTest\n[PASS] invariant_tokensStakesAndFinalityMatchIndependentLedger() (runs: 256, calls: 16384, reverts: 0)\n\n╭-------------------------+---------------+-------+---------+----------╮\n| Contract                | Selector      | Calls | Reverts | Discards |\n+======================================================================+\n| VerdictLifecycleHandler | advance       | 1391  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | askEscalation | 1336  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | askPrimary    | 1401  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | collect       | 1356  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | deliverAnswer | 1331  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | donate        | 1410  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | openMarket    | 1365  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | probeBurn     | 1386  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | probeTerminal | 1284  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | settle        | 1430  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | togglePause   | 1331  | 0       | 0        |\n|-------------------------+---------------+-------+---------+----------|\n| VerdictLifecycleHandler | wager         | 1363  | 0       | 0        |\n╰-------------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 15923\n  Bound result 123\n  Bound result 94878128846165281\n  Bound result 19633\n  Bound result 1433\n  Bound result 100\n  Bound result 191476905394724211\n  Bound result 150000\n  Bound result 21273\n  Bound result 11627\n  Bound result 746\n  Bound result 945700620506714198\n  Bound result 190\n  Bound result 147069545583802900\n\n[PASS] test_handlerReachesPrimaryEscalationFailureFinalizeAndRefundPaths() (gas: 15175354)\nLogs:\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 0\n  Bound result 101\n  Bound result 202\n  Bound result 307\n  Bound result 31\n  Bound result 17\n  Bound result 11\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 34.34s (34.35s CPU time)\n\nRan 12 test suites in 34.34s (37.53s CPU time): 103 tests passed, 0 failed, 0 skipped (103 total tests)\n","passed":true},{"durationMs":47,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"VerdictMarkets.acceptGuardian()\",\"VerdictMarkets.bet(uint256,uint8,uint256,uint256)\",\"VerdictMarkets.claim(uint256)\",\"VerdictMarkets.createMarket((bytes32,uint8,uint256,uint64,uint64,uint16,uint16,uint64,uint64,uint64,uint32,uint64,uint256[],bytes32[],uint256),bytes,bytes,string,uint256)\",\"VerdictMarkets.disableAllowlist()\",\"VerdictMarkets.escalate(uint256,bytes)\",\"VerdictMarkets.finalize(uint256)\",\"VerdictMarkets.pause()\",\"VerdictMarkets.propose(uint256,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64))\",\"VerdictMarkets.renounceGuardian()\",\"VerdictMarkets.resolve(uint256,bytes)\",\"VerdictMarkets.setCreatorAllowed(address,bool)\",\"VerdictMarkets.transferGuardian(address)\",\"VerdictMarkets.unpause()\",\"VerdictMarkets.voidMarket(uint256)\",\"VerdictOracle.acceptConfig()\",\"VerdictOracle.acceptOwnership()\",\"VerdictOracle.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"VerdictOracle.proposeConfig((address,address,address,bytes32,uint256))\",\"VerdictOracle.renounceOwnership()\",\"VerdictOracle.request(bytes)\",\"VerdictOracle.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":14,\"LICENSE\":21,\"README.md\":94,\"docs/DEPLOYMENT.md\":58,\"docs/INDEPENDENT_REVIEW.md\":65,\"docs/VERIFICATION.md\":39,\"foundry.toml\":23,\"remappings.txt\":2,\"script/SepoliaParameters.sol\":24,\"src/OracleAttestation.sol\":221,\"src/VerdictBurnVault.sol\":5,\"src/VerdictMarkets.sol\":509,\"src/VerdictOracle.sol\":172,\"src/interfaces/IIntake.sol\":14,\"src/interfaces/IVerdictOracle.sol\":12,\"test/Deployment.t.sol\":102,\"test/IndependentReview.t.sol\":239,\"test/OracleConsumerConformance.t.sol\":162,\"test/TESTING.md\":63,\"test/TestBase.sol\":135,\"test/VerdictAtomicity.t.sol\":214,\"test/VerdictInvariant.t.sol\":215,\"test/VerdictLifecycleInvariant.t.sol\":502,\"test/VerdictMarkets.t.sol\":375,\"test/VerdictMarketsValidation.t.sol\":354,\"test/VerdictOracle.t.sol\":288,\"test/VerdictOracleAdversarial.t.sol\":228,\"test/VerdictOutcomes.t.sol\":148,\"test/VerdictSettlementProperties.t.sol\":224,\"test/mocks/MockIMD.sol\":42,\"test/mocks/MockIntake.sol\":62},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a88654d4d8406a181bd2d9afaa36aa2f3662cd2ed1417ec52dfd59fa8a0c5ff3","verifiedTreeHash":"5c1ff3145c18d3a666ac035056a6776072021804","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":36649,"exitCode":0,"name":"build","output":"Compiling 67 files with Solc 0.8.26\nSolc 0.8.26 finished in 36.51s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:72:9\n   │\n72 │         address asset_,\n   │         ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:71:9\n   │\n71 │         address intake_,\n   │         ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/VerdictOracle.sol:114:9\n    │\n114 │         emit Requested(intakeRequestId, bodyHash, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:102:13\n    │\n102 │         if (token.balanceOf(address(this)) != beforeBalance + cost) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:109:13\n    │\n109 │         if (token.balanceOf(address(this)) != beforeBalance) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:126:13\n    │\n126 │         if (block.timestamp > a.expiresAt) revert AttestationExpired(a.expiresAt);\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/VerdictOracle.sol:127:13\n    │\n127 │         if (a.issuedAt > block.timestamp + ISSUED_AT_TOLERANCE) revert AttestationNotYetValid(a.issuedAt);\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/VerdictOracle.sol:137:9\n    │\n137 │         emit Answered(a.requestId, intakeRequestId, p.bodyHash, attHash);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:150:66\n    │\n150 │     function proposeConfig(Config calldata c) external onlyOwner nonReentrant {\n    │                                                                  ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:158:48\n    │\n158 │     function acceptConfig() external onlyOwner nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:159:31\n    │\n159 │         if (!configPending || block.timestamp < acceptAfter) revert ConfigNotReady();\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/VerdictMarkets.sol:271:13\n    │\n271 │         if (block.timestamp >= m.params.closeAt) revert OutsideWindow();\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/VerdictMarkets.sol:289:17\n    │\n289 │             if (block.timestamp < m.lastPrimaryAsk + 24 hours) revert RetryNotReady();\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/VerdictMarkets.sol:300:13\n    │\n300 │         if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:307:9\n    │\n307 │         emit DisputeExtended(id, m.disputeEnds);\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/VerdictMarkets.sol:445:9\n    │\n445 │         emit OracleAsked(id, requestId, escalation, cost);\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/VerdictMarkets.sol:315:13\n    │\n315 │         if (block.timestamp < m.params.answerFrom) revert OutsideWindow();\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/VerdictMarkets.sol:318:17\n    │\n318 │             if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:320:20\n    │\n320 │         } else if (block.timestamp >= m.params.voidAfter) {\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/VerdictMarkets.sol:356:13\n    │\n356 │         if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:452:9\n    │\n452 │         emit BountyReturned(id, m.creator, bounty);\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/VerdictMarkets.sol:367:9\n    │\n367 │         emit Finalized(id, m.outcome, creatorFee, burnFee, treasuryFee);\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/VerdictMarkets.sol:376:17\n    │\n376 │             if (block.timestamp < m.params.voidAfter) revert OutsideWindow();\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/VerdictMarkets.sol:379:17\n    │\n379 │             if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:411:9\n    │\n411 │         emit Claimed(id, msg.sender, amount, refund);\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/VerdictMarkets.sol:425:13\n    │\n425 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\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/VerdictMarkets.sol:425:54\n    │\n425 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictMarkets.sol:442:13\n    │\n442 │         if (collateral.balanceOf(address(this)) != beforeBalance - cost) revert InexactOracleSpend();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictMarkets.sol:470:40\n    │\n470 │                 || p.minAgreed == 0 || p.closeAt <= block.timestamp || p.closeAt > p.answerFrom\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:484:53\n    │\n484 │                 if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();\n    │                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:491:82\n    │\n491 │                 if (p.answerType == 4 && uint256(p.keys[i]) > type(uint160).max) revert InvalidParams();\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:493:49\n    │\n493 │                     if (p.keys[i] == p.keys[j]) revert InvalidParams();\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:486:20\n    │\n486 │             return uint8(p.bounds.length + 1);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:496:20\n    │\n496 │             return uint8(p.keys.length + 1);\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/VerdictMarkets.sol:523:21\n    │\n523 │                 if (first == p.keys[i]) return i;\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:508:20\n    │\n508 │             return uint8(p.bounds.length);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:526:16\n    │\n526 │         return uint8(p.keys.length);\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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:17:9\n   │\n17 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:63:9\n   │\n63 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:78:9\n   │\n78 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:183:9\n    │\n183 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:198:9\n    │\n198 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:11:9\n   │\n11 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:26:9\n   │\n26 │         vm.warp(markets.getMarket(first).params.answerFrom);\n   │         ─────────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionIndependentReview.t.sol:39:9\n    │\n 39 │         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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionIndependentReview.t.sol:39:9\n    │\n 39 │         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/RevisionIndependentReview.t.sol:39:17\n   │\n39 │         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/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:51:9\n   │\n51 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:66:9\n   │\n66 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:11:9\n   │\n11 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:50:9\n   │\n50 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:80:9\n   │\n80 │         vm.warp(markets.getMarket(first).params.answerFrom);\n   │         ─────────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:88:9\n    │\n 88 │         vm.warp(block.timestamp + 24 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:88:9\n    │\n 88 │         vm.warp(block.timestamp + 24 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/RevisionRegression.t.sol:88:17\n   │\n88 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:101:9\n    │\n101 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:106:9\n    │\n106 │         vm.warp(until - 10 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:106:9\n    │\n106 │         vm.warp(until - 10 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:125:9\n    │\n125 │         vm.warp(block.timestamp + 1 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:125:9\n    │\n125 │         vm.warp(block.timestamp + 1 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/RevisionRegression.t.sol:125:17\n    │\n125 │         vm.warp(block.timestamp + 1 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/VerdictInvariant.t.sol:164:17\n    │\n164 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictMarkets.t.sol:46:9\n   │\n46 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:142:9\n    │\n142 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:154:9\n    │\n154 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:182:9\n    │\n182 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:184:17\n    │\n184 │         vm.warp(block.timestamp + 24 hours - 1);\n    │         ────────━━━━━━━━━━━━━━━──────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:187:17\n    │\n187 │         vm.warp(block.timestamp + 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/VerdictMarkets.t.sol:191:17\n    │\n191 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:203:9\n    │\n203 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:217:9\n    │\n217 │         vm.warp(p.answerUntil);\n    │         ────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:239:9\n    │\n239 │         vm.warp(p.answerUntil - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:257:9\n    │\n257 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:257:9\n    │\n257 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:284:9\n    │\n284 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:319:9\n    │\n319 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:169:9\n    │\n169 │         vm.warp(markets.getMarket(id).params.closeAt - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:268:9\n    │\n268 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:277:9\n    │\n277 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:355:20\n    │\n355 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:355:20\n    │\n355 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:326:20\n    │\n326 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:326:20\n    │\n326 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:339:9\n    │\n339 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:211:17\n    │\n211 │         vm.warp(block.timestamp + 2 days - 1);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:238:17\n    │\n238 │         vm.warp(block.timestamp + 1 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictOutcomes.t.sol:11:9\n   │\n11 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:130:9\n    │\n130 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes 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":1839,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 199666)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 190502)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4480)\n[PASS] test_digestMatchesTheProtocol() (gas: 13408)\n[PASS] test_domainIsConsumerChainAndVersionTwo() (gas: 15761)\n[PASS] test_structHashMatchesIndependentEncoding() (gas: 251625)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 992.04µs (1.33ms CPU time)\n\nRan 5 tests for test/RevisionIndependentReview.t.sol:RevisionIndependentReviewTest\n[PASS] test_documentedUnusableOwnDeliveryStillBlocksRetry() (gas: 1239144)\n[PASS] test_escalationRejectsIssuanceBeforeItsOwnAsk() (gas: 1960042)\n[PASS] test_identicalBodyOtherMarketAnswerCannotSetOutcome() (gas: 1896821)\n[PASS] test_independentSameBodyCannotBlockOwnRetry() (gas: 1696131)\n[PASS] test_primaryLateIssuanceRemainsOutsideBriefsExplicitRange() (gas: 1333342)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 6.26ms (4.62ms CPU time)\n\nRan 8 tests for test/RevisionRegression.t.sol:RevisionRegressionTest\n[PASS] test_escalationCannotUseAnswerIssuedBeforeItsAsk() (gas: 1961597)\n[PASS] test_lateEscalationIssuedAfterAnswerUntilSettlesCorrectedOutcome() (gas: 2764355)\n[PASS] test_otherMarketAnswerCannotSetOutcomeOrBlockRetry() (gas: 2572786)\n[PASS] test_oversizeAnswerRefused() (gas: 971465)\n[PASS] test_renounceRequiresAllowlistDisabledEvenWhenEmpty() (gas: 494147)\n[PASS] test_unusableDeliveryBlocksRetry() (gas: 1239200)\n[PASS] test_zeroBoundRejectedWithoutTakingBounty() (gas: 1549940)\n[PASS] test_zeroDelayAcceptsConfigInSameBlock() (gas: 271470)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 35.23ms (6.41ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_burnVaultHasNoCallablePathOrEtherReceiver() (gas: 1013344)\n[PASS] test_exactSepoliaFactoryDeploymentWithoutDependencyCode() (gas: 19751923)\n[PASS] test_rehearsalRefusesOtherChains() (gas: 207095)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 55.27ms (46.62ms CPU time)\n\nRan 7 tests for test/VerdictOutcomes.t.sol:VerdictOutcomesTest\n[PASS] testFuzz_uintBucketDefinition(uint256) (runs: 512, μ: 1319243, ~: 1319263)\n[PASS] test_addressListUsesFirstElementOnlyAndCanonicalAddressKey() (gas: 4785569)\n[PASS] test_booleanOutcomes() (gas: 2265435)\n[PASS] test_bytes32ListUsesFirstElementOnlyAndEmptyMeansNone() (gas: 5898834)\n[PASS] test_malformedEncodedAnswerCannotSetOutcome() (gas: 1263905)\n[PASS] test_numericBucketsIncludeLowerBoundaryExcludeUpper() (gas: 7086553)\n[PASS] test_twoToEightOutcomesAndSortedUniqueDefinitions() (gas: 1767352)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 55.28ms (69.35ms CPU time)\n\nRan 15 tests for test/VerdictMarketsValidation.t.sol:VerdictMarketsValidationTest\n[PASS] test_allowlistRemovalAndPermanentDisable() (gas: 1276599)\n[PASS] test_attestationMustMatchEveryMarketFieldAndPanelRequirements() (gas: 5047338)\n[PASS] test_betZeroUnknownOutcomeAndCloseBoundary() (gas: 704338)\n[PASS] test_bodyHashAndBodySizeValidation() (gas: 717617)\n[PASS] test_bountyMustCoverTwoAsksAfterTransferFee() (gas: 236040)\n[PASS] test_creationEmitsBothFullBodies() (gas: 380282)\n[PASS] test_escalationRequiresDoubleCurrentPanelAndCorrectBody() (gas: 2769648)\n[PASS] test_feeCapAndPoolCapConstructor() (gas: 15564)\n[PASS] test_feeOnTransferCreditsOnlyActualBountyAndStakes() (gas: 1169280)\n[PASS] test_firstProposalAtVoidDeadlineCannotResurrectMarket() (gas: 1349349)\n[PASS] test_guardianHandoverIsTwoStepAndNoUnauthorizedPowers() (gas: 370210)\n[PASS] test_invalidTimesPanelsAndTypes() (gas: 614214)\n[PASS] test_minAgreedCanRequireMoreThanMinimumPanelSize() (gas: 1215513)\n[PASS] test_pauseBlocksOnlyEntryAndRenounceRequiresUnpaused() (gas: 3261673)\n[PASS] test_poolCapUsesReceivedBalanceAndFailedBetIsAtomic() (gas: 814102)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 69.19ms (12.34ms CPU time)\n\nRan 20 tests for test/VerdictMarkets.t.sol:VerdictMarketsTest\n[PASS] testFuzz_terminalConservation(uint96,uint96,uint96,uint8,bool) (runs: 512, μ: 1936989, ~: 2181109)\nLogs:\n  Bound result 66735577\n  Bound result 73084757847540364818\n  Bound result 8852121567855063785\n\n[PASS] test_asksBeforeAnswerFromAndAtOrAfterAnswerUntilRevert() (gas: 550863)\n[PASS] test_assetRotationBlocksAsksButNotRefunds() (gas: 2093333)\n[PASS] test_emptyWinningBucketCannotVoidUntilDisputeEnds() (gas: 1771204)\n[PASS] test_escalationAnswerCannotBeFirstProposal() (gas: 1194558)\n[PASS] test_escalationAskAtAnswerUntilRevertsEvenInsideDisputeWindow() (gas: 1258906)\n[PASS] test_externalSponsorCannotDeliverPrimaryOrEscalation() (gas: 3793707)\n[PASS] test_fullSettlementPaysWholePoolFeesAndExactRemainder() (gas: 2361182)\n[PASS] test_lateEscalationBeyondVoidAfterStillFinalizesWithoutAnswer() (gas: 2453724)\n[PASS] test_lateEscalationReplacementRestartsWindowOnceAndFinalizes() (gas: 2781443)\n[PASS] test_noEscalationBodyAndDuplicateEscalationAsk() (gas: 2658385)\n[PASS] test_priceIncreaseCannotSpendBettorsCollateral() (gas: 2227154)\n[PASS] test_primaryRetryBlockedAfterDeliveryEvenWithoutProposal() (gas: 1171348)\n[PASS] test_proposeAfterAnswerUntilWithTimelyStoredAnswer() (gas: 1435466)\n[PASS] test_provisionalWindowBoundariesAreStrict() (gas: 2284755)\n[PASS] test_secondPrimaryAskAfter24HoursAndMaximumTwoAsks() (gas: 1772213)\n[PASS] test_tokenReentrancyBlockedOnDepositAndClaim() (gas: 2125896)\n[PASS] test_voidNoAnswerRefundsEveryOutcomeAndUnspentBounty() (gas: 1729322)\n[PASS] test_wrongBodiesAndResolveAfterProposalRevertWithoutSpend() (gas: 1481642)\n[PASS] test_zeroAndUnknownClaimsAndUnfinishedClaimsRevert() (gas: 672266)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 69.25ms (81.00ms CPU time)\n\nRan 17 tests for test/VerdictOracle.t.sol:VerdictOracleTest\n[PASS] test_bodyLimitsAndExactPaymentRequired() (gas: 586164)\n[PASS] test_configDelayCapAndInvalidConfiguration() (gas: 9288)\n[PASS] test_consumedIntakeIdAndOracleIdCannotBeStoredTwice() (gas: 970867)\n[PASS] test_deliveredAnswerRemainsReadableAfterExpiry() (gas: 524115)\n[PASS] test_expiredFutureMalformedAndTamperedRejected() (gas: 766529)\n[PASS] test_falseAnswerStoredUnder150kGas() (gas: 575739)\nLogs:\n  cold callback gas: 126024\n\n[PASS] test_intakeAndSignerRotationPreservesInflightRequest() (gas: 2174415)\n[PASS] test_maxAnswerUnder150kGas() (gas: 610144)\nLogs:\n  maximum answer cold callback gas: 140592\n\n[PASS] test_replacingConfigProposalRestartsDelay() (gas: 283461)\n[PASS] test_requestPaysExactlyAndPinsConfiguration() (gas: 403481)\n[PASS] test_requestReentrancyFails() (gas: 486117)\n[PASS] test_reusedIntakeRequestIdRollsBackPayment() (gas: 545892)\n[PASS] test_timelockAndOwnable2Step() (gas: 558572)\n[PASS] test_wrongChainDomainStoresNothing() (gas: 417798)\n[PASS] test_wrongConsumerDomainStoresNothing() (gas: 422685)\n[PASS] test_wrongIntakeAndUnknownIdStoreNothing() (gas: 454227)\n[PASS] test_wrongSignerStoresNothingAndNoRefund() (gas: 522092)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 72.25ms (6.55ms CPU time)\n\nRan 12 tests for test/IndependentReview.t.sol:IndependentReviewTest\n[PASS] testFuzzReviewActualTransfersConserveInAnyClaimOrder(uint96,uint96,uint96,uint8) (runs: 512, μ: 2589461, ~: 2589553)\nLogs:\n  Bound result 1269\n  Bound result 1644586137742347935\n  Bound result 76510205837387322134\n\n[PASS] testReviewAgreementMinimumCanExceedMinimumPanel() (gas: 1679247)\n[PASS] testReviewDonationDoesNotAlterPayoutOrAccounting() (gas: 1793548)\n[PASS] testReviewEscalationCannotBeFirstProposalEvenWithLargePanel() (gas: 1194141)\n[PASS] testReviewEscalationCannotVoidAfterDeadline() (gas: 2268446)\n[PASS] testReviewFailedTokenTransferRollsBackClaim() (gas: 1920313)\n[PASS] testReviewLateReplacementPastVoidRemainsFinalizable() (gas: 2536759)\n[PASS] testReviewMaximumAnswerColdCallback() (gas: 1246333)\nLogs:\n  maximum answer cold callback gas: 140592\n\n[PASS] testReviewMixedMarketsCannotCrossSubsidizeClaims() (gas: 3179094)\n[PASS] testReviewNoWinnerIsVoidableAfterWindowPastVoidAfter() (gas: 1932008)\n[PASS] testReviewRotationPreservesOldCallerAndKey() (gas: 2280373)\n[PASS] testReviewSameAttestationCannotOverwriteDifferentRequest() (gas: 1409748)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 76.05ms (87.23ms CPU time)\n\nRan 1 test for test/VerdictInvariant.t.sol:VerdictInvariantTest\n[PASS] invariant_actualTokensMatchEveryMarketsAccounting() (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------------+-------+---------+----------╮\n| Contract       | Selector       | Calls | Reverts | Discards |\n+==============================================================+\n| VerdictHandler | advance        | 814   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | ask            | 829   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | askEscalation  | 805   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | collect        | 751   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | deliverPrimary | 827   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | enter          | 830   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | proposePrimary | 833   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | replaceOutcome | 866   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | settle         | 804   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | togglePause    | 833   | 0       | 0        |\n╰----------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1800000000\n  Bound result 3\n  Bound result 470161004\n  Bound result 2585\n  Bound result 7\n  Bound result 5774\n  Bound result 2506\n  Bound result 21597\n  Bound result 6270\n  Bound result 12361\n  Bound result 18296\n  Bound result 202\n  Bound result 5\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.76s (1.75s CPU time)\n\nRan 10 test suites in 1.76s (2.20s CPU time): 94 tests passed, 0 failed, 0 skipped (94 total tests)\n","passed":true},{"durationMs":48,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"VerdictMarkets.acceptGuardian()\",\"VerdictMarkets.bet(uint256,uint8,uint256,uint256)\",\"VerdictMarkets.claim(uint256)\",\"VerdictMarkets.createMarket((bytes32,uint8,uint256,uint64,uint64,uint16,uint16,uint64,uint64,uint64,uint32,uint64,uint256[],bytes32[],uint256),bytes,bytes,string,uint256)\",\"VerdictMarkets.disableAllowlist()\",\"VerdictMarkets.escalate(uint256,bytes)\",\"VerdictMarkets.finalize(uint256)\",\"VerdictMarkets.pause()\",\"VerdictMarkets.propose(uint256,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64))\",\"VerdictMarkets.renounceGuardian()\",\"VerdictMarkets.resolve(uint256,bytes)\",\"VerdictMarkets.setCreatorAllowed(address,bool)\",\"VerdictMarkets.transferGuardian(address)\",\"VerdictMarkets.unpause()\",\"VerdictMarkets.voidMarket(uint256)\",\"VerdictOracle.acceptConfig()\",\"VerdictOracle.acceptOwnership()\",\"VerdictOracle.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"VerdictOracle.proposeConfig((address,address,address,bytes32,uint256))\",\"VerdictOracle.renounceOwnership()\",\"VerdictOracle.request(bytes)\",\"VerdictOracle.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":14,\"LICENSE\":21,\"README.md\":100,\"docs/DEPLOYMENT.md\":58,\"docs/INDEPENDENT_REVIEW.md\":67,\"docs/REVISION_REVIEW.md\":41,\"docs/VERIFICATION.md\":41,\"foundry.toml\":23,\"remappings.txt\":2,\"script/SepoliaParameters.sol\":24,\"src/OracleAttestation.sol\":221,\"src/VerdictBurnVault.sol\":5,\"src/VerdictMarkets.sol\":528,\"src/VerdictOracle.sol\":178,\"src/interfaces/IIntake.sol\":14,\"src/interfaces/IVerdictOracle.sol\":14,\"test/Deployment.t.sol\":102,\"test/IndependentReview.t.sol\":239,\"test/OracleConsumerConformance.t.sol\":162,\"test/RevisionIndependentReview.t.sol\":77,\"test/RevisionRegression.t.sol\":133,\"test/TestBase.sol\":135,\"test/VerdictInvariant.t.sol\":213,\"test/VerdictMarkets.t.sol\":383,\"test/VerdictMarketsValidation.t.sol\":363,\"test/VerdictOracle.t.sol\":288,\"test/VerdictOutcomes.t.sol\":148,\"test/mocks/MockIMD.sol\":42,\"test/mocks/MockIntake.sol\":62},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4485,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/VerdictOracle.sol:94: Reentrancy in VerdictOracle.request(bytes) (src/VerdictOracle.sol#94-115):\n[high/medium] reentrancy-balance at src/VerdictMarkets.sol:428: Reentrancy in VerdictMarkets._ask(uint256,VerdictMarkets.Market,bytes,bool) (src/VerdictMarkets.sol#428-446):\n[medium/high] incorrect-equality at src/VerdictMarkets.sol:455: VerdictMarkets._pull(address,uint256) (src/VerdictMarkets.sol#455-461) uses a dangerous strict equality:\n[medium/medium] uninitialized-local at src/VerdictMarkets.sol:510: VerdictMarkets._outcome(VerdictMarkets.Params,bytes).first (src/VerdictMarkets.sol#510) is a local variable never initialized\n[low/medium] missing-zero-check at src/VerdictOracle.sol:72: VerdictOracle.constructor(address,address,address,bytes32,uint256,address,uint256).asset_ (src/VerdictOracle.sol#72) lacks a zero-check on :\n[low/medium] missing-zero-check at src/VerdictOracle.sol:71: VerdictOracle.constructor(address,address,address,bytes32,uint256,address,uint256).intake_ (src/VerdictOracle.sol#71) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/VerdictOracle.sol:94: Reentrancy in VerdictOracle.request(bytes) (src/VerdictOracle.sol#94-115):\n[low/medium] timestamp at src/VerdictMarkets.sol:467: VerdictMarkets._validateParams(VerdictMarkets.Params) (src/VerdictMarkets.sol#467-499) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:311: VerdictMarkets.propose(uint256,OracleAttestation.Attestation) (src/VerdictMarkets.sol#311-351) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:296: VerdictMarkets.escalate(uint256,bytes) (src/VerdictMarkets.sol#296-309) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:353: VerdictMarkets.finalize(uint256) (src/VerdictMarkets.sol#353-371) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictOracle.sol:158: VerdictOracle.acceptConfig() (src/VerdictOracle.sol#158-170) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictOracle.sol:117: VerdictOracle.onOracleResult(bytes32,OracleAttestation.Attestation,bytes) (src/VerdictOracle.sol#117-138) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:268: VerdictMarkets.bet(uint256,uint8,uint256,uint256) (src/VerdictMarkets.sol#268-280) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:424: VerdictMarkets._askWindow(VerdictMarkets.Market) (src/VerdictMarkets.sol#424-426) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:373: VerdictMarkets.voidMarket(uint256) (src/VerdictMarkets.sol#373-388) uses timestamp for comparisons\n[low/medium] timestamp at src/VerdictMarkets.sol:282: VerdictMarkets.resolve(uint256,bytes) (src/VerdictMarkets.sol#282-294) uses timestamp for comparisons\n[low/medium] timestamp at src/OracleAttestation.sol:157: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/OracleAttestation.sol#157-165) uses timestamp for comparisons","passed":true},{"durationMs":570,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/VerdictMarkets.sol:250: Reentrancy: State change after external call (9 places)\n[low] centralization-risk at src/VerdictOracle.sol:14: Centralization Risk (3 places)\n[low] large-numeric-literal at src/VerdictMarkets.sol:359: Large Numeric Literal (3 places)\n[low] literal-instead-of-constant at src/VerdictMarkets.sol:246: Literal Instead of Constant (17 places)\n[low] local-variable-shadowing at src/VerdictOracle.sol:19: Local Variable Shadows State Variable (5 places)\n[low] non-reentrant-not-first at src/VerdictOracle.sol:150: `nonReentrant` is Not the First Modifier (2 places)\n[low] require-revert-in-loop at src/VerdictMarkets.sol:483: Loop Contains `require`/`revert` (3 places)\n[low] state-no-address-check at src/VerdictOracle.sol:83: Address State Variable Set Without Checks (2 places)\n[low] uninitialized-local-variable at src/VerdictMarkets.sol:490: Uninitialized Local Variable (4 places)","passed":true},{"durationMs":8378,"exitCode":0,"name":"proof b1e002a6c49f","output":"Compiling 57 files with Solc 0.8.26\nSolc 0.8.26 finished in 7.87s\nCompiler run successful!\n\nRan 2 tests for test/imd-proof-6586b2c8/Proof_b1e002a6c49f.t.sol:AnswerShoppingTest\n[PASS] test_firstProposerPicksAmongDivergentAnswers() (gas: 1777324)\n[PASS] test_replacementWithoutEscalationAsk() (gas: 1970501)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.42ms (2.46ms CPU time)\n\nRan 1 test suite in 3.10ms (2.42ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)\n","passed":true},{"durationMs":8141,"exitCode":0,"name":"proof 77bcda558b57","output":"2026-10-11T02:44:05.099927Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-PaBtH0/repo/test/imd-proof-6586b2c8/Proof_b1e002a6c49f.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 7.63s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-4d24f305/Proof_77bcda558b57.t.sol:EscalationTimingProof\n[PASS] test_escalationAnswerIssuedInsideExtendedWindowReplacesPrimary() (gas: 2099142)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.10ms (1.07ms CPU time)\n\nRan 1 test suite in 2.70ms (2.10ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e09b659867e619fca91cde08d7057b2eb0e1c26993e9aa1bb5b80a88deddd876","verifiedTreeHash":"6b4979004169e8f878538df38896cd96d2f4a584","verifierVersion":"0.1.0+0e08a464"},{"checks":[{"durationMs":36103,"exitCode":0,"name":"build","output":"Compiling 67 files with Solc 0.8.26\nSolc 0.8.26 finished in 35.96s\nCompiler run successful!\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:72:9\n   │\n72 │         address asset_,\n   │         ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/VerdictOracle.sol:71:9\n   │\n71 │         address intake_,\n   │         ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/VerdictOracle.sol:114:9\n    │\n114 │         emit Requested(intakeRequestId, bodyHash, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:102:13\n    │\n102 │         if (token.balanceOf(address(this)) != beforeBalance + cost) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictOracle.sol:109:13\n    │\n109 │         if (token.balanceOf(address(this)) != beforeBalance) revert InexactPayment();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:126:13\n    │\n126 │         if (block.timestamp > a.expiresAt) revert AttestationExpired(a.expiresAt);\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/VerdictOracle.sol:127:13\n    │\n127 │         if (a.issuedAt > block.timestamp + ISSUED_AT_TOLERANCE) revert AttestationNotYetValid(a.issuedAt);\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/VerdictOracle.sol:137:9\n    │\n137 │         emit Answered(a.requestId, intakeRequestId, p.bodyHash, attHash);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:150:66\n    │\n150 │     function proposeConfig(Config calldata c) external onlyOwner nonReentrant {\n    │                                                                  ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/VerdictOracle.sol:158:48\n    │\n158 │     function acceptConfig() external onlyOwner nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictOracle.sol:159:31\n    │\n159 │         if (!configPending || block.timestamp < acceptAfter) revert ConfigNotReady();\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/VerdictMarkets.sol:271:13\n    │\n271 │         if (block.timestamp >= m.params.closeAt) revert OutsideWindow();\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/VerdictMarkets.sol:289:17\n    │\n289 │             if (block.timestamp < m.lastPrimaryAsk + 24 hours) revert RetryNotReady();\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/VerdictMarkets.sol:300:13\n    │\n300 │         if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:307:9\n    │\n307 │         emit DisputeExtended(id, m.disputeEnds);\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/VerdictMarkets.sol:445:9\n    │\n445 │         emit OracleAsked(id, requestId, escalation, cost);\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/VerdictMarkets.sol:315:13\n    │\n315 │         if (block.timestamp < m.params.answerFrom) revert OutsideWindow();\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/VerdictMarkets.sol:318:17\n    │\n318 │             if (block.timestamp >= m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:320:20\n    │\n320 │         } else if (block.timestamp >= m.params.voidAfter) {\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/VerdictMarkets.sol:356:13\n    │\n356 │         if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:452:9\n    │\n452 │         emit BountyReturned(id, m.creator, bounty);\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/VerdictMarkets.sol:367:9\n    │\n367 │         emit Finalized(id, m.outcome, creatorFee, burnFee, treasuryFee);\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/VerdictMarkets.sol:376:17\n    │\n376 │             if (block.timestamp < m.params.voidAfter) revert OutsideWindow();\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/VerdictMarkets.sol:379:17\n    │\n379 │             if (block.timestamp < m.disputeEnds) revert OutsideWindow();\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/VerdictMarkets.sol:411:9\n    │\n411 │         emit Claimed(id, msg.sender, amount, refund);\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/VerdictMarkets.sol:425:13\n    │\n425 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\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/VerdictMarkets.sol:425:54\n    │\n425 │         if (block.timestamp < m.params.answerFrom || block.timestamp >= m.params.answerUntil) revert OutsideWindow();\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/VerdictMarkets.sol:442:13\n    │\n442 │         if (collateral.balanceOf(address(this)) != beforeBalance - cost) revert InexactOracleSpend();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/VerdictMarkets.sol:470:40\n    │\n470 │                 || p.minAgreed == 0 || p.closeAt <= block.timestamp || p.closeAt > p.answerFrom\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:484:53\n    │\n484 │                 if (p.bounds[i] <= p.bounds[i - 1]) revert InvalidParams();\n    │                                                     ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:491:82\n    │\n491 │                 if (p.answerType == 4 && uint256(p.keys[i]) > type(uint160).max) revert InvalidParams();\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/VerdictMarkets.sol:493:49\n    │\n493 │                     if (p.keys[i] == p.keys[j]) revert InvalidParams();\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:486:20\n    │\n486 │             return uint8(p.bounds.length + 1);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:496:20\n    │\n496 │             return uint8(p.keys.length + 1);\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/VerdictMarkets.sol:523:21\n    │\n523 │                 if (first == p.keys[i]) return i;\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:508:20\n    │\n508 │             return uint8(p.bounds.length);\n    │                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/VerdictMarkets.sol:526:16\n    │\n526 │         return uint8(p.keys.length);\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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:17:9\n   │\n17 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:63:9\n   │\n63 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/IndependentReview.t.sol:78:9\n   │\n78 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:123:9\n    │\n123 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:183:9\n    │\n183 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/IndependentReview.t.sol:198:9\n    │\n198 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:11:9\n   │\n11 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:26:9\n   │\n26 │         vm.warp(markets.getMarket(first).params.answerFrom);\n   │         ─────────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionIndependentReview.t.sol:39:9\n    │\n 39 │         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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionIndependentReview.t.sol:39:9\n    │\n 39 │         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/RevisionIndependentReview.t.sol:39:17\n   │\n39 │         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/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:51:9\n   │\n51 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionIndependentReview.t.sol:66:9\n   │\n66 │         vm.warp(p.answerUntil - 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/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:11:9\n   │\n11 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:50:9\n   │\n50 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/RevisionRegression.t.sol:80:9\n   │\n80 │         vm.warp(markets.getMarket(first).params.answerFrom);\n   │         ─────────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:88:9\n    │\n 88 │         vm.warp(block.timestamp + 24 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:88:9\n    │\n 88 │         vm.warp(block.timestamp + 24 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/RevisionRegression.t.sol:88:17\n   │\n88 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:101:9\n    │\n101 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:106:9\n    │\n106 │         vm.warp(until - 10 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:106:9\n    │\n106 │         vm.warp(until - 10 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:125:9\n    │\n125 │         vm.warp(block.timestamp + 1 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionRegression.t.sol:125:9\n    │\n125 │         vm.warp(block.timestamp + 1 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/RevisionRegression.t.sol:125:17\n    │\n125 │         vm.warp(block.timestamp + 1 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/VerdictInvariant.t.sol:164:17\n    │\n164 │         vm.warp(block.timestamp + 14 days);\n    │         ────────━━━━━━━━━━━━━━━─────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictMarkets.t.sol:46:9\n   │\n46 │         vm.warp(markets.getMarket(id).params.answerFrom);\n   │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:90:9\n    │\n 90 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:118:9\n    │\n118 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:121:9\n    │\n121 │         vm.warp(p.voidAfter + 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:142:9\n    │\n142 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:154:9\n    │\n154 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n121 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:182:9\n    │\n182 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:184:17\n    │\n184 │         vm.warp(block.timestamp + 24 hours - 1);\n    │         ────────━━━━━━━━━━━━━━━──────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictMarkets.t.sol:187:17\n    │\n187 │         vm.warp(block.timestamp + 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/VerdictMarkets.t.sol:191:17\n    │\n191 │         vm.warp(block.timestamp + 24 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:203:9\n    │\n203 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:217:9\n    │\n217 │         vm.warp(p.answerUntil);\n    │         ────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:239:9\n    │\n239 │         vm.warp(p.answerUntil - 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/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:257:9\n    │\n257 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:257:9\n    │\n257 │         vm.warp(markets.getMarket(id).disputeEnds - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:284:9\n    │\n284 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarkets.t.sol:319:9\n    │\n319 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:169:9\n    │\n169 │         vm.warp(markets.getMarket(id).params.closeAt - 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/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:268:9\n    │\n268 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:277:9\n    │\n277 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:355:20\n    │\n355 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:355:20\n    │\n355 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:326:20\n    │\n326 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.revertToState`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:326:20\n    │\n326 │         assertTrue(vm.revertToState(snapshot));\n    │                    ────────────────────────── `vm.revertToState` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictMarketsValidation.t.sol:339:9\n    │\n339 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:211:17\n    │\n211 │         vm.warp(block.timestamp + 2 days - 1);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/VerdictOracle.t.sol:238:17\n    │\n238 │         vm.warp(block.timestamp + 1 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/TestBase.sol:61:28\n   │\n61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/VerdictOutcomes.t.sol:11:9\n   │\n11 │         vm.warp(p.answerFrom);\n   │         ───────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:101:29\n    │\n101 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:102:30\n    │\n102 │         a.expiresAt = uint64(block.timestamp + 7 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:11:9\n    │\n 11 │         vm.warp(p.answerFrom);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/TestBase.sol:61:28\n    │\n 61 │         p.closeAt = uint64(block.timestamp + 1 hours);\n    │                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/VerdictOutcomes.t.sol:130:9\n    │\n130 │         vm.warp(markets.getMarket(id).params.answerFrom);\n    │         ──────────────────────────────────────────────── `vm.warp` changes 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":1790,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 199666)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 190502)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4480)\n[PASS] test_digestMatchesTheProtocol() (gas: 13408)\n[PASS] test_domainIsConsumerChainAndVersionTwo() (gas: 15761)\n[PASS] test_structHashMatchesIndependentEncoding() (gas: 251625)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 966.78µs (1.05ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_burnVaultHasNoCallablePathOrEtherReceiver() (gas: 1013344)\n[PASS] test_exactSepoliaFactoryDeploymentWithoutDependencyCode() (gas: 19751923)\n[PASS] test_rehearsalRefusesOtherChains() (gas: 207095)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 23.82ms (24.07ms CPU time)\n\nRan 8 tests for test/RevisionRegression.t.sol:RevisionRegressionTest\n[PASS] test_escalationCannotUseAnswerIssuedBeforeItsAsk() (gas: 1961597)\n[PASS] test_lateEscalationIssuedAfterAnswerUntilSettlesCorrectedOutcome() (gas: 2764355)\n[PASS] test_otherMarketAnswerCannotSetOutcomeOrBlockRetry() (gas: 2572786)\n[PASS] test_oversizeAnswerRefused() (gas: 971465)\n[PASS] test_renounceRequiresAllowlistDisabledEvenWhenEmpty() (gas: 494147)\n[PASS] test_unusableDeliveryBlocksRetry() (gas: 1239200)\n[PASS] test_zeroBoundRejectedWithoutTakingBounty() (gas: 1549940)\n[PASS] test_zeroDelayAcceptsConfigInSameBlock() (gas: 271470)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 36.00ms (10.00ms CPU time)\n\nRan 7 tests for test/VerdictOutcomes.t.sol:VerdictOutcomesTest\n[PASS] testFuzz_uintBucketDefinition(uint256) (runs: 512, μ: 1319176, ~: 1319215)\n[PASS] test_addressListUsesFirstElementOnlyAndCanonicalAddressKey() (gas: 4785569)\n[PASS] test_booleanOutcomes() (gas: 2265435)\n[PASS] test_bytes32ListUsesFirstElementOnlyAndEmptyMeansNone() (gas: 5898834)\n[PASS] test_malformedEncodedAnswerCannotSetOutcome() (gas: 1263905)\n[PASS] test_numericBucketsIncludeLowerBoundaryExcludeUpper() (gas: 7086553)\n[PASS] test_twoToEightOutcomesAndSortedUniqueDefinitions() (gas: 1767352)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 52.00ms (48.77ms CPU time)\n\nRan 15 tests for test/VerdictMarketsValidation.t.sol:VerdictMarketsValidationTest\n[PASS] test_allowlistRemovalAndPermanentDisable() (gas: 1276599)\n[PASS] test_attestationMustMatchEveryMarketFieldAndPanelRequirements() (gas: 5047338)\n[PASS] test_betZeroUnknownOutcomeAndCloseBoundary() (gas: 704338)\n[PASS] test_bodyHashAndBodySizeValidation() (gas: 717617)\n[PASS] test_bountyMustCoverTwoAsksAfterTransferFee() (gas: 236040)\n[PASS] test_creationEmitsBothFullBodies() (gas: 380282)\n[PASS] test_escalationRequiresDoubleCurrentPanelAndCorrectBody() (gas: 2769648)\n[PASS] test_feeCapAndPoolCapConstructor() (gas: 15564)\n[PASS] test_feeOnTransferCreditsOnlyActualBountyAndStakes() (gas: 1169280)\n[PASS] test_firstProposalAtVoidDeadlineCannotResurrectMarket() (gas: 1349349)\n[PASS] test_guardianHandoverIsTwoStepAndNoUnauthorizedPowers() (gas: 370210)\n[PASS] test_invalidTimesPanelsAndTypes() (gas: 614214)\n[PASS] test_minAgreedCanRequireMoreThanMinimumPanelSize() (gas: 1215513)\n[PASS] test_pauseBlocksOnlyEntryAndRenounceRequiresUnpaused() (gas: 3261673)\n[PASS] test_poolCapUsesReceivedBalanceAndFailedBetIsAtomic() (gas: 814102)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 55.22ms (11.31ms CPU time)\n\nRan 20 tests for test/VerdictMarkets.t.sol:VerdictMarketsTest\n[PASS] testFuzz_terminalConservation(uint96,uint96,uint96,uint8,bool) (runs: 512, μ: 1944383, ~: 2181115)\nLogs:\n  Bound result 21317\n  Bound result 20730\n  Bound result 31806015238278583489\n\n[PASS] test_asksBeforeAnswerFromAndAtOrAfterAnswerUntilRevert() (gas: 550863)\n[PASS] test_assetRotationBlocksAsksButNotRefunds() (gas: 2093333)\n[PASS] test_emptyWinningBucketCannotVoidUntilDisputeEnds() (gas: 1771204)\n[PASS] test_escalationAnswerCannotBeFirstProposal() (gas: 1194558)\n[PASS] test_escalationAskAtAnswerUntilRevertsEvenInsideDisputeWindow() (gas: 1258906)\n[PASS] test_externalSponsorCannotDeliverPrimaryOrEscalation() (gas: 3793707)\n[PASS] test_fullSettlementPaysWholePoolFeesAndExactRemainder() (gas: 2361182)\n[PASS] test_lateEscalationBeyondVoidAfterStillFinalizesWithoutAnswer() (gas: 2453724)\n[PASS] test_lateEscalationReplacementRestartsWindowOnceAndFinalizes() (gas: 2781443)\n[PASS] test_noEscalationBodyAndDuplicateEscalationAsk() (gas: 2658385)\n[PASS] test_priceIncreaseCannotSpendBettorsCollateral() (gas: 2227154)\n[PASS] test_primaryRetryBlockedAfterDeliveryEvenWithoutProposal() (gas: 1171348)\n[PASS] test_proposeAfterAnswerUntilWithTimelyStoredAnswer() (gas: 1435466)\n[PASS] test_provisionalWindowBoundariesAreStrict() (gas: 2284755)\n[PASS] test_secondPrimaryAskAfter24HoursAndMaximumTwoAsks() (gas: 1772213)\n[PASS] test_tokenReentrancyBlockedOnDepositAndClaim() (gas: 2125896)\n[PASS] test_voidNoAnswerRefundsEveryOutcomeAndUnspentBounty() (gas: 1729322)\n[PASS] test_wrongBodiesAndResolveAfterProposalRevertWithoutSpend() (gas: 1481642)\n[PASS] test_zeroAndUnknownClaimsAndUnfinishedClaimsRevert() (gas: 672266)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 55.28ms (69.61ms CPU time)\n\nRan 17 tests for test/VerdictOracle.t.sol:VerdictOracleTest\n[PASS] test_bodyLimitsAndExactPaymentRequired() (gas: 586164)\n[PASS] test_configDelayCapAndInvalidConfiguration() (gas: 9288)\n[PASS] test_consumedIntakeIdAndOracleIdCannotBeStoredTwice() (gas: 970867)\n[PASS] test_deliveredAnswerRemainsReadableAfterExpiry() (gas: 524115)\n[PASS] test_expiredFutureMalformedAndTamperedRejected() (gas: 766529)\n[PASS] test_falseAnswerStoredUnder150kGas() (gas: 575739)\nLogs:\n  cold callback gas: 126024\n\n[PASS] test_intakeAndSignerRotationPreservesInflightRequest() (gas: 2174415)\n[PASS] test_maxAnswerUnder150kGas() (gas: 610144)\nLogs:\n  maximum answer cold callback gas: 140592\n\n[PASS] test_replacingConfigProposalRestartsDelay() (gas: 283461)\n[PASS] test_requestPaysExactlyAndPinsConfiguration() (gas: 403481)\n[PASS] test_requestReentrancyFails() (gas: 486117)\n[PASS] test_reusedIntakeRequestIdRollsBackPayment() (gas: 545892)\n[PASS] test_timelockAndOwnable2Step() (gas: 558572)\n[PASS] test_wrongChainDomainStoresNothing() (gas: 417798)\n[PASS] test_wrongConsumerDomainStoresNothing() (gas: 422685)\n[PASS] test_wrongIntakeAndUnknownIdStoreNothing() (gas: 454227)\n[PASS] test_wrongSignerStoresNothingAndNoRefund() (gas: 522092)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 69.60ms (6.01ms CPU time)\n\nRan 5 tests for test/RevisionIndependentReview.t.sol:RevisionIndependentReviewTest\n[PASS] test_documentedUnusableOwnDeliveryStillBlocksRetry() (gas: 1239144)\n[PASS] test_escalationRejectsIssuanceBeforeItsOwnAsk() (gas: 1960042)\n[PASS] test_identicalBodyOtherMarketAnswerCannotSetOutcome() (gas: 1896821)\n[PASS] test_independentSameBodyCannotBlockOwnRetry() (gas: 1696131)\n[PASS] test_primaryLateIssuanceRemainsOutsideBriefsExplicitRange() (gas: 1333342)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 80.40ms (5.13ms CPU time)\n\nRan 12 tests for test/IndependentReview.t.sol:IndependentReviewTest\n[PASS] testFuzzReviewActualTransfersConserveInAnyClaimOrder(uint96,uint96,uint96,uint8) (runs: 512, μ: 2589326, ~: 2589547)\nLogs:\n  Bound result 170153677\n  Bound result 50391024148540\n  Bound result 51306283281495935\n\n[PASS] testReviewAgreementMinimumCanExceedMinimumPanel() (gas: 1679247)\n[PASS] testReviewDonationDoesNotAlterPayoutOrAccounting() (gas: 1793548)\n[PASS] testReviewEscalationCannotBeFirstProposalEvenWithLargePanel() (gas: 1194141)\n[PASS] testReviewEscalationCannotVoidAfterDeadline() (gas: 2268446)\n[PASS] testReviewFailedTokenTransferRollsBackClaim() (gas: 1920313)\n[PASS] testReviewLateReplacementPastVoidRemainsFinalizable() (gas: 2536759)\n[PASS] testReviewMaximumAnswerColdCallback() (gas: 1246333)\nLogs:\n  maximum answer cold callback gas: 140592\n\n[PASS] testReviewMixedMarketsCannotCrossSubsidizeClaims() (gas: 3179094)\n[PASS] testReviewNoWinnerIsVoidableAfterWindowPastVoidAfter() (gas: 1932008)\n[PASS] testReviewRotationPreservesOldCallerAndKey() (gas: 2280373)\n[PASS] testReviewSameAttestationCannotOverwriteDifferentRequest() (gas: 1409748)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 80.55ms (90.50ms CPU time)\n\nRan 1 test for test/VerdictInvariant.t.sol:VerdictInvariantTest\n[PASS] invariant_actualTokensMatchEveryMarketsAccounting() (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------------+-------+---------+----------╮\n| Contract       | Selector       | Calls | Reverts | Discards |\n+==============================================================+\n| VerdictHandler | advance        | 813   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | ask            | 804   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | askEscalation  | 820   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | collect        | 835   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | deliverPrimary | 808   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | enter          | 799   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | proposePrimary | 841   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | replaceOutcome | 839   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | settle         | 809   | 0       | 0        |\n|----------------+----------------+-------+---------+----------|\n| VerdictHandler | togglePause    | 824   | 0       | 0        |\n╰----------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 12346\n  Bound result 16416\n  Bound result 33\n  Bound result 242\n  Bound result 5591\n  Bound result 17302\n  Bound result 4215\n  Bound result 21561\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.70s (1.70s CPU time)\n\nRan 10 test suites in 1.70s (2.16s CPU time): 94 tests passed, 0 failed, 0 skipped (94 total tests)\n","passed":true},{"durationMs":47,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"VerdictMarkets.acceptGuardian()\",\"VerdictMarkets.bet(uint256,uint8,uint256,uint256)\",\"VerdictMarkets.claim(uint256)\",\"VerdictMarkets.createMarket((bytes32,uint8,uint256,uint64,uint64,uint16,uint16,uint64,uint64,uint64,uint32,uint64,uint256[],bytes32[],uint256),bytes,bytes,string,uint256)\",\"VerdictMarkets.disableAllowlist()\",\"VerdictMarkets.escalate(uint256,bytes)\",\"VerdictMarkets.finalize(uint256)\",\"VerdictMarkets.pause()\",\"VerdictMarkets.propose(uint256,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64))\",\"VerdictMarkets.renounceGuardian()\",\"VerdictMarkets.resolve(uint256,bytes)\",\"VerdictMarkets.setCreatorAllowed(address,bool)\",\"VerdictMarkets.transferGuardian(address)\",\"VerdictMarkets.unpause()\",\"VerdictMarkets.voidMarket(uint256)\",\"VerdictOracle.acceptConfig()\",\"VerdictOracle.acceptOwnership()\",\"VerdictOracle.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"VerdictOracle.proposeConfig((address,address,address,bytes32,uint256))\",\"VerdictOracle.renounceOwnership()\",\"VerdictOracle.request(bytes)\",\"VerdictOracle.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":14,\"LICENSE\":21,\"README.md\":100,\"docs/DEPLOYMENT.md\":58,\"docs/INDEPENDENT_REVIEW.md\":67,\"docs/REVISION_REVIEW.md\":41,\"docs/VERIFICATION.md\":41,\"foundry.toml\":23,\"launch.json\":36,\"remappings.txt\":2,\"script/SepoliaParameters.sol\":24,\"src/OracleAttestation.sol\":221,\"src/VerdictBurnVault.sol\":5,\"src/VerdictMarkets.sol\":528,\"src/VerdictOracle.sol\":178,\"src/interfaces/IIntake.sol\":14,\"src/interfaces/IVerdictOracle.sol\":14,\"test/Deployment.t.sol\":102,\"test/IndependentReview.t.sol\":239,\"test/OracleConsumerConformance.t.sol\":162,\"test/RevisionIndependentReview.t.sol\":77,\"test/RevisionRegression.t.sol\":133,\"test/TestBase.sol\":135,\"test/VerdictInvariant.t.sol\":213,\"test/VerdictMarkets.t.sol\":383,\"test/VerdictMarketsValidation.t.sol\":363,\"test/VerdictOracle.t.sol\":288,\"test/VerdictOutcomes.t.sol\":148,\"test/mocks/MockIMD.sol\":42,\"test/mocks/MockIntake.sol\":62},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"efa2c60d32ef1fcc13ec81a61f7300d6a657aeff245fd823877c39a837049f91","verifiedTreeHash":"6efc5072554eeedc21130f38c6bd959bc221b1e2","verifierVersion":"0.1.0+0e08a464"}]}