{"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":"16f57975-37cf-40de-bdb2-a7b3e6c487e2","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"03a1a127cfdf54bf139f69eddc74e2cfdf1e97fc9d66db8bce3ec1f53a0d8c9f","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"cbb28491b614310b2624094dfa7a7b2775b9b28040ca65a2ca09ac1cccfcf71c","dependsOn":["adapt_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"1591fcbd5f2463034a8660e6065fa280bbdcdd4aadf2739cf8ef69d5cf4755a9","dependsOn":["adapt_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"17aeddfd1f51835fc5d2035b52c26deda411dda5efee63cddaec34dc58ded08d","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"e2d12aa6acb1ada6b89289512839b692804677c1c185ab05ced2ebd582e65dec","dependsOn":["adapt_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"1210a5a74cc22bfc21eccdb37f739b02a37695ff48ebaf51a729783a19a3b45e","dependsOn":["adapt_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"2a2fd7a65b9bd84892cb4481cb49fcc340bea6c52cd872fcb18a098714ee26ad","dependsOn":["adapt_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"45cf668f7888846507ba10cc38e7afb0ac245b414ab00e3d17bca8df23a62584","dependsOn":["audit_imported_code","adapt_contract_project","write_foundry_tests"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"2ff4cd3d0c93716cffb04b2d564e0c93b29f1715e2fbced53a1687aa1d7f4b26","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Launch hmm from this repository as it is: a custom_token launch on Ethereum mainnet, paired with IMD.\n\nToken: contract HmmToken (src/HmmToken.sol), name \"hmm\", symbol HMM, 18 decimals, constructorArgs [], totalSupply 1000000000000000000000000000 (1,000,000,000 HMM minted once to msg.sender, the factory). No owner, no mint or burn after construction, no fee or rule on transfer.\n\nApplication contracts, in this order:\n1. SwarmOracleAdapter (src/SwarmOracleAdapter.sol), constructorArgs [\"0xa43e6f75ee006411f79ac1c84120606c2330de82\", \"0x5598aa9146215bc13eb26f2c692ad1461fd32982\", \"5\", \"4\"]\n2. HmmMine (src/HmmMine.sol), constructorArgs [\"$token\", \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\", \"0xa43e6f75ee006411f79ac1c84120606c2330de82\", \"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\", \"0x876c2fb3eaa91d32ef03186853bb82433b949a71\", \"$contract:SwarmOracleAdapter\", \"0x39c593c1bc4d91e42d797456077586f6058ebf67\", \"500\", \"600\", \"15552000\", \"0\"]\n\nSwarmOracleAdapter takes no mine argument: HmmMine's constructor calls bind() on the SwarmOracleAdapter deployed just before it (an earlier contract of this launch, in the same transaction), which claims it; it moves no tokens. No constructor argument is the zero address. The fourth HmmMine argument is bytes32(\"oracle.request@oracle-1\").\n\nEconomics, copied into launch.json exactly: poolBps 2500, initialMarketCapWei 10000000000000000000000 (10,000 IMD), remainderTo 0x876c2fb3eaa91d32ef03186853bb82433b949a71.\n\nThe remainder goes to the GenesisForwarder at 0x876c2fb3eaa91d32ef03186853bb82433b949a71, deployed earlier from src/GenesisForwarder.sol with registry 0x7c9d5ee697bff5ac4f10e2e54d3f40c44e48fe23 and mineName bytes32(\"HmmMine\"). After launch, anyone calls forward(launchNumber): it reads this launch from the registry, checks the HmmMine artifact mines this token and names this forwarder, moves the whole remainder into it and starts mining.\n\nWhat it does: HMM is mined by asking the IMD swarm. Anyone proposes a question in HmmMine (the mine writes the oracle.request JSON itself from validated fields) and backs it with IMD; once it holds the Intake price it is asked through the IMD Intake (requestWithFailure) with SwarmOracleAdapter as the callback target. Answers signed by the IMD oracle signer for the adapter (panel >= 5, quorum >= 4, agreed >= quorum and a majority) credit the current 10-minute round; backers share the round's emission pro-rata to IMD paid. Emission halves every 180 days and never exceeds the reserve; 5% of each round goes to the dev address. HmmMine has no steward: it takes no steward argument and its steward stays zero forever, so nobody can change the adapter, the action id or any rule after launch; there are no owner powers at all.\n\nKeep contract logic, names, constructor arguments, fee rules and permissions exactly as they are; adapt the Foundry project only as much as the launch factory requires. The test suite (forge test) must stay green.","parentJobId":null,"planHash":"c4d022a2b748a2f77f27ad215192f51f9aaa84173f7ce1300dc3d62ba1dbe412","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"16f57975-37cf-40de-bdb2-a7b3e6c487e2","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1558-launch-hmm-repository-custom-token"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"53916","feedbackHash":"ff5645e8f4c77f7f9c9a58485de98c22fe836b1a041ee83511811a5867f6f812","nodeKey":"adapt_contract_project","submissionHash":"03a1a127cfdf54bf139f69eddc74e2cfdf1e97fc9d66db8bce3ec1f53a0d8c9f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52174","feedbackHash":"57deb6d4c4b421be305b493009a92c549c868ec25027d565a524c50a1adda2c2","nodeKey":"audit_economics","submissionHash":"cbb28491b614310b2624094dfa7a7b2775b9b28040ca65a2ca09ac1cccfcf71c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51316","feedbackHash":"a2babff66e8052a1d04c9a571ff445e0a6e91e79865a670af05b03a0785237e2","nodeKey":"audit_flow","submissionHash":"1591fcbd5f2463034a8660e6065fa280bbdcdd4aadf2739cf8ef69d5cf4755a9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52621","feedbackHash":"ede5d3ad8c3ff4a5fa7cd928ebdeb7fdc2e7ee0bd84b760e7ed3ebaf798e55b8","nodeKey":"audit_imported_code","submissionHash":"17aeddfd1f51835fc5d2035b52c26deda411dda5efee63cddaec34dc58ded08d","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51234","feedbackHash":"d5a6addf15fc77203c13333c65cf11c3e6a4b493af8d64e6e24819087f0b3097","nodeKey":"audit_judge","submissionHash":"e2d12aa6acb1ada6b89289512839b692804677c1c185ab05ced2ebd582e65dec","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51250","feedbackHash":"4eb20fff9a7b7c3e0507f6af669c93477621eebbccba16875c3aadbd983c96f2","nodeKey":"audit_math","submissionHash":"1210a5a74cc22bfc21eccdb37f739b02a37695ff48ebaf51a729783a19a3b45e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51347","feedbackHash":"f21314623960fb4a171a0c5575455c688993f56f19c22787de2a4c3ad079669d","nodeKey":"audit_permissions","submissionHash":"2a2fd7a65b9bd84892cb4481cb49fcc340bea6c52cd872fcb18a098714ee26ad","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52091","feedbackHash":"7cdce93b13685aaf8c293d11a2c8067b033a84c425d17b3a3067304c27662525","nodeKey":"manifest","submissionHash":"45cf668f7888846507ba10cc38e7afb0ac245b414ab00e3d17bca8df23a62584","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51156","feedbackHash":"1a517f8571ff84a50cf728c6d4c18e22ee1481d8a2bb16202cb4d59cba72c482","nodeKey":"write_foundry_tests","submissionHash":"2ff4cd3d0c93716cffb04b2d564e0c93b29f1715e2fbced53a1687aa1d7f4b26","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"f39b6db7e30f08bcdd3b7dbc35da04a41d1083f9d8f28f220ac0b5126b515bf4","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"38b31d2c248cdcc8a286ff78532336ac98f941e51edfa16d870cf71d283958d6","device":"505a745a77612e11","findings":[],"hash":"03a1a127cfdf54bf139f69eddc74e2cfdf1e97fc9d66db8bce3ec1f53a0d8c9f","nodeId":"ab3539fe-01f3-4fb2-b324-a6c21b810724","outcome":"completed","summary":"Implemented six reproduced audit fixes; all eight findings are documented in [ADAPTATION.md](ADAPTATION.md).\n\nValidation passed:\n\n- `forge build`\n- `forge test`: 105 tests\n- Mainnet-fork rehearsal: 5 tests\n\nConstructor arguments, token behavior, fees, economics, and protected build files remain unchanged. Late HMM still does not enlarge the mining reserve.","treeHash":"b46d07c33c1a3c4c0d3e6f42817450e9ea161e60","usage":{"cachedInputTokens":3442688,"inputTokens":165862,"model":"gpt-6-astra","outputTokens":42386,"runtime":"codex","turns":8,"wallClockMs":1551302}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0cf632e317dfab7a","findings":[{"citation":"resolved","description":"HmmMine.start() (src/HmmMine.sol:288 `if (genesis != 0) return;`) is a silent no-op once genesis is set, and reserve/baseRate are fixed by the first call only. GenesisForwarder.forward(n) is permissionless and unconditional: any HMM that reaches the forwarder after the first forward (a mistaken transfer, a second remainder) is transferred to the mine and then start() returns without touching reserve. emittedAt() is bounded by reserve (sum over 64 eras of baseRate*eraLength halvings <= reserve), claims and payDev draw only from assigned <= reserve, and HmmMine has no sweep, so the extra HMM is permanently unrecoverable. The comment on line 62 says start() reverts in that case, which is the opposite of what the code does; the manifest notes already record this as an accepted limitation (\"late HMM can reach the mine but remains outside its reserve and is unrecoverable\"). Reported at low severity because only a holder sending HMM to the forwarder after launch loses it (self-inflicted), not a backer or the launch reserve. Boundary: external call site forward -> mine.start(); assumption (per the comment): a second start reverts and rolls the transfer back; actual: the transfer stands and start() is a no-op.","line":62,"path":"src/GenesisForwarder.sol","reproduction":"State: the launch has been forwarded (mine.started() == true, reserve == 650,000,000e18). Steps: (1) any HMM holder transfers 1e18 HMM to the forwarder 0x876c2fb3eaa91d32ef03186853bb82433b949a71; (2) anyone calls forwarder.forward(launchNumber). Expected (per the comment): revert, tokens stay in the forwarder. Actual: hmm.balanceOf(mine) grows by 1e18, mine.reserve() stays 650,000,000e18, mine.emittedAt(genesis + 100*eraLength) == mine.emittedAt(genesis + 64*eraLength) <= reserve, and no function of HmmMine can transfer the extra 1e18 out. Verified with a scratch Foundry test (test/scratch/MathBoundary.t.sol test_lateForwardStrands) against the repo's HmmTestBase.","severity":"low","snippet":"        IHmmMine(mine).start(); // reverts if this mine already started","title":"GenesisForwarder.forward after the mine has started moves HMM into the mine outside its reserve, where no path can ever emit it; the inline comment claims start() reverts instead"},{"citation":"resolved","description":"This is documented design (NatSpec lines 24-25: \"A round with no answer emits nothing; what it would have emitted rolls into the next round that gets one\"), not a defect in the arithmetic: the first credit of round r assigns emittedAt(roundEnd(r)) - assigned, i.e. the integral of the halving schedule over every unanswered round since the last answered one, and the figure is exact (fuzzed by the repo's Emission tests and by the scratch test). It is recorded here because the numbers at launch are large and the launch sequence creates the idle window: genesis is fixed when forward() runs (genesisDelay 0), and the clock runs from that second whether or not anyone asks. With reserve 650,000,000 HMM and eraLength 15,552,000 s, baseRate = 20,897,633,101,852,315,604 wei/s; a steady 600 s round pays 11,911 HMM after the 5% dev share, while the first answered round after 30 idle days pays 51,470,244 HMM (7.9% of the reserve) to the backers of one 0.5 IMD question, and the backlog is winnable by whoever lands the first credited answer. No funds are lost and the reserve bound holds; the requester should decide whether the forward() call and the first questions are timed accordingly.","line":431,"path":"src/HmmMine.sol","reproduction":"Start the mine (forwarder.forward), warp to genesis + 30 days, propose and fully back one question (0.5 IMD), deliver a valid signed answer. rounds(round).reward == 51,470,244,xxx e18 (log from test/scratch/MathBoundary.t.sol test_idleBacklog), whereas with an answer every round each round's reward is baseRate*600*9500/10000 = 11,911 HMM. assigned == emittedAt(roundEnd(round)) exactly.","severity":"info","snippet":"            uint256 cumulative = emittedAt(genesis + (r + 1) * roundLength);\n            uint256 emitted = cumulative - assigned;\n            assigned = cumulative;","title":"First answer after an idle stretch captures every round's emission since the last answered round, so a single 0.5 IMD question can mine the whole backlog (51.47M HMM after 30 idle days vs 11,911 HMM p"}],"hash":"1210a5a74cc22bfc21eccdb37f739b02a37695ff48ebaf51a729783a19a3b45e","nodeId":"a62da6ad-52c5-403e-a37b-bd43d3e0f99b","outcome":"completed","summary":"Review complete. The findings file is written and the scratch checks confirm the arithmetic.\n\n**Result: no math defect that loses funds.** The file `.imd-findings.json` holds two entries and a 23-row coverage record (all 21 listed entry points plus two invariants).\n\n**What I traced in depth (Math Precision, Boundary, Numerical Gap guides):**\n- Emission schedule: `baseRate = balance / (2·eraLength)` floors, the 64-era halving sum stays under the reserve, and era boundaries align with round boundaries at this launch's parameters. Round rewards equal the exact integral of the halving rate, including the round after an era switch.\n- Round opening in `credit`: the cumulative-minus-assigned subtraction cannot underflow because rounds only advance, and the dev share rounds up per round while `devOwed` rounds down, so rewards plus dev never exceed `assigned`. Measured dust was zero over five rounds.\n- Claims: the 512-bit `mulDiv` with 128-bit operands never overflows, the result is bounded by the round reward, floors sum below the reward, and the last claimant takes the exact remainder. A 1-wei completer gets a zero-rounded-then-dust-corrected share and the totals reconcile.\n- Surplus refunds after an Intake price drop, open-state refunds, the funding deadline, the expiry boundary, the 200k callback stipend, and the vendored Intake's `requests` layout all behave as intended.\n\n**Reported:**\n1. Low: a second `GenesisForwarder.forward` after the mine started moves HMM into the mine outside its reserve, where nothing can ever emit it, while the comment on that line says `start()` reverts. Self-inflicted only, and the manifest notes already acknowledge it.\n2. Info: the first credited answer after an idle stretch captures the whole backlog. After 30 idle days one 0.5 IMD question mines about 51.5M HMM versus about 11.9k HMM per steady round. This is documented design, recorded because the launch sequence creates that idle window.\n\n**Commands run:** `forge build` (compiles), `forge test` (123 passed, 0 failed), and `forge test --match-path test/scratch/MathBoundary.t.sol` (5 passed). Slither and Aderyn were not re-run; the supplied static output was checked and every medium-or-higher line is a false positive for this code (exact modular arithmetic, zero sentinels, guarded reentrancy).\n\n**Not verified:** the live IMD token's transfer behaviour on mainnet (no RPC in this environment). The mine pulls and forwards exact amounts, so a fee-on-transfer IMD would break the Intake payment itself, not just the mine.","treeHash":null,"usage":{"cachedInputTokens":2030084,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":44175,"runtime":"claude","turns":39,"wallClockMs":720172}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"6b0a28df3d585600","findings":[],"hash":"1591fcbd5f2463034a8660e6065fa280bbdcdd4aadf2739cf8ef69d5cf4755a9","nodeId":"f10c3fcb-8c16-47a1-bb15-085cdc5d6d40","outcome":"completed","summary":"The findings file is valid and the tree is otherwise untouched (both `.imd-findings.json` and `test/scratch/` are ignored by git). Nothing further is needed from tools.\n\n**Result: no reproducible defect in the assigned area.** `.imd-findings.json` holds an empty findings list and a coverage row for all 21 entry points plus two invariant rows, every one marked `holds`.\n\n**What I checked, against the Execution Trace, Periphery and First Principles guides:**\n\n- **Execution flow within a transaction.** Parameter divergence (`back` amount capping, body hash only on completion), stale reads (price re-read in `_ask`, same `priceOf` the Intake charges), partial updates (all state set before the Intake call, nothing survives a revert), approval residuals (exact `forceApprove`, Intake pulls exactly that), sentinel inputs (zero and unknown ids revert or skip on every entry point).\n- **Across transactions.** Price rise and fall between proposal and ask, expiry versus late callback, foreign Intake requests naming the adapter, duplicate delivery, config mutation (unreachable: steward is zero forever with no way to set it).\n- **Periphery.** The forwarder's registry decode and artifact matching, the vendored Intake's `requests` and `complete` shape, OpenZeppelin 5.7 helpers, the JSON body builder's escaping and size against the Intake's 16 KiB cap.\n- **First principles.** The round reward accounting, the last-claimant dust rule across interleaved claims of two questions, schedule exhaustion after 64 eras, IMD and HMM conservation.\n\n**Evidence gathered beyond reading:**\n\n- The full unit suite passes (123 tests, reduced fuzz runs).\n- The mainnet fork rehearsal passes through the local RPC: real factory, real registry, real Intake callback inside its 200k stipend, deployed forwarder bytecode equal to source.\n- On mainnet, the forwarder at the manifest's `remainderTo` has the expected registry and mine name, and the Intake sells the action at 0.5 IMD with a 200k callback stipend.\n- The live docs list `toleranceBps` as an accepted oracle body key, closing the one lead that would have spent the price on every uint256 question.\n- Four scratch tests under `test/scratch/` confirm the hand-traced edges.\n\n**Leads from static analysis** all resolved as intentional or unreachable: the divide-before-multiply is era arithmetic by design, the strict equalities compare against zero sentinels that cannot be nonzero otherwise, the reentrancy notes sit behind `nonReentrant` or the permanent zero steward, and the `encodePacked` use is string concatenation, not hashing of ambiguous inputs.\n\n**Not reached:** the economics of rollover (one backer after a long idle period receives everything emitted since the last answered round) is documented design and belongs to the economics specialist, not this area.","treeHash":null,"usage":{"cachedInputTokens":1748473,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":38945,"runtime":"claude","turns":37,"wallClockMs":666187}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bfeaa965edf57623","findings":[{"citation":"resolved","description":"A question's `target` is frozen at the Intake price when it is proposed (`q.target = uint128(price)`, line 287). When the question is completed, `_ask` re-reads the live price only to refuse a rise (`live > price`) and then pays the Intake the full frozen `price` (`intake.requestWithFailure(act, body, ..., price)`, line 631). The Intake (test/external/Intake.sol `_request`, verified against the mainnet code at 0xa43e6f75ee006411f79ac1c84120606c2330de82) accepts any `amount >= price` and forwards whatever is paid whole. So if the Intake owner lowers `priceOf(action, IMD)` during a question's 3-day funding window, which the oracle-consumer reference explicitly anticipates (\"a moved price must not need a redeploy\"), every open question overpays the swarm by `target - live` and nothing comes back: the mine holds no surplus (openRaised is decremented by the whole target) and `refund` only serves Open questions. The round shares are still credited at the full `q.target`, so the overpaid backers get no more HMM for it either. Bounded at one price difference per question (at most 0.5 IMD today), but it is a deterministic loss of backer funds caused by a routine admin action on a contract the mine already treats as a trusted dependency. Fix shape: pass `live` to the Intake and keep `price - live` in the mine as refundable backing (reduce `raised`/`target` pro-rata, or re-target the question and let it stay Open), or at least pay `live` and leave the surplus claimable; `shares` can stay the amount actually paid.","line":621,"path":"src/HmmMine.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {HmmToken} from \"src/HmmToken.sol\";\nimport {HmmMine} from \"src/HmmMine.sol\";\nimport {SwarmOracleAdapter} from \"src/SwarmOracleAdapter.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofIMD is ERC20 {\n    constructor() ERC20(\"IMD\", \"IMD\") {}\n\n    function mint(address to, uint256 a) external {\n        _mint(to, a);\n    }\n}\n\n/// @dev The Intake as it behaves for a consumer: `amount` must be at least the price, and whatever is paid is\n/// forwarded whole to `payTo` (test/external/Intake.sol, `_request`: \"Whatever is paid is forwarded whole\").\ncontract ProofIntake {\n    mapping(bytes32 => mapping(address => uint256)) public priceOf;\n    address public payTo;\n    uint256 public nonce;\n\n    constructor(address payTo_) {\n        payTo = payTo_;\n    }\n\n    function setPrice(bytes32 action, address asset, uint256 amount) external {\n        priceOf[action][asset] = amount;\n    }\n\n    function requestWithFailure(bytes32 action, bytes calldata, IIntake.Callback calldata, bytes4, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32 requestId)\n    {\n        uint256 price = priceOf[action][asset];\n        require(price != 0 && amount >= price, \"PriceNotMet\");\n        requestId = keccak256(abi.encode(block.chainid, address(this), ++nonce));\n        ERC20(asset).transferFrom(msg.sender, payTo, amount);\n    }\n}\n\n/// @notice Fails on the current code: when the Intake price falls while a question is raising, `_ask` still pays the\n/// stale `q.target` (0.5 IMD) for an answer that costs 0.25 IMD, and the difference is gone. Passes once the mine\n/// pays the live price and keeps the surplus for its backers (or refuses to overpay).\ncontract PriceDropProof is Test {\n    bytes32 constant ACTION = bytes32(\"oracle.request@oracle-1\");\n    address payTo = makeAddr(\"payTo\");\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n    ProofIMD imd;\n    ProofIntake intake;\n    HmmToken hmm;\n    SwarmOracleAdapter adapter;\n    HmmMine mine;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        imd = new ProofIMD();\n        intake = new ProofIntake(payTo);\n        intake.setPrice(ACTION, address(imd), 0.5 ether);\n        hmm = new HmmToken();\n        adapter = new SwarmOracleAdapter(address(intake), makeAddr(\"signer\"), 5, 4);\n        address forwarder = address(this);\n        mine = new HmmMine(\n            address(hmm), address(imd), address(intake), ACTION, forwarder, address(adapter), makeAddr(\"dev\"), 500, 10 minutes, 180 days, 0\n        );\n        hmm.transfer(address(mine), 650_000_000 ether);\n        mine.start(); // this test contract is the forwarder\n        imd.mint(alice, 10 ether);\n        imd.mint(bob, 10 ether);\n        vm.prank(alice);\n        imd.approve(address(mine), type(uint256).max);\n        vm.prank(bob);\n        imd.approve(address(mine), type(uint256).max);\n    }\n\n    function _spec() internal pure returns (HmmMine.Spec memory) {\n        return HmmMine.Spec(\"Did block 1 exist\", 0, 0, 1, 24, 5, 4, 0);\n    }\n\n    function test_priceDrop_mineMustNotPayMoreThanTheLivePrice() public {\n        vm.prank(alice, alice);\n        uint256 id = mine.propose(_spec(), 0.3 ether); // target 0.5, raised 0.3\n        intake.setPrice(ACTION, address(imd), 0.25 ether); // the Intake owner lowers the price\n        bytes memory body = mine.bodyOf(_spec());\n        vm.prank(bob, bob);\n        mine.back(id, 0.2 ether, body); // completes the target: the question is asked now\n        assertEq(uint8(mine.question(id).status), uint8(HmmMine.Status.Asked), \"asked\");\n        // The swarm's live price is 0.25 IMD; the backers put in 0.5. The Intake must receive the live price and the\n        // surplus must still be in the mine, on the backers' side of the ledger.\n        assertEq(imd.balanceOf(payTo), 0.25 ether, \"the Intake was paid more than the live price\");\n        assertEq(imd.balanceOf(address(mine)), 0.25 ether, \"the backers' surplus left the mine\");\n    }\n}","reproduction":"State: mine live, Intake price 0.5 IMD. 1) alice (EOA) calls propose(spec, 0.3e18): question 1 Open, target 0.5e18, raised 0.3e18. 2) The Intake owner calls setPrice(action, IMD, 0.25e18). 3) bob (EOA) calls back(1, 0.2e18, bodyOf(spec)): raised reaches 0.5e18, `_ask` sees live 0.25e18 <= price 0.5e18 and calls requestWithFailure(..., 0.5e18). Expected: the Intake receives the live price 0.25 IMD and the mine keeps 0.25 IMD for alice and bob. Actual: imd.balanceOf(payTo) == 0.5e18, imd.balanceOf(mine) == 0, question Asked, openRaised 0; no path returns the 0.25 IMD. Proof: test/scratch/PriceDropProof.t.sol, which fails on the current code with `the Intake was paid more than the live price: 500000000000000000 != 250000000000000000`.","severity":"medium","snippet":"        if (live > price) revert PriceRose(live, price);","title":"_ask pays the question's stale target after the Intake price falls; the surplus is lost to the backers"},{"citation":"resolved","description":"The guard protects other backers from a completing call that already made an Intake request in the same transaction, because the swarm serves only the first request of a transaction (imd.fun/docs, Pay on chain > Limits: \"A transaction with several is recorded, and only the first is served\", read 2026-10-13). It checks `msg.sender == tx.origin`, which a contract cannot satisfy (verified: a plain contract completer reverts CompleterMustBeEOA), but an EOA with EIP-7702 delegated code, live on Ethereum mainnet since Pectra, satisfies it while executing a batch. The attacker's batch sends `intake.request(...)` for a question of their own and then `mine.back(id, left, body)` on a question holding other backers' IMD. The mine's request is the second in the transaction and is never served: the backers' IMD is spent, the question stays Asked and mines nothing. The attacker pays the Intake price for their own answer plus the completing backing (at least 0.01 IMD), so this is griefing at a cost at least equal to the damage, and docs/SECURITY.md lists it as a known limitation. Reported so the adapter and the next panel see the acknowledged residual: the mine has no on-chain way to tell whether the Intake was already asked in this transaction (the Intake's `nonce` is public, but a pre-call snapshot is not available to the mine).","line":600,"path":"src/HmmMine.sol","reproduction":"State: question 1 Open with alice's 0.49 IMD (target 0.5). Attacker EOA `E` with a 7702 delegation to a batch executor. One transaction from E: (a) E.execute([ intake.request(action, ownBody, Callback(E, sel), IMD, 0.5e18), mine.back(1, 0.01e18, body) ]). In the second call msg.sender == E == tx.origin, so the check passes; `_ask` runs, the mine pays 0.5 IMD and emits Asked. Expected: a completing call that already asked the Intake in this transaction is refused, as the comment intends. Actual: the mine's request is the transaction's second; per the swarm's limit only the first is served, so question 1 stays Asked forever and alice's 0.49 IMD bought nothing. (Foundry cannot set a 7702 delegation on tx.origin, so the on-chain path is described rather than attached; the contract-completer refusal was confirmed in test/scratch/Review.t.sol.)","severity":"low","snippet":"            if (mine_ != raised && msg.sender != tx.origin) revert CompleterMustBeEOA();","title":"EIP-7702 delegated EOAs pass the direct-caller check and can strand a pooled question's payment behind their own Intake request"},{"citation":"resolved","description":"The mine writes the oracle body itself from `Spec`, which is the right defence against body injection, but the body it writes has no `definitions` and no `allowAmbiguous`. The swarm's wording screen refuses a question with more than one reasonable reading (status 1, `body_refused`), and the reference says to pin the reading in `definitions`. Against the live free check (POST https://api.imd.fun/requests/check, action oracle.request, 2026-10-13) two plain factual questions were both refused as `ambiguous_question`: \"Did the IMD token at 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7 have more than one Transfer event on Ethereum mainnet in the window\" and \"How many HMM were transferred on Ethereum mainnet in the window\". On chain the same body is paid for, then `onOracleFailure(status 1, body_refused)` reaches `fail`: the question becomes Failed, the IMD is gone, and `refund` refuses (status != Open). A proposer who does not run the site's pre-check, or whose backers join a question that was never checked, loses the full price. Every other body field the mine writes was verified valid against the paid schema (v, window.hours, quorum, validForSeconds, toleranceBps for uint256, and the five chain ids match the swarm's live list exactly). This is a product limitation rather than a code error, reported so the adapter can decide whether `Spec` should carry a bounded `definitions` map (keys <= 64, values <= 512 characters, same character rules as `question`).","line":436,"path":"src/HmmMine.sol","reproduction":"Input: propose(Spec{question: \"Did the IMD token at 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7 have more than one Transfer event on Ethereum mainnet in the window\", answerType 0, evidence 0, chainId 1, windowHours 24, panelSize 5, quorum 4, toleranceBps 0}, 0.5e18) from an EOA. The mine pays 0.5 IMD and asks. The swarm's screen refuses it (the free check returned blocker `ambiguous_question` for this exact question); the writer completes with status 1 and reason body_refused; the adapter calls fail(). Expected by a backer: an unanswerable question costs nothing or can be reworded. Actual: status Failed, 0.5 IMD spent, refund(id) reverts NotRefundable.","severity":"low","snippet":"    function bodyOf(Spec calldata spec) public pure returns (bytes memory) {","title":"Spec cannot carry definitions or allowAmbiguous, and the swarm's wording screen refuses ordinary questions: a refusal spends the backers' price with no refund"},{"citation":"resolved","description":"`forward` is the only way tokens leave the forwarder, and it always ends by calling `start()`, which reverts AlreadyStarted after the first call. So once the launch's reserve has been forwarded, any HMM transferred to 0x876c2fb3eaa91d32ef03186853bb82433b949a71 (by mistake, or by a holder who believes sending HMM there grows the mine) is locked forever: `forward(n)` reverts at `start()`, there is no sweep, and the contract is immutable. The same applies to HMM sent straight to the mine after `start` (documented at line 254: never emitted), so there is no address in the system that can accept HMM later. Low: no attacker gains, but a deployed, permissionless contract with a well-known address is a plausible destination for mistaken transfers. A fix that keeps the design is to let `forward` transfer and skip `start()` when `started()` is already true, so late arrivals at least reach the mine, or to refuse the transfer when the mine has started.","line":62,"path":"src/GenesisForwarder.sol","reproduction":"State: forward(launchNumber) already ran (mine.started() == true). 1) anyone transfers 1e18 HMM to the forwarder. 2) anyone calls forward(launchNumber). Expected: either the 1 HMM moves on or the transfer is impossible. Actual: `forward` transfers the 1 HMM to the mine and then `start()` reverts AlreadyStarted, undoing the transfer; hmm.balanceOf(forwarder) stays 1e18 permanently (test/scratch/Review.t.sol test_hmmSentToForwarderAfterStart_isStuck).","severity":"low","snippet":"        IHmmMine(mine).start(); // reverts if this mine already started","title":"HMM that reaches the GenesisForwarder after it has started the mine is unrecoverable"},{"citation":"resolved","description":"The adapter has no constructor binding (removed because the launch checker refuses zero-address arguments). `bind()` is public and the first caller becomes `mine`, after which the adapter credits that address's questions. In this launch HmmMine's constructor calls bind() in the same `launchCustom` transaction as the adapter's deployment, and the Intake-side checks (`requests(requestId).target == this`, the mine's `questionOf`) mean a stranger who did bind an adapter could not credit anything on the real mine. The residual risk is operational: an adapter deployed on its own (a redeploy, a manual deployment to the same bytecode) can be claimed by anyone, and the mine that then tries to bind it reverts AlreadyBound, which for a launch means the whole launch transaction reverts. The launch factory's atomic deployment makes this unreachable here; noted so that nobody deploys the adapter separately.","line":105,"path":"src/SwarmOracleAdapter.sol","reproduction":"State: SwarmOracleAdapter deployed in a transaction that does not also deploy HmmMine. 1) attacker calls adapter.bind(): mine = attacker. 2) HmmMine's constructor later calls bind(): bound != msg.sender and bound != 0, revert AlreadyBound(attacker); the deployment fails. In the launch as described both deployments are in one transaction, so step 1 cannot interleave.","severity":"info","snippet":"        mine = msg.sender;","title":"bind() is first-caller-wins configuration after deployment; it is safe only because the mine claims it inside the launch transaction"},{"citation":"resolved","description":"The oracle-consumer reference requires every pending request to have a deadline after which it can be cleared, because a callback or failure call can run out of gas, revert or never come (the Intake attempts it once). The mine has no such path: a question whose callback is not delivered (writer never completes, `complete` with malformed args, a second request in the same transaction, a `credit` that reverts) stays `Asked` forever. No funds are at stake, since the IMD already left for the Intake and the mine promises no refund after the ask, so this is a liveness and reporting gap: `questionOf`, `stats` and front ends show the question pending indefinitely and backers cannot distinguish it from one still being answered.","line":625,"path":"src/HmmMine.sol","reproduction":"State: question 1 Asked with requestId R. The writer completes R with status 0 and args whose Attestation offsets are malformed, or with a request body the plane never picks up. Expected: after some deadline anyone can mark question 1 Failed. Actual: there is no function that moves an Asked question without a call from `q.adapter`, and the adapter only acts inside an Intake callback; the question stays Asked permanently.","severity":"info","snippet":"        q.status = Status.Asked;","title":"An Asked question has no terminal deadline when the Intake never delivers a callback"},{"citation":"resolved","description":"`claimable` floors each backer's share of `round.reward`, so a round with k backers can leave up to k-1 wei of HMM unclaimed. `assigned` already counts that HMM as emitted, so `emittedAt - assigned` never re-issues it and no function sweeps it; it stays in the mine forever. The amounts are negligible (wei per round) and the conservation invariant in the tests holds because it measures the mine's balance, so this is an accounting note only; a round's last claimant could be given the remainder if exactness is wanted.","line":478,"path":"src/HmmMine.sol","reproduction":"State: round reward 10 wei, two questions answered in it with target 3 and 4 (shares 7), each backed by its proposer. claimable(q1) = floor(10*3/7) = 4, claimable(q2) = floor(10*4/7) = 5. Expected: 10 wei leave the mine for the round. Actual: 9 leave, 1 wei stays, and the next round's emission is computed from `assigned`, which already includes it.","severity":"info","snippet":"        return Math.mulDiv(round.reward, amount, round.shares);","title":"Per-backer reward rounding leaves dust in the mine that is neither claimable nor re-emitted"},{"citation":"resolved","description":"Read in full: src/HmmToken.sol, src/HmmMine.sol, src/SwarmOracleAdapter.sol, src/GenesisForwarder.sol, src/interfaces/{IHmmMine,IIntake,ILaunchRegistry,IOracleAdapter}.sol, test/external/Intake.sol (the vendored Intake v2), test/utils/*, test/fixtures/RealAttestations.sol, script/HmmLaunch.sol, launch/config.json and launch/body.json, docs/SECURITY.md, the protected custom_token test, and the Pashov and oracle-consumer references. Checked: forge test (80 tests) green; the mainnet-fork rehearsal (test/fork/Launch.fork.t.sol, 4 tests) run against a public mainnet RPC passes through the real ProjectFactory, LaunchRegistry, Intake and IMD; HmmToken is a plain OpenZeppelin ERC-20 with no owner, mint, burn, pause, fee, delegatecall or selfdestruct, bytecode_hash is none, and all runtimes are under EIP-170 (HmmMine 15,031 bytes). Verified on Ethereum mainnet on 2026-10-13: the GenesisForwarder at 0x876c2fb3eaa91d32ef03186853bb82433b949a71 has exactly the runtime that src/GenesisForwarder.sol compiles to, with registry 0x7c9d5ee697bff5ac4f10e2e54d3f40c44e48fe23 and mineName bytes32(\"HmmMine\") as its immutables; that registry is ProjectFactory(0xff03410d0fe5fa8f7f59f743de35e333d9857120).registry(); a recorded launch (1500) decodes with the repository's ILaunchRegistry ABI; Intake 0xa43e6f75ee006411f79ac1c84120606c2330de82 sells the action at 0.5 IMD, has callbackGas 200000 and a `requests` getter of the shape the adapter reads, and its runtime equals the vendored copy except for immutable slots; the swarm's live oracle chain list is exactly {1, 56, 4663, 8453, 42161} as _checkSpec allows, and `toleranceBps` is a valid paid-body key. The adapter's EIP-712 encoding is pinned by five real attestations signed by the oracle signer 0x5598aa9146215bc13eb26f2c692ad1461fd32982 (test_realSwarmSignatures_recoverTheOracleSigner). The launch manifest inputs in the task (names <= 32 characters, 11 HmmMine arguments in declaration order, the action word decoding to \"oracle.request@oracle-1\", no zero address) are consistent with the constructors. Not reachable or not reviewed: the IMD token's own source (an owned, non-proxy contract at 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7; the mine assumes it is a plain ERC-20, which the fork rehearsal supports), the ProjectFactory and LaunchRegistry sources beyond their on-chain behaviour, the oracle writer's off-chain pairing of answers to requests, and the web front end. No critical or high defect was found: access control, reentrancy guards, round accounting, emission bounds and signature verification hold against the Pashov checklist, and no minting, pausing, freezing, delegatecall, proxy or post-deployment initializer exists beyond bind() noted above.","line":33,"path":"src/HmmMine.sol","reproduction":"Not a defect; see description. The suite ran with `forge test` and `FOUNDRY_PROFILE=fork MAINNET_RPC_URL=https://ethereum-rpc.publicnode.com forge test --match-path 'test/fork/**'`.","severity":"info","snippet":"contract HmmMine is IHmmMine, ReentrancyGuardTransient {","title":"Scope: what was read, what was verified against mainnet, and what could not be reached"}],"hash":"17aeddfd1f51835fc5d2035b52c26deda411dda5efee63cddaec34dc58ded08d","nodeId":"73cdc2b3-fb2b-4828-9618-9e477d38c2f1","outcome":"completed","summary":"The review is complete. The findings file is written at `.imd-findings.json` with eight entries, and the working tree is otherwise untouched.\n\n**Verdict.** No critical or high defect. The contracts hold up against the Pashov checklist: access control on every state change is correct, reentrancy guards cover all value paths, round emission never exceeds the reserve, rewards plus the dev share never exceed what was assigned, and the adapter's EIP-712 verification matches five real oracle signatures. The token is a plain fixed-supply ERC-20 with nothing the launch floor forbids.\n\n**Findings, by severity**\n\n- **Medium, HmmMine `_ask`.** If the Intake owner lowers the price while a question is raising, the mine still pays the frozen target and the difference is lost to the backers. Proof attached: a Foundry test that fails on the current code and passes once the mine pays the live price.\n- **Low, direct-caller guard.** An EIP-7702 delegated EOA passes the `tx.origin` check, so it can put its own Intake request first and strand a pooled question's payment. The swarm's docs confirm only the first request per transaction is served. The author already lists this as a known limitation.\n- **Low, Spec has no definitions.** The swarm's wording screen refused two plain factual questions as ambiguous on its live check endpoint. A refusal on chain spends the backers' price with no refund.\n- **Low, GenesisForwarder.** HMM sent to the forwarder after it has started the mine is locked forever.\n- **Info.** `bind()` is first-caller-wins post-deployment configuration, safe only because the launch binds it atomically. Asked questions have no terminal deadline. Reward rounding leaves dust in the mine. A scope entry lists what was read and verified.\n\n**Verified against mainnet.** The pre-deployed forwarder's runtime matches the source with the right registry and mine name baked in. That registry is the factory's. The Intake sells the action at the expected price with a 200,000 gas callback stipend, and its code matches the vendored copy apart from immutables. The swarm's live chain list and body schema match what the mine writes. The repository's mainnet-fork rehearsal passed against the real factory, registry, Intake and IMD.\n\n**Not reachable.** The IMD token's source, the factory and registry sources beyond on-chain behaviour, the oracle writer's off-chain pairing, and the web front end.","treeHash":null,"usage":{"cachedInputTokens":2023144,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":50842,"runtime":"claude","turns":40,"wallClockMs":769829}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"af9a875696459139","findings":[{"citation":"resolved","description":"Access x asymmetry seam. Every other state change on a question is restricted to a party with a stake in it: backing and refunds move only msg.sender's own IMD, credit/fail come only from the question's adapter, start only from the forwarder. expire() is the one exception: any address, with no stake, may terminate someone else's Asked question once answerDeadline(id) (7 days after the ask) has passed. The Intake request itself never expires and the oracle attestation is valid for 86400 s from issuance, so a late answer is still perfectly good when a stranger closes the question. credit() then reverts NotAsked inside the Intake callback (test/HmmMine.sol credit: `if (id == 0 || q.status != Status.Asked) revert NotAsked();`), the Intake records the completion as not delivered and never retries, and the backers' 0.5 IMD stays spent for nothing. The stranger has a concrete motive: a round's emission is split pro-rata among the questions credited in it, and after a dormant period the first credited round carries everything emitted since the last answered round, so a backer of another pending question profits by closing a competitor's question moments before the writer's completion lands. docs/SECURITY.md documents that anyone may expire, but the asymmetry with refund() (own backing only) and the irreversible loss for third parties make this a guard weaker than its effect. Preconditions: the swarm's completion is more than 7 days late (an outage of the plane or writer), which is abnormal but not privileged. Minimal fix that preserves the design: restrict expire(id) to an account with backing[id][msg.sender] != 0 (or the proposer), or make the 7-day deadline advisory by letting a later valid completion still credit while only a backer may close. Severity low: requires the >7 day delay; the loss is bounded by one question's backing and the round share it would have mined.","line":375,"path":"src/HmmMine.sol","reproduction":"State: mine started, Intake price 0.5 IMD. (1) alice (EOA) calls propose(spec, 0.5e18): question id=1 is Asked, requestId rid, alice's 0.5 IMD is paid to the Intake's payTo, answerDeadline(1) = T+7 days. (2) At T + 7 days + 1 s the oracle signs a valid attestation for the adapter (panel 5, quorum 4, agreed 5, expiresAt = now + 86400); adapter.check(a, sig) returns bytes32(0). (3) stranger (no backing in question 1) calls mine.expire(1): succeeds, status becomes Failed, event Failed(1, rid, 2, 'timeout'). (4) The writer's intake.complete(rid, 0, ..., abi.encode(rid, a, sig)) runs the adapter callback: onOracleResult -> credit(rid) reverts NotAsked, the callback reverts, Completed(..., delivered=false). Actual: mine.assigned() == 0, claimable(1, alice) == 0, alice's 0.5 IMD remains at payTo, refund(1) reverts NotRefundable. Expected: a stranger with no stake cannot turn a question with a valid in-flight answer into a permanent loss for its backers; only a backer (or nobody while the Intake request is still open) should be able to close it. A passing demonstration of exactly this sequence is in test/scratch/ExpireGriefing.t.sol (test_strangerExpiresAQuestionWhoseValidAnswerIsAboutToLand); it is a behaviour test, not a fix-gated proof.","severity":"low","snippet":"    function expire(uint256 id) external nonReentrant {\n        Question storage q = _questions[id];\n        if (q.status != Status.Asked) revert NotAsked();\n        uint256 deadline = answerDeadline[id];\n        if (block.timestamp <= deadline) revert TooEarly(deadline + 1);\n        q.status = Status.Failed;\n        emit Failed(id, q.requestId, 2, \"timeout\");\n    }","title":"Permissionless expire() lets any stranger void a still-valid oracle answer and the backers' spent IMD with it"}],"hash":"2a2fd7a65b9bd84892cb4481cb49fcc340bea6c52cd872fcb18a098714ee26ad","nodeId":"f4c190cf-ab9f-4918-b4c7-c46d263a43fc","outcome":"completed","summary":"The review is complete. The findings file is valid, every entry point has a coverage row, and the working tree is unchanged apart from the ignored report and scratch directory.\n\n## Result\n\n**One low-severity finding, no critical or high defects.** The permission model of this launch holds: the token has no owner, the mine has no steward and no path to ever name one, `credit` and `fail` are reachable only through the Intake-called adapter, and `start` only through the fixed forwarder.\n\n**Finding 1 (low), `expire(uint256)` in src/HmmMine.sol:375.** Any address with no stake may close someone else's Asked question seven days after the ask, although the Intake request never expires and a late oracle answer is still valid for a day. The writer's completion then reverts inside the callback, the Intake records it as undelivered and never retries, and the backers' spent IMD mines nothing. A competitor with a pending question in the same round profits from the larger share. Every other question mutation is restricted to a party with a stake, so this guard is weaker than its effect. It needs a swarm delay of more than seven days, hence low. A behaviour test for the exact sequence is in test/scratch/ExpireGriefing.t.sol.\n\n## What I verified\n\n- **Access control**: all 21 entry points traced; the steward surface is dead code (no constructor argument, `onlySteward` everywhere that writes pending config).\n- **Trust gap**: outsider Intake requests naming the adapter cannot credit or fail a mine question; the writer's documented powers (timing of completions, pairing an attestation with an undelivered request) are trust assumptions, recorded in coverage rather than as findings.\n- **Asymmetry**: back/refund deadline boundaries are complementary, surplus refunds and claims are order-independent, round progress gives dust only to the last claimant.\n- **Live state via cast**: forwarder at `0x876c…` has the right registry and mine name, Intake sells the action for 0.5 IMD with a 200k stipend, dev address is an EOA.\n- **Swarm checker**: the mine's body shape, including `toleranceBps` for uint256, matches the normalized body the plane produces; allowed chains and panel limits match the mine's constants.\n- **Fork rehearsal**: all 5 tests pass against a public mainnet RPC.\n\n## Not reached\n\nThe one external assumption I could not confirm independently is how the IMD deployer encodes the registry's `kind` field. The rehearsal supplies that value itself, and no live launch record was found. This is noted in the coverage record.","treeHash":null,"usage":{"cachedInputTokens":3578485,"inputTokens":548,"model":"claude-fable-5-1","outputTokens":63784,"runtime":"claude","turns":64,"wallClockMs":1167339}},{"artifacts":[],"attempt":1,"bundleHash":"f9408a045a8953897aba8f3cf6224a859fe50821ec24352033ac93824f06bab5","device":"1ccda5cdb3f24f3e","findings":[{"description":"SwarmOracleAdapter._check validates expiresAt but never checks issuedAt. The supplied canonical OracleAttestationConsumer rejects issuedAt more than five minutes ahead of block.timestamp. A correctly signed, otherwise eligible attestation outside that window currently returns zero from check(), so onOracleResult can consume it and credit the current mining round before the protocol permits it. This requires a real signer-produced future-dated attestation (for example, an attester clock error or pre-signing); it does not let an untrusted caller forge signatures. Preserve the configured signer and ownerless design while enforcing the canonical five-minute tolerance.","line":184,"path":"src/SwarmOracleAdapter.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SwarmOracleAdapter} from \"src/SwarmOracleAdapter.sol\";\n\n/// @notice The canonical consumer permits at most five minutes of attester clock drift.\ncontract FutureAttestationProof is Test {\n    // The public conformance-vector key, used only to produce test signatures.\n    uint256 constant KEY = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;\n\n    function test_futureIssuedAttestationMustNotYetCount() public {\n        vm.chainId(1);\n        vm.warp(1_800_000_000);\n        SwarmOracleAdapter adapter = new SwarmOracleAdapter(address(this), vm.addr(KEY), 5, 4);\n        SwarmOracleAdapter.Attestation memory a;\n        a.requestId = keccak256(\"future oracle request\");\n        a.chainId = 1;\n        a.questionHash = keccak256(\"question\");\n        a.answer = abi.encode(true);\n        a.panelSize = 5;\n        a.quorum = 4;\n        a.agreed = 4;\n        a.issuedAt = uint64(block.timestamp + 5 minutes + 1);\n        a.expiresAt = a.issuedAt + 1 days;\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY, adapter.digest(a, block.chainid, address(adapter)));\n        bytes memory signature = abi.encodePacked(r, s, v);\n\n        // Check both sides of the reference's tolerance boundary with the same signed attestation.\n        uint256 originalTime = block.timestamp;\n        vm.warp(originalTime + 1);\n        assertEq(adapter.check(a, signature), bytes32(0), \"five minutes of clock drift is allowed\");\n        vm.warp(originalTime);\n        assertNotEq(adapter.check(a, signature), bytes32(0), \"issuedAt beyond the five-minute tolerance must be rejected\");\n    }\n}","reproduction":"Run the attached self-contained proof as test/FutureAttestation.proof.t.sol with forge test --match-path test/FutureAttestation.proof.t.sol -vv. On chain 1 at timestamp 1800000000, sign a fresh 5/4/4 attestation for the adapter with issuedAt=1800000301 and expiresAt=1800086701. At timestamp 1800000001 the signature should be accepted (exactly five minutes of drift); at timestamp 1800000000 it must be rejected. Actual: both checks return bytes32(0), and the final assertNotEq fails. This failure was reproduced locally with forge test --match-path test/scratch/FutureAttestation.proof.t.sol -vv.","severity":"low","title":"Future-issued oracle attestations bypass the canonical validity window"}],"hash":"2ff4cd3d0c93716cffb04b2d564e0c93b29f1715e2fbced53a1687aa1d7f4b26","nodeId":"80f9712f-0c35-4f85-8748-db619116ada6","outcome":"completed","summary":"Added failure-path tests and randomized invariants for the token, ownerless mine, and forwarder.\n\n`forge build` succeeds. `forge test`: **123 passed, 0 failed**.\n\nReported one low-severity defect—future-issued oracle attestations are accepted—with a reproduced failing proof in [.imd-findings.json](/home/imd/.identitymd/work/16f57975-37cf-40de-bdb2-a7b3e6c487e2/80f9712f-0c35-4f85-8748-db619116ada6/.imd-findings.json). Contracts and configuration remain unchanged.","treeHash":"f97d4bffa83bbfe468330519b4787955302feac7","usage":{"cachedInputTokens":2003840,"inputTokens":122441,"model":"gpt-6-astra","outputTokens":24036,"runtime":"codex","turns":8,"wallClockMs":845336}},{"artifacts":[],"attempt":1,"bundleHash":"5ed2f4ddc16fb8d2ddd2c72f8569d8f48dcc312e72aa94476dd50b23cab314f8","device":"79606c6a6e3585fb","findings":[],"hash":"45cf668f7888846507ba10cc38e7afb0ac245b414ab00e3d17bca8df23a62584","nodeId":"cdd8b853-7cc5-4af7-adf9-84b537eb7c08","outcome":"completed","summary":"Created [launch.json](/home/seat24/.identitymd/work/16f57975-37cf-40de-bdb2-a7b3e6c487e2/cdd8b853-7cc5-4af7-adf9-84b537eb7c08/launch.json) with the exact launch parameters and audit notes. No other submitted file changed.\n\nOffline build and all 123 tests passed; extended fuzz checks also passed. Existing formatting issues and one Slither High alert in OpenZeppelin `Math.mulDiv` remain outside the permitted edit scope.","treeHash":"413a8e9d19c77f33e9086fdcb7aa26c7509c8a87","usage":{"cachedInputTokens":1292160,"inputTokens":79156,"model":"gpt-6-astra","outputTokens":11223,"runtime":"codex","turns":6,"wallClockMs":542833}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b4f6137e7c93a2b3","findings":[{"citation":"resolved","description":"Economic Security / break dependencies. Every path that emits HMM runs through two external constants the launch fixes forever: the action word bytes32(\"oracle.request@oracle-1\") priced by the Intake (src/HmmMine.sol:139, read at :320 and :757) and the oracle signer 0x5598... baked immutably into SwarmOracleAdapter (src/SwarmOracleAdapter.sol:53, enforced at :187). HmmMine is launched with steward == address(0) and only the steward can name one (:494), so queueConfig/applyConfig are unreachable and the adapter and action can never change. The oracle-consumer reference the task supplies says these values are expected to move (\"A new action version (oracle-2) or a moved price must not need a redeploy\"; the signer is \"owner-settable, never a constant\"). The actor is the Intake owner 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7 (read live from mainnet; it also owns the IMD token). Preconditions: one ordinary operator action at the Intake (setPrice(action, IMD, 0) when oracle-2 replaces oracle-1, or setSigner / a key rotation at the oracle). Outcome: propose and back revert NotSold forever, or every delivered answer is rejected as bad_signature and each question's 0.5 IMD is spent for nothing; the unemitted part of the ~650,000,000 HMM reserve stays in the mine permanently, since HMM only leaves via claim (needs Answered) or payDev (5% of assigned). The requester states this is intentional and docs/SECURITY.md:54 lists it as a known limitation, so this is not a permission bypass; it is recorded here as the material external-dependency risk the economics rest on. Any mitigation (e.g. a narrowly scoped action-id-only rotation, or a dead-man path that returns the reserve to the pool after N years without an answer) changes the agreed no-admin design and needs a scope decision; nothing in the code is wrong relative to the stated intent.","line":320,"path":"src/HmmMine.sol","reproduction":"State: launched mine, started, reserve R = hmm.balanceOf(mine). (a) Intake owner calls intake.setPrice(bytes32(\"oracle.request@oracle-1\"), IMD, 0). Then alice: mine.propose(spec, 0.5e18) -> reverts NotSold (src/HmmMine.sol:321); for an Open question, the completing back() reverts NotSold (:758); mine.applyConfig() -> NothingQueued; no caller can ever set steward (NotSteward for every msg.sender since steward == 0). Expected by the economics: emission continues or the reserve has an exit; actual: hmm.balanceOf(mine) == R minus already-assigned rewards forever. (b) Oracle rotates its key: an attestation signed by the new key for this adapter -> _check returns \"bad_signature\" -> mine.fail -> status Failed; backers' 0.5 IMD was paid to payTo and assigned stays 0 (reproduced in test/scratch/Probe.t.sol::test_signerRotated_everyAnswerFails, passing on this tree).","severity":"medium","snippet":"        uint256 price = intake.priceOf(action, address(imd));\n        if (price == 0) revert NotSold();","title":"Mining reserve (65% of supply) is stranded for good if the Intake retires oracle-1 or the oracle signer rotates: no steward, no fallback (documented trust assumption, design decision)"},{"citation":"resolved","description":"Flow gap, execution x periphery. q.target is set once from intake.priceOf at propose (src/HmmMine.sol:331). back() only triggers _ask when raised == q.target (:731), and _ask re-reads the live price (:757) and reverts if it rose (:759). Nothing re-quotes an Open question, and refund() on an Open question is refused until block.timestamp > q.deadline (:358). So after any price increase the completing backer's transaction reverts (gas lost), the IMD already pooled is locked for the rest of the 3-day window, and the only way forward is a fresh proposal at the new price. In the other direction, when the price falls below what is already raised (e.g. 0.4 IMD raised of a 0.5 target, live price 0.25) the question still cannot be asked until someone adds the remaining 0.1 to reach the stale target, even though the mine already holds more than it will pay; the excess is then returned as surplus. No IMD is lost in either case and docs/DESIGN.md:44 documents the rise case, so this is a liveness / capital-lockup defect rather than a loss. Minimal fix preserving the design: in _ask, treat a live price <= q.raised as fundable (ask as soon as raised >= live) and let back() complete when raised reaches the current live price rather than the frozen target; or allow refund() on an Open question once the live price exceeds its target.","line":759,"path":"src/HmmMine.sol","reproduction":"alice: propose(spec, 0.3e18) -> id, target 0.5e18. Intake owner: setPrice(action, IMD, 0.6e18). bob: back(id, 0.2e18, body) -> raised == 0.5e18 == target -> _ask -> live 0.6e18 > 0.5e18 -> revert PriceRose(0.6e18, 0.5e18); bob pays gas, nothing asked. alice: refund(id) -> NotRefundable (deadline not passed). Warp 3 days + 1 s: refund(id) returns 0.3e18. Expected: a fundable question is asked or refundable at once; actual: 0.3 IMD locked for 3 days and no completion possible. Reproduced in test/scratch/Probe.t.sol::test_priceRise_strandsOpenQuestion (passes on this tree, documenting current behaviour).","severity":"low","snippet":"        if (live > price) revert PriceRose(live, price);","title":"Funding target is frozen at proposal: an Intake price rise makes every open pooled question impossible to complete until its 3-day deadline, and a price fall still forces backers to raise the stale hi"}],"hash":"cbb28491b614310b2624094dfa7a7b2775b9b28040ca65a2ca09ac1cccfcf71c","nodeId":"6a00c491-9094-4f5b-bdeb-464211182aeb","outcome":"completed","summary":"The review is complete. Findings are in `.imd-findings.json` at the repository root, with two findings and a coverage row for all 21 entry points plus five checked invariants. No repository file was changed; only the findings file and my scratch probes under `test/scratch/` exist, both ignored by git.\n\n**What I found**\n\n- **Medium, documented trust assumption.** The whole mining economy rests on two constants nobody can change: the action word priced by the Intake and the oracle signer baked into the adapter. With no steward, one routine operator action at the Intake (retiring oracle-1 with a zero price, or rotating the signer key) stops emission forever and leaves the unemitted part of the ~650M HMM reserve in the mine. The supplied oracle-consumer reference says exactly these values are expected to move. The requester chose this deliberately and docs/SECURITY.md records it, so I flagged it as the material external-dependency risk, not as a permission bypass, and noted any mitigation is a scope decision.\n- **Low.** The funding target is frozen at proposal. After a price rise, the completing backer's transaction reverts and pooled IMD stays locked until the 3-day deadline. After a price fall, a question still has to raise the stale higher target before it can be asked. No IMD is lost either way.\n\n**What holds**\n\n- The HMM and IMD ledgers conserve on every path I traced: rewards plus dev share never exceed what the schedule assigned, assigned never exceeds the reserve, and surplus refunds sum exactly to the saved price with the last refunder taking the dust.\n- The mainnet fork rehearsal passes against the live contracts. The deployed forwarder's bytecode matches the source, the real registry decodes, and the real Intake delivers inside its 200k stipend. My worst-case probe needs about 113k of that stipend.\n- IMD on mainnet is a plain owned ERC-20 without pause or blacklist entry points. The dev address is an EOA. The live Intake price is 0.5 IMD. The manifest is schema-clean, with notes under the 4,000-character cap.\n\n**Not reached**\n\n- The off-chain plane's behaviour (whether the real writer ever delivers late or pairs answers across requests) cannot be checked from this tree. I treated the writer and signer as trusted, as the design does.","treeHash":null,"usage":{"cachedInputTokens":1891831,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":46060,"runtime":"claude","turns":37,"wallClockMs":757559}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"d00f790fc692b1a4","findings":[{"citation":"resolved","description":"Merged from audit_math. forward(n) is permissionless and unconditional: it transfers the forwarder's whole HMM balance to the mine and calls start(). HmmMine.start() (src/HmmMine.sol:288 `if (genesis != 0) return;`) is a silent no-op once genesis is set, and reserve/baseRate are fixed by the first call. emittedAt() sums at most 64 halvings of baseRate*eraLength, which is <= reserve; claim() and payDev() draw only from `assigned`; HmmMine has no sweep. So any HMM that reaches the forwarder after the first forward (a mistaken transfer to 0x876c2fb3eaa91d32ef03186853bb82433b949a71, which is a fixed, already-deployed address) is moved into the mine and permanently unrecoverable. The comment on line 62 states the opposite of what the code does. The requester documents the stranding as a known limitation (docs/SECURITY.md) and the forwarder is already deployed, so the fix is to the mine side or the documentation: either make start() revert AlreadyStarted (which leaves late HMM in the forwarder instead, equally stuck) or correct the comment and the NatSpec of forward() so that nobody relies on a revert. Loss is limited to self-inflicted transfers after launch; the launch reserve and backers' IMD are unaffected.","line":62,"path":"src/GenesisForwarder.sol","reproduction":"State: launch forwarded (mine.started() == true, mine.reserve() == 650,000,000e18 in the repo's HmmTestBase world). Steps: (1) any HMM holder transfers 1e18 HMM to the forwarder; (2) anyone calls forwarder.forward(launchNumber). Expected per the comment: revert, tokens stay in the forwarder. Actual (reproduced with a scratch Foundry test on the repo HmmTestBase world, not kept): forward() succeeds, hmm.balanceOf(mine) grows by 1e18, mine.reserve() unchanged, mine.emittedAt(genesis + 100*eraLength) == mine.emittedAt(genesis + 64*eraLength) <= reserve, and no HmmMine function can transfer the extra 1e18 out.","severity":"low","snippet":"        IHmmMine(mine).start(); // reverts if this mine already started","title":"GenesisForwarder.forward after the mine has started moves late HMM into the mine outside its reserve, where nothing can ever emit it; the inline comment claims start() reverts instead"},{"citation":"resolved","description":"Merged from audit_permissions. Every other state change on a question is restricted to a party with a stake in it (backing and refund move only msg.sender's IMD, credit/fail come only from the question's adapter, start only from the forwarder). expire(id) is callable by anyone once block.timestamp > answerDeadline[id] (ask time + 7 days) and sets the question to Failed. The Intake request itself never expires and an attestation is valid for 86,400 s from issuance, so an answer arriving after day 7 is still good; once expire() has run, the adapter's callback calls credit(requestId), which reverts NotAsked (src/HmmMine.sol:423), the whole callback reverts, the Intake records delivered == false and never retries, and the backers' price stays spent. A stranger has a motive: the first credit of a round after an idle stretch carries everything emitted since the last answered round, so a backer of a competing pending question gains by closing another question moments before its completion lands. Preconditions: the swarm's completion is more than 7 days late (abnormal, not privileged). docs/SECURITY.md documents that anyone may expire; the asymmetry (no stake needed, irreversible loss for third parties) is the defect. Minimal fix preserving the design: require backing[id][msg.sender] != 0 (or msg.sender == proposer) in expire(), or let a later valid completion still credit while only a backer may close.","line":375,"path":"src/HmmMine.sol","reproduction":"State: started mine, Intake price 0.5 IMD. (1) alice (EOA) calls propose(spec, 0.5e18): question id=1 is Asked with Intake request rid; answerDeadline(1) = T + 7 days. (2) Warp to T + 7 days + 1 s; the oracle signs a valid attestation for the adapter (panel 5, quorum 4, agreed 5, expiresAt = now + 1 day); adapter.check(a, sig) == bytes32(0). (3) stranger (backing(1, stranger) == 0) calls mine.expire(1): succeeds, status Failed. (4) The writer completes rid with abi.encode(rid, a, sig): Intake emits Completed(..., delivered=false). Actual (reproduced with a scratch Foundry test on the repo HmmTestBase world, not kept): mine.assigned() == 0, claimable(1, alice) == 0, refund(1) reverts NotRefundable; alice's 0.5 IMD is at the Intake's payTo. Expected: an account with no stake cannot turn a question with a valid in-flight answer into a permanent loss for its backers.","severity":"low","snippet":"    function expire(uint256 id) external nonReentrant {","title":"Permissionless expire() lets an address with no stake close another backer's Asked question after seven days, so a still-valid late oracle answer is refused and the backers' spent IMD mines nothing"},{"citation":"resolved","description":"Merged from audit_economics. q.target is set once from intake.priceOf at proposal (src/HmmMine.sol:331). back() only calls _ask when raised == q.target (src/HmmMine.sol:731), and _ask re-reads the live price and reverts PriceRose if it rose. Nothing re-quotes an Open question, and refund() on an Open question is refused until block.timestamp > q.deadline (src/HmmMine.sol:358). After any price rise the completing backer's transaction reverts, the IMD already pooled is locked for the rest of the 3-day window, and the only way forward is a fresh proposal. In the other direction, when the live price falls below what is already raised, the question still cannot be asked until the stale target is reached, even though the mine already holds more than it will pay; the excess is only returned afterwards as surplus. No IMD is lost (docs/DESIGN.md documents the rise case), so this is a liveness and capital-lockup defect. Minimal fix preserving the design: in _ask treat live <= raised as fundable and let back() complete when raised reaches the live price, or allow refund() on an Open question once the live price exceeds its target.","line":759,"path":"src/HmmMine.sol","reproduction":"Rise: alice propose(spec, 0.3e18) -> id with target 0.5e18. Intake owner setPrice(action, IMD, 0.6e18). bob back(id, 0.2e18, body): raised == target -> _ask -> revert PriceRose(0.6e18, 0.5e18). alice refund(id) -> NotRefundable. Warp 3 days + 1 s: refund(id) returns 0.3e18. Expected: a fundable question is asked or refundable at once; actual: 0.3 IMD locked for 3 days with no completion possible. Fall: alice propose(spec, 0.4e18); owner setPrice 0.25e18; status stays Open although raised 0.4 > live 0.25; only after bob backs 0.1 more does it ask, paying 0.25 and recording refundableSurplus 0.25. Both sequences were reproduced with a scratch Foundry test on the repo HmmTestBase world (not kept).","severity":"low","snippet":"        if (live > price) revert PriceRose(live, price);","title":"Funding target is frozen at proposal: an Intake price rise makes every open pooled question impossible to complete and locks its IMD until the 3-day deadline, and a price fall still forces backers to "},{"citation":"resolved","description":"Merged from audit_economics; recorded as a trust assumption at low severity because the no-steward design is the requester's explicit, documented decision (brief, launch.json notes, docs/SECURITY.md known limitations), not a permission bypass. Every path that emits HMM runs through two values the launch fixes for good: the action word bytes32(\"oracle.request@oracle-1\") priced by the Intake (read at src/HmmMine.sol:320 and :757) and the oracle signer baked immutably into SwarmOracleAdapter (src/SwarmOracleAdapter.sol:53, enforced at :187). steward is never set and only the steward can name one, so queueConfig/applyConfig are unreachable. The oracle-consumer reference states these values are expected to move (a new action version or a moved price must not need a redeploy; the signer is owner-settable). The actor is the Intake owner (an ordinary operator action: setPrice(action, IMD, 0) when oracle-2 replaces oracle-1) or an oracle key rotation. Outcome: propose and back revert NotSold forever, or every delivered answer is rejected bad_signature and each question's 0.5 IMD is spent for nothing; the unemitted reserve stays in the mine permanently since HMM only leaves via claim (needs Answered) or payDev. Any mitigation (a narrowly scoped action-id rotation, or a dead-man exit for the reserve after N years without an answer) changes the agreed no-admin design and needs a scope decision; nothing in the code is wrong relative to the stated intent. Live mainnet read on 2026-10-13: Intake.priceOf(action, IMD) == 0.5e18, callbackGas == 200000.","line":320,"path":"src/HmmMine.sol","reproduction":"(a) Started mine; alice propose(spec, 0.3e18) -> Open question id. Intake owner setPrice(action, IMD, 0). bob propose(spec2, 0.5e18) -> revert NotSold (src/HmmMine.sol:321); bob back(id, 0.2e18, body) -> revert NotSold (src/HmmMine.sol:758); applyConfig() -> revert NothingQueued; setSteward from any address -> NotSteward (production steward == 0, test/NoSteward.t.sol). Expected by the economics: emission continues or the reserve has an exit; actual: hmm.balanceOf(mine) stays at reserve minus already-assigned rewards forever. (b) An attestation signed by a different key for this adapter: adapter.check(a, sig) == bytes32(\"bad_signature\"); the writer's completion is delivered, the question becomes Failed, assigned stays 0 and the 0.5 IMD is spent. Both were reproduced with a scratch Foundry test on the repo HmmTestBase world (not kept).","severity":"low","snippet":"        uint256 price = intake.priceOf(action, address(imd));","title":"Documented trust assumption: mining and the unemitted reserve (~650M HMM) depend forever on the Intake continuing to sell oracle.request@oracle-1 and on the oracle signer never rotating; with no stewa"}],"hash":"e2d12aa6acb1ada6b89289512839b692804677c1c185ab05ced2ebd582e65dec","nodeId":"415dc11e-787b-4f19-8774-97d053c3b330","outcome":"completed","summary":"The review is complete. `.imd-findings.json` is written at the repository root with 4 findings and 22 coverage rows, and the tree holds nothing else new.\n\n**Outcome.** Four of the five specialist findings reproduced against the code and are kept, each recalibrated to low. One specialist entry (the idle-backlog emission) is documented design in the mine's NatSpec, not a defect, and was dropped. My own pass over the contracts, the slither and aderyn leads, the manifest, the deployment limits and the live mainnet state found nothing further. The existing suite is green on this tree.\n\n| | |\n|---|---|\n| Tests run | 123 passed, 0 failed |\n| HmmMine runtime / initcode | 18,670 B / 19,805 B, both within the limits |\n| launch.json notes | 3,971 characters, schema keys only |\n| Mainnet forwarder | registry and mine name match the source |\n| Mainnet Intake price | 0.5 IMD for the launch's action |\n\n**Findings kept, all low:**\n- A second `forward()` after the mine has started moves late HMM into the mine outside its reserve, where nothing can emit it. The comment on the call claims `start()` reverts; it is a silent no-op.\n- Permissionless `expire()` lets an address with no stake close another backer's question after seven days, so a still-valid late answer is refused and the spent IMD mines nothing.\n- The funding target is frozen at proposal. A price rise locks pooled IMD until the three-day deadline, and a price fall still forces backers to raise the stale target.\n- Documented trust assumption: with no steward, mining depends forever on the Intake selling the fixed action and the oracle signer never rotating. The requester chose this deliberately, so it is recorded as a risk rather than a blocking defect.\n\n**Verification notes.** Each kept reproduction was run as a scratch Foundry test on the repository's test base before being written up, and the scratch directory was removed afterwards. The `toleranceBps` body key, absent from the skill's example body, is confirmed as a documented key in the published oracle docs, so that lead was closed. No proofs were attached because no finding reached high or critical.","treeHash":null,"usage":{"cachedInputTokens":1684432,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":44163,"runtime":"claude","turns":35,"wallClockMs":609318}}],"verification":[{"checks":[{"durationMs":9515,"exitCode":0,"name":"build","output":"Compiling 84 files with Solc 0.8.26\nSolc 0.8.26 finished in 9.25s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/utils/HmmTestBase.sol:200:5:\n    |\n200 |     function _delivered() internal returns (bool) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n   --> test/HmmMine.t.sol:574:5:\n    |\n574 |     function test_halving_halvesTheRate() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n   --> test/fork/Launch.fork.t.sol:274:5:\n    |\n274 |     function _delivered() internal returns (bool) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/GenesisForwarder.sol:53:41\n   │\n53 │             if (a.role == ROLE_TOKEN && token == address(0)) token = a.addr;\n   │                                         ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/GenesisForwarder.sol:54:68\n   │\n54 │             else if (a.role == ROLE_OTHER && a.name == mineName && mine == address(0)) mine = a.addr;\n   │                                                                    ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/GenesisForwarder.sol:63:9\n   │\n63 │         emit Forwarded(launchNumber, token, mine, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-events-access-control]: `steward` is changed without an event but is used for access control\n    ╭▸ src/HmmMine.sol:496:9\n    │\n496 │         steward = next;\n    │         ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmOracleAdapter.sol:96:20\n   │\n96 │         minPanel = uint16(minPanel_);\n   │                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmOracleAdapter.sol:97:21\n   │\n97 │         minQuorum = uint16(minQuorum_);\n   │                     ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:127:13\n    │\n127 │             emit Rejected(requestId, a.requestId, reason);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:138:9\n    │\n138 │ ┏         emit Thought(\n139 │ ┃             requestId, a.requestId, a.chainId, a.answerType, answerHash, shown, a.panelSize, a.quorum, a.agreed\n140 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/SwarmOracleAdapter.sol:120:47\n    │\n120 │         (, address target,, bool completed) = intake.requests(requestId);\n    │                                               ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:157:9\n    │\n157 │         emit Unanswered(requestId, status, reason, agreed, answered);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:268:9\n    │\n268 │         emit ConfigApplied(adapter_, action_);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:333:9\n    │\n333 │         emit Proposed(id, msg.sender, price, q.deadline, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:730:9\n    │\n730 │         emit Backed(id, msg.sender, amount, raised);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:767:28\n    │\n767 │         if (live != price) emit PriceAdjusted(id, price, live);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:776:9\n    │\n776 │         emit Asked(id, requestId, a);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:329:22\n    │\n329 │         q.deadline = uint64(block.timestamp + FUNDING_WINDOW);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:331:20\n    │\n331 │         q.target = uint128(price);\n    │                    ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:345:13\n    │\n345 │         if (block.timestamp > q.deadline) revert FundingClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:358:17\n    │\n358 │             if (block.timestamp <= q.deadline) revert NotRefundable();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:362:25\n    │\n362 │             q.raised -= uint128(amount);\n    │                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:379:13\n    │\n379 │         if (block.timestamp <= deadline) revert TooEarly(deadline + 1);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/HmmMine.sol:394:13\n    │\n394 │             refundTotal += _takeSurplus(id, q, msg.sender);\n    │             ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:391:48\n    │\n391 │             if (q.status != Status.Answered || block.timestamp < roundEnd(q.round) || weight == 0) continue;\n    │                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:610:9\n    │\n610 │         emit SurplusRefunded(id, backer, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:401:13\n    │\n401 │             emit Claimed(id, msg.sender, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:396:35\n    │\n396 │             claimedBacking[id] += uint128(weight);\n    │                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:399:33\n    │\n399 │             progress.claimed += uint128(amount);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:437:13\n    │\n437 │             emit RoundOpened(r, emitted, devShare);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:443:9\n    │\n443 │         emit Answered(id, requestId, r, shares);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:436:28\n    │\n436 │             round.reward = uint128(emitted - devShare);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:440:25\n    │\n440 │         round.shares += uint128(shares);\n    │                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:441:19\n    │\n441 │         q.round = uint32(r);\n    │                   ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pendingAdapter` is updated\n    ╭▸ src/HmmMine.sol:482:9\n    │\n482 │         IOracleAdapter(next).bind();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:480:13\n    │\n480 │         if (block.timestamp < eta) revert TooEarly(eta);\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:490:9\n    │\n490 │         emit ConfigApplied(next, action);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/HmmMine.sol:494:25\n    │\n494 │     function setSteward(address next) external onlySteward {\n    │                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/HmmMine.sol:527:15\n    │\n527 │             ) revert BadDefinitions();\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/HmmMine.sol:529:86\n    │\n529 │                 if (keccak256(bytes(d.key)) == keccak256(bytes(definitions[j].key))) revert BadDefinitions();\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/HmmMine.sol:539:29\n    │\n539 │           bytes memory head = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n540 │ ┃             '{\"v\":1,\"question\":\"',\n541 │ ┃             spec.question,\n542 │ ┃             '\",\"chainId\":',\n    ‡ ┃\n549 │ ┃             spec.evidence == 0 ? _CHAIN : _PANEL\n550 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/HmmMine.sol:551:29\n    │\n551 │           bytes memory tail = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n552 │ ┃             '\",\"panelSize\":',\n553 │ ┃             Strings.toString(spec.panelSize),\n554 │ ┃             ',\"quorum\":',\n    ‡ ┃\n561 │ ┃             \"}\"\n562 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:576:13\n    │\n576 │         if (block.timestamp < roundEnd(r)) return 0;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:594:45\n    │\n594 │         if (q.status == Status.Open) return block.timestamp > q.deadline ? amount : 0;\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:607:29\n    │\n607 │         progress.backing += uint128(backing[id][backer]);\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:608:30\n    │\n608 │         progress.refunded += uint128(amount);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/HmmMine.sol:625:56\n    │\n625 │         if (era < MAX_ERAS) total += rate * (elapsed - era * eraLength);\n    │                                                        ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:643:23\n    │\n643 │         if (g == 0 || block.timestamp < g) return 0;\n    │                       ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:670:21\n    │\n670 │         uint256 t = block.timestamp < genesis ? genesis : block.timestamp;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:682:26\n    │\n682 │         return g != 0 && block.timestamp >= g;\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:728:20\n    │\n728 │         q.raised = uint128(raised);\n    │                    ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:765:20\n    │\n765 │         q.target = uint128(live);\n    │                    ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Emission.t.sol:51:21\n   │\n51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n   │             ────────━━━━━━━━━━━━━━━─────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Emission.t.sol:51:13\n    │\n 51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n    │             ────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Emission.t.sol:51:13\n    │\n 51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n    │             ────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:499:17\n    │\n499 │         vm.warp(block.timestamp + 3 hours + 5 minutes); // round 18\n    │         ────────━━━━━━━━━━━━━━━─────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HmmMine.t.sol:562:9\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ───────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HmmMine.t.sol:562:9\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ───────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:562:17\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n232 │         vm.warp(mine.roundEnd(_roundOf(id)));\n    │         ──────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n232 │         vm.warp(mine.roundEnd(_roundOf(id)));\n    │         ──────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:721:17\n    │\n721 │         vm.warp(block.timestamp + 40 * ERA + 7 days);\n    │         ────────━━━━━━━━━━━━━━━───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:749:17\n    │\n749 │         vm.warp(block.timestamp + 40 * ERA + 7 days);\n    │         ────────━━━━━━━━━━━━━━━───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:792:75\n    │\n792 │         vm.expectRevert(abi.encodeWithSelector(HmmMine.TooEarly.selector, block.timestamp + 3 days));\n    │                                                                           ━━━━━━━━━━━━━━━\n793 │         mine.applyConfig();\n794 │         vm.warp(block.timestamp + 3 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:794:17\n    │\n794 │         vm.warp(block.timestamp + 3 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:840:17\n    │\n840 │         vm.warp(block.timestamp + 25 minutes); // round 2\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/audit/StewardAdapter.t.sol:47:17\n   │\n47 │         vm.warp(block.timestamp + 3 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":13660,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/FactoryLaunch.t.sol:FactoryLaunchTest\n[PASS] test_exactLaunchArgumentsDeployAtomicallyWithoutExternalCodeOrTokenMovements() (gas: 568590)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.22ms (980.16µs CPU time)\n\nRan 1 test for test/audit/ForeignRequestFirst.t.sol:AuditForeignRequestFirstTest\n[PASS] test_audit_foreignRequestBeforeTheAsk_isRefused() (gas: 1369975)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.51ms (537.76µs CPU time)\n\nRan 2 tests for test/audit/StewardAdapter.t.sol:AuditStewardAdapterTest\n[PASS] test_audit_stewardAdapter_capturesEmissionWithoutAnswers() (gas: 1662394)\nLogs:\n  HMM taken for 0.5 IMD, no oracle answer (whole tokens): 56616078\n\n[PASS] test_noSteward_rulesAreFixedForever() (gas: 4316214)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.57ms (1.80ms CPU time)\n\nRan 1 test for test/audit/ConfigBoundary.t.sol:AuditConfigBoundaryTest\n[PASS] test_audit_questionProposedBeforeQueue_refusesTheNewConfig() (gas: 1169214)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.03ms (2.01ms CPU time)\n\nRan 7 tests for test/audit/RequestLifecycle.t.sol:RequestLifecycleTest\n[PASS] test_delegatedAccountsCanStillBackPartiallyOrFundOnlyTheirOwnQuestion() (gas: 1207926)\n[PASS] test_delegatedOriginCannotSpendOtherBackersFundsInABatch() (gas: 1326788)\n[PASS] test_expire_boundaryIsMeasuredFromAskAndMovesNoFunds() (gas: 814895)\n[PASS] test_expiredRequestCannotBeRevivedByALateSignedAnswerOrFailure() (gas: 711083)\n[PASS] test_malformedUndeliveredCallbackCanExpire() (gas: 580688)\n[PASS] test_onlyAskedQuestionsCanExpireAndLateAnswersRemainValidUntilCleared() (gas: 986381)\n[PASS] test_separatelyDeployedAdapterCanBeClaimedBeforeMineConstruction() (gas: 66366)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 82.03ms (5.37ms CPU time)\n\nRan 9 tests for test/GenesisForwarder.t.sol:GenesisForwarderTest\n[PASS] test_constructor_validates() (gas: 3851)\n[PASS] test_copycatLaunch_cannotTouchTheRealReserve() (gas: 9977677)\n[PASS] test_crossWiredLaunch_isRefused() (gas: 5696440)\n[PASS] test_forward_lateTokensMoveWithoutRestartingTheMine() (gas: 311768)\n[PASS] test_forward_movesTheWholeRemainderAndStarts() (gas: 4999194)\n[PASS] test_forward_refusesALaunchWithoutAMine() (gas: 226458)\n[PASS] test_forward_refusesAMineOfAnotherForwarder() (gas: 88326)\n[PASS] test_forward_refusesAMineOfAnotherToken() (gas: 872809)\n[PASS] test_forward_refusesOtherLaunchKinds() (gas: 124935)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 117.84ms (5.84ms CPU time)\n\nRan 5 tests for test/audit/Definitions.t.sol:DefinitionsTest\n[PASS] test_definitionsAppearInTheCommittedBodyAndCannotBeChangedByCompleter() (gas: 1407694)\n[PASS] test_definitionsRejectInjectionDuplicatesAndOversizedInput() (gas: 632909)\n[PASS] test_emptyDefinitionsPreserveTheExistingBodyAndSoloFlow() (gas: 481266)\n[PASS] test_maximumDefinitionsAndQuestionFitThePaidBodyLimit() (gas: 9896341)\n[PASS] test_wordingRefusalStillSpendsTheIntakePriceAndMinesNothing() (gas: 702016)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 566.46ms (22.62ms CPU time)\n\nRan 3 tests for test/audit/Rounding.t.sol:RoundingTest\n[PASS] test_multipleQuestionsOwnedByOneBackerCanClaimTheFinalDustInABatch() (gas: 2330250)\n[PASS] test_sevenSharesAndTenRewardPayFourThenSix() (gas: 1941131)\n[PASS] test_zeroRoundedClaimIsConsumedSoTheLastBackerCanTakeTheWei() (gas: 1388345)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 566.38ms (12.46ms CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKeyIncludingNoAnswer() (gas: 659412)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 650149)\n[PASS] test_callbackSelectorIsCanonical() (gas: 418)\n[PASS] test_digestMatchesTheProtocol() (gas: 29662)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 633.41ms (1.59ms CPU time)\n\nRan 11 tests for test/SwarmOracleAdapter.t.sol:SwarmOracleAdapterTest\n[PASS] testFuzz_realSignature_breaksOnAnyTamper(uint8,uint256) (runs: 2000, μ: 22874, ~: 22809)\n[PASS] test_bind_onceAndIdempotent() (gas: 125198)\n[PASS] test_check_reasons() (gas: 333794)\n[PASS] test_constructor_validates() (gas: 6172)\n[PASS] test_longAnswer_isCountedAndHashed() (gas: 2617763)\n[PASS] test_onlyTheIntakeCallsBack() (gas: 96585)\n[PASS] test_realSwarmSignatures_recoverTheOracleSigner() (gas: 76785)\n[PASS] test_selectors_matchTheSwarmsCallbackShape() (gas: 5907)\n[PASS] test_thoughtEvent_carriesTheAnswer() (gas: 686138)\n[PASS] test_unboundAdapterRefusesCallbacks() (gas: 78375)\n[PASS] test_unknownRequestIsRefused() (gas: 83194)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 633.38ms (643.20ms CPU time)\n\nRan 3 tests for test/NoSteward.t.sol:NoStewardTest\n[PASS] test_adapter_cannotBeClaimedOnceTheMineHasIt() (gas: 46518)\n[PASS] test_launchArgs_haveNoZeroAddress() (gas: 9906)\n[PASS] test_realMine_hasNoSteward_andNobodyCanNameOne() (gas: 381977)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 633.33ms (1.67ms CPU time)\n\nRan 5 tests for test/audit/PriceDrop.t.sol:PriceDropTest\n[PASS] testFuzz_priceDrop_conservesIMDAndHMMInEitherRefundOrder(uint96,uint96,uint96,uint8,bool) (runs: 2000, μ: 1660426, ~: 1660136)\n[PASS] test_claimAutomaticallyRefundsSurplusAndUsesActualPaidShares() (gas: 2203192)\n[PASS] test_failedAndExpiredRequestsKeepOnlyUnspentSurplusRefundable() (gas: 1827093)\n[PASS] test_priceDrop_matchesImportedProofAndRefundsEachBackerOnce() (gas: 1089032)\n[PASS] test_zeroRoundedSurplusCanBeAcknowledgedAndLastRefundGetsDust() (gas: 865410)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 633.50ms (637.23ms CPU time)\n\nRan 45 tests for test/HmmMine.t.sol:HmmMineTest\n[PASS] test_answerInALaterEra_isWorthLess() (gas: 1519480)\n[PASS] test_answerThatDoesNotCount_isRecordedAsFailed() (gas: 590687)\n[PASS] test_answer_creditsTheRound_withRolloverSinceGenesis() (gas: 747893)\n[PASS] test_back_minimumUnlessCompletingTheRemainder() (gas: 622319)\n[PASS] test_back_refusedWhenClosedOrNotOpen() (gas: 749116)\n[PASS] test_bodyOf_isTheExactJsonTheSwarmChecked() (gas: 65460)\n[PASS] test_callback_fitsTheIntakeStipend() (gas: 744866)\nLogs:\n  callback gas (refused path): 46589\n\n[PASS] test_callback_gasMargin() (gas: 2572847)\nLogs:\n  minimum stipend for the costliest callback: 118437\n\n[PASS] test_claim_onlyAfterTheRoundEnds() (gas: 996946)\n[PASS] test_config_cancel_andRenounce() (gas: 241339)\n[PASS] test_config_queueApplyAfterDelay_newQuestionsOnly() (gas: 1520008)\n[PASS] test_config_refusesAnAdapterBoundToAnotherMine() (gas: 186659)\n[PASS] test_constructor_validates() (gas: 2454011)\n[PASS] test_creditAndFail_onlyFromTheQuestionsAdapter() (gas: 529017)\n[PASS] test_devShare_isPaidToDev_byAnyone() (gas: 817763)\n[PASS] test_emptyRoundsRollIntoTheNextAnsweredRound() (gas: 1321923)\n[PASS] test_failure_closesTheQuestion_withoutCredit() (gas: 600576)\n[PASS] test_forgedAnswer_doesNotCount() (gas: 588878)\n[PASS] test_genesisDelay_blocksQuestionsUntilGenesis() (gas: 5495356)\n[PASS] test_halving_halvesTheRate() (gas: 153495)\n[PASS] test_oneAskPerTransaction() (gas: 1842650)\n[PASS] test_outsiderRequestNamingTheAdapter_cannotMine() (gas: 485017)\n[PASS] test_ownQuestion_completedByAContractIsFine() (gas: 916024)\n[PASS] test_pooledCompletion_mustComeFromAnAccountDirectly() (gas: 1222917)\n[PASS] test_pooledQuestion_isAskedWhenTheLastBackerCompletesIt() (gas: 932395)\n[PASS] test_priceFall_paysTheLivePriceAndKeepsTheSurplus() (gas: 696856)\n[PASS] test_priceRise_blocksTheAsk_andBackersRefund() (gas: 477773)\n[PASS] test_propose_capsAmountAtPrice() (gas: 437837)\n[PASS] test_propose_notSoldWhenPriceIsZero() (gas: 90121)\n[PASS] test_propose_rejectsDust() (gas: 53854)\n[PASS] test_refund_afterDeadlineOnly_andOnce() (gas: 598720)\n[PASS] test_refund_refusedOnceAsked() (gas: 480975)\n[PASS] test_refusal_closesTheQuestion() (gas: 541831)\n[PASS] test_sameOracleAnswer_countsOnce() (gas: 1158007)\n[PASS] test_sameRound_splitsByIMDPaid_andPooledBackersSplitByShare() (gas: 1579226)\n[PASS] test_soloAsk_paysTheSwarmAndRecordsTheRequest() (gas: 556886)\n[PASS] test_spec_rulesAndInjection() (gas: 578943)\n[PASS] test_start_needsReserve() (gas: 4821133)\n[PASS] test_start_onlyForwarder() (gas: 29596)\n[PASS] test_start_repeatedForwarderCallDoesNotRestart() (gas: 66904)\n[PASS] test_start_setsReserveGenesisAndRate() (gas: 50339)\n[PASS] test_stats_andPot() (gas: 785024)\n[PASS] test_stats_beforeStart() (gas: 4825078)\n[PASS] test_token_isPlainAndFixed() (gas: 36651)\n[PASS] test_writerCannotCreditAPendingRequestThroughAnotherCompletion() (gas: 987990)\nSuite result: ok. 45 passed; 0 failed; 0 skipped; finished in 633.42ms (36.46ms CPU time)\n\nRan 6 tests for test/Emission.t.sol:EmissionTest\n[PASS] testFuzz_answeredRounds_accountForEveryEmittedUnit(uint32[6]) (runs: 2000, μ: 4431090, ~: 4447927)\n[PASS] testFuzz_emittedAt_isMonotonic(uint64,uint64) (runs: 2000, μ: 35663, ~: 33665)\n[PASS] testFuzz_emittedAt_isTheIntegralOfTheRate(uint64) (runs: 2000, μ: 149484, ~: 43753)\n[PASS] testFuzz_emittedAt_neverExceedsTheReserve(uint256) (runs: 2000, μ: 25351, ~: 32254)\n[PASS] testFuzz_pooledClaims_neverExceedTheRound(uint96[5]) (runs: 2000, μ: 1981810, ~: 1899731)\n[PASS] test_firstEra_emitsHalfTheReserve_andTheTailIsDust() (gas: 47003)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 634.16ms (2.18s CPU time)\n\nRan 1 test for test/audit/AdversarialInvariants.t.sol:AuditAdversarialInvariantTest\n[PASS]\nAuditAdversarialInvariantTest invariants:\n[PASS] invariant_audit_hmmConservedAndSolvent\n[PASS] invariant_audit_imdConserved\n[PASS] invariant_audit_roundsConsistent\n AuditAdversarialInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭--------------------+-----------+-------+---------+----------╮\n| Contract           | Selector  | Calls | Reverts | Discards |\n+=============================================================+\n| AdversarialHandler | back      | 2075  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | claim     | 2128  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | expire    | 1997  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | movePrice | 2045  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | payDev    | 1988  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | propose   | 1994  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | refund    | 2030  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | rotate    | 2020  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | settle    | 2068  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | warp      | 2135  | 0       | 0        |\n╰--------------------+-----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.16s (8.15s CPU time)\n\nRan 1 test for test/invariant/MineInvariants.t.sol:MineInvariantTest\n[PASS]\nMineInvariantTest invariants:\n[PASS] invariant_hmmIsConserved\n[PASS] invariant_imdIsConserved\n[PASS] invariant_questionsAreConsistent\n[PASS] invariant_roundSharesMatchAnsweredQuestions\n[PASS] invariant_solvency\n MineInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭-------------+----------+-------+---------+----------╮\n| Contract    | Selector | Calls | Reverts | Discards |\n+=====================================================+\n| MineHandler | back     | 2985  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | claim    | 2898  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | payDev   | 2974  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | propose  | 2820  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | refund   | 2983  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | settle   | 2970  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | warp     | 2850  | 0       | 0        |\n╰-------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.46s (13.45s CPU time)\n\nRan 16 test suites in 13.46s (26.76s CPU time): 105 tests passed, 0 failed, 0 skipped (105 total tests)\n","passed":true},{"durationMs":94,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"GenesisForwarder.forward(uint64)\",\"HmmMine.applyConfig()\",\"HmmMine.back(uint256,uint256,bytes)\",\"HmmMine.cancelConfig()\",\"HmmMine.claim(uint256[])\",\"HmmMine.credit(bytes32)\",\"HmmMine.expire(uint256)\",\"HmmMine.fail(bytes32,uint8,bytes32)\",\"HmmMine.payDev()\",\"HmmMine.propose((string,uint8,uint8,uint32,uint16,uint16,uint16,uint16),uint256)\",\"HmmMine.proposeWithDefinitions((string,uint8,uint8,uint32,uint16,uint16,uint16,uint16),(string,string)[],uint256)\",\"HmmMine.queueConfig(address,bytes32)\",\"HmmMine.refund(uint256)\",\"HmmMine.setSteward(address)\",\"HmmMine.start()\",\"HmmToken.approve(address,uint256)\",\"HmmToken.transfer(address,uint256)\",\"HmmToken.transferFrom(address,address,uint256)\",\"SwarmOracleAdapter.bind()\",\"SwarmOracleAdapter.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"SwarmOracleAdapter.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\"],\"files\":{\".github/workflows/test.yml\":20,\".gitignore\":18,\"ADAPTATION.md\":178,\"LICENSE\":21,\"README.md\":66,\"devnet/activity.mjs\":129,\"devnet/package-lock.json\":217,\"devnet/package.json\":12,\"devnet/preview-tunnel.sh\":21,\"devnet/preview.mjs\":127,\"devnet/start.sh\":44,\"devnet/stop.sh\":9,\"devnet/swarm.mjs\":222,\"docs/DESIGN.md\":90,\"docs/LAUNCH.md\":94,\"docs/SECURITY.md\":89,\"docs/TOKENOMICS.md\":56,\"foundry.toml\":52,\"launch/body.json\":36,\"launch/build-site-body.mjs\":22,\"launch/build.mjs\":107,\"launch/buy-imd.mjs\":65,\"launch/check.mjs\":21,\"launch/config.json\":12,\"launch/export-public.sh\":33,\"launch/export-site.sh\":40,\"launch/metrics.mjs\":70,\"launch/package-lock.json\":248,\"launch/package.json\":11,\"launch/pay.mjs\":205,\"launch/watch.mjs\":88,\"remappings.txt\":2,\"script/DeployForwarder.s.sol\":31,\"script/Devnet.s.sol\":87,\"script/HmmLaunch.sol\":143,\"script/IProjectFactory.sol\":64,\"src/GenesisForwarder.sol\":65,\"src/HmmMine.sol\":778,\"src/HmmToken.sol\":15,\"src/SwarmOracleAdapter.sol\":217,\"src/interfaces/IHmmMine.sol\":20,\"src/interfaces/IIntake.sol\":31,\"src/interfaces/ILaunchRegistry.sol\":27,\"src/interfaces/IOracleAdapter.sol\":15,\"test/Emission.t.sol\":118,\"test/FactoryLaunch.t.sol\":67,\"test/GenesisForwarder.t.sol\":112,\"test/HmmMine.t.sol\":874,\"test/NoSteward.t.sol\":73,\"test/OracleConsumerConformance.t.sol\":100,\"test/SwarmOracleAdapter.t.sol\":190,\"test/audit/AdversarialInvariants.t.sol\":282,\"test/audit/ConfigBoundary.t.sol\":44,\"test/audit/Definitions.t.sol\":130,\"test/audit/ForeignRequestFirst.t.sol\":57,\"test/audit/PriceDrop.t.sol\":180,\"test/audit/RequestLifecycle.t.sol\":144,\"test/audit/Rounding.t.sol\":99,\"test/audit/StewardAdapter.t.sol\":113,\"test/external/Intake.sol\":325,\"test/fixtures/RealAttestations.sol\":137,\"test/fork/Launch.fork.t.sol\":290,\"test/invariant/MineInvariants.t.sol\":241,\"test/utils/HmmMineStewarded.sol\":26,\"test/utils/HmmTestBase.sol\":234,\"test/utils/Mocks.sol\":45,\"web/.env.example\":22,\"web/.gitignore\":5,\"web/.npmrc\":1,\"web/README.md\":184,\"web/e2e/devnet.e2e.test.ts\":248,\"web/index.html\":24,\"web/lab/pond-lab.tsx\":267,\"web/lab/pond.html\":18,\"web/package-lock.json\":8959,\"web/package.json\":41,\"web/proxy/check-worker.js\":71,\"web/public/favicon.svg\":18,\"web/scripts/abi.mjs\":49,\"web/src/App.tsx\":113,\"web/src/abi/genesisForwarder.ts\":194,\"web/src/abi/hmmMine.ts\":1666,\"web/src/abi/hmmToken.ts\":329,\"web/src/abi/index.ts\":5,\"web/src/abi/swarmOracleAdapter.ts\":739,\"web/src/components/EmissionChart.tsx\":173,\"web/src/components/Footer.tsx\":46,\"web/src/components/FrogMascot.tsx\":142,\"web/src/components/Header.tsx\":109,\"web/src/components/LaunchBanner.tsx\":34,\"web/src/components/LiveNotifier.tsx\":40,\"web/src/components/MoonGlyph.tsx\":101,\"web/src/components/ScrollStory.tsx\":439,\"web/src/components/ShareCard.tsx\":236,\"web/src/components/Wallet.tsx\":225,\"web/src/components/icons.tsx\":70,\"web/src/components/question.tsx\":246,\"web/src/components/states.tsx\":63,\"web/src/components/toast.tsx\":97,\"web/src/components/ui.tsx\":416,\"web/src/config.ts\":209,\"web/src/data/app.tsx\":125,\"web/src/data/claim.ts\":19,\"web/src/data/clock.ts\":56,\"web/src/data/discovery.ts\":158,\"web/src/data/hooks.ts\":506,\"web/src/data/indexer.test.ts\":164,\"web/src/data/indexer.ts\":603,\"web/src/data/liveRound.test.ts\":45,\"web/src/data/mining.ts\":90,\"web/src/data/pondFeed.ts\":56,\"web/src/data/rpcErrors.ts\":10,\"web/src/data/token.ts\":33,\"web/src/data/tx.ts\":93,\"web/src/devnet/connectors.ts\":14,\"web/src/devnet/keys.ts\":13,\"web/src/devnet/localKey.ts\":123,\"web/src/devnet/ui.tsx\":144,\"web/src/env.d.ts\":4,\"web/src/lib/answer.test.ts\":51,\"web/src/lib/answer.ts\":97,\"web/src/lib/body.test.ts\":168,\"web/src/lib/body.ts\":321,\"web/src/lib/check.ts\":71,\"web/src/lib/emission.test.ts\":119,\"web/src/lib/emission.ts\":134,\"web/src/lib/errors.ts\":85,\"web/src/lib/format.test.ts\":88,\"web/src/lib/format.ts\":166,\"web/src/lib/reasons.test.ts\":34,\"web/src/lib/reasons.ts\":101,\"web/src/lib/spec.test.ts\":89,\"web/src/lib/spec.ts\":116,\"web/src/main.tsx\":49,\"web/src/pages/AskPage.tsx\":826,\"web/src/pages/FaqPage.tsx\":88,\"web/src/pages/HowPage.tsx\":293,\"web/src/pages/LedgerPage.tsx\":204,\"web/src/pages/MePage.tsx\":251,\"web/src/pages/MinersPage.tsx\":112,\"web/src/pages/MoonPage.tsx\":207,\"web/src/pages/NotFound.tsx\":9,\"web/src/pages/OpenPage.tsx\":97,\"web/src/pages/PondPage.tsx\":806,\"web/src/pages/QuestionPage.tsx\":277,\"web/src/pages/TokenPage.tsx\":222,\"web/src/pond/PondCanvas.tsx\":60,\"web/src/pond/camera.ts\":107,\"web/src/pond/crowd.ts\":629,\"web/src/pond/effects.ts\":889,\"web/src/pond/engine.ts\":1999,\"web/src/pond/fallback2d.ts\":159,\"web/src/pond/moon.ts\":222,\"web/src/pond/rng.ts\":100,\"web/src/pond/sim.ts\":278,\"web/src/pond/sprites.ts\":451,\"web/src/pond/types.ts\":130,\"web/src/pond/water-gl.ts\":480,\"web/src/sound/SoundToggle.tsx\":29,\"web/src/sound/engine.ts\":362,\"web/src/styles/app.css\":594,\"web/src/styles/global.css\":1171,\"web/src/styles/pages.css\":2073,\"web/src/theme.ts\":27,\"web/src/wagmi.ts\":32,\"web/tsconfig.json\":34,\"web/vite.config.ts\":166,\"web/vitest.e2e.config.ts\":14},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":3465,"exitCode":0,"name":"slither","output":"[medium/medium] divide-before-multiply at src/HmmMine.sol:614: HmmMine.emittedAt(uint256) (src/HmmMine.sol#614-626) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/HmmMine.sol:629: HmmMine.rateAt(uint256) (src/HmmMine.sol#629-634) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HmmMine.sol:657: HmmMine.stats() (src/HmmMine.sol#657-676) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HmmMine.sol:286: HmmMine.start() (src/HmmMine.sol#286-297) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HmmMine.sol:641: HmmMine.currentRound() (src/HmmMine.sol#641-645) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HmmMine.sol:614: HmmMine.emittedAt(uint256) (src/HmmMine.sol#614-626) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/GenesisForwarder.sol:45: GenesisForwarder.forward(uint64) (src/GenesisForwarder.sol#45-64) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HmmMine.sol:286: HmmMine.start() (src/HmmMine.sol#286-297) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/HmmMine.sol:743: Reentrancy in HmmMine._ask(uint256,HmmMine.Question,bytes) (src/HmmMine.sol#743-777):\n[medium/medium] reentrancy-no-eth at src/HmmMine.sol:477: Reentrancy in HmmMine.applyConfig() (src/HmmMine.sol#477-491):\n[medium/medium] uninitialized-local at src/GenesisForwarder.sol:49: GenesisForwarder.forward(uint64).token (src/GenesisForwarder.sol#49) is a local variable never initialized\n[medium/medium] uninitialized-local at src/HmmMine.sol:386: HmmMine.claim(uint256[]).refundTotal (src/HmmMine.sol#386) is a local variable never initialized\n[medium/medium] uninitialized-local at src/SwarmOracleAdapter.sol:136: SwarmOracleAdapter._thought(bytes32,SwarmOracleAdapter.Attestation,bytes32).shown (src/SwarmOracleAdapter.sol#136) is a local variable never initialized\n[medium/medium] uninitialized-local at src/GenesisForwarder.sol:50: GenesisForwarder.forward(uint64).mine (src/GenesisForwarder.sol#50) is a local variable never initialized\n[medium/medium] unused-return at src/SwarmOracleAdapter.sol:174: SwarmOracleAdapter._check(SwarmOracleAdapter.Attestation,bytes32,bytes) (src/SwarmOracleAdapter.sol#174-189) ignores return value by (recovered,err,None) = ECDSA.tryRecover(_digest(a,answerHash,block.chainid,address(this)),signature) (src/SwarmOracleAdapter.sol#185-186)\n[medium/medium] unused-return at src/SwarmOracleAdapter.sol:115: SwarmOracleAdapter.onOracleResult(bytes32,SwarmOracleAdapter.Attestation,bytes) (src/SwarmOracleAdapter.sol#115-133) ignores return value by (None,target,None,completed) = intake.requests(requestId) (src/SwarmOracleAdapter.sol#120)\n[low/medium] missing-zero-check at src/HmmMine.sol:494: HmmMine.setSteward(address).next (src/HmmMine.sol#494) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/HmmMine.sol:743: Reentrancy in HmmMine._ask(uint256,HmmMine.Question,bytes) (src/HmmMine.sol#743-777):\n[low/medium] reentrancy-benign at src/HmmMine.sol:477: Reentrancy in HmmMine.applyConfig() (src/HmmMine.sol#477-491):\n[low/medium] reentrancy-events at src/SwarmOracleAdapter.sol:145: Reentrancy in SwarmOracleAdapter.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes) (src/SwarmOracleAdapter.sol#145-158):\n[low/medium] reentrancy-events at src/SwarmOracleAdapter.sol:115: Reentrancy in SwarmOracleAdapter.onOracleResult(bytes32,SwarmOracleAdapter.Attestation,bytes) (src/SwarmOracleAdapter.sol#115-133):\n[low/medium] reentrancy-events at src/SwarmOracleAdapter.sol:115: Reentrancy in SwarmOracleAdapter.onOracleResult(bytes32,SwarmOracleAdapter.Attestation,bytes) (src/SwarmOracleAdapter.sol#115-133):\n[low/medium] reentrancy-events at src/GenesisForwarder.sol:45: Reentrancy in GenesisForwarder.forward(uint64) (src/GenesisForwarder.sol#45-64):\n[low/medium] timestamp at src/HmmMine.sol:572: HmmMine.claimable(uint256,address) (src/HmmMine.sol#572-588) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:591: HmmMine.refundable(uint256,address) (src/HmmMine.sol#591-600) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:657: HmmMine.stats() (src/HmmMine.sol#657-676) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:341: HmmMine.back(uint256,uint256,bytes) (src/HmmMine.sol#341-350) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:468: HmmMine.cancelConfig() (src/HmmMine.sol#468-474) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:375: HmmMine.expire(uint256) (src/HmmMine.sol#375-382) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:385: HmmMine.claim(uint256[]) (src/HmmMine.sol#385-406) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmOracleAdapter.sol:174: SwarmOracleAdapter._check(SwarmOracleAdapter.Attestation,bytes32,bytes) (src/SwarmOracleAdapter.sol#174-189) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:614: HmmMine.emittedAt(uint256) (src/HmmMine.sol#614-626) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:354: HmmMine.refund(uint256) (src/HmmMine.sol#354-371) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:680: HmmMine._live() (src/HmmMine.sol#680-683) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:477: HmmMine.applyConfig() (src/HmmMine.sol#477-491) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:641: HmmMine.currentRound() (src/HmmMine.sol#641-645) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:279: HmmMine.started() (src/HmmMine.sol#279-281) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:286: HmmMine.start() (src/HmmMine.sol#286-297) uses timestamp for comparisons\n[low/medium] timestamp at src/HmmMine.sol:629: HmmMine.rateAt(uint256) (src/HmmMine.sol#629-634) uses timestamp for comparisons","passed":true},{"durationMs":742,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/HmmMine.sol:539: `abi.encodePacked()` Hash Collision (3 places)\n[high] reentrancy-state-change at src/HmmMine.sol:289: Reentrancy: State change after external call (4 places)\n[high] unsafe-casting at src/HmmMine.sol:399: Unsafe Casting of integers (3 places)\n[low] costly-loop at src/HmmMine.sol:387: Costly operations inside loop\n[low] large-numeric-literal at src/HmmMine.sol:435: Large Numeric Literal (5 places)\n[low] literal-instead-of-constant at src/HmmMine.sol:435: Literal Instead of Constant (7 places)\n[low] local-variable-shadowing at src/HmmMine.sol:71: Local Variable Shadows State Variable (7 places)\n[low] require-revert-in-loop at src/HmmMine.sol:522: Loop Contains `require`/`revert` (2 places)\n[low] state-no-address-check at src/HmmMine.sol:496: Address State Variable Set Without Checks\n[low] uninitialized-local-variable at src/HmmMine.sol:528: Uninitialized Local Variable\n[low] unused-error at src/HmmMine.sol:193: Unused Error\n[low] unused-public-function at src/HmmMine.sol:279: Public Function Not Used Internally\n[low] unused-state-variable at src/HmmMine.sol:127: Unused State Variable","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"03a1a127cfdf54bf139f69eddc74e2cfdf1e97fc9d66db8bce3ec1f53a0d8c9f","verifiedTreeHash":"b46d07c33c1a3c4c0d3e6f42817450e9ea161e60","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":10370,"exitCode":0,"name":"build","output":"Compiling 89 files with Solc 0.8.26\nSolc 0.8.26 finished in 10.16s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/utils/HmmTestBase.sol:200:5:\n    |\n200 |     function _delivered() internal returns (bool) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n   --> test/HmmMine.t.sol:574:5:\n    |\n574 |     function test_halving_halvesTheRate() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n   --> test/fork/Launch.fork.t.sol:274:5:\n    |\n274 |     function _delivered() internal returns (bool) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmOracleAdapter.sol:96:20\n   │\n96 │         minPanel = uint16(minPanel_);\n   │                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/GenesisForwarder.sol:54:68\n   │\n54 │             else if (a.role == ROLE_OTHER && a.name == mineName && mine == address(0)) mine = a.addr;\n   │                                                                    ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/GenesisForwarder.sol:53:41\n   │\n53 │             if (a.role == ROLE_TOKEN && token == address(0)) token = a.addr;\n   │                                         ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmOracleAdapter.sol:97:21\n   │\n97 │         minQuorum = uint16(minQuorum_);\n   │                     ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/GenesisForwarder.sol:63:9\n   │\n63 │         emit Forwarded(launchNumber, token, mine, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:127:13\n    │\n127 │             emit Rejected(requestId, a.requestId, reason);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:138:9\n    │\n138 │ ┏         emit Thought(\n139 │ ┃             requestId, a.requestId, a.chainId, a.answerType, answerHash, shown, a.panelSize, a.quorum, a.agreed\n140 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/SwarmOracleAdapter.sol:120:47\n    │\n120 │         (, address target,, bool completed) = intake.requests(requestId);\n    │                                               ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[missing-events-access-control]: `steward` is changed without an event but is used for access control\n    ╭▸ src/HmmMine.sol:496:9\n    │\n496 │         steward = next;\n    │         ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:157:9\n    │\n157 │         emit Unanswered(requestId, status, reason, agreed, answered);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:268:9\n    │\n268 │         emit ConfigApplied(adapter_, action_);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:333:9\n    │\n333 │         emit Proposed(id, msg.sender, price, q.deadline, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:730:9\n    │\n730 │         emit Backed(id, msg.sender, amount, raised);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:767:28\n    │\n767 │         if (live != price) emit PriceAdjusted(id, price, live);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:776:9\n    │\n776 │         emit Asked(id, requestId, a);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:329:22\n    │\n329 │         q.deadline = uint64(block.timestamp + FUNDING_WINDOW);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:331:20\n    │\n331 │         q.target = uint128(price);\n    │                    ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:345:13\n    │\n345 │         if (block.timestamp > q.deadline) revert FundingClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:358:17\n    │\n358 │             if (block.timestamp <= q.deadline) revert NotRefundable();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:362:25\n    │\n362 │             q.raised -= uint128(amount);\n    │                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:379:13\n    │\n379 │         if (block.timestamp <= deadline) revert TooEarly(deadline + 1);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/HmmMine.sol:394:13\n    │\n394 │             refundTotal += _takeSurplus(id, q, msg.sender);\n    │             ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:391:48\n    │\n391 │             if (q.status != Status.Answered || block.timestamp < roundEnd(q.round) || weight == 0) continue;\n    │                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:610:9\n    │\n610 │         emit SurplusRefunded(id, backer, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:401:13\n    │\n401 │             emit Claimed(id, msg.sender, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:396:35\n    │\n396 │             claimedBacking[id] += uint128(weight);\n    │                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:399:33\n    │\n399 │             progress.claimed += uint128(amount);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:437:13\n    │\n437 │             emit RoundOpened(r, emitted, devShare);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:443:9\n    │\n443 │         emit Answered(id, requestId, r, shares);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:436:28\n    │\n436 │             round.reward = uint128(emitted - devShare);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:440:25\n    │\n440 │         round.shares += uint128(shares);\n    │                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:441:19\n    │\n441 │         q.round = uint32(r);\n    │                   ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pendingAdapter` is updated\n    ╭▸ src/HmmMine.sol:482:9\n    │\n482 │         IOracleAdapter(next).bind();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:480:13\n    │\n480 │         if (block.timestamp < eta) revert TooEarly(eta);\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:490:9\n    │\n490 │         emit ConfigApplied(next, action);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/HmmMine.sol:494:25\n    │\n494 │     function setSteward(address next) external onlySteward {\n    │                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/HmmMine.sol:527:15\n    │\n527 │             ) revert BadDefinitions();\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/HmmMine.sol:529:86\n    │\n529 │                 if (keccak256(bytes(d.key)) == keccak256(bytes(definitions[j].key))) revert BadDefinitions();\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/HmmMine.sol:539:29\n    │\n539 │           bytes memory head = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n540 │ ┃             '{\"v\":1,\"question\":\"',\n541 │ ┃             spec.question,\n542 │ ┃             '\",\"chainId\":',\n    ‡ ┃\n549 │ ┃             spec.evidence == 0 ? _CHAIN : _PANEL\n550 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/HmmMine.sol:551:29\n    │\n551 │           bytes memory tail = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n552 │ ┃             '\",\"panelSize\":',\n553 │ ┃             Strings.toString(spec.panelSize),\n554 │ ┃             ',\"quorum\":',\n    ‡ ┃\n561 │ ┃             \"}\"\n562 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:576:13\n    │\n576 │         if (block.timestamp < roundEnd(r)) return 0;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:594:45\n    │\n594 │         if (q.status == Status.Open) return block.timestamp > q.deadline ? amount : 0;\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:607:29\n    │\n607 │         progress.backing += uint128(backing[id][backer]);\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:608:30\n    │\n608 │         progress.refunded += uint128(amount);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/HmmMine.sol:625:56\n    │\n625 │         if (era < MAX_ERAS) total += rate * (elapsed - era * eraLength);\n    │                                                        ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:643:23\n    │\n643 │         if (g == 0 || block.timestamp < g) return 0;\n    │                       ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:670:21\n    │\n670 │         uint256 t = block.timestamp < genesis ? genesis : block.timestamp;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:682:26\n    │\n682 │         return g != 0 && block.timestamp >= g;\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:728:20\n    │\n728 │         q.raised = uint128(raised);\n    │                    ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:765:20\n    │\n765 │         q.target = uint128(live);\n    │                    ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Emission.t.sol:51:21\n   │\n51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n   │             ────────━━━━━━━━━━━━━━━─────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Emission.t.sol:51:13\n    │\n 51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n    │             ────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Emission.t.sol:51:13\n    │\n 51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n    │             ────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:499:17\n    │\n499 │         vm.warp(block.timestamp + 3 hours + 5 minutes); // round 18\n    │         ────────━━━━━━━━━━━━━━━─────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HmmMine.t.sol:562:9\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ───────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HmmMine.t.sol:562:9\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ───────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:562:17\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n232 │         vm.warp(mine.roundEnd(_roundOf(id)));\n    │         ──────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n232 │         vm.warp(mine.roundEnd(_roundOf(id)));\n    │         ──────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:721:17\n    │\n721 │         vm.warp(block.timestamp + 40 * ERA + 7 days);\n    │         ────────━━━━━━━━━━━━━━━───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:749:17\n    │\n749 │         vm.warp(block.timestamp + 40 * ERA + 7 days);\n    │         ────────━━━━━━━━━━━━━━━───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:792:75\n    │\n792 │         vm.expectRevert(abi.encodeWithSelector(HmmMine.TooEarly.selector, block.timestamp + 3 days));\n    │                                                                           ━━━━━━━━━━━━━━━\n793 │         mine.applyConfig();\n794 │         vm.warp(block.timestamp + 3 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:794:17\n    │\n794 │         vm.warp(block.timestamp + 3 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:840:17\n    │\n840 │         vm.warp(block.timestamp + 25 minutes); // round 2\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/OwnerlessFailurePaths.t.sol:143:9\n    │\n143 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/OwnerlessFailurePaths.t.sol:143:9\n    │\n143 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/audit/StewardAdapter.t.sol:47:17\n   │\n47 │         vm.warp(block.timestamp + 3 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":14508,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/FactoryLaunch.t.sol:FactoryLaunchTest\n[PASS] test_exactLaunchArgumentsDeployAtomicallyWithoutExternalCodeOrTokenMovements() (gas: 568590)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 903.66µs (747.95µs CPU time)\n\nRan 1 test for test/invariant/ForwarderReserves.t.sol:ForwarderAtomicityTest\n[PASS] test_startFailureRollsBackTheWholeTokenTransferAndCanBeRetried() (gas: 1633967)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.28ms (1.07ms CPU time)\n\nRan 1 test for test/audit/ForeignRequestFirst.t.sol:AuditForeignRequestFirstTest\n[PASS] test_audit_foreignRequestBeforeTheAsk_isRefused() (gas: 1369975)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.24ms (536.12µs CPU time)\n\nRan 1 test for test/audit/ConfigBoundary.t.sol:AuditConfigBoundaryTest\n[PASS] test_audit_questionProposedBeforeQueue_refusesTheNewConfig() (gas: 1169214)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.44ms (702.02µs CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKeyIncludingNoAnswer() (gas: 659412)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 650149)\n[PASS] test_callbackSelectorIsCanonical() (gas: 418)\n[PASS] test_digestMatchesTheProtocol() (gas: 29662)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 3.56ms (999.60µs CPU time)\n\nRan 2 tests for test/audit/StewardAdapter.t.sol:AuditStewardAdapterTest\n[PASS] test_audit_stewardAdapter_capturesEmissionWithoutAnswers() (gas: 1662394)\nLogs:\n  HMM taken for 0.5 IMD, no oracle answer (whole tokens): 56616078\n\n[PASS] test_noSteward_rulesAreFixedForever() (gas: 4316214)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.66ms (1.23ms CPU time)\n\nRan 3 tests for test/NoSteward.t.sol:NoStewardTest\n[PASS] test_adapter_cannotBeClaimedOnceTheMineHasIt() (gas: 46518)\n[PASS] test_launchArgs_haveNoZeroAddress() (gas: 9906)\n[PASS] test_realMine_hasNoSteward_andNobodyCanNameOne() (gas: 381977)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.76ms (1.62ms CPU time)\n\nRan 9 tests for test/GenesisForwarder.t.sol:GenesisForwarderTest\n[PASS] test_constructor_validates() (gas: 3851)\n[PASS] test_copycatLaunch_cannotTouchTheRealReserve() (gas: 9977677)\n[PASS] test_crossWiredLaunch_isRefused() (gas: 5696440)\n[PASS] test_forward_lateTokensMoveWithoutRestartingTheMine() (gas: 311768)\n[PASS] test_forward_movesTheWholeRemainderAndStarts() (gas: 4999194)\n[PASS] test_forward_refusesALaunchWithoutAMine() (gas: 226458)\n[PASS] test_forward_refusesAMineOfAnotherForwarder() (gas: 88326)\n[PASS] test_forward_refusesAMineOfAnotherToken() (gas: 872809)\n[PASS] test_forward_refusesOtherLaunchKinds() (gas: 124935)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 4.66ms (2.59ms CPU time)\n\nRan 3 tests for test/audit/Rounding.t.sol:RoundingTest\n[PASS] test_multipleQuestionsOwnedByOneBackerCanClaimTheFinalDustInABatch() (gas: 2330250)\n[PASS] test_sevenSharesAndTenRewardPayFourThenSix() (gas: 1941131)\n[PASS] test_zeroRoundedClaimIsConsumedSoTheLastBackerCanTakeTheWei() (gas: 1388345)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.53ms (3.62ms CPU time)\n\nRan 7 tests for test/audit/RequestLifecycle.t.sol:RequestLifecycleTest\n[PASS] test_delegatedAccountsCanStillBackPartiallyOrFundOnlyTheirOwnQuestion() (gas: 1207926)\n[PASS] test_delegatedOriginCannotSpendOtherBackersFundsInABatch() (gas: 1326788)\n[PASS] test_expire_boundaryIsMeasuredFromAskAndMovesNoFunds() (gas: 814895)\n[PASS] test_expiredRequestCannotBeRevivedByALateSignedAnswerOrFailure() (gas: 711083)\n[PASS] test_malformedUndeliveredCallbackCanExpire() (gas: 580688)\n[PASS] test_onlyAskedQuestionsCanExpireAndLateAnswersRemainValidUntilCleared() (gas: 986381)\n[PASS] test_separatelyDeployedAdapterCanBeClaimedBeforeMineConstruction() (gas: 66366)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 6.33ms (5.01ms CPU time)\n\nRan 8 tests for test/OwnerlessFailurePaths.t.sol:OwnerlessFailurePathsTest\n[PASS] testFuzz_noncanonicalSignaturesAreRecordedAsFailure(uint8) (runs: 256, μ: 632502, ~: 631866)\n[PASS] test_actionDelistedWhileFundingCannotTakeTheFinalBackersMoney() (gas: 522092)\n[PASS] test_attestationAtExpiryIsAcceptedButOneSecondLaterIsRejected() (gas: 1225619)\n[PASS] test_duplicateDeliveryDoesNotConsumeANewAnswerOrReopenASettledQuestion() (gas: 846377)\n[PASS] test_failedCompleterCannotChangeBodyOrConsumeTheirAllowance() (gas: 831832)\n[PASS] test_foreignFailureCannotCloseOrDebitAnHonestRequest() (gas: 1211256)\n[PASS] test_intakeRevertRollsBackPriceAdjustmentApprovalAndCompleterPayment() (gas: 976956)\n[PASS] test_proposalWithoutAllowanceLeavesNoQuestionOrPayment() (gas: 261668)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 345.09ms (346.02ms CPU time)\n\nRan 5 tests for test/audit/Definitions.t.sol:DefinitionsTest\n[PASS] test_definitionsAppearInTheCommittedBodyAndCannotBeChangedByCompleter() (gas: 1407694)\n[PASS] test_definitionsRejectInjectionDuplicatesAndOversizedInput() (gas: 632909)\n[PASS] test_emptyDefinitionsPreserveTheExistingBodyAndSoloFlow() (gas: 481266)\n[PASS] test_maximumDefinitionsAndQuestionFitThePaidBodyLimit() (gas: 9896341)\n[PASS] test_wordingRefusalStillSpendsTheIntakePriceAndMinesNothing() (gas: 702016)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 576.62ms (25.70ms CPU time)\n\nRan 11 tests for test/SwarmOracleAdapter.t.sol:SwarmOracleAdapterTest\n[PASS] testFuzz_realSignature_breaksOnAnyTamper(uint8,uint256) (runs: 2000, μ: 22870, ~: 22800)\n[PASS] test_bind_onceAndIdempotent() (gas: 125198)\n[PASS] test_check_reasons() (gas: 333794)\n[PASS] test_constructor_validates() (gas: 6172)\n[PASS] test_longAnswer_isCountedAndHashed() (gas: 2617763)\n[PASS] test_onlyTheIntakeCallsBack() (gas: 96585)\n[PASS] test_realSwarmSignatures_recoverTheOracleSigner() (gas: 76785)\n[PASS] test_selectors_matchTheSwarmsCallbackShape() (gas: 5907)\n[PASS] test_thoughtEvent_carriesTheAnswer() (gas: 686138)\n[PASS] test_unboundAdapterRefusesCallbacks() (gas: 78375)\n[PASS] test_unknownRequestIsRefused() (gas: 83194)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 576.54ms (594.45ms CPU time)\n\nRan 5 tests for test/audit/PriceDrop.t.sol:PriceDropTest\n[PASS] testFuzz_priceDrop_conservesIMDAndHMMInEitherRefundOrder(uint96,uint96,uint96,uint8,bool) (runs: 2000, μ: 1660463, ~: 1707488)\n[PASS] test_claimAutomaticallyRefundsSurplusAndUsesActualPaidShares() (gas: 2203192)\n[PASS] test_failedAndExpiredRequestsKeepOnlyUnspentSurplusRefundable() (gas: 1827093)\n[PASS] test_priceDrop_matchesImportedProofAndRefundsEachBackerOnce() (gas: 1089032)\n[PASS] test_zeroRoundedSurplusCanBeAcknowledgedAndLastRefundGetsDust() (gas: 865410)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 576.92ms (577.81ms CPU time)\n\nRan 6 tests for test/HmmTokenProperties.t.sol:HmmTokenPropertiesTest\n[PASS] testFuzz_transferAndTransferFromHaveNoFee(uint256,bool) (runs: 1000, μ: 124186, ~: 95255)\n[PASS] test_factoryAndStrangerHaveNoAdministrativeOrBurnPowers() (gas: 1135557)\n[PASS] test_failedTransferFromRollsBackTheAllowance() (gas: 117924)\n[PASS] test_infiniteAllowanceIsNotSpentAndCanBeRevoked() (gas: 181559)\n[PASS] test_selfTransfersAndZeroTransfersPreserveBalances() (gas: 171868)\n[PASS] test_zeroReceiverAndSpenderAreRejectedWithoutBurning() (gas: 158099)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 586.37ms (587.04ms CPU time)\n\nRan 45 tests for test/HmmMine.t.sol:HmmMineTest\n[PASS] test_answerInALaterEra_isWorthLess() (gas: 1519480)\n[PASS] test_answerThatDoesNotCount_isRecordedAsFailed() (gas: 590687)\n[PASS] test_answer_creditsTheRound_withRolloverSinceGenesis() (gas: 747893)\n[PASS] test_back_minimumUnlessCompletingTheRemainder() (gas: 622319)\n[PASS] test_back_refusedWhenClosedOrNotOpen() (gas: 749116)\n[PASS] test_bodyOf_isTheExactJsonTheSwarmChecked() (gas: 65460)\n[PASS] test_callback_fitsTheIntakeStipend() (gas: 744866)\nLogs:\n  callback gas (refused path): 46589\n\n[PASS] test_callback_gasMargin() (gas: 2572847)\nLogs:\n  minimum stipend for the costliest callback: 118437\n\n[PASS] test_claim_onlyAfterTheRoundEnds() (gas: 996946)\n[PASS] test_config_cancel_andRenounce() (gas: 241339)\n[PASS] test_config_queueApplyAfterDelay_newQuestionsOnly() (gas: 1520008)\n[PASS] test_config_refusesAnAdapterBoundToAnotherMine() (gas: 186659)\n[PASS] test_constructor_validates() (gas: 2454011)\n[PASS] test_creditAndFail_onlyFromTheQuestionsAdapter() (gas: 529017)\n[PASS] test_devShare_isPaidToDev_byAnyone() (gas: 817763)\n[PASS] test_emptyRoundsRollIntoTheNextAnsweredRound() (gas: 1321923)\n[PASS] test_failure_closesTheQuestion_withoutCredit() (gas: 600576)\n[PASS] test_forgedAnswer_doesNotCount() (gas: 588878)\n[PASS] test_genesisDelay_blocksQuestionsUntilGenesis() (gas: 5495356)\n[PASS] test_halving_halvesTheRate() (gas: 153495)\n[PASS] test_oneAskPerTransaction() (gas: 1842650)\n[PASS] test_outsiderRequestNamingTheAdapter_cannotMine() (gas: 485017)\n[PASS] test_ownQuestion_completedByAContractIsFine() (gas: 916024)\n[PASS] test_pooledCompletion_mustComeFromAnAccountDirectly() (gas: 1222917)\n[PASS] test_pooledQuestion_isAskedWhenTheLastBackerCompletesIt() (gas: 932395)\n[PASS] test_priceFall_paysTheLivePriceAndKeepsTheSurplus() (gas: 696856)\n[PASS] test_priceRise_blocksTheAsk_andBackersRefund() (gas: 477773)\n[PASS] test_propose_capsAmountAtPrice() (gas: 437837)\n[PASS] test_propose_notSoldWhenPriceIsZero() (gas: 90121)\n[PASS] test_propose_rejectsDust() (gas: 53854)\n[PASS] test_refund_afterDeadlineOnly_andOnce() (gas: 598720)\n[PASS] test_refund_refusedOnceAsked() (gas: 480975)\n[PASS] test_refusal_closesTheQuestion() (gas: 541831)\n[PASS] test_sameOracleAnswer_countsOnce() (gas: 1158007)\n[PASS] test_sameRound_splitsByIMDPaid_andPooledBackersSplitByShare() (gas: 1579226)\n[PASS] test_soloAsk_paysTheSwarmAndRecordsTheRequest() (gas: 556886)\n[PASS] test_spec_rulesAndInjection() (gas: 578943)\n[PASS] test_start_needsReserve() (gas: 4821133)\n[PASS] test_start_onlyForwarder() (gas: 29596)\n[PASS] test_start_repeatedForwarderCallDoesNotRestart() (gas: 66904)\n[PASS] test_start_setsReserveGenesisAndRate() (gas: 50339)\n[PASS] test_stats_andPot() (gas: 785024)\n[PASS] test_stats_beforeStart() (gas: 4825078)\n[PASS] test_token_isPlainAndFixed() (gas: 36651)\n[PASS] test_writerCannotCreditAPendingRequestThroughAnotherCompletion() (gas: 987990)\nSuite result: ok. 45 passed; 0 failed; 0 skipped; finished in 586.48ms (26.04ms CPU time)\n\nRan 6 tests for test/Emission.t.sol:EmissionTest\n[PASS] testFuzz_answeredRounds_accountForEveryEmittedUnit(uint32[6]) (runs: 2000, μ: 4428864, ~: 4447927)\n[PASS] testFuzz_emittedAt_isMonotonic(uint64,uint64) (runs: 2000, μ: 35589, ~: 32987)\n[PASS] testFuzz_emittedAt_isTheIntegralOfTheRate(uint64) (runs: 2000, μ: 147134, ~: 43753)\n[PASS] testFuzz_emittedAt_neverExceedsTheReserve(uint256) (runs: 2000, μ: 25508, ~: 32254)\n[PASS] testFuzz_pooledClaims_neverExceedTheRound(uint96[5]) (runs: 2000, μ: 1980662, ~: 1899731)\n[PASS] test_firstEra_emitsHalfTheReserve_andTheTailIsDust() (gas: 47003)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 586.88ms (2.87s CPU time)\n\nRan 1 test for test/invariant/ForwarderReserves.t.sol:ForwarderReservesInvariantTest\n[PASS] invariant_eachLaunchRetainsItsEntireOwnReserve() (runs: 256, calls: 25600, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| ForwarderReservesHandler | advance       | 6458  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| ForwarderReservesHandler | donate        | 6333  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| ForwarderReservesHandler | forward       | 6354  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| ForwarderReservesHandler | invalidLaunch | 6455  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.30s (7.30s CPU time)\n\nRan 1 test for test/HmmTokenProperties.t.sol:HmmTokenLedgerInvariantTest\n[PASS] invariant_balancesAndAllowancesMatchTheIndependentLedger() (runs: 256, calls: 25600, reverts: 0)\n\n╭-----------------------+--------------+-------+---------+----------╮\n| Contract              | Selector     | Calls | Reverts | Discards |\n+===================================================================+\n| HmmTokenLedgerHandler | approve      | 8645  | 0       | 0        |\n|-----------------------+--------------+-------+---------+----------|\n| HmmTokenLedgerHandler | transfer     | 8525  | 0       | 0        |\n|-----------------------+--------------+-------+---------+----------|\n| HmmTokenLedgerHandler | transferFrom | 8430  | 0       | 0        |\n╰-----------------------+--------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.72s (7.72s CPU time)\n\nRan 1 test for test/audit/AdversarialInvariants.t.sol:AuditAdversarialInvariantTest\n[PASS]\nAuditAdversarialInvariantTest invariants:\n[PASS] invariant_audit_hmmConservedAndSolvent\n[PASS] invariant_audit_imdConserved\n[PASS] invariant_audit_roundsConsistent\n AuditAdversarialInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭--------------------+-----------+-------+---------+----------╮\n| Contract           | Selector  | Calls | Reverts | Discards |\n+=============================================================+\n| AdversarialHandler | back      | 2032  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | claim     | 2051  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | expire    | 2013  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | movePrice | 2001  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | payDev    | 2113  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | propose   | 2046  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | refund    | 2018  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | rotate    | 2081  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | settle    | 2021  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | warp      | 2104  | 0       | 0        |\n╰--------------------+-----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.08s (8.07s CPU time)\n\nRan 1 test for test/invariant/MineInvariants.t.sol:MineInvariantTest\n[PASS]\nMineInvariantTest invariants:\n[PASS] invariant_hmmIsConserved\n[PASS] invariant_imdIsConserved\n[PASS] invariant_questionsAreConsistent\n[PASS] invariant_roundSharesMatchAnsweredQuestions\n[PASS] invariant_solvency\n MineInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭-------------+----------+-------+---------+----------╮\n| Contract    | Selector | Calls | Reverts | Discards |\n+=====================================================+\n| MineHandler | back     | 2904  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | claim    | 2936  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | payDev   | 2887  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | propose  | 2946  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | refund   | 2940  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | settle   | 2940  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | warp     | 2927  | 0       | 0        |\n╰-------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.48s (12.48s CPU time)\n\nRan 1 test for test/invariant/OwnerlessMineLifecycle.t.sol:OwnerlessMineLifecycleInvariantTest\n[PASS]\nOwnerlessMineLifecycleInvariantTest invariants:\n[PASS] invariant_ownerlessRulesAndReserveRemainFixed\n[PASS] invariant_questionLedgersAndTerminalStatesAreConsistent\n[PASS] invariant_tokensCoverEveryOutstandingObligation\n OwnerlessMineLifecycleInvariantTest invariants (runs: 256, calls: 25600, reverts: 0)\n\n╭---------------------------+------------------+-------+---------+----------╮\n| Contract                  | Selector         | Calls | Reverts | Discards |\n+===========================================================================+\n| OwnerlessLifecycleHandler | back             | 2168  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | claim            | 2163  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | donate           | 2147  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | duplicateClaim   | 2063  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | expireChecked    | 2149  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | movePrice        | 2157  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | payDev           | 2152  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | propose          | 2090  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | refund           | 2123  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | settleChecked    | 2184  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | tryChangingRules | 2119  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | warp             | 2085  | 0       | 0        |\n╰---------------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 14.37s (14.36s CPU time)\n\nRan 22 test suites in 14.37s (53.82s CPU time): 123 tests passed, 0 failed, 0 skipped (123 total tests)\n","passed":true},{"durationMs":87,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"GenesisForwarder.forward(uint64)\",\"HmmMine.applyConfig()\",\"HmmMine.back(uint256,uint256,bytes)\",\"HmmMine.cancelConfig()\",\"HmmMine.claim(uint256[])\",\"HmmMine.credit(bytes32)\",\"HmmMine.expire(uint256)\",\"HmmMine.fail(bytes32,uint8,bytes32)\",\"HmmMine.payDev()\",\"HmmMine.propose((string,uint8,uint8,uint32,uint16,uint16,uint16,uint16),uint256)\",\"HmmMine.proposeWithDefinitions((string,uint8,uint8,uint32,uint16,uint16,uint16,uint16),(string,string)[],uint256)\",\"HmmMine.queueConfig(address,bytes32)\",\"HmmMine.refund(uint256)\",\"HmmMine.setSteward(address)\",\"HmmMine.start()\",\"HmmToken.approve(address,uint256)\",\"HmmToken.transfer(address,uint256)\",\"HmmToken.transferFrom(address,address,uint256)\",\"SwarmOracleAdapter.bind()\",\"SwarmOracleAdapter.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"SwarmOracleAdapter.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\"],\"files\":{\".github/workflows/test.yml\":20,\".gitignore\":18,\"ADAPTATION.md\":178,\"LICENSE\":21,\"README.md\":66,\"devnet/activity.mjs\":129,\"devnet/package-lock.json\":217,\"devnet/package.json\":12,\"devnet/preview-tunnel.sh\":21,\"devnet/preview.mjs\":127,\"devnet/start.sh\":44,\"devnet/stop.sh\":9,\"devnet/swarm.mjs\":222,\"docs/DESIGN.md\":90,\"docs/LAUNCH.md\":94,\"docs/SECURITY.md\":89,\"docs/TOKENOMICS.md\":56,\"foundry.toml\":52,\"launch/body.json\":36,\"launch/build-site-body.mjs\":22,\"launch/build.mjs\":107,\"launch/buy-imd.mjs\":65,\"launch/check.mjs\":21,\"launch/config.json\":12,\"launch/export-public.sh\":33,\"launch/export-site.sh\":40,\"launch/metrics.mjs\":70,\"launch/package-lock.json\":248,\"launch/package.json\":11,\"launch/pay.mjs\":205,\"launch/watch.mjs\":88,\"remappings.txt\":2,\"script/DeployForwarder.s.sol\":31,\"script/Devnet.s.sol\":87,\"script/HmmLaunch.sol\":143,\"script/IProjectFactory.sol\":64,\"src/GenesisForwarder.sol\":65,\"src/HmmMine.sol\":778,\"src/HmmToken.sol\":15,\"src/SwarmOracleAdapter.sol\":217,\"src/interfaces/IHmmMine.sol\":20,\"src/interfaces/IIntake.sol\":31,\"src/interfaces/ILaunchRegistry.sol\":27,\"src/interfaces/IOracleAdapter.sol\":15,\"test/Emission.t.sol\":118,\"test/FactoryLaunch.t.sol\":67,\"test/GenesisForwarder.t.sol\":112,\"test/HmmMine.t.sol\":874,\"test/HmmTokenProperties.t.sol\":235,\"test/NoSteward.t.sol\":73,\"test/OracleConsumerConformance.t.sol\":100,\"test/OwnerlessFailurePaths.t.sol\":208,\"test/SwarmOracleAdapter.t.sol\":190,\"test/audit/AdversarialInvariants.t.sol\":282,\"test/audit/ConfigBoundary.t.sol\":44,\"test/audit/Definitions.t.sol\":130,\"test/audit/ForeignRequestFirst.t.sol\":57,\"test/audit/PriceDrop.t.sol\":180,\"test/audit/RequestLifecycle.t.sol\":144,\"test/audit/Rounding.t.sol\":99,\"test/audit/StewardAdapter.t.sol\":113,\"test/external/Intake.sol\":325,\"test/fixtures/RealAttestations.sol\":137,\"test/fork/Launch.fork.t.sol\":290,\"test/invariant/ForwarderReserves.t.sol\":208,\"test/invariant/MineInvariants.t.sol\":241,\"test/invariant/OwnerlessMineLifecycle.t.sol\":294,\"test/utils/HmmMineStewarded.sol\":26,\"test/utils/HmmTestBase.sol\":234,\"test/utils/Mocks.sol\":45,\"test/utils/OwnerlessMineTestBase.sol\":60,\"web/.env.example\":22,\"web/.gitignore\":5,\"web/.npmrc\":1,\"web/README.md\":184,\"web/e2e/devnet.e2e.test.ts\":248,\"web/index.html\":24,\"web/lab/pond-lab.tsx\":267,\"web/lab/pond.html\":18,\"web/package-lock.json\":8959,\"web/package.json\":41,\"web/proxy/check-worker.js\":71,\"web/public/favicon.svg\":18,\"web/scripts/abi.mjs\":49,\"web/src/App.tsx\":113,\"web/src/abi/genesisForwarder.ts\":194,\"web/src/abi/hmmMine.ts\":1666,\"web/src/abi/hmmToken.ts\":329,\"web/src/abi/index.ts\":5,\"web/src/abi/swarmOracleAdapter.ts\":739,\"web/src/components/EmissionChart.tsx\":173,\"web/src/components/Footer.tsx\":46,\"web/src/components/FrogMascot.tsx\":142,\"web/src/components/Header.tsx\":109,\"web/src/components/LaunchBanner.tsx\":34,\"web/src/components/LiveNotifier.tsx\":40,\"web/src/components/MoonGlyph.tsx\":101,\"web/src/components/ScrollStory.tsx\":439,\"web/src/components/ShareCard.tsx\":236,\"web/src/components/Wallet.tsx\":225,\"web/src/components/icons.tsx\":70,\"web/src/components/question.tsx\":246,\"web/src/components/states.tsx\":63,\"web/src/components/toast.tsx\":97,\"web/src/components/ui.tsx\":416,\"web/src/config.ts\":209,\"web/src/data/app.tsx\":125,\"web/src/data/claim.ts\":19,\"web/src/data/clock.ts\":56,\"web/src/data/discovery.ts\":158,\"web/src/data/hooks.ts\":506,\"web/src/data/indexer.test.ts\":164,\"web/src/data/indexer.ts\":603,\"web/src/data/liveRound.test.ts\":45,\"web/src/data/mining.ts\":90,\"web/src/data/pondFeed.ts\":56,\"web/src/data/rpcErrors.ts\":10,\"web/src/data/token.ts\":33,\"web/src/data/tx.ts\":93,\"web/src/devnet/connectors.ts\":14,\"web/src/devnet/keys.ts\":13,\"web/src/devnet/localKey.ts\":123,\"web/src/devnet/ui.tsx\":144,\"web/src/env.d.ts\":4,\"web/src/lib/answer.test.ts\":51,\"web/src/lib/answer.ts\":97,\"web/src/lib/body.test.ts\":168,\"web/src/lib/body.ts\":321,\"web/src/lib/check.ts\":71,\"web/src/lib/emission.test.ts\":119,\"web/src/lib/emission.ts\":134,\"web/src/lib/errors.ts\":85,\"web/src/lib/format.test.ts\":88,\"web/src/lib/format.ts\":166,\"web/src/lib/reasons.test.ts\":34,\"web/src/lib/reasons.ts\":101,\"web/src/lib/spec.test.ts\":89,\"web/src/lib/spec.ts\":116,\"web/src/main.tsx\":49,\"web/src/pages/AskPage.tsx\":826,\"web/src/pages/FaqPage.tsx\":88,\"web/src/pages/HowPage.tsx\":293,\"web/src/pages/LedgerPage.tsx\":204,\"web/src/pages/MePage.tsx\":251,\"web/src/pages/MinersPage.tsx\":112,\"web/src/pages/MoonPage.tsx\":207,\"web/src/pages/NotFound.tsx\":9,\"web/src/pages/OpenPage.tsx\":97,\"web/src/pages/PondPage.tsx\":806,\"web/src/pages/QuestionPage.tsx\":277,\"web/src/pages/TokenPage.tsx\":222,\"web/src/pond/PondCanvas.tsx\":60,\"web/src/pond/camera.ts\":107,\"web/src/pond/crowd.ts\":629,\"web/src/pond/effects.ts\":889,\"web/src/pond/engine.ts\":1999,\"web/src/pond/fallback2d.ts\":159,\"web/src/pond/moon.ts\":222,\"web/src/pond/rng.ts\":100,\"web/src/pond/sim.ts\":278,\"web/src/pond/sprites.ts\":451,\"web/src/pond/types.ts\":130,\"web/src/pond/water-gl.ts\":480,\"web/src/sound/SoundToggle.tsx\":29,\"web/src/sound/engine.ts\":362,\"web/src/styles/app.css\":594,\"web/src/styles/global.css\":1171,\"web/src/styles/pages.css\":2073,\"web/src/theme.ts\":27,\"web/src/wagmi.ts\":32,\"web/tsconfig.json\":34,\"web/vite.config.ts\":166,\"web/vitest.e2e.config.ts\":14},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"2ff4cd3d0c93716cffb04b2d564e0c93b29f1715e2fbced53a1687aa1d7f4b26","verifiedTreeHash":"f97d4bffa83bbfe468330519b4787955302feac7","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":12144,"exitCode":0,"name":"build","output":"Compiling 89 files with Solc 0.8.26\nSolc 0.8.26 finished in 11.85s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/utils/HmmTestBase.sol:200:5:\n    |\n200 |     function _delivered() internal returns (bool) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n   --> test/HmmMine.t.sol:574:5:\n    |\n574 |     function test_halving_halvesTheRate() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n   --> test/fork/Launch.fork.t.sol:274:5:\n    |\n274 |     function _delivered() internal returns (bool) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmOracleAdapter.sol:96:20\n   │\n96 │         minPanel = uint16(minPanel_);\n   │                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/GenesisForwarder.sol:53:41\n   │\n53 │             if (a.role == ROLE_TOKEN && token == address(0)) token = a.addr;\n   │                                         ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/GenesisForwarder.sol:54:68\n   │\n54 │             else if (a.role == ROLE_OTHER && a.name == mineName && mine == address(0)) mine = a.addr;\n   │                                                                    ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmOracleAdapter.sol:97:21\n   │\n97 │         minQuorum = uint16(minQuorum_);\n   │                     ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/GenesisForwarder.sol:63:9\n   │\n63 │         emit Forwarded(launchNumber, token, mine, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-events-access-control]: `steward` is changed without an event but is used for access control\n    ╭▸ src/HmmMine.sol:496:9\n    │\n496 │         steward = next;\n    │         ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:127:13\n    │\n127 │             emit Rejected(requestId, a.requestId, reason);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:138:9\n    │\n138 │ ┏         emit Thought(\n139 │ ┃             requestId, a.requestId, a.chainId, a.answerType, answerHash, shown, a.panelSize, a.quorum, a.agreed\n140 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/SwarmOracleAdapter.sol:120:47\n    │\n120 │         (, address target,, bool completed) = intake.requests(requestId);\n    │                                               ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmOracleAdapter.sol:157:9\n    │\n157 │         emit Unanswered(requestId, status, reason, agreed, answered);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:268:9\n    │\n268 │         emit ConfigApplied(adapter_, action_);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:333:9\n    │\n333 │         emit Proposed(id, msg.sender, price, q.deadline, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:730:9\n    │\n730 │         emit Backed(id, msg.sender, amount, raised);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:767:28\n    │\n767 │         if (live != price) emit PriceAdjusted(id, price, live);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:776:9\n    │\n776 │         emit Asked(id, requestId, a);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:329:22\n    │\n329 │         q.deadline = uint64(block.timestamp + FUNDING_WINDOW);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:331:20\n    │\n331 │         q.target = uint128(price);\n    │                    ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:345:13\n    │\n345 │         if (block.timestamp > q.deadline) revert FundingClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:358:17\n    │\n358 │             if (block.timestamp <= q.deadline) revert NotRefundable();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:362:25\n    │\n362 │             q.raised -= uint128(amount);\n    │                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:379:13\n    │\n379 │         if (block.timestamp <= deadline) revert TooEarly(deadline + 1);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/HmmMine.sol:394:13\n    │\n394 │             refundTotal += _takeSurplus(id, q, msg.sender);\n    │             ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:391:48\n    │\n391 │             if (q.status != Status.Answered || block.timestamp < roundEnd(q.round) || weight == 0) continue;\n    │                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:610:9\n    │\n610 │         emit SurplusRefunded(id, backer, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:401:13\n    │\n401 │             emit Claimed(id, msg.sender, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:396:35\n    │\n396 │             claimedBacking[id] += uint128(weight);\n    │                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:399:33\n    │\n399 │             progress.claimed += uint128(amount);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:437:13\n    │\n437 │             emit RoundOpened(r, emitted, devShare);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:443:9\n    │\n443 │         emit Answered(id, requestId, r, shares);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:436:28\n    │\n436 │             round.reward = uint128(emitted - devShare);\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:440:25\n    │\n440 │         round.shares += uint128(shares);\n    │                         ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:441:19\n    │\n441 │         q.round = uint32(r);\n    │                   ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pendingAdapter` is updated\n    ╭▸ src/HmmMine.sol:482:9\n    │\n482 │         IOracleAdapter(next).bind();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:480:13\n    │\n480 │         if (block.timestamp < eta) revert TooEarly(eta);\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/HmmMine.sol:490:9\n    │\n490 │         emit ConfigApplied(next, action);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/HmmMine.sol:494:25\n    │\n494 │     function setSteward(address next) external onlySteward {\n    │                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/HmmMine.sol:527:15\n    │\n527 │             ) revert BadDefinitions();\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/HmmMine.sol:529:86\n    │\n529 │                 if (keccak256(bytes(d.key)) == keccak256(bytes(definitions[j].key))) revert BadDefinitions();\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/HmmMine.sol:539:29\n    │\n539 │           bytes memory head = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n540 │ ┃             '{\"v\":1,\"question\":\"',\n541 │ ┃             spec.question,\n542 │ ┃             '\",\"chainId\":',\n    ‡ ┃\n549 │ ┃             spec.evidence == 0 ? _CHAIN : _PANEL\n550 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/HmmMine.sol:551:29\n    │\n551 │           bytes memory tail = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n552 │ ┃             '\",\"panelSize\":',\n553 │ ┃             Strings.toString(spec.panelSize),\n554 │ ┃             ',\"quorum\":',\n    ‡ ┃\n561 │ ┃             \"}\"\n562 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:576:13\n    │\n576 │         if (block.timestamp < roundEnd(r)) return 0;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:594:45\n    │\n594 │         if (q.status == Status.Open) return block.timestamp > q.deadline ? amount : 0;\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:607:29\n    │\n607 │         progress.backing += uint128(backing[id][backer]);\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:608:30\n    │\n608 │         progress.refunded += uint128(amount);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/HmmMine.sol:625:56\n    │\n625 │         if (era < MAX_ERAS) total += rate * (elapsed - era * eraLength);\n    │                                                        ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:643:23\n    │\n643 │         if (g == 0 || block.timestamp < g) return 0;\n    │                       ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:670:21\n    │\n670 │         uint256 t = block.timestamp < genesis ? genesis : block.timestamp;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/HmmMine.sol:682:26\n    │\n682 │         return g != 0 && block.timestamp >= g;\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:728:20\n    │\n728 │         q.raised = uint128(raised);\n    │                    ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/HmmMine.sol:765:20\n    │\n765 │         q.target = uint128(live);\n    │                    ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Emission.t.sol:51:21\n   │\n51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n   │             ────────━━━━━━━━━━━━━━━─────────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Emission.t.sol:51:13\n    │\n 51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n    │             ────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Emission.t.sol:51:13\n    │\n 51 │             vm.warp(block.timestamp + bound(uint256(gaps[i]), 1, 30 days));\n    │             ────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:499:17\n    │\n499 │         vm.warp(block.timestamp + 3 hours + 5 minutes); // round 18\n    │         ────────━━━━━━━━━━━━━━━─────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HmmMine.t.sol:562:9\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ───────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HmmMine.t.sol:562:9\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ───────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:562:17\n    │\n562 │         vm.warp(block.timestamp + 10 * ROUND);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    ‡\n232 │         vm.warp(mine.roundEnd(_roundOf(id)));\n    │         ──────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n232 │         vm.warp(mine.roundEnd(_roundOf(id)));\n    │         ──────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:721:17\n    │\n721 │         vm.warp(block.timestamp + 40 * ERA + 7 days);\n    │         ────────━━━━━━━━━━━━━━━───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:749:17\n    │\n749 │         vm.warp(block.timestamp + 40 * ERA + 7 days);\n    │         ────────━━━━━━━━━━━━━━━───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:792:75\n    │\n792 │         vm.expectRevert(abi.encodeWithSelector(HmmMine.TooEarly.selector, block.timestamp + 3 days));\n    │                                                                           ━━━━━━━━━━━━━━━\n793 │         mine.applyConfig();\n794 │         vm.warp(block.timestamp + 3 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:794:17\n    │\n794 │         vm.warp(block.timestamp + 3 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HmmMine.t.sol:840:17\n    │\n840 │         vm.warp(block.timestamp + 25 minutes); // round 2\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:155:29\n    │\n155 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/OwnerlessFailurePaths.t.sol:143:9\n    │\n143 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/utils/HmmTestBase.sol:156:30\n    │\n156 │         a.expiresAt = uint64(block.timestamp + 1 days);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/OwnerlessFailurePaths.t.sol:143:9\n    │\n143 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/audit/StewardAdapter.t.sol:47:17\n   │\n47 │         vm.warp(block.timestamp + 3 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":16745,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/invariant/ForwarderReserves.t.sol:ForwarderAtomicityTest\n[PASS] test_startFailureRollsBackTheWholeTokenTransferAndCanBeRetried() (gas: 1633967)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.22ms (1.03ms CPU time)\n\nRan 1 test for test/FactoryLaunch.t.sol:FactoryLaunchTest\n[PASS] test_exactLaunchArgumentsDeployAtomicallyWithoutExternalCodeOrTokenMovements() (gas: 568590)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 816.75µs (681.52µs CPU time)\n\nRan 1 test for test/audit/ForeignRequestFirst.t.sol:AuditForeignRequestFirstTest\n[PASS] test_audit_foreignRequestBeforeTheAsk_isRefused() (gas: 1369975)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.03ms (593.43µs CPU time)\n\nRan 3 tests for test/NoSteward.t.sol:NoStewardTest\n[PASS] test_adapter_cannotBeClaimedOnceTheMineHasIt() (gas: 46518)\n[PASS] test_launchArgs_haveNoZeroAddress() (gas: 9906)\n[PASS] test_realMine_hasNoSteward_andNobodyCanNameOne() (gas: 381977)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 4.37ms (1.11ms CPU time)\n\nRan 2 tests for test/audit/StewardAdapter.t.sol:AuditStewardAdapterTest\n[PASS] test_audit_stewardAdapter_capturesEmissionWithoutAnswers() (gas: 1662394)\nLogs:\n  HMM taken for 0.5 IMD, no oracle answer (whole tokens): 56616078\n\n[PASS] test_noSteward_rulesAreFixedForever() (gas: 4316214)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.70ms (1.48ms CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKeyIncludingNoAnswer() (gas: 659412)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 650149)\n[PASS] test_callbackSelectorIsCanonical() (gas: 418)\n[PASS] test_digestMatchesTheProtocol() (gas: 29662)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 6.82ms (1.28ms CPU time)\n\nRan 1 test for test/audit/ConfigBoundary.t.sol:AuditConfigBoundaryTest\n[PASS] test_audit_questionProposedBeforeQueue_refusesTheNewConfig() (gas: 1169214)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.17ms (1.33ms CPU time)\n\nRan 3 tests for test/audit/Rounding.t.sol:RoundingTest\n[PASS] test_multipleQuestionsOwnedByOneBackerCanClaimTheFinalDustInABatch() (gas: 2330250)\n[PASS] test_sevenSharesAndTenRewardPayFourThenSix() (gas: 1941131)\n[PASS] test_zeroRoundedClaimIsConsumedSoTheLastBackerCanTakeTheWei() (gas: 1388345)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 11.06ms (5.30ms CPU time)\n\nRan 7 tests for test/audit/RequestLifecycle.t.sol:RequestLifecycleTest\n[PASS] test_delegatedAccountsCanStillBackPartiallyOrFundOnlyTheirOwnQuestion() (gas: 1207926)\n[PASS] test_delegatedOriginCannotSpendOtherBackersFundsInABatch() (gas: 1326788)\n[PASS] test_expire_boundaryIsMeasuredFromAskAndMovesNoFunds() (gas: 814895)\n[PASS] test_expiredRequestCannotBeRevivedByALateSignedAnswerOrFailure() (gas: 711083)\n[PASS] test_malformedUndeliveredCallbackCanExpire() (gas: 580688)\n[PASS] test_onlyAskedQuestionsCanExpireAndLateAnswersRemainValidUntilCleared() (gas: 986381)\n[PASS] test_separatelyDeployedAdapterCanBeClaimedBeforeMineConstruction() (gas: 66366)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 11.43ms (6.62ms CPU time)\n\nRan 8 tests for test/OwnerlessFailurePaths.t.sol:OwnerlessFailurePathsTest\n[PASS] testFuzz_noncanonicalSignaturesAreRecordedAsFailure(uint8) (runs: 256, μ: 632301, ~: 631866)\n[PASS] test_actionDelistedWhileFundingCannotTakeTheFinalBackersMoney() (gas: 522092)\n[PASS] test_attestationAtExpiryIsAcceptedButOneSecondLaterIsRejected() (gas: 1225619)\n[PASS] test_duplicateDeliveryDoesNotConsumeANewAnswerOrReopenASettledQuestion() (gas: 846377)\n[PASS] test_failedCompleterCannotChangeBodyOrConsumeTheirAllowance() (gas: 831832)\n[PASS] test_foreignFailureCannotCloseOrDebitAnHonestRequest() (gas: 1211256)\n[PASS] test_intakeRevertRollsBackPriceAdjustmentApprovalAndCompleterPayment() (gas: 976956)\n[PASS] test_proposalWithoutAllowanceLeavesNoQuestionOrPayment() (gas: 261668)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 105.28ms (105.90ms CPU time)\n\nRan 5 tests for test/audit/Definitions.t.sol:DefinitionsTest\n[PASS] test_definitionsAppearInTheCommittedBodyAndCannotBeChangedByCompleter() (gas: 1407694)\n[PASS] test_definitionsRejectInjectionDuplicatesAndOversizedInput() (gas: 632909)\n[PASS] test_emptyDefinitionsPreserveTheExistingBodyAndSoloFlow() (gas: 481266)\n[PASS] test_maximumDefinitionsAndQuestionFitThePaidBodyLimit() (gas: 9896341)\n[PASS] test_wordingRefusalStillSpendsTheIntakePriceAndMinesNothing() (gas: 702016)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 679.29ms (27.36ms CPU time)\n\nRan 11 tests for test/SwarmOracleAdapter.t.sol:SwarmOracleAdapterTest\n[PASS] testFuzz_realSignature_breaksOnAnyTamper(uint8,uint256) (runs: 2000, μ: 22879, ~: 22800)\n[PASS] test_bind_onceAndIdempotent() (gas: 125198)\n[PASS] test_check_reasons() (gas: 333794)\n[PASS] test_constructor_validates() (gas: 6172)\n[PASS] test_longAnswer_isCountedAndHashed() (gas: 2617763)\n[PASS] test_onlyTheIntakeCallsBack() (gas: 96585)\n[PASS] test_realSwarmSignatures_recoverTheOracleSigner() (gas: 76785)\n[PASS] test_selectors_matchTheSwarmsCallbackShape() (gas: 5907)\n[PASS] test_thoughtEvent_carriesTheAnswer() (gas: 686138)\n[PASS] test_unboundAdapterRefusesCallbacks() (gas: 78375)\n[PASS] test_unknownRequestIsRefused() (gas: 83194)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 679.83ms (683.79ms CPU time)\n\nRan 45 tests for test/HmmMine.t.sol:HmmMineTest\n[PASS] test_answerInALaterEra_isWorthLess() (gas: 1519480)\n[PASS] test_answerThatDoesNotCount_isRecordedAsFailed() (gas: 590687)\n[PASS] test_answer_creditsTheRound_withRolloverSinceGenesis() (gas: 747893)\n[PASS] test_back_minimumUnlessCompletingTheRemainder() (gas: 622319)\n[PASS] test_back_refusedWhenClosedOrNotOpen() (gas: 749116)\n[PASS] test_bodyOf_isTheExactJsonTheSwarmChecked() (gas: 65460)\n[PASS] test_callback_fitsTheIntakeStipend() (gas: 744866)\nLogs:\n  callback gas (refused path): 46589\n\n[PASS] test_callback_gasMargin() (gas: 2572847)\nLogs:\n  minimum stipend for the costliest callback: 118437\n\n[PASS] test_claim_onlyAfterTheRoundEnds() (gas: 996946)\n[PASS] test_config_cancel_andRenounce() (gas: 241339)\n[PASS] test_config_queueApplyAfterDelay_newQuestionsOnly() (gas: 1520008)\n[PASS] test_config_refusesAnAdapterBoundToAnotherMine() (gas: 186659)\n[PASS] test_constructor_validates() (gas: 2454011)\n[PASS] test_creditAndFail_onlyFromTheQuestionsAdapter() (gas: 529017)\n[PASS] test_devShare_isPaidToDev_byAnyone() (gas: 817763)\n[PASS] test_emptyRoundsRollIntoTheNextAnsweredRound() (gas: 1321923)\n[PASS] test_failure_closesTheQuestion_withoutCredit() (gas: 600576)\n[PASS] test_forgedAnswer_doesNotCount() (gas: 588878)\n[PASS] test_genesisDelay_blocksQuestionsUntilGenesis() (gas: 5495356)\n[PASS] test_halving_halvesTheRate() (gas: 153495)\n[PASS] test_oneAskPerTransaction() (gas: 1842650)\n[PASS] test_outsiderRequestNamingTheAdapter_cannotMine() (gas: 485017)\n[PASS] test_ownQuestion_completedByAContractIsFine() (gas: 916024)\n[PASS] test_pooledCompletion_mustComeFromAnAccountDirectly() (gas: 1222917)\n[PASS] test_pooledQuestion_isAskedWhenTheLastBackerCompletesIt() (gas: 932395)\n[PASS] test_priceFall_paysTheLivePriceAndKeepsTheSurplus() (gas: 696856)\n[PASS] test_priceRise_blocksTheAsk_andBackersRefund() (gas: 477773)\n[PASS] test_propose_capsAmountAtPrice() (gas: 437837)\n[PASS] test_propose_notSoldWhenPriceIsZero() (gas: 90121)\n[PASS] test_propose_rejectsDust() (gas: 53854)\n[PASS] test_refund_afterDeadlineOnly_andOnce() (gas: 598720)\n[PASS] test_refund_refusedOnceAsked() (gas: 480975)\n[PASS] test_refusal_closesTheQuestion() (gas: 541831)\n[PASS] test_sameOracleAnswer_countsOnce() (gas: 1158007)\n[PASS] test_sameRound_splitsByIMDPaid_andPooledBackersSplitByShare() (gas: 1579226)\n[PASS] test_soloAsk_paysTheSwarmAndRecordsTheRequest() (gas: 556886)\n[PASS] test_spec_rulesAndInjection() (gas: 578943)\n[PASS] test_start_needsReserve() (gas: 4821133)\n[PASS] test_start_onlyForwarder() (gas: 29596)\n[PASS] test_start_repeatedForwarderCallDoesNotRestart() (gas: 66904)\n[PASS] test_start_setsReserveGenesisAndRate() (gas: 50339)\n[PASS] test_stats_andPot() (gas: 785024)\n[PASS] test_stats_beforeStart() (gas: 4825078)\n[PASS] test_token_isPlainAndFixed() (gas: 36651)\n[PASS] test_writerCannotCreditAPendingRequestThroughAnotherCompletion() (gas: 987990)\nSuite result: ok. 45 passed; 0 failed; 0 skipped; finished in 692.64ms (34.86ms CPU time)\n\nRan 9 tests for test/GenesisForwarder.t.sol:GenesisForwarderTest\n[PASS] test_constructor_validates() (gas: 3851)\n[PASS] test_copycatLaunch_cannotTouchTheRealReserve() (gas: 9977677)\n[PASS] test_crossWiredLaunch_isRefused() (gas: 5696440)\n[PASS] test_forward_lateTokensMoveWithoutRestartingTheMine() (gas: 311768)\n[PASS] test_forward_movesTheWholeRemainderAndStarts() (gas: 4999194)\n[PASS] test_forward_refusesALaunchWithoutAMine() (gas: 226458)\n[PASS] test_forward_refusesAMineOfAnotherForwarder() (gas: 88326)\n[PASS] test_forward_refusesAMineOfAnotherToken() (gas: 872809)\n[PASS] test_forward_refusesOtherLaunchKinds() (gas: 124935)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 693.84ms (3.22ms CPU time)\n\nRan 6 tests for test/HmmTokenProperties.t.sol:HmmTokenPropertiesTest\n[PASS] testFuzz_transferAndTransferFromHaveNoFee(uint256,bool) (runs: 1000, μ: 124355, ~: 95255)\n[PASS] test_factoryAndStrangerHaveNoAdministrativeOrBurnPowers() (gas: 1135557)\n[PASS] test_failedTransferFromRollsBackTheAllowance() (gas: 117924)\n[PASS] test_infiniteAllowanceIsNotSpentAndCanBeRevoked() (gas: 181559)\n[PASS] test_selfTransfersAndZeroTransfersPreserveBalances() (gas: 171868)\n[PASS] test_zeroReceiverAndSpenderAreRejectedWithoutBurning() (gas: 158099)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 693.99ms (694.46ms CPU time)\n\nRan 5 tests for test/audit/PriceDrop.t.sol:PriceDropTest\n[PASS] testFuzz_priceDrop_conservesIMDAndHMMInEitherRefundOrder(uint96,uint96,uint96,uint8,bool) (runs: 2000, μ: 1658610, ~: 1612492)\n[PASS] test_claimAutomaticallyRefundsSurplusAndUsesActualPaidShares() (gas: 2203192)\n[PASS] test_failedAndExpiredRequestsKeepOnlyUnspentSurplusRefundable() (gas: 1827093)\n[PASS] test_priceDrop_matchesImportedProofAndRefundsEachBackerOnce() (gas: 1089032)\n[PASS] test_zeroRoundedSurplusCanBeAcknowledgedAndLastRefundGetsDust() (gas: 865410)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 694.18ms (695.76ms CPU time)\n\nRan 6 tests for test/Emission.t.sol:EmissionTest\n[PASS] testFuzz_answeredRounds_accountForEveryEmittedUnit(uint32[6]) (runs: 2000, μ: 4424600, ~: 4447915)\n[PASS] testFuzz_emittedAt_isMonotonic(uint64,uint64) (runs: 2000, μ: 35720, ~: 33665)\n[PASS] testFuzz_emittedAt_isTheIntegralOfTheRate(uint64) (runs: 2000, μ: 147385, ~: 43753)\n[PASS] testFuzz_emittedAt_neverExceedsTheReserve(uint256) (runs: 2000, μ: 25427, ~: 32254)\n[PASS] testFuzz_pooledClaims_neverExceedTheRound(uint96[5]) (runs: 2000, μ: 1973645, ~: 1899731)\n[PASS] test_firstEra_emitsHalfTheReserve_andTheTailIsDust() (gas: 47003)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 693.94ms (2.53s CPU time)\n\nRan 1 test for test/invariant/ForwarderReserves.t.sol:ForwarderReservesInvariantTest\n[PASS] invariant_eachLaunchRetainsItsEntireOwnReserve() (runs: 256, calls: 25600, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| ForwarderReservesHandler | advance       | 6522  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| ForwarderReservesHandler | donate        | 6351  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| ForwarderReservesHandler | forward       | 6386  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| ForwarderReservesHandler | invalidLaunch | 6341  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.74s (7.74s CPU time)\n\nRan 1 test for test/audit/AdversarialInvariants.t.sol:AuditAdversarialInvariantTest\n[PASS]\nAuditAdversarialInvariantTest invariants:\n[PASS] invariant_audit_hmmConservedAndSolvent\n[PASS] invariant_audit_imdConserved\n[PASS] invariant_audit_roundsConsistent\n AuditAdversarialInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭--------------------+-----------+-------+---------+----------╮\n| Contract           | Selector  | Calls | Reverts | Discards |\n+=============================================================+\n| AdversarialHandler | back      | 2047  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | claim     | 2108  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | expire    | 2069  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | movePrice | 2008  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | payDev    | 1985  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | propose   | 2053  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | refund    | 2080  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | rotate    | 2076  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | settle    | 1976  | 0       | 0        |\n|--------------------+-----------+-------+---------+----------|\n| AdversarialHandler | warp      | 2078  | 0       | 0        |\n╰--------------------+-----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.74s (8.73s CPU time)\n\nRan 1 test for test/HmmTokenProperties.t.sol:HmmTokenLedgerInvariantTest\n[PASS] invariant_balancesAndAllowancesMatchTheIndependentLedger() (runs: 256, calls: 25600, reverts: 0)\n\n╭-----------------------+--------------+-------+---------+----------╮\n| Contract              | Selector     | Calls | Reverts | Discards |\n+===================================================================+\n| HmmTokenLedgerHandler | approve      | 8444  | 0       | 0        |\n|-----------------------+--------------+-------+---------+----------|\n| HmmTokenLedgerHandler | transfer     | 8630  | 0       | 0        |\n|-----------------------+--------------+-------+---------+----------|\n| HmmTokenLedgerHandler | transferFrom | 8526  | 0       | 0        |\n╰-----------------------+--------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.93s (8.93s CPU time)\n\nRan 1 test for test/invariant/MineInvariants.t.sol:MineInvariantTest\n[PASS]\nMineInvariantTest invariants:\n[PASS] invariant_hmmIsConserved\n[PASS] invariant_imdIsConserved\n[PASS] invariant_questionsAreConsistent\n[PASS] invariant_roundSharesMatchAnsweredQuestions\n[PASS] invariant_solvency\n MineInvariantTest invariants (runs: 256, calls: 20480, reverts: 0)\n\n╭-------------+----------+-------+---------+----------╮\n| Contract    | Selector | Calls | Reverts | Discards |\n+=====================================================+\n| MineHandler | back     | 2869  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | claim    | 2926  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | payDev   | 2921  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | propose  | 2925  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | refund   | 2948  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | settle   | 3011  | 0       | 0        |\n|-------------+----------+-------+---------+----------|\n| MineHandler | warp     | 2880  | 0       | 0        |\n╰-------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.69s (13.68s CPU time)\n\nRan 1 test for test/invariant/OwnerlessMineLifecycle.t.sol:OwnerlessMineLifecycleInvariantTest\n[PASS]\nOwnerlessMineLifecycleInvariantTest invariants:\n[PASS] invariant_ownerlessRulesAndReserveRemainFixed\n[PASS] invariant_questionLedgersAndTerminalStatesAreConsistent\n[PASS] invariant_tokensCoverEveryOutstandingObligation\n OwnerlessMineLifecycleInvariantTest invariants (runs: 256, calls: 25600, reverts: 0)\n\n╭---------------------------+------------------+-------+---------+----------╮\n| Contract                  | Selector         | Calls | Reverts | Discards |\n+===========================================================================+\n| OwnerlessLifecycleHandler | back             | 2207  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | claim            | 2148  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | donate           | 2161  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | duplicateClaim   | 2048  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | expireChecked    | 2098  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | movePrice        | 2150  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | payDev           | 2025  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | propose          | 2182  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | refund           | 2161  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | settleChecked    | 2151  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | tryChangingRules | 2127  | 0       | 0        |\n|---------------------------+------------------+-------+---------+----------|\n| OwnerlessLifecycleHandler | warp             | 2142  | 0       | 0        |\n╰---------------------------+------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 16.54s (16.54s CPU time)\n\nRan 22 test suites in 16.55s (60.63s CPU time): 123 tests passed, 0 failed, 0 skipped (123 total tests)\n","passed":true},{"durationMs":121,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"GenesisForwarder.forward(uint64)\",\"HmmMine.applyConfig()\",\"HmmMine.back(uint256,uint256,bytes)\",\"HmmMine.cancelConfig()\",\"HmmMine.claim(uint256[])\",\"HmmMine.credit(bytes32)\",\"HmmMine.expire(uint256)\",\"HmmMine.fail(bytes32,uint8,bytes32)\",\"HmmMine.payDev()\",\"HmmMine.propose((string,uint8,uint8,uint32,uint16,uint16,uint16,uint16),uint256)\",\"HmmMine.proposeWithDefinitions((string,uint8,uint8,uint32,uint16,uint16,uint16,uint16),(string,string)[],uint256)\",\"HmmMine.queueConfig(address,bytes32)\",\"HmmMine.refund(uint256)\",\"HmmMine.setSteward(address)\",\"HmmMine.start()\",\"HmmToken.approve(address,uint256)\",\"HmmToken.transfer(address,uint256)\",\"HmmToken.transferFrom(address,address,uint256)\",\"SwarmOracleAdapter.bind()\",\"SwarmOracleAdapter.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"SwarmOracleAdapter.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\"],\"files\":{\".github/workflows/test.yml\":20,\".gitignore\":18,\"ADAPTATION.md\":178,\"LICENSE\":21,\"README.md\":66,\"devnet/activity.mjs\":129,\"devnet/package-lock.json\":217,\"devnet/package.json\":12,\"devnet/preview-tunnel.sh\":21,\"devnet/preview.mjs\":127,\"devnet/start.sh\":44,\"devnet/stop.sh\":9,\"devnet/swarm.mjs\":222,\"docs/DESIGN.md\":90,\"docs/LAUNCH.md\":94,\"docs/SECURITY.md\":89,\"docs/TOKENOMICS.md\":56,\"foundry.toml\":52,\"launch.json\":50,\"launch/body.json\":36,\"launch/build-site-body.mjs\":22,\"launch/build.mjs\":107,\"launch/buy-imd.mjs\":65,\"launch/check.mjs\":21,\"launch/config.json\":12,\"launch/export-public.sh\":33,\"launch/export-site.sh\":40,\"launch/metrics.mjs\":70,\"launch/package-lock.json\":248,\"launch/package.json\":11,\"launch/pay.mjs\":205,\"launch/watch.mjs\":88,\"remappings.txt\":2,\"script/DeployForwarder.s.sol\":31,\"script/Devnet.s.sol\":87,\"script/HmmLaunch.sol\":143,\"script/IProjectFactory.sol\":64,\"src/GenesisForwarder.sol\":65,\"src/HmmMine.sol\":778,\"src/HmmToken.sol\":15,\"src/SwarmOracleAdapter.sol\":217,\"src/interfaces/IHmmMine.sol\":20,\"src/interfaces/IIntake.sol\":31,\"src/interfaces/ILaunchRegistry.sol\":27,\"src/interfaces/IOracleAdapter.sol\":15,\"test/Emission.t.sol\":118,\"test/FactoryLaunch.t.sol\":67,\"test/GenesisForwarder.t.sol\":112,\"test/HmmMine.t.sol\":874,\"test/HmmTokenProperties.t.sol\":235,\"test/NoSteward.t.sol\":73,\"test/OracleConsumerConformance.t.sol\":100,\"test/OwnerlessFailurePaths.t.sol\":208,\"test/SwarmOracleAdapter.t.sol\":190,\"test/audit/AdversarialInvariants.t.sol\":282,\"test/audit/ConfigBoundary.t.sol\":44,\"test/audit/Definitions.t.sol\":130,\"test/audit/ForeignRequestFirst.t.sol\":57,\"test/audit/PriceDrop.t.sol\":180,\"test/audit/RequestLifecycle.t.sol\":144,\"test/audit/Rounding.t.sol\":99,\"test/audit/StewardAdapter.t.sol\":113,\"test/external/Intake.sol\":325,\"test/fixtures/RealAttestations.sol\":137,\"test/fork/Launch.fork.t.sol\":290,\"test/invariant/ForwarderReserves.t.sol\":208,\"test/invariant/MineInvariants.t.sol\":241,\"test/invariant/OwnerlessMineLifecycle.t.sol\":294,\"test/utils/HmmMineStewarded.sol\":26,\"test/utils/HmmTestBase.sol\":234,\"test/utils/Mocks.sol\":45,\"test/utils/OwnerlessMineTestBase.sol\":60,\"web/.env.example\":22,\"web/.gitignore\":5,\"web/.npmrc\":1,\"web/README.md\":184,\"web/e2e/devnet.e2e.test.ts\":248,\"web/index.html\":24,\"web/lab/pond-lab.tsx\":267,\"web/lab/pond.html\":18,\"web/package-lock.json\":8959,\"web/package.json\":41,\"web/proxy/check-worker.js\":71,\"web/public/favicon.svg\":18,\"web/scripts/abi.mjs\":49,\"web/src/App.tsx\":113,\"web/src/abi/genesisForwarder.ts\":194,\"web/src/abi/hmmMine.ts\":1666,\"web/src/abi/hmmToken.ts\":329,\"web/src/abi/index.ts\":5,\"web/src/abi/swarmOracleAdapter.ts\":739,\"web/src/components/EmissionChart.tsx\":173,\"web/src/components/Footer.tsx\":46,\"web/src/components/FrogMascot.tsx\":142,\"web/src/components/Header.tsx\":109,\"web/src/components/LaunchBanner.tsx\":34,\"web/src/components/LiveNotifier.tsx\":40,\"web/src/components/MoonGlyph.tsx\":101,\"web/src/components/ScrollStory.tsx\":439,\"web/src/components/ShareCard.tsx\":236,\"web/src/components/Wallet.tsx\":225,\"web/src/components/icons.tsx\":70,\"web/src/components/question.tsx\":246,\"web/src/components/states.tsx\":63,\"web/src/components/toast.tsx\":97,\"web/src/components/ui.tsx\":416,\"web/src/config.ts\":209,\"web/src/data/app.tsx\":125,\"web/src/data/claim.ts\":19,\"web/src/data/clock.ts\":56,\"web/src/data/discovery.ts\":158,\"web/src/data/hooks.ts\":506,\"web/src/data/indexer.test.ts\":164,\"web/src/data/indexer.ts\":603,\"web/src/data/liveRound.test.ts\":45,\"web/src/data/mining.ts\":90,\"web/src/data/pondFeed.ts\":56,\"web/src/data/rpcErrors.ts\":10,\"web/src/data/token.ts\":33,\"web/src/data/tx.ts\":93,\"web/src/devnet/connectors.ts\":14,\"web/src/devnet/keys.ts\":13,\"web/src/devnet/localKey.ts\":123,\"web/src/devnet/ui.tsx\":144,\"web/src/env.d.ts\":4,\"web/src/lib/answer.test.ts\":51,\"web/src/lib/answer.ts\":97,\"web/src/lib/body.test.ts\":168,\"web/src/lib/body.ts\":321,\"web/src/lib/check.ts\":71,\"web/src/lib/emission.test.ts\":119,\"web/src/lib/emission.ts\":134,\"web/src/lib/errors.ts\":85,\"web/src/lib/format.test.ts\":88,\"web/src/lib/format.ts\":166,\"web/src/lib/reasons.test.ts\":34,\"web/src/lib/reasons.ts\":101,\"web/src/lib/spec.test.ts\":89,\"web/src/lib/spec.ts\":116,\"web/src/main.tsx\":49,\"web/src/pages/AskPage.tsx\":826,\"web/src/pages/FaqPage.tsx\":88,\"web/src/pages/HowPage.tsx\":293,\"web/src/pages/LedgerPage.tsx\":204,\"web/src/pages/MePage.tsx\":251,\"web/src/pages/MinersPage.tsx\":112,\"web/src/pages/MoonPage.tsx\":207,\"web/src/pages/NotFound.tsx\":9,\"web/src/pages/OpenPage.tsx\":97,\"web/src/pages/PondPage.tsx\":806,\"web/src/pages/QuestionPage.tsx\":277,\"web/src/pages/TokenPage.tsx\":222,\"web/src/pond/PondCanvas.tsx\":60,\"web/src/pond/camera.ts\":107,\"web/src/pond/crowd.ts\":629,\"web/src/pond/effects.ts\":889,\"web/src/pond/engine.ts\":1999,\"web/src/pond/fallback2d.ts\":159,\"web/src/pond/moon.ts\":222,\"web/src/pond/rng.ts\":100,\"web/src/pond/sim.ts\":278,\"web/src/pond/sprites.ts\":451,\"web/src/pond/types.ts\":130,\"web/src/pond/water-gl.ts\":480,\"web/src/sound/SoundToggle.tsx\":29,\"web/src/sound/engine.ts\":362,\"web/src/styles/app.css\":594,\"web/src/styles/global.css\":1171,\"web/src/styles/pages.css\":2073,\"web/src/theme.ts\":27,\"web/src/wagmi.ts\":32,\"web/tsconfig.json\":34,\"web/vite.config.ts\":166,\"web/vitest.e2e.config.ts\":14},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"45cf668f7888846507ba10cc38e7afb0ac245b414ab00e3d17bca8df23a62584","verifiedTreeHash":"413a8e9d19c77f33e9086fdcb7aa26c7509c8a87","verifierVersion":"0.1.0+327e1e9f"}]}