{"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":"254f03ee-e7c5-4651-a3de-996ae711121a","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"784c18d068c7531fe2af0d3a14ada7f5c422193e41e4bf5ae0adee60fdb2782f","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"5b9220390166d83aeecce24c9ce1ccaf363c7ca2e9feaae0ec189aa026cb934c","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"61dc9178c0e1d47ab16c7961d0f87ad893a12b9b65b501e1e36c483f0f318d30","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","subagents":4,"tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"6eb0edceb2ec8699b85c37da42dbe208fbc69ad6cc25072db5f6affd59bba997","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"011d61b135e2d0824b224d02e8189ff49ecd88553c88e3cc7ec2cc275f40aad9","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"ae8724ea3aab7136089ee4e1db893f52301f824e4161c429308031f8fd7979e7","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"15b04fc8f60521936b9e2b37c09a804685ec689fc98cd5b04510d986d3106a15","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"15b04fc8f60521936b9e2b37c09a804685ec689fc98cd5b04510d986d3106a15","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"ae81ced700f69eee64c3574690b7c111dfbc7f57d54ffbb7f74391940ae850af","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"18cba0c8f00fec7597d306a3da5d49b86d2ff03863c72b89d02be5a217f84753","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","subagents":4,"tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Create a complete Squeekchain prediction market project called \"Squeek Predict\".\n\nProject goal:\nA simple on-chain prediction market where users can bet on how many Squeek blocks the hamster will complete in the next 24 hours (or next 7 days).\n\nRequirements:\n- Read settled data from SqueekCore on Sepolia testnet\n- Contract address of SqueekCore: 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f\n- Users can place yes/no bets (e.g. \"Will the hamster complete more than X Squeek blocks in the next 24h?\")\n- Resolution based on the official settled work / Squeek block count from SqueekCore\n- Include a basic frontend (or clear instructions) so people can interact with it\n- Clean README explaining the project, how it works, and how it uses Squeekchain data\n- Minimal but functional MVP (not a full production app)\n- Make it clear this is a project built for the Squeekchain ecosystem / Buildooooor badge\n\nTech:\n- Solidity contract for the prediction market\n- Use Sepolia testnet\n- Keep it simple and verifiable","parentJobId":null,"planHash":"61c4cd9bd8c9aba3b00013d8542f1099a6331b7a80aa2244f466b15b7b836bf2","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"254f03ee-e7c5-4651-a3de-996ae711121a","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2711-create-complete-squeekchain-prediction"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"53937","feedbackHash":"1826818ba60a4aeca8f8e9a8c44a6696671739255597c7a9c3ffe3689610666d","nodeKey":"audit_economics","submissionHash":"784c18d068c7531fe2af0d3a14ada7f5c422193e41e4bf5ae0adee60fdb2782f","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52255","feedbackHash":"120dfe32a4b5b877344a3d4f4f18a9bd06297adbc7ead50118765bf86e5c95b8","nodeKey":"audit_flow","submissionHash":"5b9220390166d83aeecce24c9ce1ccaf363c7ca2e9feaae0ec189aa026cb934c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52665","feedbackHash":"55a3cb1c0e1ed7e65bd4181266493ddd2c2ae75f0f549863b042bd0ad1ea1ab3","nodeKey":"audit_judge","submissionHash":"61dc9178c0e1d47ab16c7961d0f87ad893a12b9b65b501e1e36c483f0f318d30","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52130","feedbackHash":"441cab45e4e3f638cade575a50c5d9f0ebf1a3034d481f5dcb403866fbca3011","nodeKey":"audit_judge","submissionHash":"42e35bc8b7b91973a6feb9e117e357dea63ed9c3a534cf5bf81cb19e875bec1f","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52114","feedbackHash":"9e3111ccac7dfbc44985110c328ae2bd7f8c79f5d423c7cc34e043d894e24be3","nodeKey":"audit_math","submissionHash":"6eb0edceb2ec8699b85c37da42dbe208fbc69ad6cc25072db5f6affd59bba997","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52292","feedbackHash":"11dc7c64f070da12944a58ba76dcd93e0c9bd21a53dfc2409028059f4c925b97","nodeKey":"audit_permissions","submissionHash":"011d61b135e2d0824b224d02e8189ff49ecd88553c88e3cc7ec2cc275f40aad9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51011","feedbackHash":"a6e5717e7f7321b7034bf1c016428371d051f710cab57d32449f501718893303","nodeKey":"build_contract_project","submissionHash":"288a36ce0820a7f2bc0f7166258062c7cef52330c39e52dad14fd86efb33bf62","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"53909","feedbackHash":"118d39acc3cbdb76e0e9ffc0b3fcf1bb1f21d3c9807dfe799b6ba48e430f8a2b","nodeKey":"build_contract_project","submissionHash":"ae8724ea3aab7136089ee4e1db893f52301f824e4161c429308031f8fd7979e7","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51096","feedbackHash":"3e1618a2d3350009a726dbb632c35d146fa6ed565c7e1c66346027db1e1a4977","nodeKey":"manifest","submissionHash":"9c868c47cec4281b1c3b65f5c00417a9ee0fe012a7601e829406a8c2951963ac","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51487","feedbackHash":"6d20dfa63e89dc44a02d1504a0a255c21e5327d250c7500f5f37e8fe7e1aa75f","nodeKey":"manifest","submissionHash":"ae81ced700f69eee64c3574690b7c111dfbc7f57d54ffbb7f74391940ae850af","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51169","feedbackHash":"ad4a0bf63f4a2b4957129774b784d096935979b808c9de7dc417b6f3efd57633","nodeKey":"write_foundry_tests","submissionHash":"18cba0c8f00fec7597d306a3da5d49b86d2ff03863c72b89d02be5a217f84753","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"50991","feedbackHash":"c36bd26bced789b510724a8a7a11394ccc4be8c0db540588eece22efa30187b7","nodeKey":"write_foundry_tests","submissionHash":"e94981930694d6c4153bdb68785cafc1897784ad9f0f141f2eb6a120649494ba","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"ccf0a26c8a38e508bed75c9c2869e36938d315ebc3ae8de51b7461ce04709929","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ddcecd7483f623f7","findings":[{"citation":"resolved","description":"resolve() is only allowed while endsAt <= block.timestamp < refundAt (line 163 `if (block.timestamp >= m.refundAt) revert ResolutionExpired();`), and refundAt = endsAt + RESOLUTION_GRACE = endsAt + 3 days (line 121). Once refundAt passes, anyone (in practice the losing side) calls cancelExpired(id) (line 203 `if (block.timestamp < m.refundAt) revert TooEarly();`) and the market is refunded with no Core read, even if Core later certifies the window. The guarantee 'resolution based on the official settled work' therefore only holds if the Core Reporter certifies endRound within 3 days of the window's end. Measured on Sepolia during this review (2026-10-30, block 12025830, ts 1793353128): state().settledThroughRound = 1973 while the current round is 2509 (genesis 1791847800, 600 s rounds); round 1973 ended at 1793031600, i.e. 3.7 days earlier; the frontier was already 1973 at block 12018630 (~24 h earlier) and in docs/core-observation.json; eth_getLogs on the Core proxy returns no events from block 12005830 to the tip (~2.8 days). Under this observed cadence every market created now would reach refundAt with NotSettled still reverting and be cancelled by cancelExpired. The asymmetry is that the refund path is unconditional and permissionless while the resolution path is conditional on a third party's timing, so the losing side wins by default whenever the Reporter is more than 3 days late. The README documents delayed settlement as a risk but the chosen constant is already exceeded by the live oracle. Suggested minimal fix preserving the design: raise RESOLUTION_GRACE substantially (e.g. 14-30 days), and/or have cancelExpired refuse while Core currently reports settledThroughRound >= endRound with a compatible configuration (wrapped in try/catch so an unavailable or upgraded Core still refunds), so that certified data takes precedence over a refund whenever it exists.","line":18,"path":"src/SqueekPredict.sol","reproduction":"On a Sepolia fork or live: cast call 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f \"state()((uint64,uint64,uint96,uint64,uint96,uint32,uint256,bool))\" --rpc-url https://ethereum-sepolia-rpc.publicnode.com returns settledThroughRound=1973 at ts ~1793353128 while (ts-1791847800)/600+1 = 2509. Locally (same mechanism as test_CoreUpgradeInvalidatesMarketAndTimeoutStillRefunds): createMarket(10, 107, 1 days) with MockSqueekCore frontier 100; alice bet(id,true) 2 ether, bob bet(id,false) 3 ether; leave core frontier below endRound (250) for the whole window; vm.warp(endsAt) -> resolve(id) reverts NotSettled; vm.warp(refundAt) -> cancelExpired(id) succeeds, status=Cancelled, claimable(alice)=2 ether, claimable(bob)=3 ether; then core.setFrontier(250) with a YES history -> resolve(id) reverts MarketFinalized. Expected: a market whose window Core eventually certifies resolves from that data; actual: it is refunded and the certified outcome can never be applied.","severity":"medium","snippet":"    uint64 public constant RESOLUTION_GRACE = 3 days;","title":"3-day resolution grace is shorter than the live SqueekCore settlement lag, so markets refund instead of resolving"},{"citation":"resolved","description":"bet() enforces a single cap on yesPool + noPool. A wallet that bets MAX_POOL (or the remaining capacity while the other side is still empty) in the block after createMarket leaves zero capacity, so every later bet on either side reverts PoolLimit, including the MIN_BET needed to give the market an opposing side. Because the market is then one-sided by construction, resolve() (line 182) and cancelUnmatched() (line 196) both route it to _cancel, and the blocker's claim() returns its full stake. The blocker never has a losing exposure: the only cost is gas and locking the capital until startsAt. This is an unprivileged, repeatable denial of service on any market (the creator's included) and a no-risk way to make a market somebody else opened unusable. Suggested minimal fix preserving the design: cap each side separately (e.g. MAX_POOL / 2 per side) or cap each wallet's stake per market, and/or always admit a MIN_BET bet on an empty side.","line":145,"path":"src/SqueekPredict.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SqueekPredict} from \"src/SqueekPredict.sol\";\nimport {ISqueekCore} from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal V3 fixture: version 3, 600s rounds, 1e9 units per block, settled frontier 100.\ncontract CoreFixture {\n    uint64 public constant GENESIS = 1_700_000_000;\n\n    function implementationCodeVersion() external pure returns (uint64) {\n        return 3;\n    }\n\n    function implementationCodeAddress() external view returns (address) {\n        return address(this);\n    }\n\n    function configuration() external pure returns (ISqueekCore.CoreConfiguration memory c) {\n        c.streamId = keccak256(\"fixture\");\n        c.genesisTimestamp = GENESIS;\n        c.roundDuration = 600;\n        c.blockUnitsPerBlock = 1_000_000_000;\n    }\n\n    function state() external pure returns (ISqueekCore.CoreState memory s) {\n        s.settledThroughRound = 100;\n    }\n\n    function roundPage(uint64, uint64 r, uint256) external pure returns (ISqueekCore.RoundPage memory p) {\n        p.certifiedThroughRound = r;\n    }\n}\n\n/// Fails on the current code: one wallet fills the whole MAX_POOL on YES right after creation, every\n/// other bettor is rejected with PoolLimit, the market is one-sided by construction, and after betting\n/// closes the blocker recovers its entire stake through cancelUnmatched + claim without any exposure.\ncontract PoolCapLockTest is Test {\n    address internal constant CORE = 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f;\n    SqueekPredict internal predict;\n    address internal blocker = makeAddr(\"blocker\");\n    address internal honest = makeAddr(\"honest\");\n\n    function setUp() public {\n        vm.chainId(11_155_111);\n        vm.etch(CORE, address(new CoreFixture()).code);\n        vm.warp(CoreFixture(CORE).GENESIS() + 100 * 600);\n        predict = new SqueekPredict();\n        vm.deal(blocker, 1000 ether);\n        vm.deal(honest, 1000 ether);\n    }\n\n    function test_OneWalletCannotExcludeEveryCounterpartyRiskFree() public {\n        uint256 id = predict.createMarket(10, 107, 1 days);\n        uint256 maxPool = predict.MAX_POOL();\n        uint256 minBet = predict.MIN_BET();\n\n        // Blocker puts as much as the contract accepts on YES in the first block after creation.\n        vm.prank(blocker);\n        (bool blocked,) = address(predict).call{value: maxPool}(abi.encodeCall(SqueekPredict.bet, (id, true)));\n        uint256 blockerStake = blocked ? maxPool : 0;\n\n        // An honest counterparty must still be able to take the empty side with the minimum stake.\n        vm.prank(honest);\n        (bool matched,) = address(predict).call{value: minBet}(abi.encodeCall(SqueekPredict.bet, (id, false)));\n        assertTrue(matched, \"honest NO bet rejected: one wallet excluded every counterparty\");\n\n        // And the blocker must not be able to walk away with a full refund after excluding everyone.\n        vm.warp(predict.getMarket(id).startsAt);\n        (bool cancelled,) = address(predict).call(abi.encodeCall(SqueekPredict.cancelUnmatched, (id)));\n        if (cancelled) {\n            uint256 before = blocker.balance;\n            vm.prank(blocker);\n            predict.claim(id, payable(blocker));\n            assertLt(blocker.balance - before, blockerStake, \"blocker refunded in full after locking the market\");\n        }\n    }\n}","reproduction":"createMarket(10, 107, 1 days) at ts genesis+100*600 with a V3 Core fixture; blocker: bet{value: 100 ether}(id, true) succeeds; honest: bet{value: 0.0001 ether}(id, false) reverts PoolLimit (actual) although it should be admissible (expected); vm.warp(startsAt); cancelUnmatched(id) succeeds; blocker claim(id, blocker) returns 100 ether. Proof test test/scratch/PoolCapLock.t.sol fails on the current code with 'honest NO bet rejected'.","severity":"low","snippet":"        if (msg.value > MAX_POOL - m.yesPool - m.noPool) revert PoolLimit();","title":"Shared 100 ETH pool cap lets one wallet exclude every counterparty and get a guaranteed full refund"}],"hash":"011d61b135e2d0824b224d02e8189ff49ecd88553c88e3cc7ec2cc275f40aad9","nodeId":"4a1397eb-6cbb-4594-8755-384ab02d032c","outcome":"completed","summary":"Review complete. The findings file holds two substantiated defects and a coverage row for all six entry points plus four invariants.\n\n**What I found**\n\n- **Medium, resolution grace vs. live oracle lag** (src/SqueekPredict.sol:18). Resolution is only allowed for 3 days after a window ends, after which anyone can refund the market without a Core read. On Sepolia today the Core frontier sits at round 1973 while the current round is 2509, so settlement is about 3.7 days behind, unchanged for at least 24 hours, with no Core events for roughly 2.8 days. Under that cadence every market created now ends in a refund, and a later-certified outcome can never be applied. A local scratch test confirms the sequence: resolve reverts NotSettled, cancelExpired succeeds at refundAt, and resolve then reverts MarketFinalized even after Core certifies a clear YES. Suggested fix keeps the design: a much longer grace and, optionally, a try/catch check in cancelExpired that refuses to refund while Core already certifies the window.\n- **Low, shared pool cap enables a risk-free market lock** (src/SqueekPredict.sol:145). One wallet can bet the full 100 ETH on one side right after creation, every other bet then reverts PoolLimit, the market is one-sided by construction, and the blocker gets a full refund via cancelUnmatched and claim. The attached proof test fails on the current code at the honest counterparty's rejected NO bet. A per-side or per-wallet cap, or always admitting a minimum bet on an empty side, fixes it.\n\n**What holds in my area.** There is no owner, role, initializer, receive or fallback, so the permission model is purely time and status based. I traced createMarket, bet, resolve, cancelUnmatched, cancelExpired and claim for guard gaps, storage-write symmetry, branch symmetry and trust seams. The resolve/cancelExpired windows are disjoint, claims are caller-keyed with effects before the transfer, and the final-claimant remainder rule can only reach the sole remaining winner. The live Core answers point queries exactly as the contract assumes. The aderyn reentrancy lead is a false positive: every call before the writes in createMarket is a STATICCALL. The slither timestamp lines are the documented deadline design.\n\n**Not reached.** I did not review the frontend beyond its call wiring, and deep Core history could not be sampled because the public RPC prunes state older than about a day.","treeHash":null,"usage":{"cachedInputTokens":838071,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":33285,"runtime":"claude","turns":34,"wallClockMs":480094}},{"artifacts":[],"attempt":1,"bundleHash":"2b641a732cca7bcf54b3dad07faac7dd777146fc7ee5e2b6043bceab962773a0","device":"87804e27e9c9f85a","findings":[],"hash":"18cba0c8f00fec7597d306a3da5d49b86d2ff03863c72b89d02be5a217f84753","nodeId":"8963b742-63ff-4a68-a59d-5098134543bf","outcome":"completed","summary":"All 70 tests pass, both with a plain `forge test` and with the verifier's fuzz seed. I found no new defect, so there is no `.imd-findings.json`.\n\n**Why three of my tests had broken.** The implementation changed two rules since my last round: the resolution grace went from 3 days to 30 days, and the 100 ETH cap now applies to each side separately instead of to the whole market. My older tests still expected the old rules. These were intended spec changes, not bugs, so I updated the tests rather than reporting them.\n\n- **`test/SqueekPredict.stateful.t.sol`:** the stateful test that drives random sequences of calls now uses a 30-day grace for its time jumps, refund deadlines and deadline checks. Its bet logic now works out the remaining room from the side being bet on, and its invariant checks each side is at most 100 ETH rather than the two together.\n- **`test/SqueekPredict.boundaries.t.sol`:** fixed the deadline check to expect 30 days, and added three tests for the new rules:\n  - At any second inside the grace, the timeout refund is rejected and resolving works. Once a market is resolved, it can't be cancelled afterwards.\n  - If certified data arrives exactly at the refund deadline, the market can no longer be resolved and can only be refunded.\n  - Each side is capped on its own, to the wei. A full side rejects even the minimum bet, but the other side still takes a full 100 ETH, so a market can hold 200 ETH.\n- **`test/helpers/PredictTestBase.sol`, `test/TESTING.md`:** a comment noting the cap is per side, and the coverage table updated.\n\nI only changed files under `test/` and haven't committed anything. I couldn't run the two protected check files locally: they import `floor/OwnerChecks.sol`, which only exists on the verifier.","treeHash":"9f84c4f01f4afd40991ad3d034aed1126936b761","usage":{"cachedInputTokens":617571,"inputTokens":28,"model":"claude-opus-5-5","outputTokens":7869,"runtime":"claude","turns":17,"wallClockMs":194012}},{"artifacts":[],"attempt":1,"bundleHash":"74c50dafadfe3e11dca9f4f56e6ca9d7706ade3565c92da45102c5f726473dd4","device":"20c10dbba93106ff","findings":[],"hash":"288a36ce0820a7f2bc0f7166258062c7cef52330c39e52dad14fd86efb33bf62","nodeId":"eca02a39-c021-4264-9d07-98ccf5d27091","outcome":"completed","summary":"Implemented **Squeek Predict** with:\n\n- 24-hour and 7-day YES/NO markets using certified SqueekCore history.\n- Proportional payouts, timeout refunds, and reentrancy protection.\n- Wallet frontend, deployment instructions, and security notes.\n\nVerified: `forge build`, `forge test` (38 passing), `forge fmt --check`, and 5 frontend/ABI tests. Live Sepolia reads also succeeded.\n\nDeployment and independent security review remain pending.","treeHash":"bf410c22fea73358f61b57f6d289d20101fba4bc","usage":{"cachedInputTokens":1335680,"inputTokens":176596,"model":"gpt-6.1-sol","outputTokens":40567,"runtime":"codex","turns":6,"wallClockMs":886431}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1c29c7c6e4cf57eb","findings":[{"citation":"resolved","description":"Merged from audit_economics (low), audit_flow (medium), audit_permissions (medium) and audit_math (medium); all four have the same root cause. refundAt = startsAt + duration + RESOLUTION_GRACE (line 121, constant `uint64 public constant RESOLUTION_GRACE = 3 days;` line 18). resolve() needs CORE.state().settledThroughRound >= m.endRound (line 169) and reverts permanently once block.timestamp >= refundAt (line 163). After that, anyone can call cancelExpired (line 203), which refunds without reading Core, and Cancelled cannot be undone (_openMarket line 282). The brief's guarantee, resolution from SqueekCore's official settled block count, therefore holds only if the Reporter certifies the window's last round within 3 days of its end. The live dependency does not do that. I read it myself on Sepolia at block 12025908 (timestamp 1793354064): state() returns settledThroughRound=1973, paused=false, authorizationNonce=1657, and docs/core-observation.json (block 12025776) shows the same frontier. Round 1973 ended at genesis 1791847800 + 1973*600 = 1793031600. The wall-clock round is 2510, so the frontier is about 322,000 s (3.73 days) behind, more than RESOLUTION_GRACE (259,200 s). Every market whose window ends during such an outage is refunded even after Core catches up, so the winning side loses its payout and the losing side recovers its stake. No funds are lost or misdirected, but a guarantee breaks under a condition that exists on the live chain today, so this is medium. The refund fallback is still needed for a Core that never recovers. Minimal fix that keeps the design: lengthen RESOLUTION_GRACE substantially (for example 14-30 days; MAX_POOL still bounds exposure), and/or keep resolve() available after refundAt until someone has actually called cancelExpired.","line":163,"path":"src/SqueekPredict.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SqueekPredict} from \"src/SqueekPredict.sol\";\nimport {ISqueekCore} from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal V3 fixture: a settable certified frontier and per-round ledger points.\ncontract StalledCore is ISqueekCore {\n    CoreConfiguration private _config;\n    uint64 public frontier;\n    mapping(uint64 => LedgerPosition) private _points;\n\n    function configure(uint64 genesis) external {\n        _config.genesisTimestamp = genesis;\n        _config.roundDuration = 600;\n        _config.blockUnitsPerBlock = 1_000_000_000;\n        _config.streamId = keccak256(\"stalled fixture\");\n    }\n\n    function setFrontier(uint64 round) external {\n        frontier = round;\n    }\n\n    function setPoint(uint64 round, uint96 units) external {\n        _points[round] = LedgerPosition(uint64(units / 1e9), units, 10_875);\n    }\n\n    function state() external view returns (CoreState memory result) {\n        result.settledThroughRound = frontier;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _config;\n    }\n\n    function roundPage(uint64 afterRound, uint64 throughRound, uint256) external view returns (RoundPage memory result) {\n        require(afterRound == throughRound && throughRound <= frontier, \"InvalidRoundPageBounds\");\n        result.certifiedThroughRound = throughRound;\n        result.start = _points[throughRound];\n        result.end = _points[throughRound];\n    }\n\n    function implementationCodeVersion() external pure returns (uint64) {\n        return 3;\n    }\n\n    function implementationCodeAddress() external view returns (address) {\n        return address(this);\n    }\n}\n\n/// @notice Live SqueekCore (Sepolia, read 2026-10-30 at block 12025823) certified round 1973 at\n///         timestamp 1793031636 and nothing since: 3.72 days. A market whose last round is 1974\n///         can never resolve, because RESOLUTION_GRACE (3 days) elapses before the frontier reaches\n///         endRound and resolve() then rejects the certified result. This test replays that outage\n///         length. It fails on the current code (ResolutionExpired) and passes once the resolution\n///         window outlasts an outage of this length.\ncontract ResolutionGraceTest is Test {\n    uint64 internal constant GENESIS = 1_700_000_000;\n    address internal constant CORE = 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f;\n    SqueekPredict internal predict;\n    StalledCore internal core;\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.chainId(11_155_111);\n        vm.warp(GENESIS + 100 * 600);\n        StalledCore template = new StalledCore();\n        vm.etch(CORE, address(template).code);\n        core = StalledCore(CORE);\n        core.configure(GENESIS);\n        core.setFrontier(100);\n        predict = new SqueekPredict();\n        vm.deal(alice, 10 ether);\n        vm.deal(bob, 10 ether);\n    }\n\n    function test_MarketResolvesOnceCertifiedAfterObservedReporterOutage() public {\n        uint256 id = predict.createMarket(0, 107, 1 days);\n        SqueekPredict.Market memory m = predict.getMarket(id);\n        vm.prank(alice);\n        predict.bet{value: 2 ether}(id, true);\n        vm.prank(bob);\n        predict.bet{value: 3 ether}(id, false);\n\n        // Reporter stalls one round short of the market's last round (frontier 249 < endRound 250).\n        core.setPoint(m.startRound - 1, 100e9);\n        core.setFrontier(m.endRound - 1);\n        vm.warp(m.endsAt);\n        vm.expectRevert(SqueekPredict.NotSettled.selector);\n        predict.resolve(id);\n\n        // Observed live outage length: 3 days 17 hours after the round ended, Core certifies it\n        // (one block completed inside the window).\n        vm.warp(m.endsAt + 3 days + 17 hours);\n        core.setPoint(m.endRound, 101e9);\n        core.setFrontier(m.endRound);\n\n        // The result is certified and the market is still Open, so it should resolve.\n        predict.resolve(id);\n        m = predict.getMarket(id);\n        assertEq(uint256(m.status), uint256(SqueekPredict.Status.Resolved), \"resolved from certified data\");\n        assertTrue(m.yesWins, \"one completed block > threshold 0\");\n        assertEq(predict.claimable(id, alice), 5 ether, \"winner is paid the pool, not refunded\");\n        assertEq(predict.claimable(id, bob), 0, \"loser is not refunded\");\n    }\n}","reproduction":"Proof (test/scratch, V3 fixture etched at the Core address, roundPage(r,r,0) returning certifiedThroughRound=r with start==end, which matches the live call roundPage(1900,1900,0) -> (1900, pos, pos, [])): createMarket(0,107,1 days) -> endRound 250. alice bet{2 ether}(id,true), bob bet{3 ether}(id,false). Core frontier held at 249: at endsAt, resolve reverts NotSettled. At endsAt+3d17h (the observed live outage length) Core certifies round 250 with units 101e9 vs 100e9 at round 106 (1 block > threshold 0), and resolve(id) is called. Expected: Resolved, yesWins, claimable(alice)=5 ether, claimable(bob)=0. Actual: revert ResolutionExpired() at line 163; the only path left is cancelExpired -> claimable(alice)=2 ether, claimable(bob)=3 ether. Ran with forge test --match-path: [FAIL: ResolutionExpired()]. Live precondition: cast call 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f state() at Sepolia block 12025908 -> settledThroughRound 1973 while (1793354064-1791847800)/600 = round 2510.","severity":"medium","snippet":"        if (block.timestamp >= m.refundAt) revert ResolutionExpired();","title":"3-day RESOLUTION_GRACE is shorter than the live SqueekCore Reporter outage: certified outcomes are rejected and decided markets are refunded"},{"citation":"resolved","description":"Merged from audit_economics (low) and audit_permissions (low); both have the same root cause. MAX_POOL limits yesPool + noPool together. While one side is still empty, bets on the filled side can consume the whole cap, so every bet on the empty side reverts PoolLimit, even MIN_BET. The market then can only be one-sided, so cancelUnmatched (line 196) or resolve (line 182) cancels it and every stake, including the filler's, is refunded. Anyone willing to lock up to 100 Sepolia ETH until startsAt can void any market whose other side is still empty, with no exposure to losing. Honest bettors are forced into refunds, and the two-sided question the brief asks for is defeated. Funds are not lost and the capital needed is large, so this is low. Fix: cap each side separately, or always leave room for at least MIN_BET on an empty side.","line":145,"path":"src/SqueekPredict.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SqueekPredict} from \"src/SqueekPredict.sol\";\nimport {ISqueekCore} from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal V3 Core stand-in so createMarket's configuration checks pass. Reads only.\ncontract CoreStub is ISqueekCore {\n    uint64 public frontier;\n\n    function configuration() external pure returns (CoreConfiguration memory c) {\n        c.streamId = keccak256(\"stub\");\n        c.genesisTimestamp = 1_700_000_000;\n        c.roundDuration = 600;\n        c.blockUnitsPerBlock = 1_000_000_000;\n    }\n\n    function state() external view returns (CoreState memory s) {\n        s.settledThroughRound = frontier;\n    }\n\n    function roundPage(uint64 afterRound, uint64, uint256) external pure returns (RoundPage memory r) {\n        r.certifiedThroughRound = afterRound;\n    }\n\n    function implementationCodeVersion() external pure returns (uint64) {\n        return 3;\n    }\n\n    function implementationCodeAddress() external view returns (address) {\n        return address(this);\n    }\n}\n\n/// @notice One actor fills the shared 100 ETH pool cap on a single side; the opposite side can no longer\n/// place even the minimum stake, so the market can only ever be refunded. The griefer loses nothing:\n/// cancelUnmatched at startsAt returns its full 60 ETH.\ncontract PoolCapGriefingTest is Test {\n    address internal constant CORE = 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f;\n    SqueekPredict internal predict;\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n    address internal griefer = makeAddr(\"griefer\");\n\n    function setUp() public {\n        vm.chainId(11_155_111);\n        vm.warp(1_700_000_000 + 100 * 600);\n        vm.etch(CORE, address(new CoreStub()).code);\n        predict = new SqueekPredict();\n        vm.deal(alice, 100 ether);\n        vm.deal(bob, 100 ether);\n        vm.deal(griefer, 100 ether);\n    }\n\n    function test_OppositeSideCanStillEnterAfterOneSideIsFilled() public {\n        uint256 id = predict.createMarket(10, 107, 1 days);\n        vm.prank(alice);\n        predict.bet{value: 40 ether}(id, true);\n\n        // Griefer tops the single shared cap up on the same side as the existing stake.\n        vm.prank(griefer);\n        predict.bet{value: 60 ether}(id, true);\n\n        // Expected: a NO bettor can still take the other side of a market that has only YES stakes.\n        // Actual on current code: PoolLimit, because YES alone consumed the whole shared cap.\n        vm.prank(bob);\n        predict.bet{value: 0.0001 ether}(id, false);\n\n        SqueekPredict.Market memory m = predict.getMarket(id);\n        assertGt(m.noPool, 0, \"NO side was locked out of the market\");\n    }\n}","reproduction":"createMarket(10,107,1 days). alice bet{40 ether}(id,true); griefer bet{60 ether}(id,true) -> yesPool=100e18, noPool=0. bob bet{0.0001 ether}(id,false): expected accepted, actual revert PoolLimit() at line 145 (0.0001e18 > 100e18-100e18-0). warp(startsAt); cancelUnmatched(id) succeeds; griefer claim(id,griefer) returns 60 ether. Proof run with forge test --match-path: [FAIL: PoolLimit()] test_OppositeSideCanStillEnterAfterOneSideIsFilled.","severity":"low","snippet":"        if (msg.value > MAX_POOL - m.yesPool - m.noPool) revert PoolLimit();","title":"Single 100 ETH cap shared by both sides lets one side fill it, locking the other side out and forcing a risk-free refund"}],"hash":"42e35bc8b7b91973a6feb9e117e357dea63ed9c3a534cf5bf81cb19e875bec1f","nodeId":"8fe43b03-6d24-4949-b6d4-2350cfaa2c2b","outcome":"completed","summary":"The review is finished and `.imd-findings.json` holds 2 findings and 8 coverage rows. The 6 specialist findings reduce to 2 root causes, and both reproduce on the current code.\n\n**1. Medium: 3-day resolution grace is shorter than the live Core outage** (`src/SqueekPredict.sol:163`, constant at line 18)\n- **What happens:** `resolve()` stops working at `refundAt = endsAt + 3 days`. After that, anyone can call `cancelExpired()`, which refunds everyone and can't be undone, even if SqueekCore later certifies the result.\n- **Live check:** I read SqueekCore on Sepolia myself at block 12025908. It is settled only through round 1973, while the clock is at round 2510. That is about 3.73 days behind, longer than the 3-day grace.\n- **Impact:** markets whose window ends during an outage like this are refunded. Winners lose their payout and losers get their stake back. No funds are lost, but the brief's \"resolve from official data\" guarantee breaks.\n- **Proof:** the math specialist's test fails with `ResolutionExpired()` as described, so it is attached to this finding.\n- **Merged:** this one cause was reported by all four specialists (economics, flow, permissions, math).\n- **Suggested fix:** a longer grace (14–30 days), or let `resolve()` still run until someone actually calls `cancelExpired`.\n\n**2. Low: one 100 ETH cap shared by both sides** (`src/SqueekPredict.sol:145`)\n- **What happens:** while one side is still empty, bettors on the other side can fill the whole 100 ETH cap. After that, even a 0.0001 ETH bet on the empty side reverts with `PoolLimit`.\n- **Impact:** the market can only be refunded, and whoever filled the cap gets everything back. It is low because no funds are lost and it takes a large amount of locked capital.\n- **Proof:** the economics specialist's test fails with `PoolLimit()` as described, so it is attached to this finding.\n- **Merged:** reported by both economics and permissions.\n- **Suggested fix:** a cap per side, or always leave room for the minimum bet on an empty side.\n\n**Coverage and leads I dropped:**\n- All 6 entry points are answered: `bet` has finding 2, `resolve` and `cancelExpired` have finding 1, and `cancelUnmatched`, `claim` and `createMarket` hold.\n- The live point query `roundPage(1900,1900,0)` returns exactly what the contract's endpoint check expects.\n- Aderyn's \"reentrancy\" lead in `createMarket` doesn't apply: the external calls there only read a fixed Core address.\n- Slither's timestamp warnings are by design; the market is time-based.\n- The contract deploys within size limits (8,768 B runtime, 8,796 B initcode), and `launch.json` uses only schema keys.\n- The project's own 63 tests all pass.\n\nI changed no tracked files. My scratch copies of the proofs are removed. Untracked dotfiles (`.bashrc`, `.claude/` and others) are in the working directory; I didn't create them and left them alone.","treeHash":null,"usage":{"cachedInputTokens":462624,"inputTokens":19,"model":"claude-opus-5-5","outputTokens":10739,"runtime":"claude","turns":12,"wallClockMs":194253}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e06554fd2816f9d7","findings":[{"citation":"resolved","description":"Flow-gap seam (periphery x first principles). resolve() requires CORE.state().settledThroughRound >= m.endRound (line 169) and is permanently disabled once block.timestamp >= m.refundAt (line 163), where refundAt = endsAt + RESOLUTION_GRACE = endsAt + 3 days (lines 18, 121). From refundAt on, cancelExpired() (line 203) turns the market into a full refund with no Core check, and the Cancelled status can never be reverted (line 282). The contract therefore assumes the official Reporter certifies a round within 3 days of its end. The live dependency does not meet that assumption. Reading the real SqueekCore proxy 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f on Sepolia (verified source fetched from Sourcify, implementation 0x0a71C86ab63a77675002A389FDF4D096A07b11e2) at block 12025832 (timestamp 1793353152): genesisTimestamp = 1791847800, so wall-clock round = floor((1793353152-1791847800)/600) = 2508, but state().settledThroughRound = 1973 and paused = false. The last BatchSettled event is at block 11999145 (timestamp 1793031636): the Reporter has been stalled for 321516 s (3.72 days) and counting, with no Paused/Unpaused event. Daily samples via archive RPC show settled = 1973 at timestamps 1793093376, 1793179860, 1793266392 and 1793353152, and an earlier 131-round (~22 h) lag at timestamp 1792656204. Because the stall exceeds RESOLUTION_GRACE, every market whose endRound is between 1974 and 2000 has already passed refundAt with the window never certifiable, and any market created today will meet the same fate if the stall continues 3 more days. Consequence: the product's defining guarantee ('Resolution based on the official settled work from SqueekCore') is silently replaced by refunds; a winner whose outcome is already visible in the partially certified ledger receives only their stake back, and the losing side can be the one to call cancelExpired. No unprivileged actor can cause this (it depends on Reporter inactivity, a documented trust assumption), which is why this is reported as a design-parameter defect rather than an exploit; the README's statement that refunds happen 'even if data was available' describes the behaviour but the parameter was chosen without checking the dependency's actual cadence, and neither createMarket nor the frontend warn when the frontier already lags. Suggested minimal fixes that keep the agreed design: (a) raise RESOLUTION_GRACE substantially (e.g. 14-30 days) or make it a per-market creator parameter with a sane minimum; and/or (b) in cancelExpired, allow the refund only when the data is genuinely unavailable (try CORE.state(); if the call succeeds and settledThroughRound >= m.endRound, revert so that resolve() must be used instead), keeping the Core-independent refund path for outages while preventing a refund from overriding an available certified result; (c) optionally have createMarket reject or the UI warn when settledThroughRound is already far behind the current round.","line":163,"path":"src/SqueekPredict.sol","reproduction":"State copied from live Sepolia (genesis 1791847800, frontier 1973). 1) At timestamp genesis+1850*600 call createMarket(10, 1857, 1 days): endRound = 2000, endsAt = 1793047800, refundAt = 1793307000. 2) alice bet(id,true){1 ether}; bob bet(id,false){1 ether}. 3) Reporter settles through round 1973 only, with ledger after round 1856 = 100e9 units and after 1973 = 150e9 units (50 blocks already completed inside the window, so YES is certain). 4) At endsAt and at refundAt-1, resolve(id) reverts NotSettled (settledThroughRound 1973 < 2000). 5) At refundAt bob calls cancelExpired(id): status = Cancelled, claimable(alice) = 1 ether, claimable(bob) = 1 ether. 6) Reporter later certifies round 2000 (frontier 2010): resolve(id) now reverts MarketFinalized forever. Expected: a market whose window Core certifies is resolved from that data and alice receives 2 ether. Actual: alice receives 1 ether, bob keeps his stake. Verified with a Foundry test under test/scratch (Core mock reproducing the verified roundPage(r,r,0) semantics) and with the cast reads quoted in the description.","severity":"medium","snippet":"        if (block.timestamp >= m.refundAt) revert ResolutionExpired();","title":"Fixed 3-day resolution grace is shorter than the live Reporter's observed settlement stalls, so markets refund instead of resolving even when the outcome is certified later"}],"hash":"5b9220390166d83aeecce24c9ce1ccaf363c7ca2e9feaae0ec189aa026cb934c","nodeId":"83f1a49f-ebdf-45aa-ac64-090d26ab856a","outcome":"completed","summary":"Review complete. The findings file is written and the tree is otherwise untouched.\n\n**Outcome: one medium finding, no exploitable defect in the control-flow area.**\n\nThe contract's execution paths are sound. I verified the one external boundary that matters against the real dependency: I pulled the verified SqueekCore V3 source from Sourcify and called the live Sepolia proxy. Round numbering (rounds from 1, round r starts at genesis + (r-1)·600), the `roundPage(r, r, 0)` point semantics (certifiedThroughRound equals r, empty record list, identical start/end positions), the out-of-frontier revert, and the implementation pinning all match what `SqueekPredict` assumes. Claim accounting, the last-winner remainder rule, the reentrancy guard, and the refund/resolution boundary behave as documented. Both static-analysis leads were rejected: the aderyn \"reentrancy\" is a sequence of view calls to a fixed address, and the timestamp uses are the intended deadlines.\n\n**The finding (medium, periphery × first principles):** the 3-day resolution grace is shorter than the live Reporter's actual settlement behaviour. On Sepolia right now the Reporter has not settled since block 11999145, a stall of about 3.7 days with Core unpaused, and the frontier sits at round 1973 while wall-clock time is at round 2508. Any market whose window ends during such a stall can never be resolved: `resolve` reverts with NotSettled until `refundAt`, then is disabled forever, and `cancelExpired` refunds without checking whether data exists. A winner whose outcome is already visible in the partially certified ledger gets only their stake back, and the losing side can be the one to trigger it. I reproduced the full sequence with a Foundry test using the live genesis and frontier values. No unprivileged actor can cause it, so I flagged it as a design-parameter defect, with fixes that preserve the design: a longer or creator-chosen grace, and letting `cancelExpired` refund only when Core cannot certify the window.\n\n**Coverage:** all six entry points have rows (four hold, `resolve` and `cancelExpired` reference the finding), plus rows for the ABI/semantics check, payout conservation, the frontend helpers, and the static-analysis leads. Nothing in the assigned area was left unreached. The existing 38 Forge tests and 5 Node tests pass.","treeHash":null,"usage":{"cachedInputTokens":1299200,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":34728,"runtime":"claude","turns":43,"wallClockMs":521331}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0ef0cddb99617930","findings":[],"hash":"61dc9178c0e1d47ab16c7961d0f87ad893a12b9b65b501e1e36c483f0f318d30","nodeId":"8fe43b03-6d24-4949-b6d4-2350cfaa2c2b","outcome":"completed","summary":"Both earlier findings are fixed and I found nothing new. The review is recorded in `.imd-findings.json` with an empty findings list and all six entry points marked as holding.\n\n**Medium, resolution grace shorter than the live Reporter outage.** Fixed. The grace constant in `src/SqueekPredict.sol:21` is now 30 days, and the uint64 overflow guard on the refund deadline is kept. My attached proof and the math specialist's proof, copied under test/scratch and run with forge, both pass on the revised code. The scenario they replay is the observed outage: the frontier stays one round short through the window end, a refund attempt at three days and seventeen hours is rejected as too early, and resolution succeeds once Core certifies the round, paying the winner the full pool. The author's choice to keep resolution exclusive before the refund deadline is sound, since an overlap would let a losing side front-run a late resolution with a refund. The 30-day lock for a market Core never certifies is documented in the README, the security review and the frontend text.\n\n**Low, shared pool cap letting one side lock the other out.** Fixed. The cap is now per side at `src/SqueekPredict.sol:150`, so a filled YES pool still accepts NO stakes. The subtraction cannot underflow because each pool only grows through that check, and the worst-case payout product stays far below the uint256 limit. The economics specialist's proof passes. The permissions specialist's proof no longer compiles because it reads the removed shared-cap getter, but it covers the same root cause and the author's new test exercises its exact scenario.\n\n**Static-analysis leads.** Neither reproduces. The aderyn reentrancy line points at view calls to a constant Core address, which compile to static calls and cannot reenter. The slither timestamp lines are round-boundary comparisons whose outcome is read from certified Core history, not from the clock.\n\n**Test runs.** The project suite passed 70 of 70 including the invariant campaign, the three compiling proofs passed, and the frontend node test passed 5 of 5 with the packaged ABI matching the compiled contract. I deleted my scratch copies, so the tree has no changes beyond the findings file.","treeHash":null,"usage":{"cachedInputTokens":270237,"inputTokens":162,"model":"claude-fable-5-1","outputTokens":6777,"runtime":"claude","turns":13,"wallClockMs":159224}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"918f8261a6fd589c","findings":[{"citation":"resolved","description":"resolve() only accepts a result while endsAt <= block.timestamp < refundAt, and refundAt = endsAt + RESOLUTION_GRACE (src/SqueekPredict.sol:18 `uint64 public constant RESOLUTION_GRACE = 3 days;`, :121). Resolution also needs CORE.state().settledThroughRound >= endRound (:169). The window therefore assumes the Squeekchain Reporter certifies a round within 3 days of its wall-clock end. The live SqueekCore proxy on Sepolia (0x74665dAecA35A2303e767E76a2FF1FB6F93e119f) does not meet that: read at block 12025823 (timestamp 1793353044), state().settledThroughRound = 1973 while the current round is floor((1793353044-1791847800)/600)+1 = 2509, a lag of 536 rounds = 3.72 days. Daily archive samples show the frontier tracked the clock within 1-4 rounds from 2026-10-16 to 2026-10-25 (e.g. block 11997023: round 1931 current, 1930 settled), then stopped: the last SqueekCore event is in block 11999145 (timestamp 1793031636) and blocks 12004223, 12011423, 12018623 and 12025823 all return settledThroughRound = 1973. An earlier 38-round (6.3 h) stall is visible at block 11946623. The Squeekchain docs state there is 'no guaranteed uptime or catch-up deadline' for settlement. Boundary x invariant seam: the guard at :163 is a pure time boundary, while the data dependency at :169 is a separate boundary driven by the oracle's cadence; whenever the oracle crosses the 3-day boundary later than the market does, the invariant 'a two-sided market with certified history pays winners' is replaced by a full refund, and after refundAt the certified result is rejected forever even though the market is still Open and nobody has called cancelExpired. Concretely, on the live chain any market whose endRound is 1974 (endsAt 1793032200, refundAt 1793291400 < now) or later-up-to-current can no longer resolve once round 1974 is certified; its bettors are refunded and the winning side loses its payout. Impact: the product's core guarantee (official-data resolution) silently degrades to refund under a condition that is currently live, with no funds lost. Suggested minimal fix that preserves the design: lengthen RESOLUTION_GRACE substantially (the observed outage already exceeds 3.7 days; 14-30 days would still bound exposure via MAX_POOL), or let the creator choose a grace within [3 days, 30 days] at createMarket, and surface the chosen refundAt in the UI. Keeping resolution disabled after refundAt (avoiding the resolve/cancelExpired race) is fine once the window is realistic. The README's statement that refunds happen 'if nobody submits resolution' should also say the oracle itself can cause this.","line":163,"path":"src/SqueekPredict.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SqueekPredict} from \"src/SqueekPredict.sol\";\nimport {ISqueekCore} from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal V3 fixture: a settable certified frontier and per-round ledger points.\ncontract StalledCore is ISqueekCore {\n    CoreConfiguration private _config;\n    uint64 public frontier;\n    mapping(uint64 => LedgerPosition) private _points;\n\n    function configure(uint64 genesis) external {\n        _config.genesisTimestamp = genesis;\n        _config.roundDuration = 600;\n        _config.blockUnitsPerBlock = 1_000_000_000;\n        _config.streamId = keccak256(\"stalled fixture\");\n    }\n\n    function setFrontier(uint64 round) external {\n        frontier = round;\n    }\n\n    function setPoint(uint64 round, uint96 units) external {\n        _points[round] = LedgerPosition(uint64(units / 1e9), units, 10_875);\n    }\n\n    function state() external view returns (CoreState memory result) {\n        result.settledThroughRound = frontier;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _config;\n    }\n\n    function roundPage(uint64 afterRound, uint64 throughRound, uint256) external view returns (RoundPage memory result) {\n        require(afterRound == throughRound && throughRound <= frontier, \"InvalidRoundPageBounds\");\n        result.certifiedThroughRound = throughRound;\n        result.start = _points[throughRound];\n        result.end = _points[throughRound];\n    }\n\n    function implementationCodeVersion() external pure returns (uint64) {\n        return 3;\n    }\n\n    function implementationCodeAddress() external view returns (address) {\n        return address(this);\n    }\n}\n\n/// @notice Live SqueekCore (Sepolia, read 2026-10-30 at block 12025823) certified round 1973 at\n///         timestamp 1793031636 and nothing since: 3.72 days. A market whose last round is 1974\n///         can never resolve, because RESOLUTION_GRACE (3 days) elapses before the frontier reaches\n///         endRound and resolve() then rejects the certified result. This test replays that outage\n///         length. It fails on the current code (ResolutionExpired) and passes once the resolution\n///         window outlasts an outage of this length.\ncontract ResolutionGraceTest is Test {\n    uint64 internal constant GENESIS = 1_700_000_000;\n    address internal constant CORE = 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f;\n    SqueekPredict internal predict;\n    StalledCore internal core;\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.chainId(11_155_111);\n        vm.warp(GENESIS + 100 * 600);\n        StalledCore template = new StalledCore();\n        vm.etch(CORE, address(template).code);\n        core = StalledCore(CORE);\n        core.configure(GENESIS);\n        core.setFrontier(100);\n        predict = new SqueekPredict();\n        vm.deal(alice, 10 ether);\n        vm.deal(bob, 10 ether);\n    }\n\n    function test_MarketResolvesOnceCertifiedAfterObservedReporterOutage() public {\n        uint256 id = predict.createMarket(0, 107, 1 days);\n        SqueekPredict.Market memory m = predict.getMarket(id);\n        vm.prank(alice);\n        predict.bet{value: 2 ether}(id, true);\n        vm.prank(bob);\n        predict.bet{value: 3 ether}(id, false);\n\n        // Reporter stalls one round short of the market's last round (frontier 249 < endRound 250).\n        core.setPoint(m.startRound - 1, 100e9);\n        core.setFrontier(m.endRound - 1);\n        vm.warp(m.endsAt);\n        vm.expectRevert(SqueekPredict.NotSettled.selector);\n        predict.resolve(id);\n\n        // Observed live outage length: 3 days 17 hours after the round ended, Core certifies it\n        // (one block completed inside the window).\n        vm.warp(m.endsAt + 3 days + 17 hours);\n        core.setPoint(m.endRound, 101e9);\n        core.setFrontier(m.endRound);\n\n        // The result is certified and the market is still Open, so it should resolve.\n        predict.resolve(id);\n        m = predict.getMarket(id);\n        assertEq(uint256(m.status), uint256(SqueekPredict.Status.Resolved), \"resolved from certified data\");\n        assertTrue(m.yesWins, \"one completed block > threshold 0\");\n        assertEq(predict.claimable(id, alice), 5 ether, \"winner is paid the pool, not refunded\");\n        assertEq(predict.claimable(id, bob), 0, \"loser is not refunded\");\n    }\n}","reproduction":"State: Sepolia, SqueekCore V3 reachable, genesis g. Steps (reproduced with the Foundry proof using a V3 fixture): 1) createMarket(0, 107, 86400) -> endRound 250, endsAt = g + 250*600, refundAt = endsAt + 259200. 2) alice bet(id,true) 2 ETH; bob bet(id,false) 3 ETH. 3) Core settledThroughRound stays at 249 (one round short), as it did live from 2026-10-26 (round 1973) on. 4) warp to endsAt: resolve(id) reverts NotSettled (expected). 5) warp to endsAt + 3 days + 17 hours (the live outage length) and Core certifies round 250 with cumulativeBlockUnits 101e9 vs 100e9 at round 106 (1 completed block > threshold 0). 6) resolve(id). Expected: market Resolved, yesWins = true, claimable(alice) = 5 ETH, claimable(bob) = 0. Actual: revert ResolutionExpired() at src/SqueekPredict.sol:163; the only remaining path is cancelExpired(id), after which claimable(alice) = 2 ETH and claimable(bob) = 3 ETH, i.e. the certified winner forfeits the 3 ETH it won. Live numbers: cast call 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f 'state()' at block 12025823 -> settledThroughRound 1973; block timestamp 1793353044; genesisTimestamp 1791847800; last Core log at block 11999145 (timestamp 1793031636).","severity":"medium","snippet":"        if (block.timestamp >= m.refundAt) revert ResolutionExpired();","title":"Fixed 3-day resolution grace is shorter than the live oracle's observed settlement outage, so funded markets are refunded instead of resolved"}],"hash":"6eb0edceb2ec8699b85c37da42dbe208fbc69ad6cc25072db5f6affd59bba997","nodeId":"32eb9afc-afff-4998-bffa-c3df1ffc0898","outcome":"completed","summary":"Review complete. The findings file is written and the working tree has no tracked changes.\n\n**Outcome.** One substantiated finding, medium severity. The arithmetic in the contract is sound. The defect is a boundary assumption about the oracle.\n\n**Finding 1 (medium), `src/SqueekPredict.sol:163`.** Resolution is only accepted while the clock is inside a fixed 3-day window after the market ends. The live SqueekCore on Sepolia does not certify rounds that fast right now. I read it at block 12025823: the settled frontier is round 1973 while the current round is 2509, a stall of 3.72 days. Archive samples show settlement tracked the clock within one to four rounds from 2026-10-16 to 2026-10-25, then stopped after the last Core event on 2026-10-26. So any market ending at round 1974 or later can never resolve once the data arrives. The winning side is refunded its stake instead of paid, with no funds lost. The proof test under test/scratch replays that outage length, fails on the current code with ResolutionExpired, and passes in a scratch copy with a 14-day grace. Suggested fix: lengthen the grace or let the creator pick one within bounds.\n\n**What held.** Round-to-timestamp math matches the documented numbering, every uint64 narrowing is bounds-checked, the block-count formula matches the Squeekchain docs, pool-cap and stake arithmetic cannot underflow, payouts never round to zero and conserve the pool with the final winner taking the remainder. I also confirmed live that the ABI decodes and that point reads via roundPage behave exactly as the contract assumes. The slither timestamp leads are the intended deadline design and the aderyn reentrancy lead is a false positive on view calls.\n\n**Coverage.** All six entry points have rows, five hold and resolve carries the finding, plus three invariant rows. Nothing in my area was left unreached. The frontend was only spot-checked for its round suggestion math, which is correct.","treeHash":null,"usage":{"cachedInputTokens":1096329,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":31514,"runtime":"claude","turns":37,"wallClockMs":490436}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"33bef35e96ccb653","findings":[{"citation":"resolved","description":"MAX_POOL is one cap shared by yesPool and noPool (Pashov Economic Security: 'starve shared capacity'). Whoever brings the combined pool to exactly 100 ETH on one side makes every later bet on the other side revert with PoolLimit, including the 0.0001 ETH minimum. If nobody has yet taken the other side the market is now permanently one-sided: at startsAt anyone calls cancelUnmatched (or resolve later cancels it) and every stake is refunded. The actor who filled the cap gets its full stake back, so the cost of voiding any market before its betting window ends is gas plus a temporary lock of at most 100 Sepolia ETH. Honest bettors who already staked are forced into a refund instead of the market they entered; the opposite side is denied entry at any price. The same lever lets a late bettor who already holds the larger side cap the counterparty's size, so no fund loss, but the market's stated purpose (a two-sided question) can be defeated unilaterally. The project's own test only covers the cap being reached across both sides. Minimal fix preserving the design: bound each side separately (MAX_POOL per side, or require yesPool <= MAX_POOL and noPool <= MAX_POOL), or always reserve room for the empty side while it is empty.","line":145,"path":"src/SqueekPredict.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SqueekPredict} from \"src/SqueekPredict.sol\";\nimport {ISqueekCore} from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal V3 Core stand-in so createMarket's configuration checks pass. Reads only.\ncontract CoreStub is ISqueekCore {\n    uint64 public frontier;\n\n    function configuration() external pure returns (CoreConfiguration memory c) {\n        c.streamId = keccak256(\"stub\");\n        c.genesisTimestamp = 1_700_000_000;\n        c.roundDuration = 600;\n        c.blockUnitsPerBlock = 1_000_000_000;\n    }\n\n    function state() external view returns (CoreState memory s) {\n        s.settledThroughRound = frontier;\n    }\n\n    function roundPage(uint64 afterRound, uint64, uint256) external pure returns (RoundPage memory r) {\n        r.certifiedThroughRound = afterRound;\n    }\n\n    function implementationCodeVersion() external pure returns (uint64) {\n        return 3;\n    }\n\n    function implementationCodeAddress() external view returns (address) {\n        return address(this);\n    }\n}\n\n/// @notice One actor fills the shared 100 ETH pool cap on a single side; the opposite side can no longer\n/// place even the minimum stake, so the market can only ever be refunded. The griefer loses nothing:\n/// cancelUnmatched at startsAt returns its full 60 ETH.\ncontract PoolCapGriefingTest is Test {\n    address internal constant CORE = 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f;\n    SqueekPredict internal predict;\n    address internal alice = makeAddr(\"alice\");\n    address internal bob = makeAddr(\"bob\");\n    address internal griefer = makeAddr(\"griefer\");\n\n    function setUp() public {\n        vm.chainId(11_155_111);\n        vm.warp(1_700_000_000 + 100 * 600);\n        vm.etch(CORE, address(new CoreStub()).code);\n        predict = new SqueekPredict();\n        vm.deal(alice, 100 ether);\n        vm.deal(bob, 100 ether);\n        vm.deal(griefer, 100 ether);\n    }\n\n    function test_OppositeSideCanStillEnterAfterOneSideIsFilled() public {\n        uint256 id = predict.createMarket(10, 107, 1 days);\n        vm.prank(alice);\n        predict.bet{value: 40 ether}(id, true);\n\n        // Griefer tops the single shared cap up on the same side as the existing stake.\n        vm.prank(griefer);\n        predict.bet{value: 60 ether}(id, true);\n\n        // Expected: a NO bettor can still take the other side of a market that has only YES stakes.\n        // Actual on current code: PoolLimit, because YES alone consumed the whole shared cap.\n        vm.prank(bob);\n        predict.bet{value: 0.0001 ether}(id, false);\n\n        SqueekPredict.Market memory m = predict.getMarket(id);\n        assertGt(m.noPool, 0, \"NO side was locked out of the market\");\n    }\n}","reproduction":"State: Sepolia, open market id=1 (createMarket(10, 107, 1 days)). 1) alice: bet{value: 40 ether}(1, true). 2) griefer: bet{value: 60 ether}(1, true) -> yesPool = 100 ether, noPool = 0. 3) bob: bet{value: 0.0001 ether}(1, false). Expected: NO side can enter a market that has only YES stakes. Actual: revert PoolLimit() at line 145 because 0.0001e18 > 100e18 - 100e18 - 0. 4) warp to startsAt; cancelUnmatched(1) succeeds (noPool == 0). 5) griefer: claim(1, griefer) returns 60 ether; griefer's balance is unchanged from before step 2. Test: test/scratch/PoolCapGriefing.t.sol fails on current code with PoolLimit().","severity":"low","snippet":"        if (msg.value > MAX_POOL - m.yesPool - m.noPool) revert PoolLimit();","title":"Single shared 100 ETH pool cap lets one side lock the other side out and void any market at zero cost"},{"citation":"resolved","description":"resolve() needs settledThroughRound >= endRound (line 169) and is disabled once block.timestamp >= refundAt = endsAt + 3 days (line 163); after that cancelExpired() refunds everyone. The guarantee the brief asks for ('resolution based on the official settled block count') therefore depends on the Reporter certifying the window's last round within 3 days of its end. Live SqueekCore on Sepolia (0x74665dAecA35A2303e767E76a2FF1FB6F93e119f, read through https://ethereum-sepolia-rpc.publicnode.com at block 12025829, timestamp 1793353116 = 2026-10-30 09:38 UTC) reports settledThroughRound = 1973, whose round ends at genesis 1791847800 + 1973*600 = 1793031600 = 2026-10-26 16:20 UTC. The frontier was unchanged at every sampled block over the previous 24 h (blocks 12018629 to 12025829, authorizationNonce 1657 throughout) and no Core event was emitted in the last 10,000 blocks; Etherscan shows the Reporter relayer posting every 10-20 minutes until 2026-10-26 16:20:36 UTC and nothing since. The stall is 3.7 days and counting, longer than RESOLUTION_GRACE. Consequence: every daily market with endsAt between 2026-10-26 16:20 and now (any created 2026-10-24 to 2026-10-25) is unresolvable for its whole grace period and must be refunded, even though the window's activity will later be certified and the losing side knows the outcome off-chain. The refund fallback itself is correct and documented; the defect is the parameter choice: a grace period calibrated to a normal 10-20 minute cadence makes a realised multi-day outage convert decided markets into refunds, which removes the payout a winner was promised and hands the loser a free exit. Minimal fix preserving the design: lengthen RESOLUTION_GRACE (for example 14 days), or allow resolve() after refundAt until someone has actually called cancelExpired() (first-come between the two), so a certified outcome can still settle when the Reporter catches up.","line":18,"path":"src/SqueekPredict.sol","reproduction":"Mock reproduction (test/scratch/OracleStall.t.sol, passes on current code and demonstrates the path): market createMarket(10, 107, 1 days) covers rounds 107..250, 1 ETH YES and 1 ETH NO. Core frontier sits at 249 from endsAt until refundAt - 1: resolve(1) reverts NotSettled at both times. At refundAt the frontier moves to 260 with 50 blocks certified for the window (YES is the true outcome): resolve(1) reverts ResolutionExpired; the NO bettor calls cancelExpired(1); claimable is 1 ETH for each side. Expected: YES bettor receives 2 ETH once the data exists. Actual: both receive their stake back. Live state satisfying the precondition today: settledThroughRound 1973 (round end 1793031600) vs current round 2509 at timestamp 1793353116, a gap of 321,516 s > 259,200 s = RESOLUTION_GRACE.","severity":"low","snippet":"    uint64 public constant RESOLUTION_GRACE = 3 days;","title":"3-day resolution grace is shorter than the Reporter stall observed live, so markets whose window ended during the stall refund instead of resolving"}],"hash":"784c18d068c7531fe2af0d3a14ada7f5c422193e41e4bf5ae0adee60fdb2782f","nodeId":"35b76116-3e88-412d-ac4f-c5fef9b3dcc0","outcome":"completed","summary":"Review complete. The findings file is written and both snippets match the tree. Git status shows nothing tracked changed; only the findings file and my scratch tests exist outside the tree.\n\n**Outcome.** The economics of `SqueekPredict` hold up well. Fund conservation, pari-mutuel payout math, refund backing, and reentrancy ordering all check out, and the project's 38 tests plus its invariant suite pass. I found two low-severity defects, both substantiated, and no loss-of-funds path.\n\n**Findings written to `.imd-findings.json`:**\n\n1. **Shared pool cap lets one side void any market at zero cost (low).** The 100 ETH cap is shared across YES and NO. Filling it on one side makes every opposite-side bet revert, the market becomes permanently one-sided, and the filler is refunded in full at `startsAt`. The proof test in `test/scratch/PoolCapGriefing.t.sol` fails on current code with `PoolLimit()`.\n\n2. **Three-day resolution grace is shorter than the live Reporter stall (low).** Live SqueekCore on Sepolia has sat at settled round 1973 since 2026-10-26 16:20 UTC, a gap of over 3.7 days with no Core events in the last 10,000 blocks. Any daily market whose window ended in that span cannot resolve before `refundAt` and must refund, even though the outcome will later be certified. The mock reproduction in `test/scratch/OracleStall.t.sol` walks the path. The refund fallback is correct and documented; the issue is the parameter.\n\n**Coverage.** All six entry points have rows: `bet` and `cancelExpired`/`resolve` point at the findings above, `createMarket`, `cancelUnmatched`, and `claim` hold. I verified the Core integration against the live contract: round boundaries, point-read semantics (`certifiedThroughRound == r`, `start == end`, revert for uncertified rounds), and the units scale all match the contract's assumptions. Static-analysis leads were checked and rejected: the timestamp comparisons are intended deadlines, and the aderyn reentrancy lead in `createMarket` is unreachable because every Core call is a `staticcall`.\n\n**Not reached.** Whether Core can rewrite certified history while paused could not be verified because the published ABI and docs returned 403, so resolving-while-paused is noted in coverage but not reported.","treeHash":null,"usage":{"cachedInputTokens":1293799,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":36979,"runtime":"claude","turns":40,"wallClockMs":649396}},{"artifacts":[],"attempt":1,"bundleHash":"155df65537b6a1bf16710f21b3de508cd731ec95b3ced09aac8c18e69caf8c00","device":"1d142f9c9d30c62a","findings":[],"hash":"9c868c47cec4281b1c3b65f5c00417a9ee0fe012a7601e829406a8c2951963ac","nodeId":"180e6b4a-86b5-49c1-94dc-7d6a24b0b8ec","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/254f03ee-e7c5-4651-a3de-996ae711121a/180e6b4a-86b5-49c1-94dc-7d6a24b0b8ec/launch.json) listing `SqueekPredict` with no constructor arguments and explanatory notes.\n\nManifest structure and compiled ABI checks passed. Offline `forge build` succeeded; `forge test` passed all 38 tests using the required fuzz seed.\n\nOnly `launch.json` is changed for submission.","treeHash":"b7551edf3f7a02921e72b8c3be67a76c4b7b3c3c","usage":{"cachedInputTokens":211328,"inputTokens":67584,"model":"gpt-6-astra","outputTokens":3840,"runtime":"codex","turns":4,"wallClockMs":157656}},{"artifacts":[],"attempt":1,"bundleHash":"fe525cdb048665798d7de2a5863f7886eafeee98ccbba96c2e235d17488a242e","device":"9e51ef2afd7c2af8","findings":[],"hash":"ae81ced700f69eee64c3574690b7c111dfbc7f57d54ffbb7f74391940ae850af","nodeId":"180e6b4a-86b5-49c1-94dc-7d6a24b0b8ec","outcome":"completed","summary":"Done. Only launch.json changed.\n\n**What I found.** The accepted source still has a single contract, SqueekPredict, with no constructor and no owner, so the manifest's contract list and empty constructorArgs were already correct. The latest build-side commit changed two constants the old notes described: the resolution grace is now 30 days instead of 3, and the 100 ETH cap is now per side rather than per market.\n\n**What I did.** I rewrote the notes paragraph to describe the accepted implementation: the per-side cap, the 30-day grace and why it was lengthened, and that expiry refunds open only after the grace passes. The kind, contract name and constructor arguments are unchanged.\n\n**Checks run:**\n\n- Manifest shape: exactly the keys kind, contracts and notes, one unique identifier under 32 characters, string arguments, notes at 1533 of 4000 characters.\n- `forge build` succeeds.\n- `forge test` with the verifier's fuzz seed: 42 tests passed, 0 failed, including the invariant suite.\n- `git status` shows launch.json as the only modified file.\n\nThe protected tests rehearse constructor deployment and check that no application is owned by the factory or IMD. SqueekPredict has no owner at all, so both pass by construction.","treeHash":"8f1578eb5dc1b4fe262eafabfd4d1eb6df6330e5","usage":{"cachedInputTokens":268108,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":3401,"runtime":"claude","turns":10,"wallClockMs":51399}},{"artifacts":[],"attempt":1,"bundleHash":"96eedfc63024e2bbdc8b93dc9f58cf39137d88ba0481b0e9a3a269939b210295","device":"782f24113d209be2","findings":[],"hash":"ae8724ea3aab7136089ee4e1db893f52301f824e4161c429308031f8fd7979e7","nodeId":"eca02a39-c021-4264-9d07-98ccf5d27091","outcome":"completed","summary":"Both findings reproduced and are fixed. The reviewer's proof now passes, the full suite passes with the pinned fuzz seed, and `forge build`, `forge fmt --check` and the node frontend tests are clean.\n\n**Finding 1, resolution grace (medium): fixed.** The proof failed on the starting tree with `ResolutionExpired`, and a fresh read of SqueekCore on Sepolia confirmed the precondition: the certified frontier is still round 1973 while the wall-clock round is 2510, so the Reporter is about 3.7 days behind and the outage is ongoing. `RESOLUTION_GRACE` is now 30 days. I kept resolution exclusive before `refundAt` instead of letting it overlap with `cancelExpired`, because an overlap would let a losing side front-run a late resolution with a cancellation. Two regression tests were added: one replays the 3-day-17-hour outage and shows the market resolving from the late certification with the winner paid, and one shows resolution still works 29 days in while refunds stay rejected.\n\n**Finding 2, shared pool cap (low): judged real and fixed.** The cap is now per side via `MAX_SIDE_POOL`, so a filled YES pool still accepts NO stakes and a griefer can no longer force a risk-free refund through `cancelUnmatched`. A test fills YES with 100 ETH, enters NO with the minimum stake, and shows the cancel rejected and the filler losing on resolution. The invariant handler, frontend pre-check and regenerated `frontend/abi.json` follow the new cap.\n\n**Documentation.** The README, frontend copy and security review now state the 30-day grace, why it was lengthened, its trade-off (an uncertified market holds stakes for up to 30 days after its window), and the per-side cap with its 200 ETH per-market maximum.\n\nChanged files:\n- `src/SqueekPredict.sol`: grace constant, per-side cap in `bet`, comments\n- `test/SqueekPredict.t.sol`, `test/SqueekPredict.invariant.t.sol`: updated assertions, four new tests\n- `frontend/app.js`, `frontend/index.html`, `frontend/abi.json`\n- `README.md`, `docs/SECURITY_REVIEW.md`\n- `.imd-responses.json`: both findings answered as fixed\n\nThe protected floor tests could not be run locally because they need the verifier's harness and environment variables. The constructor is unchanged, so this revision does not touch what they rehearse.","treeHash":"70c22e86245f689b1f5ab5ae14d30cddc98b66d4","usage":{"cachedInputTokens":908676,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":20167,"runtime":"claude","turns":40,"wallClockMs":266583}},{"artifacts":[],"attempt":1,"bundleHash":"8ccb82427527df435d8d2baa4090bf5f461875935b8a4307fad7c900df28092d","device":"8d210756eb9ac4d7","findings":[],"hash":"e94981930694d6c4153bdb68785cafc1897784ad9f0f141f2eb6a120649494ba","nodeId":"8963b742-63ff-4a68-a59d-5098134543bf","outcome":"completed","summary":"Added failure-path, fuzz, and stateful invariant tests, all under `test/`.\n\n- `forge build` passes.\n- `forge test` passes with the required seed: **63 passed, 0 failed, 0 skipped**.\n- New invariants exercised **32,768 random calls**.\n- No implementation defects were reproduced.","treeHash":"2a6393562368db66d15cb4e7c124702ab2af7a85","usage":{"cachedInputTokens":1956864,"inputTokens":85742,"model":"gpt-6-astra","outputTokens":27202,"runtime":"codex","turns":7,"wallClockMs":959843}}],"verification":[{"checks":[{"durationMs":2822,"exitCode":0,"name":"build","output":"Compiling 29 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.75s\nCompiler run successful!\n","passed":true},{"durationMs":34229,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 18 tests for test/SqueekPredict.boundaries.t.sol:SqueekPredictBoundariesTest\n[PASS] testFuzz_BlockCompletionCountsProgressCarry(uint64,uint64,uint32,uint32,bool) (runs: 1000, μ: 1380301, ~: 1380169)\nLogs:\n  Bound result 18446744073709551612\n  Bound result 1\n  Bound result 425397603\n  Bound result 10622123\n\n[PASS] testFuzz_EachSideIsCappedIndependentlyToTheWei(uint96,bool) (runs: 1000, μ: 576685, ~: 576795)\nLogs:\n  Bound result 99999800000003215004\n\n[PASS] testFuzz_EitherMalformedEndpointRollsBackAndCanBeRetried(bool,uint8) (runs: 1000, μ: 990706, ~: 994532)\nLogs:\n  Bound result 0\n\n[PASS] testFuzz_IncompatibleConfigurationAtResolutionStillAllowsFullRefund(uint8) (runs: 1000, μ: 1062016, ~: 1059976)\nLogs:\n  Bound result 2\n\n[PASS] testFuzz_InvalidIdsNeverAllocatePositionsOrAcceptValue(uint256) (runs: 1000, μ: 595454, ~: 595379)\nLogs:\n  Bound result 11000000000000000000\n\n[PASS] testFuzz_OnlyDailyAndWeeklyDurationsAreAccepted(uint64) (runs: 1000, μ: 37676, ~: 37668)\n[PASS] testFuzz_ResolutionAndTimeoutRefundNeverOverlapAcrossTheGrace(uint32) (runs: 1000, μ: 871907, ~: 871708)\nLogs:\n  Bound result 2080001\n\n[PASS] testFuzz_RoundAlignmentAndImmutableIdentity(uint32,bool,uint64) (runs: 1000, μ: 240633, ~: 240491)\nLogs:\n  Bound result 399593\n\n[PASS] testFuzz_TruncatedOracleReturnNeverFinalizes(uint8) (runs: 1000, μ: 908343, ~: 899143)\nLogs:\n  Bound result 4\n\n[PASS] test_CertifiedDataAtRefundAtCannotResolveOnlyRefund() (gas: 711253)\n[PASS] test_DecreasingWorkIsRejectedEvenWhenBlockUnitsIncrease() (gas: 732950)\n[PASS] test_EventsDescribeCreationBetResolutionAndActualPayment() (gas: 847129)\n[PASS] test_LeadTimeLimitsToTheSecond() (gas: 464790)\n[PASS] test_MaximumRepresentableBlockHeightAndThreshold() (gas: 1346066)\n[PASS] test_NoBlockCompletedAtThresholdZeroPaysNo() (gas: 798611)\n[PASS] test_OneWeiAndOversizedBetsRevertWithoutChangingAccounting() (gas: 569911)\n[PASS] test_ResolutionUsesBothExactPointsNotCurrentStateOrDifficulty() (gas: 949023)\n[PASS] test_TimeoutCancellationEmitsOnceAndRefundIgnoresCore() (gas: 611225)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 372.89ms (2.76s CPU time)\n\nRan 41 tests for test/SqueekPredict.t.sol:SqueekPredictTest\n[PASS] testFuzz_CompletePayoutConservesFundsAndRounding(uint96,uint96,uint96,bool,bool) (runs: 256, μ: 1094040, ~: 1084528)\nLogs:\n  Bound result 29999910000000000001\n  Bound result 29999900001000000001\n  Bound result 29999910000000000001\n\n[PASS] testFuzz_OfficialHeightDifference(uint64,uint32,uint64,uint64) (runs: 256, μ: 786148, ~: 785813)\nLogs:\n  Bound result 72\n  Bound result 73691104868\n  Bound result 172769742966080\n\n[PASS] testFuzz_TimeoutRefundsBothPositions(uint96,uint96) (runs: 256, μ: 623270, ~: 623503)\nLogs:\n  Bound result 39999900000064027954\n  Bound result 39999900000000000007\n\n[PASS] test_BettingClosesAtExactStart() (gas: 353070)\n[PASS] test_CarriedProgressCountsCompletedBlockRatherThanFloorOfDelta() (gas: 798625)\n[PASS] test_CertifiedZeroWorkGapsResolveNo() (gas: 741788)\n[PASS] test_ClaimRefundCannotBeRepeatedAndCancelledMarketStaysFinal() (gas: 591787)\n[PASS] test_CoreStreamAndGenesisChangesCannotResolve() (gas: 663025)\n[PASS] test_CoreUpgradeInvalidatesMarketAndTimeoutStillRefunds() (gas: 598638)\n[PASS] test_CreateDailyAndWeeklyExactWindow() (gas: 397577)\n[PASS] test_CreateRejectsInvalidStartsAndAllowsMaxLead() (gas: 414633)\n[PASS] test_CreateRejectsPausedOrMissingCore() (gas: 143962)\n[PASS] test_CreateRejectsTimestampThatWouldTruncateStoredDeadline() (gas: 60011)\n[PASS] test_CreateRejectsUnsupportedVersionAndConfiguration() (gas: 704100)\n[PASS] test_CreateRejectsWrongChainAndInvalidDuration() (gas: 55204)\n[PASS] test_DecreasingHistoryIsRejected() (gas: 668856)\n[PASS] test_DelayedResolutionExcludesLaterWorkAndBatchedFrontier() (gas: 867657)\n[PASS] test_DeploysOnEmptyChainWithoutAdminOrExternalCalls() (gas: 23966)\n[PASS] test_DirectEthIsRejectedAndForcedSurplusCannotInflatePayouts() (gas: 892038)\n[PASS] test_EqualThresholdIsNoAndBothSideHolderOnlyReceivesWinningPayout() (gas: 898878)\n[PASS] test_FinalStatesCannotChangeOrAcceptBets() (gas: 862830)\n[PASS] test_FullBothSidesPayoutConservesPool() (gas: 863132)\n[PASS] test_InvalidMarketIdsAndClaims() (gas: 1227406)\n[PASS] test_MalformedPointResponsesAreRejected() (gas: 1009811)\n[PASS] test_MarketResolvesOnceCertifiedAfterObservedReporterOutage() (gas: 943363)\n[PASS] test_MarketsAreFinanciallyIsolated() (gas: 1251892)\n[PASS] test_MatchedMarketCannotCancelEarly() (gas: 439937)\n[PASS] test_NotElapsedOrNotSettledCannotResolve() (gas: 559337)\n[PASS] test_OppositeSideCanStillEnterAfterOneSideIsFilled() (gas: 1022539)\n[PASS] test_PausedCoreCanResolveAlreadyCertifiedHistory() (gas: 803600)\n[PASS] test_ReentrancyCannotDoubleClaim() (gas: 1309406)\n[PASS] test_RejectingRecipientDoesNotConsumeClaimOrBlockOtherWinner() (gas: 1595279)\n[PASS] test_RepeatedAndBothSideBetsAccumulate() (gas: 591871)\n[PASS] test_ResolutionJustBeforeTimeoutBecomesFinalAndCannotBeRefunded() (gas: 733162)\n[PASS] test_ResolutionStillPossibleLateInGraceAndRefundOnlyAfterIt() (gas: 836528)\n[PASS] test_ResolveAlsoRefundsOneSidedMarket() (gas: 682649)\n[PASS] test_StakeMinimumAndPerSidePoolCap() (gas: 699533)\n[PASS] test_TimeoutBoundaryIsExclusiveForResolutionAndInclusiveForRefunds() (gas: 773772)\n[PASS] test_UnmatchedAndEmptyMarketsRefundAfterBettingCloses() (gas: 666552)\n[PASS] test_WeeklyMarketResolves() (gas: 774672)\n[PASS] test_YesWinAndProportionalPayout() (gas: 1137574)\nSuite result: ok. 41 passed; 0 failed; 0 skipped; finished in 372.87ms (587.14ms CPU time)\n\nRan 8 tests for test/SqueekPredict.claims.t.sol:SqueekPredictClaimsTest\n[PASS] testFuzz_SixWinnersBothSidePositionsAndArbitraryClaimOrder(uint96[6],uint96[6],uint256,bool) (runs: 1000, μ: 3128557, ~: 3120192)\nLogs:\n  Bound result 7999900001046363171\n  Bound result 7999910000000000001\n  Bound result 7999900000000003972\n  Bound result 7999900001000000001\n  Bound result 100000000000000\n  Bound result 7999910000000000001\n  Bound result 100000000000000\n  Bound result 4892751612694128168\n  Bound result 100000000000000\n  Bound result 7999900000000006634\n  Bound result 7999900000000012345\n  Bound result 100000000000000\n\n[PASS] testFuzz_SplittingBetsWithinOneWalletCannotChangeItsEntitlement(uint96,bool) (runs: 1000, μ: 1774911, ~: 1793154)\nLogs:\n  Bound result 39999800000000021233\n\n[PASS] test_CallbackCanReinvestOnlyPaidFundsWithoutCorruptingOtherMarket() (gas: 2070001)\n[PASS] test_ClaimsHaveNoExpiryAndOracleOutagesCannotEraseFinalEntitlements() (gas: 1009810)\n[PASS] test_CrossMarketRecursiveClaimIsBlockedAndLaterClaimRemainsLive() (gas: 2247891)\n[PASS] test_FullPoolExtremeWinnerWeightsRemainPayable() (gas: 1060495)\n[PASS] test_LastWinnerReceivesExactlyThreeWeiOfRoundingDust() (gas: 1491178)\n[PASS] test_RejectedTransferRollsBackEveryClaimEffectAndGuard() (gas: 1975378)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 374.50ms (745.75ms CPU time)\n\nRan 1 test for test/SqueekPredict.invariant.t.sol:SqueekPredictInvariantTest\n[PASS]\nSqueekPredictInvariantTest invariants:\n[PASS] invariant_AllMarketsBackTheirRemainingPayouts\n[PASS] invariant_BalanceAndLiabilitiesConserveEveryDeposit\n SqueekPredictInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+----------+-------+---------+----------╮\n| Contract      | Selector | Calls | Reverts | Discards |\n+=======================================================+\n| MarketHandler | advance  | 2054  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | finalize | 2024  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | place    | 2074  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | withdraw | 2040  | 0       | 0        |\n╰---------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 14638\n  Bound result 144\n  Bound result 1763\n  Bound result 1200\n  Bound result 3722\n  Bound result 43141\n  Bound result 300\n  Bound result 31898\n  Bound result 6643\n  Bound result 3157\n  Bound result 7347\n  Bound result 601\n  Bound result 0\n  Bound result 144\n  Bound result 1110\n  Bound result 12\n  Bound result 95\n  Bound result 126\n  Bound result 5\n  Bound result 1200\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.03s (1.03s CPU time)\n\nRan 2 tests for test/SqueekPredict.stateful.t.sol:SqueekPredictStatefulTest\n[PASS]\nSqueekPredictStatefulTest invariants:\n[PASS] invariant_EveryWeiAndEveryPositionMatchesIndependentCashflows\n[PASS] invariant_QuestionsAreImmutableAndFinalStatesNeverReopen\n SqueekPredictStatefulTest invariants (runs: 256, calls: 32768, reverts: 0)\n\n╭-------------------------+----------------+-------+---------+----------╮\n| Contract                | Selector       | Calls | Reverts | Discards |\n+=======================================================================+\n| PredictLifecycleHandler | advance        | 4224  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | bet            | 4078  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | changeOracle   | 4189  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | create         | 4003  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | donate         | 4015  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | finalize       | 4121  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | jumpToBoundary | 4103  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | withdraw       | 4035  | 0       | 0        |\n╰-------------------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8\n  Bound result 9926\n  Bound result 20\n  Bound result 10277\n  Bound result 167\n  Bound result 1000000000\n  Bound result 1000000000\n  Bound result 106\n  Bound result 68\n  Bound result 99\n  Bound result 26743379168\n  Bound result 0\n  Bound result 73709551614815532560\n  Bound result 2056\n  Bound result 10000000000000\n  Bound result 10334\n  Bound result 9269\n  Bound result 300\n  Bound result 29263030027007317664\n  Bound result 4797\n  Bound result 1173\n  Bound result 4085\n  Bound result 6494\n  Bound result 50\n  Bound result 4389\n  Bound result 857\n  Bound result 39988\n  Bound result 753\n  Bound result 14264337592751668709\n  Bound result 0\n  Bound result 3\n  Bound result 19\n  Bound result 73709551614815532560\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 3480\n  Bound result 0\n  Bound result 152\n  Bound result 3828665430082350312\n  Bound result 0\n  Bound result 11248\n  Bound result 1009\n  Bound result 107\n  Bound result 20\n  Bound result 58118\n  Bound result 20\n\n[PASS] test_HandlerExercisesSuccessRejectionRecoveryAndBothOutcomes() (gas: 4302987)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 1\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 34.13s (34.13s CPU time)\n\nRan 5 test suites in 34.13s (36.28s CPU time): 70 tests passed, 0 failed, 0 skipped (70 total tests)\n","passed":true},{"durationMs":40,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SqueekPredict.bet(uint256,bool)\",\"SqueekPredict.cancelExpired(uint256)\",\"SqueekPredict.cancelUnmatched(uint256)\",\"SqueekPredict.claim(uint256,address)\",\"SqueekPredict.createMarket(uint64,uint64,uint64)\",\"SqueekPredict.resolve(uint256)\"],\"files\":{\".gitignore\":3,\"LICENSE\":21,\"README.md\":133,\"THIRD_PARTY.md\":8,\"docs/CORE_INTEGRATION.md\":26,\"docs/SECURITY_REVIEW.md\":39,\"docs/core-observation.json\":19,\"foundry.toml\":19,\"frontend/abi.json\":716,\"frontend/app.js\":218,\"frontend/core-abi.json\":265,\"frontend/helpers.js\":30,\"frontend/index.html\":87,\"frontend/styles.css\":64,\"frontend/vendor/ethers-6.15.0.umd.min.js\":1,\"frontend/vendor/ethers-LICENSE.md\":21,\"remappings.txt\":1,\"scripts/read-core.cjs\":58,\"src/SqueekPredict.sol\":290,\"src/interfaces/ISqueekCore.sol\":61,\"test/SqueekPredict.boundaries.t.sol\":364,\"test/SqueekPredict.claims.t.sol\":285,\"test/SqueekPredict.invariant.t.sol\":128,\"test/SqueekPredict.stateful.t.sol\":465,\"test/SqueekPredict.t.sol\":714,\"test/TESTING.md\":80,\"test/frontend.test.cjs\":61,\"test/helpers/PredictTestBase.sol\":69,\"test/mocks/MockSqueekCore.sol\":116,\"test/mocks/TimelineSqueekCore.sol\":69},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"18cba0c8f00fec7597d306a3da5d49b86d2ff03863c72b89d02be5a217f84753","verifiedTreeHash":"9f84c4f01f4afd40991ad3d034aed1126936b761","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":1481,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.41s\nCompiler run successful!\n","passed":true},{"durationMs":936,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 37 tests for test/SqueekPredict.t.sol:SqueekPredictTest\n[PASS] testFuzz_CompletePayoutConservesFundsAndRounding(uint96,uint96,uint96,bool,bool) (runs: 256, μ: 1100608, ~: 1091154)\nLogs:\n  Bound result 29999900081345816801\n  Bound result 15030076064750698182\n  Bound result 402933733387771147\n\n[PASS] testFuzz_OfficialHeightDifference(uint64,uint32,uint64,uint64) (runs: 256, μ: 790453, ~: 790112)\nLogs:\n  Bound result 51\n  Bound result 0\n  Bound result 21\n\n[PASS] testFuzz_TimeoutRefundsBothPositions(uint96,uint96) (runs: 256, μ: 627718, ~: 627997)\nLogs:\n  Bound result 39999900001000000001\n  Bound result 39999900000719206528\n\n[PASS] test_BettingClosesAtExactStart() (gas: 355302)\n[PASS] test_CarriedProgressCountsCompletedBlockRatherThanFloorOfDelta() (gas: 802946)\n[PASS] test_CertifiedZeroWorkGapsResolveNo() (gas: 746086)\n[PASS] test_ClaimRefundCannotBeRepeatedAndCancelledMarketStaysFinal() (gas: 593970)\n[PASS] test_CoreStreamAndGenesisChangesCannotResolve() (gas: 667212)\n[PASS] test_CoreUpgradeInvalidatesMarketAndTimeoutStillRefunds() (gas: 602958)\n[PASS] test_CreateDailyAndWeeklyExactWindow() (gas: 389256)\n[PASS] test_CreateRejectsInvalidStartsAndAllowsMaxLead() (gas: 414830)\n[PASS] test_CreateRejectsPausedOrMissingCore() (gas: 144094)\n[PASS] test_CreateRejectsTimestampThatWouldTruncateStoredDeadline() (gas: 60055)\n[PASS] test_CreateRejectsUnsupportedVersionAndConfiguration() (gas: 704254)\n[PASS] test_CreateRejectsWrongChainAndInvalidDuration() (gas: 55203)\n[PASS] test_DecreasingHistoryIsRejected() (gas: 673155)\n[PASS] test_DelayedResolutionExcludesLaterWorkAndBatchedFrontier() (gas: 872000)\n[PASS] test_DeploysOnEmptyChainWithoutAdminOrExternalCalls() (gas: 23988)\n[PASS] test_DirectEthIsRejectedAndForcedSurplusCannotInflatePayouts() (gas: 896399)\n[PASS] test_EqualThresholdIsNoAndBothSideHolderOnlyReceivesWinningPayout() (gas: 905354)\n[PASS] test_FinalStatesCannotChangeOrAcceptBets() (gas: 867018)\n[PASS] test_InvalidMarketIdsAndClaims() (gas: 1231921)\n[PASS] test_MalformedPointResponsesAreRejected() (gas: 1013620)\n[PASS] test_MarketsAreFinanciallyIsolated() (gas: 1258437)\n[PASS] test_MatchedMarketCannotCancelEarly() (gas: 444347)\n[PASS] test_NotElapsedOrNotSettledCannotResolve() (gas: 563569)\n[PASS] test_PausedCoreCanResolveAlreadyCertifiedHistory() (gas: 807888)\n[PASS] test_ReentrancyCannotDoubleClaim() (gas: 1313784)\n[PASS] test_RejectingRecipientDoesNotConsumeClaimOrBlockOtherWinner() (gas: 1601850)\n[PASS] test_RepeatedAndBothSideBetsAccumulate() (gas: 600603)\n[PASS] test_ResolutionJustBeforeTimeoutBecomesFinalAndCannotBeRefunded() (gas: 737505)\n[PASS] test_ResolveAlsoRefundsOneSidedMarket() (gas: 684737)\n[PASS] test_StakeMinimumAndPoolCap() (gas: 490790)\n[PASS] test_TimeoutBoundaryIsExclusiveForResolutionAndInclusiveForRefunds() (gas: 778195)\n[PASS] test_UnmatchedAndEmptyMarketsRefundAfterBettingCloses() (gas: 668840)\n[PASS] test_WeeklyMarketResolves() (gas: 778873)\n[PASS] test_YesWinAndProportionalPayout() (gas: 1144189)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 35.32ms (107.66ms CPU time)\n\nRan 1 test for test/SqueekPredict.invariant.t.sol:SqueekPredictInvariantTest\n[PASS]\nSqueekPredictInvariantTest invariants:\n[PASS] invariant_AllMarketsBackTheirRemainingPayouts\n[PASS] invariant_BalanceAndLiabilitiesConserveEveryDeposit\n SqueekPredictInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+----------+-------+---------+----------╮\n| Contract      | Selector | Calls | Reverts | Discards |\n+=======================================================+\n| MarketHandler | advance  | 2054  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | finalize | 2024  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | place    | 2074  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | withdraw | 2040  | 0       | 0        |\n╰---------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 874\n  Bound result 6\n  Bound result 4999900001000000001\n  Bound result 5999\n  Bound result 4\n  Bound result 3721\n  Bound result 43199\n  Bound result 20076\n  Bound result 10107\n  Bound result 6602\n  Bound result 3019\n  Bound result 7654\n  Bound result 106\n  Bound result 43187\n  Bound result 6\n  Bound result 599\n  Bound result 1110\n  Bound result 95\n  Bound result 1008\n  Bound result 16\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 844.64ms (842.91ms CPU time)\n\nRan 2 test suites in 845.94ms (879.96ms CPU time): 38 tests passed, 0 failed, 0 skipped (38 total tests)\n","passed":true},{"durationMs":35,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SqueekPredict.bet(uint256,bool)\",\"SqueekPredict.cancelExpired(uint256)\",\"SqueekPredict.cancelUnmatched(uint256)\",\"SqueekPredict.claim(uint256,address)\",\"SqueekPredict.createMarket(uint64,uint64,uint64)\",\"SqueekPredict.resolve(uint256)\"],\"files\":{\".gitignore\":3,\"LICENSE\":21,\"README.md\":131,\"THIRD_PARTY.md\":8,\"docs/CORE_INTEGRATION.md\":26,\"docs/SECURITY_REVIEW.md\":37,\"docs/core-observation.json\":19,\"foundry.toml\":19,\"frontend/abi.json\":716,\"frontend/app.js\":218,\"frontend/core-abi.json\":265,\"frontend/helpers.js\":30,\"frontend/index.html\":87,\"frontend/styles.css\":64,\"frontend/vendor/ethers-6.15.0.umd.min.js\":1,\"frontend/vendor/ethers-LICENSE.md\":21,\"remappings.txt\":1,\"scripts/read-core.cjs\":58,\"src/SqueekPredict.sol\":284,\"src/interfaces/ISqueekCore.sol\":61,\"test/SqueekPredict.invariant.t.sol\":128,\"test/SqueekPredict.t.sol\":633,\"test/frontend.test.cjs\":61,\"test/mocks/MockSqueekCore.sol\":116},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":555,"exitCode":0,"name":"slither","output":"[low/medium] timestamp at src/SqueekPredict.sol:141: SqueekPredict.bet(uint256,bool) (src/SqueekPredict.sol#141-156) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:193: SqueekPredict.cancelUnmatched(uint256) (src/SqueekPredict.sol#193-198) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:110: SqueekPredict.createMarket(uint64,uint64,uint64) (src/SqueekPredict.sol#110-138) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:160: SqueekPredict.resolve(uint256) (src/SqueekPredict.sol#160-190) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:254: SqueekPredict._configuration() (src/SqueekPredict.sol#254-262) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:201: SqueekPredict.cancelExpired(uint256) (src/SqueekPredict.sol#201-205) uses timestamp for comparisons","passed":true},{"durationMs":229,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/SqueekPredict.sol:114: Reentrancy: State change after external call (4 places)\n[low] large-numeric-literal at src/SqueekPredict.sol:13: Large Numeric Literal\n[low] modifier-used-only-once at src/SqueekPredict.sol:100: Modifier Invoked Only Once","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"288a36ce0820a7f2bc0f7166258062c7cef52330c39e52dad14fd86efb33bf62","verifiedTreeHash":"bf410c22fea73358f61b57f6d289d20101fba4bc","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":1580,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.50s\nCompiler run successful!\n","passed":true},{"durationMs":958,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 37 tests for test/SqueekPredict.t.sol:SqueekPredictTest\n[PASS] testFuzz_CompletePayoutConservesFundsAndRounding(uint96,uint96,uint96,bool,bool) (runs: 256, μ: 1100608, ~: 1091154)\nLogs:\n  Bound result 29999900000000000006\n  Bound result 565536184372352\n  Bound result 28238704127844973686\n\n[PASS] testFuzz_OfficialHeightDifference(uint64,uint32,uint64,uint64) (runs: 256, μ: 790453, ~: 790112)\nLogs:\n  Bound result 3871045\n  Bound result 610414949630\n  Bound result 2\n\n[PASS] testFuzz_TimeoutRefundsBothPositions(uint96,uint96) (runs: 256, μ: 627718, ~: 627997)\nLogs:\n  Bound result 39999900000128241361\n  Bound result 39999900000000004670\n\n[PASS] test_BettingClosesAtExactStart() (gas: 355302)\n[PASS] test_CarriedProgressCountsCompletedBlockRatherThanFloorOfDelta() (gas: 802946)\n[PASS] test_CertifiedZeroWorkGapsResolveNo() (gas: 746086)\n[PASS] test_ClaimRefundCannotBeRepeatedAndCancelledMarketStaysFinal() (gas: 593970)\n[PASS] test_CoreStreamAndGenesisChangesCannotResolve() (gas: 667212)\n[PASS] test_CoreUpgradeInvalidatesMarketAndTimeoutStillRefunds() (gas: 602958)\n[PASS] test_CreateDailyAndWeeklyExactWindow() (gas: 389256)\n[PASS] test_CreateRejectsInvalidStartsAndAllowsMaxLead() (gas: 414830)\n[PASS] test_CreateRejectsPausedOrMissingCore() (gas: 144094)\n[PASS] test_CreateRejectsTimestampThatWouldTruncateStoredDeadline() (gas: 60055)\n[PASS] test_CreateRejectsUnsupportedVersionAndConfiguration() (gas: 704254)\n[PASS] test_CreateRejectsWrongChainAndInvalidDuration() (gas: 55203)\n[PASS] test_DecreasingHistoryIsRejected() (gas: 673155)\n[PASS] test_DelayedResolutionExcludesLaterWorkAndBatchedFrontier() (gas: 872000)\n[PASS] test_DeploysOnEmptyChainWithoutAdminOrExternalCalls() (gas: 23988)\n[PASS] test_DirectEthIsRejectedAndForcedSurplusCannotInflatePayouts() (gas: 896399)\n[PASS] test_EqualThresholdIsNoAndBothSideHolderOnlyReceivesWinningPayout() (gas: 905354)\n[PASS] test_FinalStatesCannotChangeOrAcceptBets() (gas: 867018)\n[PASS] test_InvalidMarketIdsAndClaims() (gas: 1231921)\n[PASS] test_MalformedPointResponsesAreRejected() (gas: 1013620)\n[PASS] test_MarketsAreFinanciallyIsolated() (gas: 1258437)\n[PASS] test_MatchedMarketCannotCancelEarly() (gas: 444347)\n[PASS] test_NotElapsedOrNotSettledCannotResolve() (gas: 563569)\n[PASS] test_PausedCoreCanResolveAlreadyCertifiedHistory() (gas: 807888)\n[PASS] test_ReentrancyCannotDoubleClaim() (gas: 1313784)\n[PASS] test_RejectingRecipientDoesNotConsumeClaimOrBlockOtherWinner() (gas: 1601850)\n[PASS] test_RepeatedAndBothSideBetsAccumulate() (gas: 600603)\n[PASS] test_ResolutionJustBeforeTimeoutBecomesFinalAndCannotBeRefunded() (gas: 737505)\n[PASS] test_ResolveAlsoRefundsOneSidedMarket() (gas: 684737)\n[PASS] test_StakeMinimumAndPoolCap() (gas: 490790)\n[PASS] test_TimeoutBoundaryIsExclusiveForResolutionAndInclusiveForRefunds() (gas: 778195)\n[PASS] test_UnmatchedAndEmptyMarketsRefundAfterBettingCloses() (gas: 668840)\n[PASS] test_WeeklyMarketResolves() (gas: 778873)\n[PASS] test_YesWinAndProportionalPayout() (gas: 1144189)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 41.83ms (119.78ms CPU time)\n\nRan 1 test for test/SqueekPredict.invariant.t.sol:SqueekPredictInvariantTest\n[PASS]\nSqueekPredictInvariantTest invariants:\n[PASS] invariant_AllMarketsBackTheirRemainingPayouts\n[PASS] invariant_BalanceAndLiabilitiesConserveEveryDeposit\n SqueekPredictInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+----------+-------+---------+----------╮\n| Contract      | Selector | Calls | Reverts | Discards |\n+=======================================================+\n| MarketHandler | advance  | 2054  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | finalize | 2024  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | place    | 2074  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | withdraw | 2040  | 0       | 0        |\n╰---------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 874\n  Bound result 6\n  Bound result 4999900001000000001\n  Bound result 5999\n  Bound result 4\n  Bound result 3721\n  Bound result 43199\n  Bound result 20076\n  Bound result 10107\n  Bound result 6602\n  Bound result 3019\n  Bound result 7654\n  Bound result 106\n  Bound result 43187\n  Bound result 6\n  Bound result 599\n  Bound result 1110\n  Bound result 95\n  Bound result 1008\n  Bound result 16\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 866.87ms (864.50ms CPU time)\n\nRan 2 test suites in 868.24ms (908.69ms CPU time): 38 tests passed, 0 failed, 0 skipped (38 total tests)\n","passed":true},{"durationMs":34,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SqueekPredict.bet(uint256,bool)\",\"SqueekPredict.cancelExpired(uint256)\",\"SqueekPredict.cancelUnmatched(uint256)\",\"SqueekPredict.claim(uint256,address)\",\"SqueekPredict.createMarket(uint64,uint64,uint64)\",\"SqueekPredict.resolve(uint256)\"],\"files\":{\".gitignore\":3,\"LICENSE\":21,\"README.md\":131,\"THIRD_PARTY.md\":8,\"docs/CORE_INTEGRATION.md\":26,\"docs/SECURITY_REVIEW.md\":37,\"docs/core-observation.json\":19,\"foundry.toml\":19,\"frontend/abi.json\":716,\"frontend/app.js\":218,\"frontend/core-abi.json\":265,\"frontend/helpers.js\":30,\"frontend/index.html\":87,\"frontend/styles.css\":64,\"frontend/vendor/ethers-6.15.0.umd.min.js\":1,\"frontend/vendor/ethers-LICENSE.md\":21,\"launch.json\":10,\"remappings.txt\":1,\"scripts/read-core.cjs\":58,\"src/SqueekPredict.sol\":284,\"src/interfaces/ISqueekCore.sol\":61,\"test/SqueekPredict.invariant.t.sol\":128,\"test/SqueekPredict.t.sol\":633,\"test/frontend.test.cjs\":61,\"test/mocks/MockSqueekCore.sol\":116},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"9c868c47cec4281b1c3b65f5c00417a9ee0fe012a7601e829406a8c2951963ac","verifiedTreeHash":"b7551edf3f7a02921e72b8c3be67a76c4b7b3c3c","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":1620,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.55s\nCompiler run successful!\n","passed":true},{"durationMs":960,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 41 tests for test/SqueekPredict.t.sol:SqueekPredictTest\n[PASS] testFuzz_CompletePayoutConservesFundsAndRounding(uint96,uint96,uint96,bool,bool) (runs: 256, μ: 1093974, ~: 1084528)\nLogs:\n  Bound result 100000000000000\n  Bound result 100000000000000\n  Bound result 29999900000000011666\n\n[PASS] testFuzz_OfficialHeightDifference(uint64,uint32,uint64,uint64) (runs: 256, μ: 786163, ~: 785831)\nLogs:\n  Bound result 51\n  Bound result 0\n  Bound result 21\n\n[PASS] testFuzz_TimeoutRefundsBothPositions(uint96,uint96) (runs: 256, μ: 623224, ~: 623503)\nLogs:\n  Bound result 39999900000064027954\n  Bound result 39999900000000000007\n\n[PASS] test_BettingClosesAtExactStart() (gas: 353070)\n[PASS] test_CarriedProgressCountsCompletedBlockRatherThanFloorOfDelta() (gas: 798625)\n[PASS] test_CertifiedZeroWorkGapsResolveNo() (gas: 741788)\n[PASS] test_ClaimRefundCannotBeRepeatedAndCancelledMarketStaysFinal() (gas: 591787)\n[PASS] test_CoreStreamAndGenesisChangesCannotResolve() (gas: 663025)\n[PASS] test_CoreUpgradeInvalidatesMarketAndTimeoutStillRefunds() (gas: 598638)\n[PASS] test_CreateDailyAndWeeklyExactWindow() (gas: 397577)\n[PASS] test_CreateRejectsInvalidStartsAndAllowsMaxLead() (gas: 414633)\n[PASS] test_CreateRejectsPausedOrMissingCore() (gas: 143962)\n[PASS] test_CreateRejectsTimestampThatWouldTruncateStoredDeadline() (gas: 60011)\n[PASS] test_CreateRejectsUnsupportedVersionAndConfiguration() (gas: 704100)\n[PASS] test_CreateRejectsWrongChainAndInvalidDuration() (gas: 55204)\n[PASS] test_DecreasingHistoryIsRejected() (gas: 668856)\n[PASS] test_DelayedResolutionExcludesLaterWorkAndBatchedFrontier() (gas: 867657)\n[PASS] test_DeploysOnEmptyChainWithoutAdminOrExternalCalls() (gas: 23966)\n[PASS] test_DirectEthIsRejectedAndForcedSurplusCannotInflatePayouts() (gas: 892038)\n[PASS] test_EqualThresholdIsNoAndBothSideHolderOnlyReceivesWinningPayout() (gas: 898878)\n[PASS] test_FinalStatesCannotChangeOrAcceptBets() (gas: 862830)\n[PASS] test_FullBothSidesPayoutConservesPool() (gas: 863132)\n[PASS] test_InvalidMarketIdsAndClaims() (gas: 1227406)\n[PASS] test_MalformedPointResponsesAreRejected() (gas: 1009811)\n[PASS] test_MarketResolvesOnceCertifiedAfterObservedReporterOutage() (gas: 943363)\n[PASS] test_MarketsAreFinanciallyIsolated() (gas: 1251892)\n[PASS] test_MatchedMarketCannotCancelEarly() (gas: 439937)\n[PASS] test_NotElapsedOrNotSettledCannotResolve() (gas: 559337)\n[PASS] test_OppositeSideCanStillEnterAfterOneSideIsFilled() (gas: 1022539)\n[PASS] test_PausedCoreCanResolveAlreadyCertifiedHistory() (gas: 803600)\n[PASS] test_ReentrancyCannotDoubleClaim() (gas: 1309406)\n[PASS] test_RejectingRecipientDoesNotConsumeClaimOrBlockOtherWinner() (gas: 1595279)\n[PASS] test_RepeatedAndBothSideBetsAccumulate() (gas: 591871)\n[PASS] test_ResolutionJustBeforeTimeoutBecomesFinalAndCannotBeRefunded() (gas: 733162)\n[PASS] test_ResolutionStillPossibleLateInGraceAndRefundOnlyAfterIt() (gas: 836528)\n[PASS] test_ResolveAlsoRefundsOneSidedMarket() (gas: 682649)\n[PASS] test_StakeMinimumAndPerSidePoolCap() (gas: 699533)\n[PASS] test_TimeoutBoundaryIsExclusiveForResolutionAndInclusiveForRefunds() (gas: 773772)\n[PASS] test_UnmatchedAndEmptyMarketsRefundAfterBettingCloses() (gas: 666552)\n[PASS] test_WeeklyMarketResolves() (gas: 774672)\n[PASS] test_YesWinAndProportionalPayout() (gas: 1137574)\nSuite result: ok. 41 passed; 0 failed; 0 skipped; finished in 54.38ms (140.64ms CPU time)\n\nRan 1 test for test/SqueekPredict.invariant.t.sol:SqueekPredictInvariantTest\n[PASS]\nSqueekPredictInvariantTest invariants:\n[PASS] invariant_AllMarketsBackTheirRemainingPayouts\n[PASS] invariant_BalanceAndLiabilitiesConserveEveryDeposit\n SqueekPredictInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+----------+-------+---------+----------╮\n| Contract      | Selector | Calls | Reverts | Discards |\n+=======================================================+\n| MarketHandler | advance  | 2054  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | finalize | 2024  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | place    | 2074  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | withdraw | 2040  | 0       | 0        |\n╰---------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 14638\n  Bound result 14248\n  Bound result 1759\n  Bound result 2\n  Bound result 3722\n  Bound result 43187\n  Bound result 17999\n  Bound result 31898\n  Bound result 6642\n  Bound result 3019\n  Bound result 7353\n  Bound result 250\n  Bound result 3600\n  Bound result 43200\n  Bound result 20076\n  Bound result 60\n  Bound result 95\n  Bound result 1110\n  Bound result 16\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 870.33ms (867.65ms CPU time)\n\nRan 2 test suites in 871.62ms (924.70ms CPU time): 42 tests passed, 0 failed, 0 skipped (42 total tests)\n","passed":true},{"durationMs":32,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SqueekPredict.bet(uint256,bool)\",\"SqueekPredict.cancelExpired(uint256)\",\"SqueekPredict.cancelUnmatched(uint256)\",\"SqueekPredict.claim(uint256,address)\",\"SqueekPredict.createMarket(uint64,uint64,uint64)\",\"SqueekPredict.resolve(uint256)\"],\"files\":{\".gitignore\":3,\"LICENSE\":21,\"README.md\":133,\"THIRD_PARTY.md\":8,\"docs/CORE_INTEGRATION.md\":26,\"docs/SECURITY_REVIEW.md\":39,\"docs/core-observation.json\":19,\"foundry.toml\":19,\"frontend/abi.json\":716,\"frontend/app.js\":218,\"frontend/core-abi.json\":265,\"frontend/helpers.js\":30,\"frontend/index.html\":87,\"frontend/styles.css\":64,\"frontend/vendor/ethers-6.15.0.umd.min.js\":1,\"frontend/vendor/ethers-LICENSE.md\":21,\"launch.json\":10,\"remappings.txt\":1,\"scripts/read-core.cjs\":58,\"src/SqueekPredict.sol\":290,\"src/interfaces/ISqueekCore.sol\":61,\"test/SqueekPredict.invariant.t.sol\":128,\"test/SqueekPredict.t.sol\":714,\"test/frontend.test.cjs\":61,\"test/mocks/MockSqueekCore.sol\":116},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ae81ced700f69eee64c3574690b7c111dfbc7f57d54ffbb7f74391940ae850af","verifiedTreeHash":"8f1578eb5dc1b4fe262eafabfd4d1eb6df6330e5","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":1810,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.73s\nCompiler run successful!\n","passed":true},{"durationMs":1075,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 41 tests for test/SqueekPredict.t.sol:SqueekPredictTest\n[PASS] testFuzz_CompletePayoutConservesFundsAndRounding(uint96,uint96,uint96,bool,bool) (runs: 256, μ: 1093974, ~: 1084528)\nLogs:\n  Bound result 29999900081345816801\n  Bound result 15030076064750698182\n  Bound result 402933733387771147\n\n[PASS] testFuzz_OfficialHeightDifference(uint64,uint32,uint64,uint64) (runs: 256, μ: 786163, ~: 785831)\nLogs:\n  Bound result 51\n  Bound result 0\n  Bound result 21\n\n[PASS] testFuzz_TimeoutRefundsBothPositions(uint96,uint96) (runs: 256, μ: 623224, ~: 623503)\nLogs:\n  Bound result 39999900001000000001\n  Bound result 39999900001064470262\n\n[PASS] test_BettingClosesAtExactStart() (gas: 353070)\n[PASS] test_CarriedProgressCountsCompletedBlockRatherThanFloorOfDelta() (gas: 798625)\n[PASS] test_CertifiedZeroWorkGapsResolveNo() (gas: 741788)\n[PASS] test_ClaimRefundCannotBeRepeatedAndCancelledMarketStaysFinal() (gas: 591787)\n[PASS] test_CoreStreamAndGenesisChangesCannotResolve() (gas: 663025)\n[PASS] test_CoreUpgradeInvalidatesMarketAndTimeoutStillRefunds() (gas: 598638)\n[PASS] test_CreateDailyAndWeeklyExactWindow() (gas: 397577)\n[PASS] test_CreateRejectsInvalidStartsAndAllowsMaxLead() (gas: 414633)\n[PASS] test_CreateRejectsPausedOrMissingCore() (gas: 143962)\n[PASS] test_CreateRejectsTimestampThatWouldTruncateStoredDeadline() (gas: 60011)\n[PASS] test_CreateRejectsUnsupportedVersionAndConfiguration() (gas: 704100)\n[PASS] test_CreateRejectsWrongChainAndInvalidDuration() (gas: 55204)\n[PASS] test_DecreasingHistoryIsRejected() (gas: 668856)\n[PASS] test_DelayedResolutionExcludesLaterWorkAndBatchedFrontier() (gas: 867657)\n[PASS] test_DeploysOnEmptyChainWithoutAdminOrExternalCalls() (gas: 23966)\n[PASS] test_DirectEthIsRejectedAndForcedSurplusCannotInflatePayouts() (gas: 892038)\n[PASS] test_EqualThresholdIsNoAndBothSideHolderOnlyReceivesWinningPayout() (gas: 898878)\n[PASS] test_FinalStatesCannotChangeOrAcceptBets() (gas: 862830)\n[PASS] test_FullBothSidesPayoutConservesPool() (gas: 863132)\n[PASS] test_InvalidMarketIdsAndClaims() (gas: 1227406)\n[PASS] test_MalformedPointResponsesAreRejected() (gas: 1009811)\n[PASS] test_MarketResolvesOnceCertifiedAfterObservedReporterOutage() (gas: 943363)\n[PASS] test_MarketsAreFinanciallyIsolated() (gas: 1251892)\n[PASS] test_MatchedMarketCannotCancelEarly() (gas: 439937)\n[PASS] test_NotElapsedOrNotSettledCannotResolve() (gas: 559337)\n[PASS] test_OppositeSideCanStillEnterAfterOneSideIsFilled() (gas: 1022539)\n[PASS] test_PausedCoreCanResolveAlreadyCertifiedHistory() (gas: 803600)\n[PASS] test_ReentrancyCannotDoubleClaim() (gas: 1309406)\n[PASS] test_RejectingRecipientDoesNotConsumeClaimOrBlockOtherWinner() (gas: 1595279)\n[PASS] test_RepeatedAndBothSideBetsAccumulate() (gas: 591871)\n[PASS] test_ResolutionJustBeforeTimeoutBecomesFinalAndCannotBeRefunded() (gas: 733162)\n[PASS] test_ResolutionStillPossibleLateInGraceAndRefundOnlyAfterIt() (gas: 836528)\n[PASS] test_ResolveAlsoRefundsOneSidedMarket() (gas: 682649)\n[PASS] test_StakeMinimumAndPerSidePoolCap() (gas: 699533)\n[PASS] test_TimeoutBoundaryIsExclusiveForResolutionAndInclusiveForRefunds() (gas: 773772)\n[PASS] test_UnmatchedAndEmptyMarketsRefundAfterBettingCloses() (gas: 666552)\n[PASS] test_WeeklyMarketResolves() (gas: 774672)\n[PASS] test_YesWinAndProportionalPayout() (gas: 1137574)\nSuite result: ok. 41 passed; 0 failed; 0 skipped; finished in 45.47ms (132.98ms CPU time)\n\nRan 1 test for test/SqueekPredict.invariant.t.sol:SqueekPredictInvariantTest\n[PASS]\nSqueekPredictInvariantTest invariants:\n[PASS] invariant_AllMarketsBackTheirRemainingPayouts\n[PASS] invariant_BalanceAndLiabilitiesConserveEveryDeposit\n SqueekPredictInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+----------+-------+---------+----------╮\n| Contract      | Selector | Calls | Reverts | Discards |\n+=======================================================+\n| MarketHandler | advance  | 2054  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | finalize | 2024  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | place    | 2074  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | withdraw | 2040  | 0       | 0        |\n╰---------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 14638\n  Bound result 14248\n  Bound result 1759\n  Bound result 2\n  Bound result 3722\n  Bound result 43187\n  Bound result 17999\n  Bound result 31898\n  Bound result 6642\n  Bound result 3019\n  Bound result 7353\n  Bound result 250\n  Bound result 3600\n  Bound result 43200\n  Bound result 20076\n  Bound result 60\n  Bound result 95\n  Bound result 1110\n  Bound result 16\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 946.43ms (944.14ms CPU time)\n\nRan 2 test suites in 947.90ms (991.91ms CPU time): 42 tests passed, 0 failed, 0 skipped (42 total tests)\n","passed":true},{"durationMs":52,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SqueekPredict.bet(uint256,bool)\",\"SqueekPredict.cancelExpired(uint256)\",\"SqueekPredict.cancelUnmatched(uint256)\",\"SqueekPredict.claim(uint256,address)\",\"SqueekPredict.createMarket(uint64,uint64,uint64)\",\"SqueekPredict.resolve(uint256)\"],\"files\":{\".gitignore\":3,\"LICENSE\":21,\"README.md\":133,\"THIRD_PARTY.md\":8,\"docs/CORE_INTEGRATION.md\":26,\"docs/SECURITY_REVIEW.md\":39,\"docs/core-observation.json\":19,\"foundry.toml\":19,\"frontend/abi.json\":716,\"frontend/app.js\":218,\"frontend/core-abi.json\":265,\"frontend/helpers.js\":30,\"frontend/index.html\":87,\"frontend/styles.css\":64,\"frontend/vendor/ethers-6.15.0.umd.min.js\":1,\"frontend/vendor/ethers-LICENSE.md\":21,\"remappings.txt\":1,\"scripts/read-core.cjs\":58,\"src/SqueekPredict.sol\":290,\"src/interfaces/ISqueekCore.sol\":61,\"test/SqueekPredict.invariant.t.sol\":128,\"test/SqueekPredict.t.sol\":714,\"test/frontend.test.cjs\":61,\"test/mocks/MockSqueekCore.sol\":116},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":619,"exitCode":0,"name":"slither","output":"[low/medium] timestamp at src/SqueekPredict.sol:260: SqueekPredict._configuration() (src/SqueekPredict.sol#260-268) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:114: SqueekPredict.createMarket(uint64,uint64,uint64) (src/SqueekPredict.sol#114-142) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:166: SqueekPredict.resolve(uint256) (src/SqueekPredict.sol#166-196) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:146: SqueekPredict.bet(uint256,bool) (src/SqueekPredict.sol#146-161) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:199: SqueekPredict.cancelUnmatched(uint256) (src/SqueekPredict.sol#199-204) uses timestamp for comparisons\n[low/medium] timestamp at src/SqueekPredict.sol:207: SqueekPredict.cancelExpired(uint256) (src/SqueekPredict.sol#207-211) uses timestamp for comparisons","passed":true},{"durationMs":271,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/SqueekPredict.sol:118: Reentrancy: State change after external call (4 places)\n[low] large-numeric-literal at src/SqueekPredict.sol:13: Large Numeric Literal\n[low] modifier-used-only-once at src/SqueekPredict.sol:104: Modifier Invoked Only Once","passed":true},{"durationMs":1491,"exitCode":0,"name":"proof f2f871d98ff4","output":"Compiling 23 files with Solc 0.8.26\nSolc 0.8.26 finished in 938.77ms\nCompiler run successful!\n\nRan 1 test for test/imd-proof-8b6a3692/Proof_f2f871d98ff4.t.sol:ResolutionGraceTest\n[PASS] test_MarketResolvesOnceCertifiedAfterObservedReporterOutage() (gas: 823970)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.32ms (525.04µs CPU time)\n\nRan 1 test suite in 3.20ms (1.32ms 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":"ae8724ea3aab7136089ee4e1db893f52301f824e4161c429308031f8fd7979e7","verifiedTreeHash":"70c22e86245f689b1f5ab5ae14d30cddc98b66d4","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":2617,"exitCode":0,"name":"build","output":"Compiling 29 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.54s\nCompiler run successful!\n","passed":true},{"durationMs":33623,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 37 tests for test/SqueekPredict.t.sol:SqueekPredictTest\n[PASS] testFuzz_CompletePayoutConservesFundsAndRounding(uint96,uint96,uint96,bool,bool) (runs: 256, μ: 1100675, ~: 1091154)\nLogs:\n  Bound result 29999910000000000001\n  Bound result 29999900001000000001\n  Bound result 29999910000000000001\n\n[PASS] testFuzz_OfficialHeightDifference(uint64,uint32,uint64,uint64) (runs: 256, μ: 790459, ~: 790130)\nLogs:\n  Bound result 72\n  Bound result 73691104868\n  Bound result 172769742966080\n\n[PASS] testFuzz_TimeoutRefundsBothPositions(uint96,uint96) (runs: 256, μ: 627764, ~: 627997)\nLogs:\n  Bound result 39999900000000018514\n  Bound result 39999900001000000001\n\n[PASS] test_BettingClosesAtExactStart() (gas: 355302)\n[PASS] test_CarriedProgressCountsCompletedBlockRatherThanFloorOfDelta() (gas: 802946)\n[PASS] test_CertifiedZeroWorkGapsResolveNo() (gas: 746086)\n[PASS] test_ClaimRefundCannotBeRepeatedAndCancelledMarketStaysFinal() (gas: 593970)\n[PASS] test_CoreStreamAndGenesisChangesCannotResolve() (gas: 667212)\n[PASS] test_CoreUpgradeInvalidatesMarketAndTimeoutStillRefunds() (gas: 602958)\n[PASS] test_CreateDailyAndWeeklyExactWindow() (gas: 389256)\n[PASS] test_CreateRejectsInvalidStartsAndAllowsMaxLead() (gas: 414830)\n[PASS] test_CreateRejectsPausedOrMissingCore() (gas: 144094)\n[PASS] test_CreateRejectsTimestampThatWouldTruncateStoredDeadline() (gas: 60055)\n[PASS] test_CreateRejectsUnsupportedVersionAndConfiguration() (gas: 704254)\n[PASS] test_CreateRejectsWrongChainAndInvalidDuration() (gas: 55203)\n[PASS] test_DecreasingHistoryIsRejected() (gas: 673155)\n[PASS] test_DelayedResolutionExcludesLaterWorkAndBatchedFrontier() (gas: 872000)\n[PASS] test_DeploysOnEmptyChainWithoutAdminOrExternalCalls() (gas: 23988)\n[PASS] test_DirectEthIsRejectedAndForcedSurplusCannotInflatePayouts() (gas: 896399)\n[PASS] test_EqualThresholdIsNoAndBothSideHolderOnlyReceivesWinningPayout() (gas: 905354)\n[PASS] test_FinalStatesCannotChangeOrAcceptBets() (gas: 867018)\n[PASS] test_InvalidMarketIdsAndClaims() (gas: 1231921)\n[PASS] test_MalformedPointResponsesAreRejected() (gas: 1013620)\n[PASS] test_MarketsAreFinanciallyIsolated() (gas: 1258437)\n[PASS] test_MatchedMarketCannotCancelEarly() (gas: 444347)\n[PASS] test_NotElapsedOrNotSettledCannotResolve() (gas: 563569)\n[PASS] test_PausedCoreCanResolveAlreadyCertifiedHistory() (gas: 807888)\n[PASS] test_ReentrancyCannotDoubleClaim() (gas: 1313784)\n[PASS] test_RejectingRecipientDoesNotConsumeClaimOrBlockOtherWinner() (gas: 1601850)\n[PASS] test_RepeatedAndBothSideBetsAccumulate() (gas: 600603)\n[PASS] test_ResolutionJustBeforeTimeoutBecomesFinalAndCannotBeRefunded() (gas: 737505)\n[PASS] test_ResolveAlsoRefundsOneSidedMarket() (gas: 684737)\n[PASS] test_StakeMinimumAndPoolCap() (gas: 490790)\n[PASS] test_TimeoutBoundaryIsExclusiveForResolutionAndInclusiveForRefunds() (gas: 778195)\n[PASS] test_UnmatchedAndEmptyMarketsRefundAfterBettingCloses() (gas: 668840)\n[PASS] test_WeeklyMarketResolves() (gas: 778873)\n[PASS] test_YesWinAndProportionalPayout() (gas: 1144189)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 321.01ms (863.54ms CPU time)\n\nRan 8 tests for test/SqueekPredict.claims.t.sol:SqueekPredictClaimsTest\n[PASS] testFuzz_SixWinnersBothSidePositionsAndArbitraryClaimOrder(uint96[6],uint96[6],uint256,bool) (runs: 1000, μ: 3155213, ~: 3146844)\nLogs:\n  Bound result 100000000000002\n  Bound result 6496012594661211777\n  Bound result 7999900000000000028\n  Bound result 6920003619217405264\n  Bound result 7999900000000000035\n  Bound result 7999902031853101942\n  Bound result 2687629895795985977\n  Bound result 3626390084143541\n  Bound result 100000000000000\n  Bound result 4420289550197323735\n  Bound result 5406184671994415815\n  Bound result 7999902251173139782\n\n[PASS] testFuzz_SplittingBetsWithinOneWalletCannotChangeItsEntitlement(uint96,bool) (runs: 1000, μ: 1790189, ~: 1808448)\nLogs:\n  Bound result 200000000000000\n\n[PASS] test_CallbackCanReinvestOnlyPaidFundsWithoutCorruptingOtherMarket() (gas: 2076571)\n[PASS] test_ClaimsHaveNoExpiryAndOracleOutagesCannotEraseFinalEntitlements() (gas: 1014171)\n[PASS] test_CrossMarketRecursiveClaimIsBlockedAndLaterClaimRemainsLive() (gas: 2256613)\n[PASS] test_FullPoolExtremeWinnerWeightsRemainPayable() (gas: 1067044)\n[PASS] test_LastWinnerReceivesExactlyThreeWeiOfRoundingDust() (gas: 1502213)\n[PASS] test_RejectedTransferRollsBackEveryClaimEffectAndGuard() (gas: 1981971)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 322.73ms (634.76ms CPU time)\n\nRan 15 tests for test/SqueekPredict.boundaries.t.sol:SqueekPredictBoundariesTest\n[PASS] testFuzz_BlockCompletionCountsProgressCarry(uint64,uint64,uint32,uint32,bool) (runs: 1000, μ: 1388595, ~: 1388465)\nLogs:\n  Bound result 1\n  Bound result 1008\n  Bound result 18234\n  Bound result 292164409\n\n[PASS] testFuzz_EitherMalformedEndpointRollsBackAndCanBeRetried(bool,uint8) (runs: 1000, μ: 994625, ~: 998452)\nLogs:\n  Bound result 1\n\n[PASS] testFuzz_IncompatibleConfigurationAtResolutionStillAllowsFullRefund(uint8) (runs: 1000, μ: 1066083, ~: 1064064)\nLogs:\n  Bound result 2\n\n[PASS] testFuzz_InvalidIdsNeverAllocatePositionsOrAcceptValue(uint256) (runs: 1000, μ: 599724, ~: 599686)\nLogs:\n  Bound result 3153600000\n\n[PASS] testFuzz_OnlyDailyAndWeeklyDurationsAreAccepted(uint64) (runs: 1000, μ: 37698, ~: 37690)\n[PASS] testFuzz_RoundAlignmentAndImmutableIdentity(uint32,bool,uint64) (runs: 1000, μ: 240579, ~: 240426)\nLogs:\n  Bound result 399593\n\n[PASS] testFuzz_TruncatedOracleReturnNeverFinalizes(uint8) (runs: 1000, μ: 911964, ~: 903109)\nLogs:\n  Bound result 0\n\n[PASS] test_DecreasingWorkIsRejectedEvenWhenBlockUnitsIncrease() (gas: 737075)\n[PASS] test_EventsDescribeCreationBetResolutionAndActualPayment() (gas: 851376)\n[PASS] test_LeadTimeLimitsToTheSecond() (gas: 464820)\n[PASS] test_MaximumRepresentableBlockHeightAndThreshold() (gas: 1354522)\n[PASS] test_NoBlockCompletedAtThresholdZeroPaysNo() (gas: 802804)\n[PASS] test_OneWeiAndOversizedBetsRevertWithoutChangingAccounting() (gas: 576383)\n[PASS] test_ResolutionUsesBothExactPointsNotCurrentStateOrDifficulty() (gas: 953090)\n[PASS] test_TimeoutCancellationEmitsOnceAndRefundIgnoresCore() (gas: 615617)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 322.78ms (1.94s CPU time)\n\nRan 1 test for test/SqueekPredict.invariant.t.sol:SqueekPredictInvariantTest\n[PASS]\nSqueekPredictInvariantTest invariants:\n[PASS] invariant_AllMarketsBackTheirRemainingPayouts\n[PASS] invariant_BalanceAndLiabilitiesConserveEveryDeposit\n SqueekPredictInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭---------------+----------+-------+---------+----------╮\n| Contract      | Selector | Calls | Reverts | Discards |\n+=======================================================+\n| MarketHandler | advance  | 2054  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | finalize | 2024  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | place    | 2074  | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| MarketHandler | withdraw | 2040  | 0       | 0        |\n╰---------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 874\n  Bound result 1008\n  Bound result 4999910000000000001\n  Bound result 1760\n  Bound result 200\n  Bound result 3721\n  Bound result 3600\n  Bound result 60\n  Bound result 10107\n  Bound result 6602\n  Bound result 3019\n  Bound result 7373\n  Bound result 12000\n  Bound result 0\n  Bound result 1008\n  Bound result 12\n  Bound result 18\n  Bound result 95\n  Bound result 8\n  Bound result 2\n  Bound result 200\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.00s (1.00s CPU time)\n\nRan 2 tests for test/SqueekPredict.stateful.t.sol:SqueekPredictStatefulTest\n[PASS]\nSqueekPredictStatefulTest invariants:\n[PASS] invariant_EveryWeiAndEveryPositionMatchesIndependentCashflows\n[PASS] invariant_QuestionsAreImmutableAndFinalStatesNeverReopen\n SqueekPredictStatefulTest invariants (runs: 256, calls: 32768, reverts: 0)\n\n╭-------------------------+----------------+-------+---------+----------╮\n| Contract                | Selector       | Calls | Reverts | Discards |\n+=======================================================================+\n| PredictLifecycleHandler | advance        | 4224  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | bet            | 4078  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | changeOracle   | 4189  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | create         | 4003  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | donate         | 4015  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | finalize       | 4121  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | jumpToBoundary | 4103  | 0       | 0        |\n|-------------------------+----------------+-------+---------+----------|\n| PredictLifecycleHandler | withdraw       | 4035  | 0       | 0        |\n╰-------------------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8\n  Bound result 9645\n  Bound result 20\n  Bound result 12000\n  Bound result 106\n  Bound result 1000000000\n  Bound result 9999900000000001952\n  Bound result 1000000000\n  Bound result 106\n  Bound result 139\n  Bound result 19\n  Bound result 26743379168\n  Bound result 0\n  Bound result 73709551614815532560\n  Bound result 1957\n  Bound result 10000000000000\n  Bound result 10327\n  Bound result 7878\n  Bound result 60\n  Bound result 29263030027007317664\n  Bound result 4772\n  Bound result 414\n  Bound result 2037090744\n  Bound result 6527\n  Bound result 50\n  Bound result 4805\n  Bound result 413\n  Bound result 39988\n  Bound result 369\n  Bound result 14264337592751668709\n  Bound result 0\n  Bound result 3\n  Bound result 19\n  Bound result 73709551614815532560\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 3445\n  Bound result 0\n  Bound result 152\n  Bound result 3828665430082350312\n  Bound result 0\n  Bound result 10979\n  Bound result 1009\n  Bound result 40650\n  Bound result 67\n  Bound result 58118\n  Bound result 7\n\n[PASS] test_HandlerExercisesSuccessRejectionRecoveryAndBothOutcomes() (gas: 4305366)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 1\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 33.53s (33.53s CPU time)\n\nRan 5 test suites in 33.53s (35.50s CPU time): 63 tests passed, 0 failed, 0 skipped (63 total tests)\n","passed":true},{"durationMs":43,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SqueekPredict.bet(uint256,bool)\",\"SqueekPredict.cancelExpired(uint256)\",\"SqueekPredict.cancelUnmatched(uint256)\",\"SqueekPredict.claim(uint256,address)\",\"SqueekPredict.createMarket(uint64,uint64,uint64)\",\"SqueekPredict.resolve(uint256)\"],\"files\":{\".gitignore\":3,\"LICENSE\":21,\"README.md\":131,\"THIRD_PARTY.md\":8,\"docs/CORE_INTEGRATION.md\":26,\"docs/SECURITY_REVIEW.md\":37,\"docs/core-observation.json\":19,\"foundry.toml\":19,\"frontend/abi.json\":716,\"frontend/app.js\":218,\"frontend/core-abi.json\":265,\"frontend/helpers.js\":30,\"frontend/index.html\":87,\"frontend/styles.css\":64,\"frontend/vendor/ethers-6.15.0.umd.min.js\":1,\"frontend/vendor/ethers-LICENSE.md\":21,\"remappings.txt\":1,\"scripts/read-core.cjs\":58,\"src/SqueekPredict.sol\":284,\"src/interfaces/ISqueekCore.sol\":61,\"test/SqueekPredict.boundaries.t.sol\":310,\"test/SqueekPredict.claims.t.sol\":285,\"test/SqueekPredict.invariant.t.sol\":128,\"test/SqueekPredict.stateful.t.sol\":463,\"test/SqueekPredict.t.sol\":633,\"test/TESTING.md\":80,\"test/frontend.test.cjs\":61,\"test/helpers/PredictTestBase.sol\":69,\"test/mocks/MockSqueekCore.sol\":116,\"test/mocks/TimelineSqueekCore.sol\":69},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e94981930694d6c4153bdb68785cafc1897784ad9f0f141f2eb6a120649494ba","verifiedTreeHash":"2a6393562368db66d15cb4e7c124702ab2af7a85","verifierVersion":"0.1.0+d372f99e"}]}