{"assessments":[],"deployments":[{"attestationHash":"45f8231e7bbfbba7d651db61521ee37ec64988da01d2a2cbcc05a7640300c285","chainId":1,"contracts":[{"address":"0xc0b130319ad1e9bb059bc8aab147ca064399bbe6","blockNumber":26222086,"name":"SwarmWager","role":"other","txHash":"0x7d380cc9ce9b389e8635e15b97a6a6bd69febc6d418c2900840490c53dd905ee"}],"id":"9781dc7e-23dc-4f1c-93f8-4766c016cac7","manifestHash":"73249dde5cb10841cb9a4a4ffbd219cf5fe5921cc177371ce76742cd2d0e79ba","status":"live"}],"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":"b34bbf68-48c5-4271-af67-49b3bc522e6c","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"92de674ceadae96ec3a9ff5dfcdd327eb9163722a9cd1f235a65cbed0f24103c","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":"89e42291f6fd2fa0ac104b913918baf24eed879826a9ef996dd42a0b157dddaa","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"afa7b0dd03679014a5e07e01e8eadd9ba5723336bb6e9d911e5fdd586a105492","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"4905939e9bc2717140b369e3da8542bda459222dc8abb8645a53bc54f549fd90","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":"baf582fb72745eb192265c33b89cd71a2b7aa0926941f471a90c005632bcd976","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":"ab2183348a9b136f948bf84c3142dd2a58fe141dacbba76a258fff26bf34b55b","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"7f19daaeb97fe5ad2eec89c3fbac64374d8ebe2f06bb573849c03ecde21f7b23","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"cf7a5219af907dde922f683e4135a67fb618ec2f344fe888f5b2055999ae7f55","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"3eb1914698faec6ed0d0cc827901e0dac5d979fb05a204fbccd60861980c6c83","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Audit and deploy SwarmWager (src/SwarmWager.sol, Foundry project at the repo root) on Ethereum mainnet, unchanged if it passes review. Deploy only SwarmWager; AskSwarmRegistry is already live and must not be redeployed.\n\nWhat it is: two people bet IMD on a yes/no question and the IMD swarm settles it through AskSwarmRegistry (live at 0x53e1e2f33f05086086adf618ca92c3cb0ab111cd, IMD launch #2099). A creator calls create(body, side, stake, joinBy, resolveAfter) with an oracle.request JSON body for a bool question; the contract pulls the stake plus the registry's current price as an escrowed fee. A counterparty calls join(id) with an equal stake on the other side before joinBy. After resolveAfter anyone calls resolve(id): the contract approves exactly the registry's current price, calls askAtMost(body, price), returns any fee remainder to the creator and records the registry requestId. Anyone then calls settle(id): it reads registry.get(requestId) and pays the whole pot to the right side only for a verified answer of type bool, 32 bytes, value 0 or 1, agreed by a strict majority of its panel; every other terminal outcome (refused, split panel, unverified, lost, other answer type) and no answer within ANSWER_WINDOW (3 days) refunds both stakes. cancel unwinds an unmatched wager; abandon unwinds a matched wager that could never be resolved.\n\nConstructor: (address registry, address imd) = (0x53e1e2f33f05086086adf618ca92c3cb0ab111cd, 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7). No owner, admin, upgrade path, ETH handling or loops; the constructor makes no external call. Fork tests in test/SwarmWager.t.sol (15) cover yes and no wins, split, refused, non-bool, minority, non-canonical bool, pending timeout, cancel, join deadline, self-match, resolve timing, double settle, abandon and bad terms.\n\nIt is the first contract built on AskSwarmRegistry's verified memory, part of AskSwarm (github.com/ChromiaAgents/askswarm).","parentJobId":null,"planHash":"b7972bca817e6aa7c9ed8628bb38093f26aefd4377a772d5cbd3a5e80da7e96d","previousHash":"774f42e75239ebb2d208e6f85a18977a21f58d16e113c256aeeefe4aa06d9ce1","projectId":"b34bbf68-48c5-4271-af67-49b3bc522e6c","publication":{"commit":"4a00e720340a8ec3ff99ceeff089bc98ef7a3beb","deliveredAt":"2026-10-18T21:15:13.972Z","repoUrl":"https://github.com/identity-md-launches/launch-2189-src-swarmwager-sol"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"09d60e305d59f6269a87709cd067529b3af67079cf2d9b702c6961cd1dd2b750","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"f2b67e8f611f21177ff37700d9d1d083dad17a794d41f4b87296a2943d53be40","device":"fe36973c683b5abb","findings":[],"hash":"3eb1914698faec6ed0d0cc827901e0dac5d979fb05a204fbccd60861980c6c83","nodeId":"2411945e-3c5c-44dc-b77b-20be28c2e405","outcome":"completed","summary":"Added failure-path, boundary, fuzz, and custody invariant tests under `test/`.\n\n`forge build` succeeds. All **157 tests pass** with the required seed, including **32,768 randomized invariant calls**.\n\nNo new defects found. Implementation and configuration remain unchanged. Live-fork verification remains outstanding; no deployment was performed.","treeHash":"0a4afc1359caaa4f92c4b45bde808445952f81ad","usage":{"cachedInputTokens":3489920,"inputTokens":165537,"model":"gpt-6-astra","outputTokens":28339,"runtime":"codex","turns":7,"wallClockMs":691569}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"723b11f958c65250","findings":[{"citation":"resolved","description":"The NatSpec invariant says every wager can be unwound (cancel, abandon, or settle after ANSWER_WINDOW). create only checks resolveAfter >= joinBy; it puts no upper bound on resolveAfter (or joinBy). Once a counterparty joins, the only exits from Matched are resolve (requires block.timestamp >= resolveAfter, line 178) and abandon (requires block.timestamp > resolveAfter + 3 days, line 197). With resolveAfter = type(uint64).max (or any value centuries out) neither condition is ever true, so the joiner's stake, the creator's stake and the escrowed fee are stuck in the contract permanently. The joiner can read the terms, but the contract's own guarantee is that terms cannot trap funds, and a UI that shows a date may render 2^64-1 as garbage or overflow. Fix: bound both deadlines in create to a horizon the chain can reach (e.g. resolveAfter <= block.timestamp + 365 days and joinBy likewise), or give abandon a path that does not depend on resolveAfter (e.g. either party may abandon once block.timestamp > joinBy + MAX_TERM).","line":127,"path":"src/SwarmWager.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SwarmWager, IAskSwarmRegistry} from \"src/SwarmWager.sol\";\n\n/// Minimal IMD stand-in: plain ERC-20 semantics, returns true.\ncontract MockIMD {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        uint256 a = allowance[from][msg.sender];\n        if (a != type(uint256).max) allowance[from][msg.sender] = a - amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n}\n\n/// Registry stand-in: a fixed price; `askAtMost` and `get` are never reached in this test.\ncontract MockRegistry {\n    uint256 public price = 0.5 ether;\n\n    function askAtMost(bytes calldata, uint256) external pure returns (bytes32) {\n        return bytes32(uint256(1));\n    }\n\n    function get(bytes32) external pure returns (IAskSwarmRegistry.Ask memory k, IAskSwarmRegistry.Answer memory a) {}\n}\n\n/// The contract's own invariant (SwarmWager.sol NatSpec): \"A wager can always be unwound: unmatched by\n/// `cancel`, unresolvable by `abandon`, unanswered by `settle` after ANSWER_WINDOW.\"\n/// A creator may pass resolveAfter = type(uint64).max: `create` accepts it, a counterparty's `join`\n/// escrows a second stake, and from then on `resolve` reverts TooEarly (timestamp < resolveAfter) and\n/// `abandon` reverts TooEarly (timestamp <= resolveAfter + 3 days) at every block that can ever exist.\n/// Both stakes and the fee are locked forever.\n///\n/// Fails on the current code. Passes once `create` bounds `resolveAfter` (and `joinBy`) to a horizon\n/// the chain can reach, or once `abandon` has a path that does not depend on resolveAfter.\ncontract SwarmWagerUnwindTest is Test {\n    MockIMD imd;\n    MockRegistry reg;\n    SwarmWager wager;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        imd = new MockIMD();\n        reg = new MockRegistry();\n        wager = new SwarmWager(address(reg), address(imd));\n        imd.mint(alice, 10 ether);\n        imd.mint(bob, 10 ether);\n        vm.prank(alice);\n        imd.approve(address(wager), type(uint256).max);\n        vm.prank(bob);\n        imd.approve(address(wager), type(uint256).max);\n        vm.warp(1_760_000_000); // 2025-10\n    }\n\n    function test_matchedWagerWithMaxResolveAfterCanBeUnwound() public {\n        uint64 joinBy = uint64(block.timestamp + 1 hours);\n        uint256 id;\n        vm.prank(alice);\n        try wager.create('{\"v\":1,\"question\":\"q?\",\"answerType\":\"bool\",\"panelSize\":2,\"quorum\":2}', true, 1 ether, joinBy, type(uint64).max)\n        returns (uint256 created) {\n            id = created;\n        } catch {\n            // A fixed `create` refuses a horizon the chain can never reach: the invariant holds.\n            return;\n        }\n        vm.prank(bob);\n        wager.join(id);\n        assertEq(imd.balanceOf(address(wager)), 2 ether + 0.5 ether, \"both stakes and the fee are escrowed\");\n\n        // Walk as far into the future as a uint64 timestamp allows: resolve and abandon must become\n        // possible at some point for the invariant to hold. With resolveAfter = uint64.max they never do.\n        vm.warp(type(uint64).max - 1);\n        (bool resolvable,) = address(wager).call(abi.encodeCall(wager.resolve, (id)));\n        (bool abandonable,) = address(wager).call(abi.encodeCall(wager.abandon, (id)));\n        assertTrue(resolvable || abandonable, \"matched wager can neither be resolved nor abandoned at any reachable time\");\n        assertEq(imd.balanceOf(address(wager)), 0, \"escrow left behind\");\n    }\n}","reproduction":"alice: create(body, true, 1e18, now+1h, type(uint64).max) -> succeeds, pulls 1e18 + 0.5e18. bob: join(id) -> succeeds, pulls 1e18. At any later timestamp t (including t = 2^64-2): resolve(id) reverts TooEarly (t < resolveAfter); abandon(id) reverts TooEarly (t <= resolveAfter + 3 days); cancel(id) reverts WrongState(Matched); settle(id) reverts WrongState(Matched). Expected: the stated invariant that every wager can be unwound. Actual: 2.5e18 IMD is unrecoverable. Proof: test/scratch/SwarmWagerUnwind.t.sol fails on the current code and passes once create refuses the horizon or abandon gains a resolveAfter-independent path.","severity":"medium","snippet":"        if (body.length == 0 || stake == 0 || joinBy <= block.timestamp || resolveAfter < joinBy) revert BadTerms();","title":"create accepts an unreachable resolveAfter, so a matched wager can never be resolved or abandoned and both stakes plus the fee are locked forever"},{"citation":"resolved","description":"The fee is escrowed at create at the price then quoted. resolve compares the live price to that escrow and reverts if it is higher, and nobody can add the difference. IMD can change Intake.priceOf at any time (the registry reads it live). So a 1 wei increase between create and resolveAfter makes every open matched wager unresolvable; the parties must wait until resolveAfter + ANSWER_WINDOW (3 days) and then abandon, and the wager they agreed on cannot run at all even though either party would gladly pay 0.1 IMD more. This is a liveness delay and a lost wager, not a loss of principal, so it is low. Fix options that preserve the design: let anyone (typically the creator) top up w.fee while Matched, or let resolve's caller pay the shortfall from msg.sender.","line":180,"path":"src/SwarmWager.sol","reproduction":"State: registry price 0.5e18 at create; alice creates (fee escrow 0.5e18), bob joins, resolveAfter = T. Before T, Intake sets priceOf(oracle.request, IMD) = 0.6e18. At T: resolve(id) reverts BadTerms; abandon(id) reverts TooEarly until T + 3 days + 1. Expected: a way to run or promptly unwind the agreed wager. Actual: 2 stakes + 0.5e18 idle for 3 days, then refund; the question is never asked.","severity":"low","snippet":"        if (p > w.fee) revert BadTerms(); // price rose above the escrow: wait, then `abandon`","title":"A registry price rise after matching strands both stakes until resolveAfter + 3 days with no way to top up the fee"},{"citation":"resolved","description":"The body is sent to the swarm only when resolve is called, and resolve may be called by anyone at any time at or after resolveAfter with no upper bound. The body's window is relative ({\"hours\":N}) to the moment of the ask. For a question about a state that changes over time (a price level, a leaderboard position, 'is X live now'), the ask moment decides the answer, and the party who expects the current state to favour them can call resolve the instant it does, while the other side has no way to force an earlier or later read. The NatSpec claim that 'Nobody, including the creator, can pick the outcome' therefore holds only for questions about a fixed past fact. The contract cannot validate wording; this is a design limitation to document for both parties and in the UI, or to mitigate with a resolveBy upper bound after which only abandon is possible, so the ask window is bounded.","line":186,"path":"src/SwarmWager.sol","reproduction":"body = {\"v\":1,\"question\":\"Is ETH trading above 4000 USD right now?\",\"chainId\":1,\"window\":{\"hours\":1},\"answerType\":\"bool\",\"evidence\":\"panel\",\"panelSize\":15,\"quorum\":11,\"validForSeconds\":3600}; alice says yes, bob joins, resolveAfter = T. ETH is 3900 at T and 4100 at T + 2 days. Alice simply waits and calls resolve at T + 2 days; the panel reads 4100 and answers yes; settle pays alice the pot. Expected per the NatSpec: the outcome is independent of the parties. Actual: the resolve caller's timing selects it; bob could only have won by calling resolve first at T.","severity":"low","snippet":"        bytes32 rid = REGISTRY.askAtMost(bodyOf[id], p);","title":"Whoever calls resolve picks the moment the swarm reads the question, so for time-varying questions the first caller after resolveAfter can choose the outcome"},{"citation":"resolved","description":"settle trusts the registry record under w.requestId without comparing a.questionHash to anything. The registry itself documents that 'the pairing of an answer with the ask that bought it is the writer's', and Intake forwards status-0 completion arguments unchecked. Because the body uses a relative window the wager cannot compute the question hash in advance, so this cannot be fixed inside the contract without moving to absolute windows and the OracleQuestion library. It is the stated design ('the registry is the only source of truth') and is not a defect; it is recorded so the adapter and the panel know the IMD writer and oracle signer are trusted parties for every pot. The same key signs every answer, so a compromised signer or writer could settle every open wager.","line":211,"path":"src/SwarmWager.sol","reproduction":"Two wagers A and B are Asked; the writer completes A's intake request with the attestation signed for B's question (a bool with a different questionHash). Registry stores it as Answered/verified under A's requestId. settle(A) pays A's pot on B's answer; no check in SwarmWager refuses it. Expected: documented trust, which this is; no code change is proposed.","severity":"info","snippet":"        (IAskSwarmRegistry.Ask memory k, IAskSwarmRegistry.Answer memory a) = REGISTRY.get(w.requestId);","title":"Trust assumption: the wager does not bind the answer to its question hash, so a mispaired delivery by the Intake writer settles the pot"},{"citation":"resolved","description":"All 15 fork tests pass against mainnet (run here at block 26221858). Edges not exercised: (1) registry price lower than the escrow at resolve (remainder refund path, line 181-188) and higher (BadTerms at line 180); (2) a delivery the registry records as Unverified (bad signature or expired attestation) reaching settle's refund branch; (3) Status.Lost via markLost; (4) an answer that arrives after askedAt + ANSWER_WINDOW while nobody has settled, which pays the winner, versus a loser's settle landing first, which refunds; (5) resolve called after resolveAfter + 3 days racing abandon; (6) a bool answer of length other than 32 bytes; (7) terms with joinBy == resolveAfter == now+1 at the exact boundary. Every helper uses joinBy == resolveAfter, so the gap between them is never tested. The suite constructs a new AskSwarmRegistry with a test signer instead of pointing the wager at the live registry 0x53e1e2f33f05086086adf618ca92c3cb0ab111cd, so the live ABI pairing (verified manually here: get, askAtMost and price respond as the source predicts, runtime size 20455 bytes matches the compiled source) is not covered by a test.","line":44,"path":"test/SwarmWager.t.sol","reproduction":"Example for (1): create at price 0.5e18, then vm.mockCall the registry's price() to 0.4e18 before resolve; assert the creator receives 0.1e18 and the contract holds exactly 2*stake. Example for (4): _open, warp askedAt + 3 days + 1, deliver a verified yes answer, then settle: expected Paid to yes; then re-run with settle before the delivery: expected Refunded reason 2.","severity":"info","snippet":"        id = wager.create(BODY, aliceSaysYes, STAKE, uint64(block.timestamp + 1 hours), uint64(block.timestamp + 1 hours));","title":"Fork suite does not exercise price changes, Unverified/Lost outcomes, or the late-answer race; it also deploys a fresh registry rather than the live one"},{"citation":"resolved","description":"contracts/launch.json is the accepted manifest of launch #2099 and lists AskSwarmRegistry with the Intake, IMD and signer addresses. ADAPTATION-2099.md line 202 says it is left in place and the manifest step writes this launch's own file. For the adapter and manifest step: the manifest for this launch must list exactly one contract, SwarmWager, with constructorArgs [\"0x53e1e2f33f05086086adf618ca92c3cb0ab111cd\", \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\"] in that order (registry, imd), and no entry for AskSwarmRegistry. Both constructor arguments are static addresses; there is no owner argument and no $owner placeholder is needed, which is consistent with the brief's no-owner design and the OwnerChecks floor.","line":5,"path":"contracts/launch.json","reproduction":"If the existing file were taken as this launch's manifest, the factory would deploy a second AskSwarmRegistry (brief: 'must not be redeployed') and no SwarmWager at all. Expected manifest: {\"kind\":\"evm_contracts\",\"contracts\":[{\"contract\":\"SwarmWager\",\"constructorArgs\":[\"0x53e1e2f33f05086086adf618ca92c3cb0ab111cd\",\"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\"]}],\"notes\":\"...\"}.","severity":"info","snippet":"      \"contract\": \"AskSwarmRegistry\",","title":"Tree carries the previous launch's manifest naming AskSwarmRegistry, which this launch must not redeploy"}],"hash":"4905939e9bc2717140b369e3da8542bda459222dc8abb8645a53bc54f549fd90","nodeId":"e710163f-474a-4484-90cf-d933e7bb524e","outcome":"completed","summary":"Review complete. The source is byte-identical to HEAD, the findings file holds six entries, and the one proof fails on the current code and passes with a one-line bound in `create`.\n\n**Verdict:** SwarmWager has no critical or high defect. Access control, checks-effects-interactions ordering, fee and stake accounting, and the bool-answer decoding all hold up. Nothing the launch forbids is present: no owner, proxy, initializer, DELEGATECALL, SELFDESTRUCT, ETH handling or loops, and the constructor makes no external call.\n\n**What I read and reached**\n- `src/SwarmWager.sol` in full, plus `src/AskSwarmRegistry.sol` and `src/IIntake.sol` for the surface it calls.\n- The live registry at 0x53e1…11cd over a public mainnet RPC. Its runtime size matches the compiled source exactly, and `price`, `get` and `askAtMost` respond as the source predicts. Price is currently 0.5 IMD.\n- The IMD token's verified source from Blockscout. It is a plain OpenZeppelin ERC20 wrapped as a LayerZero OFT, with no transfer hooks, pause or blacklist, so no payout path can be blocked.\n- The 15 fork tests, which all pass against mainnet at block 26221858.\n- Not reached: the Intake contract's own source (only its interface in the repo) and the IMD plane writer, which I treated as the trusted parties they are documented to be.\n\n**Findings, by severity**\n- **Medium, with proof.** `create` puts no upper bound on `resolveAfter`. A creator passes `type(uint64).max`, a counterparty joins, and both stakes plus the fee are locked forever because `resolve` and `abandon` each revert `TooEarly` at every timestamp that can exist. This breaks the contract's own stated invariant that every wager can be unwound. The proof is in `test/scratch/SwarmWagerUnwind.t.sol`.\n- **Low.** A registry price rise after matching makes `resolve` revert with no way to top up the fee, so the agreed wager dies and funds idle until `resolveAfter` plus three days.\n- **Low.** The resolve caller chooses when the swarm reads the question. For a time-varying question, the first caller after `resolveAfter` effectively picks the outcome, which weakens the \"nobody picks the outcome\" claim.\n- **Info.** The wager does not bind an answer to its question hash, so the Intake writer and oracle signer are trusted for every pot. This is the stated design, recorded for the panel.\n- **Info.** Test gaps: price change at resolve, Unverified and Lost outcomes, the late-answer race, and no test against the live registry address.\n- **Info.** The tree carries launch #2099's manifest naming AskSwarmRegistry. This launch's manifest must list only SwarmWager with the two static constructor addresses in order (registry, IMD).\n\n**For the adapter:** the only code change that reproduces is bounding the deadlines in `create` (or giving `abandon` a path independent of `resolveAfter`). Everything else is documentation or test coverage, and the contract can otherwise ship unchanged.","treeHash":null,"usage":{"cachedInputTokens":1089751,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":31813,"runtime":"claude","turns":32,"wallClockMs":667943}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a0f4c3f900dedd4a","findings":[{"citation":"resolved","description":"resolve is permissionless and has only a lower time bound (resolveAfter). abandon only becomes possible ANSWER_WINDOW (3 days) later, and resolve stays callable until someone abandons, so the moment the body is sent to the swarm is chosen unilaterally by the first caller within a window of at least 3 days. For a body with a relative window ({\"window\":{\"hours\":N}}) the plane resolves the observation window from the ask time, so for any time-varying question the resolver, who is normally one of the two parties, picks the state of the world that is judged. The header comment (lines 47-48) acknowledges this and tells parties to agree on a fixed fact, but nothing in create enforces it and the contract cannot parse the body. Both parties are permitted to call resolve (access), the pot flows to whichever side the chosen window favours (economics), and the party who is attentive at resolveAfter or during the 3-day span gains a free lookback option the other does not (asymmetry). The access guard and the payout rule are each correct in isolation; the asymmetric value flow only appears when they are combined with a relative-window body. Minimal fix that preserves the design: let create take a resolveBy term (resolveAfter <= resolveBy <= resolveAfter + ANSWER_WINDOW, default a few minutes) after which resolve reverts and abandon is allowed, so the pick window is bounded by both parties' agreement rather than by the 3-day abandonment deadline. Severity is low because the only victims are parties who chose a question type the documentation warns against.","line":202,"path":"src/SwarmWager.sol","reproduction":"State: alice creates with body {\"v\":1,\"question\":\"Is the ETH/USD price above 4000 USD?\",\"chainId\":1,\"window\":{\"hours\":1},\"answerType\":\"bool\",\"evidence\":\"panel\",\"panelSize\":15,\"quorum\":11,\"validForSeconds\":86400}, creatorSaysYes=true, stake=3e18, joinBy=T, resolveAfter=T. bob joins (says no). Expected by the parties: the question is judged at or about T. Actual: from T until someone calls abandon (earliest T+3 days+1), any caller may resolve at a moment of their choosing; test/SwarmWagerReview.t.sol test_resolveCallerChoosesAskTimeForRelativeWindows shows askedAt and the registry's askedAt equal the caller-selected time (START + 2 hours + 2 days) with the body forwarded unchanged. If ETH is below 4000 at T but above 4000 at any point in the next 3 days, alice (yes) resolves at that point and wins 3e18 from bob; if bob had been watching he would have resolved at T and won instead. The outcome is set by attentiveness, not by the fact the parties staked on. No guard in create or resolve prevents this body shape or bounds the pick window.","severity":"low","snippet":"    function resolve(uint256 id) external {\n        Wager storage w = wagers[id];\n        if (w.state != State.Matched) revert WrongState(w.state);\n        if (block.timestamp < w.resolveAfter) revert TooEarly();","title":"Trust gap (economics x asymmetry): whoever calls resolve first picks the observation window of a relative-window question, over a span of at least ANSWER_WINDOW"},{"citation":"resolved","description":"Documented, not a defect; recorded so the judge has the privileged actors and preconditions in one place. settle (lines 240-258) pays the whole pot on registry.get(requestId) being Answered+verified with a canonical bool and a strict panel majority. The live registry (bytecode checked against src/AskSwarmRegistry.sol at 0x53e1e2f33f05086086adf618ca92c3cb0ab111cd: identical except the four immutables) verifies only that SIGNER 0x5598aa9146215bc13eb26f2c692ad1461fd32982 signed the attestation for the registry's own EIP-712 domain; it does not compare a.questionHash or a.requestId with the ask, and Intake v2 forwards the writer's args to the callback unchecked. SwarmWager cannot pin the question hash either, because the registry's hash is the plane's normalized document and the body is opaque JSON. Hence (1) the Intake writer key can settle any wager either way by delivering, to the wager's requestId, a valid signed bool attestation that anyone bought for a different question through registry.ask; (2) the oracle signer key can sign any bool answer. Both are IMD hot keys outside the author's control. The design accepts this ('strong signal for moderate value'); the author should state the stake sizes it is intended for.","line":50,"path":"src/SwarmWager.sol","reproduction":"test/SwarmWagerReview.t.sol test_writerPairingOfAnotherQuestionsAnswerIsTrusted: wager idA is resolved (alice yes, bob no, 3e18 each). bob calls registry.ask(\"a different question\") and receives ridB. The writer calls Intake.complete(ridA, 0, ..., abi.encode(ridA, attestationB, signatureB)) where attestationB carries questionHash keccak256(\"different question's canonical document\"), answerType 0, answer abi.encode(true), signed by SIGNER. Expected if the pairing were enforced: registry records Unverified and settle refunds. Actual: registry records Answered/verified under ridA, settle(idA) pays 6e18 to alice, and ridB stays Pending. Only the writer can perform this step (Intake.complete is writer-only), so the reproduction is a trust statement, not a public bypass.","severity":"info","snippet":"/// The registry is the only source of truth: this contract never reads a signature or a price feed.\n/// It trusts the Intake writer's pairing of the request and signed question, and the oracle signer.","title":"Trust assumption: the IdentityMD Intake writer and the oracle signer can decide any wager; SwarmWager binds nothing about the question to the answer it pays on"},{"citation":"resolved","description":"Documented at lines 235-236 and tested (test_timeoutSettlementBeforeLateAnswerRemainsRefunded); recorded for completeness of the asymmetry review. settle is permissionless and, once the registry has been Pending for more than 3 days since askedAt, the first call refunds both stakes finally; a later delivery to the registry is then ignored by the wager. The two parties have opposite incentives at that moment and both are allowed to call, so when the swarm is late the party who expects to lose gets a refund by racing the delivery. The alternative (waiting indefinitely) would let a never-answered request lock stakes forever, so the author's choice is defensible; no change is required unless the author wants a longer window.","line":242,"path":"src/SwarmWager.sol","reproduction":"alice yes, bob no, 3e18 each; resolve at time A (askedAt=A). No delivery for 3 days. At A+3 days+1 bob calls settle(id): both stakes return (reason 2), state Refunded. One block later the writer delivers a verified bool true (alice should have won 6e18); settle reverts WrongState(Refunded). Expected by alice: payout; actual: refund. Reverse the roles and alice can do the same when the pending answer would have been false.","severity":"info","snippet":"        if (k.status == IAskSwarmRegistry.Status.Pending || k.status == IAskSwarmRegistry.Status.None) {\n            if (block.timestamp <= uint256(w.askedAt) + ANSWER_WINDOW) revert StillPending();\n            return _refund(w, id, 2);\n        }","title":"Documented race: after ANSWER_WINDOW the party that would lose can refund a still-pending wager before the answer lands"}],"hash":"7f19daaeb97fe5ad2eec89c3fbac64374d8ebe2f06bb573849c03ecde21f7b23","nodeId":"6414b129-40bf-45f2-9a4c-73551ddadb78","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the result. The working tree is otherwise untouched (git status is clean apart from the findings file, which the harness expects).\n\n**Outcome: no permission bypass, escalation path, or asymmetric state write in SwarmWager.** The access model is a permissionless state machine (Open → Matched or Refunded, Matched → Asked or Refunded, Asked → Paid or Refunded), every transition is terminal-once and written before any transfer, and the only approval the contract ever grants is exactly the registry price it immediately spends. The 47 existing tests pass offline.\n\nWhat I verified against mainnet, since the brief depends on live contracts:\n\n- **Live registry matches the source.** The runtime bytecode at the registry address is byte-identical to the compiled `src/AskSwarmRegistry.sol` except for its four immutables, which read back as the Intake, IMD and signer addresses in the brief and a price of 0.5 IMD. So the enum ordering and struct layout the wager compiles against are the deployed ones.\n- **IMD cannot block refunds or re-enter.** Its verified source is a plain OpenZeppelin ERC20 under LayerZero's OFT. The owner can only rename the token. There is no pause, blocklist, fee or transfer hook, so the push-to-both refunds in `settle` and `abandon` cannot be stranded by one party.\n\nFindings recorded, all with reproductions:\n\n1. **Low, Trust Gap seam economics × asymmetry.** `resolve` has only a lower time bound, and `abandon` opens 3 days later, so the first caller picks the ask time for a relative-window body over a span of at least 3 days. For a time-varying question the attentive party gains a free lookback option. The header comment acknowledges this. A `resolveBy` term chosen by both parties would bound the window without changing the design.\n2. **Info, trust assumption.** The Intake writer and the oracle signer can decide any wager, because neither the registry nor the wager binds the question to the answer. The existing pairing test demonstrates it. Documented in the contract header.\n3. **Info, documented race.** After the 3-day answer window, the party expecting to lose can refund a still-pending wager before a late answer lands.\n\nCoverage has 17 rows: all 13 listed entry points plus four invariants, with no `unreached` rows. No finding reached high or critical, so no proof test was written.","treeHash":null,"usage":{"cachedInputTokens":875380,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":28220,"runtime":"claude","turns":27,"wallClockMs":498725}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"771f83f312eace21","findings":[{"citation":"resolved","description":"Flow gap (execution x periphery). `create` validates only that the body is non-empty, but the body is forwarded unchanged at `resolve` through AskSwarmRegistry._ask to Intake._request, which reverts `BodyTooLong(length)` for any body over `MAX_BODY_BYTES = 16_384` (verified Intake source at 0xa43e6f75ee006411f79ac1c84120606c2330de82, `if (body.length > MAX_BODY_BYTES) revert BodyTooLong(body.length);`). That check is only hit after both stakes are escrowed. Because the revert is the body's and not the price's, `topUpFee` cannot repair it, and the only exit is `abandon`, which is gated on `block.timestamp > resolveAfter + ANSWER_WINDOW`. With `resolveAfter` at the permitted maximum the counterparty's stake sits in the contract for 365 days + 3 days with no possible payout, while the creator loses nothing but gas: `abandon` returns the full fee escrow (and any third-party top-ups) to the creator. The existing suites never exercise a body at or above the Intake bound (MockIntake has no length check; RecordingIntake has one but no SwarmWager test reaches it), so this edge is untested. Economics: pure griefing / forced capital lock-up, no profit to the creator, loss limited to the counterparty's time value and gas; a counterparty could in principle inspect the body length before joining, which bounds the severity at low. Minimal fix that preserves the design: add `|| body.length > 16_384` to the `BadTerms` condition in `create` (mirroring Intake.MAX_BODY_BYTES), so the escrow can only be opened on a body Intake will accept.","line":139,"path":"src/SwarmWager.sol","reproduction":"Offline, against src/AskSwarmRegistry.sol and the RecordingIntake helper (which enforces the same 16_384 limit as the live Intake), run on the fixture clock START = 1_800_000_000 with alice and bob each holding 100 IMD and approving the wager:\n1. body = new bytes(16_385); body[0] = '{'.\n2. alice: create(body, true, 3 ether, START+1h, START+1h) -> succeeds, pulls 3.5 IMD.\n3. bob: join(id) -> succeeds, pulls 3 IMD. Contract holds 6.5 IMD.\n4. warp to START+1h; anyone: resolve(id) -> reverts BodyTooLong(16385) from Intake via registry._ask. State stays Matched.\n5. bob: topUpFee(id, 1 ether); resolve(id) -> still reverts BodyTooLong.\n6. warp to START+1h+3d: abandon(id) -> TooEarly. warp +1s: abandon(id) succeeds; alice ends with 101 IMD (her stake, her fee, and bob's 1 IMD top-up), bob with 99 IMD; intake.nonce() == 0, so no question was ever bought.\nExpected: step 2 should revert BadTerms, since no request with this body can ever be made. Actual: the wager is matched and bob's stake is locked until resolveAfter + 3 days (up to 368 days with resolveAfter = now + MAX_TERM). Verified with a Foundry test under test/scratch/ (both the 1-hour and the MAX_TERM variants pass as described).","severity":"low","snippet":"            body.length == 0 || stake == 0 || joinBy <= block.timestamp || resolveAfter < joinBy","title":"create() accepts a body longer than Intake's 16,384-byte cap, so a matched wager can never be resolved and the counterparty's stake is locked until abandon"},{"citation":"resolved","description":"Documented in the contract's NatSpec (\"It trusts the Intake writer's pairing of the request and signed question, and the oracle signer\") and asserted as intended by test_writerPairingOfAnotherQuestionsAnswerIsTrusted, so this is recorded as a trust assumption rather than a defect. `settle` checks status, `verified`, answer type, length and strict majority, but never compares `a.questionHash`, `panelSize` or `quorum` with anything derived from the wager's own body, and the body (any JSON, possibly with a relative window) cannot be hashed on chain. AskSwarmRegistry.onOracleResult accepts any attestation signed for the registry's domain and delivered by Intake for a Pending id of the registry, so the correctness of which answer pays which wager is entirely the plane's writer and signer. Both are hot keys operated by IdentityMD (writer 0x3d3C0Df7C1a17d384545e9D7C8228897bD9625CB, signer 0x5598Aa9146215Bc13eb26f2c692Ad1461Fd32982 on mainnet). Impact if that trust fails: the whole pot (2 x stake) can be paid to the wrong side with a validly signed answer to a different, cheaper or smaller-panel question. No code change is proposed; this is the registry's and the oracle protocol's stated model for every Intake consumer. Users should size stakes to that trust, as the oracle-consumer reference says.","line":246,"path":"src/SwarmWager.sol","reproduction":"Offline, with the registry and RecordingIntake fixtures: alice/bob open wager A (alice says yes) and resolve it; bob separately calls registry.ask(\"a different question\") getting ridB; build an attestation for ridB with answerType 0, answer abi.encode(true), a different questionHash, panelSize 15 / agreed 11, sign it with the registry's signer key, and have the writer deliver it as the completion of wager A's request id. registry.get(A.requestId) reads Answered+verified; settle(A) pays the full 6 IMD pot to alice although her question was never answered (test_writerPairingOfAnotherQuestionsAnswerIsTrusted in test/SwarmWagerReview.t.sol performs exactly this).","severity":"info","snippet":"        bool usable = k.status == IAskSwarmRegistry.Status.Answered && a.verified && a.answerType == BOOL","title":"Trust assumption: payout rests on the Intake writer's pairing of answer to request; the wager binds nothing about the question to the answer it pays on"},{"citation":"resolved","description":"Both behaviours are stated in the NatSpec and covered by tests (test_resolveCallerChoosesAskTimeForRelativeWindows, test_timeoutSettlementBeforeLateAnswerRemainsRefunded, test_resolutionAfterAbandonDeadlineCanWinTheRace), so they are recorded as accepted limitations, not defects. (1) `resolve` is permissionless and has no upper deadline: for a body with `\"window\":{\"hours\":N}` the question is evaluated over the N hours before whichever block `resolve` lands in, anywhere from `resolveAfter` until someone abandons at resolveAfter + 3 days or later. For a time-varying fact (a price level, a count) the party currently favoured resolves immediately and the other party has no way to stop it; the parties must agree on a fact fixed by `resolveAfter` or use an absolute block window. (2) Once `askedAt + 3 days` has passed with the registry still Pending, whichever party expects to lose can call `settle` to lock in a refund before a late delivery lands; a usable answer that lands first still pays. The plane normally answers within minutes, so this only matters during a multi-day plane outage, and the fee is spent either way. Neither lever lets a party take the other's stake; they only decide between payout and refund, or when the fact is sampled. No change proposed beyond what the NatSpec already says.","line":243,"path":"src/SwarmWager.sol","reproduction":"(1) body {\"question\":\"Is ETH/USD above 4000 at the end of the window?\",\"window\":{\"hours\":1},\"answerType\":\"bool\",...}, resolveAfter = T. If ETH is below 4000 at T and above at T + 2 days, the NO side calls resolve(id) at T and the YES side can do nothing; had nobody called at T, the YES side resolves at T + 2 days instead. Same body, same stakes, opposite winner depending only on who called resolve when. (2) open and resolve a wager; warp to askedAt + 3 days + 1; the losing party calls settle(id) -> both stakes refunded (reason 2); the writer then delivers a verified YES; settle(id) reverts WrongState(Refunded) and the YES side never collects (test_timeoutSettlementBeforeLateAnswerRemainsRefunded).","severity":"info","snippet":"            if (block.timestamp <= uint256(w.askedAt) + ANSWER_WINDOW) revert StillPending();","title":"Two documented timing levers: the resolve caller picks the observation moment for relative-window questions, and after ANSWER_WINDOW the first settle call decides between a late answer and a refund"}],"hash":"89e42291f6fd2fa0ac104b913918baf24eed879826a9ef996dd42a0b157dddaa","nodeId":"88e7dcdf-01a2-4a62-8111-f02ed4f4af00","outcome":"completed","summary":"The review is complete. The findings file is written at the repository root, the scratch test is removed, and the working tree holds no other changes.\n\n**Outcome.** SwarmWager passes the Economic Security, Invariant and Flow Gap checks with one low defect and two documented trust assumptions. Nothing in my area reaches critical or high, so no proof file was attached.\n\n**What I verified**\n- The live IMD token at the constructor address is BridgedFP, a LayerZero OFT on a plain OpenZeppelin ERC-20. It has no transfer fee, pause, or blocklist, so push payments cannot be blocked and escrow conservation holds on every path.\n- The live Intake's verified source confirms the registry's expected ABI, exact-price pull, the 200k callback stipend, and a hard 16,384-byte body limit at request time.\n- The protocol's own bool decoder reads a 32-byte ABI word, so the wager's length-32 and value 0/1 check matches what the oracle signs.\n- All 47 offline SwarmWager tests pass unchanged. Every state transition sets state before any token call, and every unwind path (cancel, abandon, timeout settle) avoids the Intake, so a retired or paused oracle cannot strand stakes.\n\n**Findings written**\n1. **Low.** `create` accepts a body longer than Intake's cap. The wager matches, every `resolve` reverts inside Intake with BodyTooLong, top-ups cannot repair it, and the counterparty's stake is locked until `abandon`, up to a year and three days. The creator loses only gas. Reproduced with a scratch Foundry test against the RecordingIntake helper. Fix: bound body length in `create`.\n2. **Info.** Payout rests on the Intake writer's pairing of answer to request. The wager binds nothing about its question to the answer it pays on. This is documented in the NatSpec and asserted by an existing test, so it is recorded as a trust assumption with the hot-key addresses it depends on.\n3. **Info.** Two documented timing levers: the `resolve` caller chooses the sampling moment for relative-window questions, and after the three-day window the first `settle` decides between a late answer and a refund.\n\n**Coverage.** All 13 listed entry points have rows, plus two invariant rows. Twelve hold, `create` carries finding 1, none are unreached. The registry's `reindex` and `ask` are outside the wager's value flow and are marked as holding on that basis.","treeHash":null,"usage":{"cachedInputTokens":1557755,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":37551,"runtime":"claude","turns":34,"wallClockMs":616534}},{"artifacts":[],"attempt":1,"bundleHash":"6c847d8e1bc760323d76610487929c62d22a98c41e2a1bd45744f855885be82e","device":"fb0c125072325b07","findings":[],"hash":"92de674ceadae96ec3a9ff5dfcdd327eb9163722a9cd1f235a65cbed0f24103c","nodeId":"11ff0a97-6a79-4fc7-97d3-5e89f306884f","outcome":"completed","summary":"Prepared SwarmWager for IMD’s factory launch.\n\n- Added a 365-day term limit and explicit fee top-ups.\n- Updated deployment tooling to target only SwarmWager and removed the stale registry manifest.\n- Documented all six audit findings, changes and remaining timing/oracle trust assumptions in [ADAPTATION.md](/home/imd7/.identitymd/work/b34bbf68-48c5-4271-af67-49b3bc522e6c/11ff0a97-6a79-4fc7-97d3-5e89f306884f/ADAPTATION.md).\n\nValidation passed: `forge build`, all **142 offline tests** with the supplied seed, and **17 mainnet-fork tests**, including live-registry integration.\n\nNo transaction was broadcast; deployment remains with IMD’s launch service.","treeHash":"c394c0c28c7ce8e2fcd45c60fd7aaddc3cc4d154","usage":{"cachedInputTokens":2589863,"inputTokens":151294,"model":"gpt-6.1-sol","outputTokens":30960,"runtime":"codex","turns":7,"wallClockMs":663671}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"918f8261a6fd589c","findings":[{"citation":"resolved","description":"Area: Math Precision 'round at sole-occupant boundary' and Boundary 'empty / zero / max input'. The only strength test settle applies is `agreed * 2 > panelSize`, read from the attestation the registry stored. The body both parties staked on fixes panelSize and quorum (15 and 11 in the shipped tests), but the contract never compares the signed panelSize/quorum against those, and the inequality degenerates at the bottom of the domain: panelSize 1 / agreed 1 (2 > 1) and panelSize 0 / quorum 0 / agreed 1 (2 > 0) both count as a 'strict majority'. The registry marks such an attestation verified because its own rule is only `agreed >= quorum`. The oracle-consumer reference this launch was written against says a consumer that moves value must 'require agreed >= quorum and that the panel and quorum are at least what the contract asked for', precisely because 'a small panel is cheap to fill with seats one holder controls'. Precondition: the attestation must carry the oracle signer's signature, so an outside attacker cannot forge it; the exposure is to a plane rerun or signing path that reports a smaller panel than the body requested. Impact under that precondition: the whole pot (2 * stake) is paid on a one-seat or zero-seat 'majority' instead of being refunded. A minimal fix within the agreed design: store the minimum panel and quorum beside the wager (two uint16 constructor- or create-time parameters, or constants matching the body) and add `a.panelSize >= minPanel && a.quorum >= minQuorum` to `usable`; the body is opaque bytes so the contract cannot derive them from it.","line":246,"path":"src/SwarmWager.sol","reproduction":"Offline, with the repo's test/helpers/RegistryTestSupport.sol fixtures (PaymentToken, RecordingIntake, a fresh AskSwarmRegistry signed by key 0xA11CE) and a SwarmWager(registry, token): (1) alice create(BODY with \"panelSize\":15,\"quorum\":11, true, 3e18, START+1h, START+2h); bob join(id); warp START+2h; resolve(id). (2) Writer delivers an attestation for w.requestId with answerType 0, answer abi.encode(true), panelSize 1, quorum 1, agreed 1, issuedAt now, expiresAt now+1d, signed by the registry's SIGNER. Registry stores it Answered/verified. (3) settle(id). Expected (body asked for 15/11, a one-seat panel is not the agreed panel): refund both stakes. Actual: state Paid, winner alice, alice balance 100e18 + 3e18 - 0.5e18. Same with panelSize 0, quorum 0, agreed 1 and answer abi.encode(false): state Paid, winner bob. Both ran in test/scratch/MathBoundary.t.sol (test_panelOfOnePaysThePot, test_panelOfZeroAgreedOnePaysThePot) and pass against the current code, i.e. the pot is paid.","severity":"low","snippet":"        bool usable = k.status == IAskSwarmRegistry.Status.Answered && a.verified && a.answerType == BOOL\n            && a.answer.length == 32 && uint256(a.agreed) * 2 > a.panelSize;","title":"settle pays the pot on a strict majority of whatever panel the attestation reports, not the panel the body asked for (panel 1/agreed 1 and panel 0/agreed 1 both pay)"},{"citation":"resolved","description":"Coverage note for the math area, not a code defect. test/SwarmWager.t.sol (the 15 fork tests the brief cites) never drives: registry price() == 0 at create (BadTerms, nothing pulled); price() > type(uint96).max at create (BadTerms); price() == type(uint96).max at create (fee escrow at the cast ceiling, cancel returns stake + fee); price retired to 0 at resolve (registry reverts NotSold, resolve stays atomic, abandon unwinds after resolveAfter + 3 days); price() reverting (create and resolve revert, cancel/abandon still unwind because the unwind paths read no price); panelSize 0 / agreed 0 (refund) versus panelSize 0 / agreed 1 and panelSize 1 / agreed 1 (paid, finding 1); panelSize == agreed == 65535 (no overflow in uint256); a verified bool-typed answer longer than 32 bytes (registry reads back empty bytes, refund); a 1 wei stake; two concurrent wagers sharing one balance. test/SwarmWagerReview.t.sol covers the uint96 fee ceiling on topUpFee, the exact 3-day timeout boundary, the exact joinBy/resolveAfter boundary and the strict-majority fuzz, so only the cases listed here are uncovered.","line":268,"path":"test/SwarmWager.t.sol","reproduction":"All of the listed cases were run in test/scratch/MathBoundary.t.sol against the current tree: 14 tests, all pass, i.e. every case except the two in finding 1 behaves as the NatSpec intends. Expected: the shipped suite asserts these edges; actual: it does not, so a regression in any of them would not be caught.","severity":"info","snippet":"    function test_badTerms() public {","title":"Shipped fork suite does not exercise the price and panel edges of create, resolve and settle"}],"hash":"ab2183348a9b136f948bf84c3142dd2a58fe141dacbba76a258fff26bf34b55b","nodeId":"2b2706df-49ab-479c-98df-97d899467541","outcome":"completed","summary":"Review complete. The findings file is written and validated, and no tracked file changed (only `.imd-findings.json` and `test/scratch/` were touched).\n\n**Outcome:** the math in `SwarmWager` is sound. Every cast, sum, subtraction and timestamp comparison I traced is bounded before it executes, and the token it moves is a plain OpenZeppelin ERC20, so received amounts always equal requested amounts. I found one low-severity boundary defect and one coverage gap.\n\n**Finding 1 (low), `src/SwarmWager.sol:246`.** The strict-majority rule in `settle` is `agreed * 2 > panelSize` read from the signed attestation, and nothing compares that panel against the panel the staked body asked for. At the bottom of the domain the rule degenerates: panel 1 with agreed 1, and panel 0 with quorum 0 and agreed 1, both count as a majority and pay the whole pot. The registry marks such attestations verified because its own rule is only `agreed >= quorum`. The oracle-consumer reference says a value-moving consumer must require the panel and quorum to be at least what it asked for. The precondition is an attestation carrying the oracle signer's signature, so an outsider cannot trigger it. Both cases are reproduced in the scratch test and pay the pot on the current code.\n\n**Finding 2 (info), `test/SwarmWager.t.sol:268`.** The 15 fork tests the brief cites never drive price zero, price above or at the uint96 ceiling, price retired at resolve, a reverting price read, degenerate panels, over-long bool answers, a 1 wei stake, or two concurrent wagers. I ran all of those in the scratch file and every one behaves as the NatSpec intends, so this is a coverage note, not a code defect.\n\n**Coverage:** all 13 listed entry points have a row. Twelve hold; `settle` carries finding 1. Two invariant rows record the balance conservation checks and the live IMD token semantics verified on Blockscout.\n\n**Verification run:**\n\n| Suite | Result |\n| --- | --- |\n| Existing SwarmWager suites (offline) | 47 passed |\n| Scratch math and boundary probes | 14 passed |\n\nNot reached: the registry's EIP-712 digest construction and the Intake writer's request pairing, which are outside the math area and belong to the other specialists.","treeHash":null,"usage":{"cachedInputTokens":1655191,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":31017,"runtime":"claude","turns":30,"wallClockMs":449796}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8db4eebdd7bd2744","findings":[{"citation":"resolved","description":"create (src/SwarmWager.sol:138-141) validates only that body is non-empty. The live Intake v2 at 0xa43e6f75ee006411f79ac1c84120606c2330de82 (verified source, _request) reverts BodyTooLong(length) for any body above MAX_BODY_BYTES = 16_384, and AskSwarmRegistry forwards the stored body unchanged in askAtMost. A wager created with a 16,385-byte body therefore reaches Matched normally (join pulls the counterparty's stake), but every resolve(id) call reverts inside Intake for the whole life of the wager, at any price and after any topUpFee. The only exit is abandon(id), which is gated at resolveAfter + ANSWER_WINDOW (up to 368 days from creation) and returns the creator's full fee escrow. Compared with the documented refund paths (a refused or split question costs the creator the 0.5 IMD fee), this path is free for the creator: it deterministically locks the counterparty's stake for the full term and refunds everything to the creator. The condition is fixed at creation and cannot be detected by SwarmWager at join time without reading bodyOf(id).length; the Created event carries the body, but nothing in the contract or the tests (SwarmWager.t.sol, SwarmWagerReview.t.sol, SwarmWagerLiveRegistry.t.sol) exercises a body above the Intake cap. Minimal fix: reject body.length > 16_384 in create (constant mirroring Intake.MAX_BODY_BYTES) before quoting the fee, so a matched wager is always resolvable at some price. This preserves the opaque-body design and adds no owner or new exit.","line":139,"path":"src/SwarmWager.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SwarmWager} from \"src/SwarmWager.sol\";\nimport {AskSwarmRegistry} from \"src/AskSwarmRegistry.sol\";\nimport {IIntake} from \"src/IIntake.sol\";\n\n/// Minimal ERC20 stand-in for IMD (OpenZeppelin semantics: returns true, reverts on shortfall).\ncontract Token {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        require(balanceOf[msg.sender] >= amount, \"balance\");\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        uint256 a = allowance[from][msg.sender];\n        require(a >= amount, \"allowance\");\n        if (a != type(uint256).max) allowance[from][msg.sender] = a - amount;\n        require(balanceOf[from] >= amount, \"balance\");\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n}\n\n/// Models the live Intake v2 (0xa43e…de82) `_request` guards copied from its verified source:\n/// `if (body.length > MAX_BODY_BYTES) revert BodyTooLong(body.length);` with MAX_BODY_BYTES = 16_384.\ncontract BodyCappedIntake {\n    uint256 public constant MAX_BODY_BYTES = 16_384;\n    uint256 public constant PRICE = 0.5 ether;\n    address public immutable asset;\n    uint256 public nonce;\n\n    error EmptyBody();\n    error BodyTooLong(uint256 length);\n\n    constructor(address token) {\n        asset = token;\n    }\n\n    function priceOf(bytes32, address token) external view returns (uint256) {\n        return token == asset ? PRICE : 0;\n    }\n\n    function requestWithFailure(bytes32, bytes calldata body, IIntake.Callback calldata, bytes4, address, uint256 amount)\n        external\n        payable\n        returns (bytes32 requestId)\n    {\n        if (body.length == 0) revert EmptyBody();\n        if (body.length > MAX_BODY_BYTES) revert BodyTooLong(body.length);\n        require(Token(asset).transferFrom(msg.sender, address(this), amount), \"pull\");\n        requestId = keccak256(abi.encode(block.chainid, address(this), ++nonce));\n    }\n\n    function requests(bytes32) external pure returns (address, address, bytes4, bool) {\n        return (address(0), address(0), bytes4(0), false);\n    }\n\n    function writer() external pure returns (address) {\n        return address(0);\n    }\n}\n\ncontract SwarmWagerOverlongBodyTest is Test {\n    Token token;\n    BodyCappedIntake intake;\n    AskSwarmRegistry registry;\n    SwarmWager wager;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        token = new Token();\n        intake = new BodyCappedIntake(address(token));\n        registry = new AskSwarmRegistry(address(intake), address(token), makeAddr(\"signer\"));\n        wager = new SwarmWager(address(registry), address(token));\n        token.mint(alice, 10 ether);\n        token.mint(bob, 10 ether);\n        vm.prank(alice);\n        token.approve(address(wager), type(uint256).max);\n        vm.prank(bob);\n        token.approve(address(wager), type(uint256).max);\n    }\n\n    /// `create` must refuse a body the Intake can never accept, so a matched wager is always\n    /// resolvable. On the current code the create succeeds, the counterparty's stake is escrowed,\n    /// `resolve` reverts forever, and only `abandon` (after resolveAfter + 3 days) frees the funds,\n    /// returning the creator's fee untouched.\n    function test_createRefusesBodyAboveIntakeCap() public {\n        bytes memory body = new bytes(intake.MAX_BODY_BYTES() + 1);\n        body[0] = \"{\";\n        uint64 joinBy = uint64(block.timestamp + 1 hours);\n        uint64 resolveAfter = joinBy;\n\n        vm.prank(alice);\n        vm.expectRevert(SwarmWager.BadTerms.selector);\n        wager.create(body, true, 1 ether, joinBy, resolveAfter);\n    }\n\n    /// The same defect from the counterparty's side: once joined, no call at any time before\n    /// resolveAfter + ANSWER_WINDOW can release bob's stake, and the creator loses nothing.\n    function test_overlongBodyLocksCounterpartyUntilAbandon() public {\n        bytes memory body = new bytes(intake.MAX_BODY_BYTES() + 1);\n        body[0] = \"{\";\n        uint64 joinBy = uint64(block.timestamp + 1 hours);\n        uint64 resolveAfter = joinBy;\n\n        vm.prank(alice);\n        (bool created,) = address(wager).call(\n            abi.encodeCall(SwarmWager.create, (body, true, 1 ether, joinBy, resolveAfter))\n        );\n        // Expected behaviour: the create is refused; nothing follows.\n        assertFalse(created, \"create accepted a body the Intake rejects on-chain (BodyTooLong)\");\n    }\n}","reproduction":"State: SwarmWager(registry, IMD) on mainnet, Intake price 0.5 IMD. 1) alice: create(body = 16_385 bytes starting with '{', creatorSaysYes=true, stake=1e18, joinBy=now+1h, resolveAfter=now+1h) -> succeeds, pulls 1.5 IMD, wager Open. 2) bob: join(id) -> succeeds, pulls 1 IMD, wager Matched. 3) at or after resolveAfter, anyone: resolve(id) -> AskSwarmRegistry.askAtMost -> Intake.requestWithFailure reverts BodyTooLong(16385); wager stays Matched; topUpFee changes nothing. 4) settle(id) reverts WrongState(Matched); cancel(id) reverts WrongState(Matched). 5) Only at resolveAfter + 3 days + 1 does abandon(id) succeed: alice receives 1 IMD stake + 0.5 IMD fee back, bob receives 1 IMD. Expected: step 1 reverts BadTerms (or any matched wager is resolvable at some price). Actual: create succeeds and bob's stake is immobilised for the full term with the creator paying nothing. Proof test (test/scratch/SwarmWagerOverlongBody.t.sol) models Intake's _request guard verbatim and fails on the current code: 'next call did not revert as expected' and 'create accepted a body the Intake rejects on-chain (BodyTooLong)'.","severity":"low","snippet":"            body.length == 0 || stake == 0 || joinBy <= block.timestamp || resolveAfter < joinBy\n                || uint256(resolveAfter) > block.timestamp + MAX_TERM\n        ) revert BadTerms();","title":"create accepts a body longer than Intake's on-chain cap, so the wager can never be resolved and the counterparty's stake is locked until abandon at no cost to the creator"}],"hash":"afa7b0dd03679014a5e07e01e8eadd9ba5723336bb6e9d911e5fdd586a105492","nodeId":"41614344-c8c2-4de5-8584-6b313dd6639d","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds one finding and a coverage row for all 13 listed entry points plus two invariants. No tracked file was changed. The only writes were the findings file and the scratch proof under `test/scratch/`.\n\n**Finding (low):** `create` accepts a body longer than the Intake's on-chain cap of 16,384 bytes. The live Intake's `_request` reverts `BodyTooLong` for such a body, and the registry forwards the stored body unchanged. A wager with a 16,385-byte body reaches Matched normally, but every `resolve` call reverts for its whole life, at any price and after any top-up. The only exit is `abandon` after `resolveAfter` plus three days, up to 368 days from creation, and it returns the creator's entire fee. Unlike the documented refund paths, which cost the creator the 0.5 IMD fee, this locks the counterparty's stake for the full term at zero cost to the creator. The proof at `test/scratch/SwarmWagerOverlongBody.t.sol` models the Intake guard verbatim, fails on the current code, and passes with a one-token fix that rejects oversized bodies in `create`.\n\n**What I verified in my area (Execution Trace, Periphery, First Principles):**\n- Every state transition writes state before any external call. The brief post-call window in `resolve` is harmless because `settle` hits `StillPending` on a zero request id.\n- Conservation holds on every path. Each push is funded by the same wager's earlier pulls.\n- IMD on mainnet is a plain LayerZero OFT over OpenZeppelin ERC20. It has no transfer hooks, fee, rebasing, pause or blacklist, so the Slither reentrancy leads are dismissed.\n- The live registry's runtime bytecode is byte-identical to the compiled repo source apart from its four immutables, and its `get` layout, `markLost` and VERSION match what `settle` decodes.\n- The live Intake derives request ids from a nonce, collects exactly the amount passed, and only calls the callback once with a 200k stipend.\n- The timeout-versus-late-answer race and the resolve-versus-abandon race are documented design, tested in both orders, and are not reported as defects.\n\n**Untested edges worth noting for the author:** no test sends a body above the Intake cap, and no test covers an absolute-window question whose window closes after `resolveAfter`, where an early permissionless `resolve` yields a refused answer and a spent fee.","treeHash":null,"usage":{"cachedInputTokens":1526780,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":40325,"runtime":"claude","turns":39,"wallClockMs":619528}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"74a99f640688d37b","findings":[{"citation":"resolved","description":"Merged from audit_economics and audit_flow (same root cause). create validates only body.length != 0, but resolve forwards bodyOf[id] unchanged through AskSwarmRegistry._ask to Intake.requestWithFailure, and the live Intake v2 at 0xa43e6f75ee006411f79ac1c84120606c2330de82 reverts BodyTooLong for any body above MAX_BODY_BYTES (read live over RPC: MAX_BODY_BYTES() == 16384). The check is only reached after both stakes are escrowed. The revert is the body's, not the price's, so topUpFee cannot repair it; settle and cancel revert WrongState(Matched); the only exit is abandon, gated at resolveAfter + ANSWER_WINDOW, which can be up to 368 days after creation and returns the creator's full fee escrow (plus any third-party top-ups). The existing test test/SwarmWagerBoundaries.t.sol test_oversizedBodyRejectedByTransportLeavesFeeAndStakesRefundable documents this behaviour as accepted rather than preventing it. Severity low: the lock is symmetric (the creator's own stake and fee are locked for the same period), the body is public in the Created event and bodyOf before anyone joins, no funds are lost and the invariant 'a wager can always be unwound' still holds. Minimal fix preserving the design: add `|| body.length > 16_384` (a constant mirroring Intake.MAX_BODY_BYTES) to the BadTerms condition so an escrow can only open on a body Intake will accept.","line":139,"path":"src/SwarmWager.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SwarmWager} from \"src/SwarmWager.sol\";\nimport {AskSwarmRegistry} from \"src/AskSwarmRegistry.sol\";\nimport {IIntake} from \"src/IIntake.sol\";\n\n/// Minimal ERC20 stand-in for IMD (OpenZeppelin semantics: returns true, reverts on shortfall).\ncontract Token {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        require(balanceOf[msg.sender] >= amount, \"balance\");\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        uint256 a = allowance[from][msg.sender];\n        require(a >= amount, \"allowance\");\n        if (a != type(uint256).max) allowance[from][msg.sender] = a - amount;\n        require(balanceOf[from] >= amount, \"balance\");\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n}\n\n/// Models the live Intake v2 (0xa43e…de82) `_request` guards copied from its verified source:\n/// `if (body.length > MAX_BODY_BYTES) revert BodyTooLong(body.length);` with MAX_BODY_BYTES = 16_384.\ncontract BodyCappedIntake {\n    uint256 public constant MAX_BODY_BYTES = 16_384;\n    uint256 public constant PRICE = 0.5 ether;\n    address public immutable asset;\n    uint256 public nonce;\n\n    error EmptyBody();\n    error BodyTooLong(uint256 length);\n\n    constructor(address token) {\n        asset = token;\n    }\n\n    function priceOf(bytes32, address token) external view returns (uint256) {\n        return token == asset ? PRICE : 0;\n    }\n\n    function requestWithFailure(bytes32, bytes calldata body, IIntake.Callback calldata, bytes4, address, uint256 amount)\n        external\n        payable\n        returns (bytes32 requestId)\n    {\n        if (body.length == 0) revert EmptyBody();\n        if (body.length > MAX_BODY_BYTES) revert BodyTooLong(body.length);\n        require(Token(asset).transferFrom(msg.sender, address(this), amount), \"pull\");\n        requestId = keccak256(abi.encode(block.chainid, address(this), ++nonce));\n    }\n\n    function requests(bytes32) external pure returns (address, address, bytes4, bool) {\n        return (address(0), address(0), bytes4(0), false);\n    }\n\n    function writer() external pure returns (address) {\n        return address(0);\n    }\n}\n\ncontract SwarmWagerOverlongBodyTest is Test {\n    Token token;\n    BodyCappedIntake intake;\n    AskSwarmRegistry registry;\n    SwarmWager wager;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        token = new Token();\n        intake = new BodyCappedIntake(address(token));\n        registry = new AskSwarmRegistry(address(intake), address(token), makeAddr(\"signer\"));\n        wager = new SwarmWager(address(registry), address(token));\n        token.mint(alice, 10 ether);\n        token.mint(bob, 10 ether);\n        vm.prank(alice);\n        token.approve(address(wager), type(uint256).max);\n        vm.prank(bob);\n        token.approve(address(wager), type(uint256).max);\n    }\n\n    /// `create` must refuse a body the Intake can never accept, so a matched wager is always\n    /// resolvable. On the current code the create succeeds, the counterparty's stake is escrowed,\n    /// `resolve` reverts forever, and only `abandon` (after resolveAfter + 3 days) frees the funds,\n    /// returning the creator's fee untouched.\n    function test_createRefusesBodyAboveIntakeCap() public {\n        bytes memory body = new bytes(intake.MAX_BODY_BYTES() + 1);\n        body[0] = \"{\";\n        uint64 joinBy = uint64(block.timestamp + 1 hours);\n        uint64 resolveAfter = joinBy;\n\n        vm.prank(alice);\n        vm.expectRevert(SwarmWager.BadTerms.selector);\n        wager.create(body, true, 1 ether, joinBy, resolveAfter);\n    }\n\n    /// The same defect from the counterparty's side: once joined, no call at any time before\n    /// resolveAfter + ANSWER_WINDOW can release bob's stake, and the creator loses nothing.\n    function test_overlongBodyLocksCounterpartyUntilAbandon() public {\n        bytes memory body = new bytes(intake.MAX_BODY_BYTES() + 1);\n        body[0] = \"{\";\n        uint64 joinBy = uint64(block.timestamp + 1 hours);\n        uint64 resolveAfter = joinBy;\n\n        vm.prank(alice);\n        (bool created,) = address(wager).call(\n            abi.encodeCall(SwarmWager.create, (body, true, 1 ether, joinBy, resolveAfter))\n        );\n        // Expected behaviour: the create is refused; nothing follows.\n        assertFalse(created, \"create accepted a body the Intake rejects on-chain (BodyTooLong)\");\n    }\n}","reproduction":"Fixture: AskSwarmRegistry(intake, token, signer) with an Intake that enforces the live 16,384-byte cap (test/helpers RecordingIntake does, or the proof's BodyCappedIntake), SwarmWager(registry, token), alice and bob each approved. 1) alice: create(body = new bytes(16_385) with body[0]='{', true, 1 ether, now+1h, now+1h) -> succeeds, pulls 1.5 IMD, state Open. 2) bob: join(id) -> succeeds, pulls 1 IMD, state Matched. 3) warp to resolveAfter; anyone: resolve(id) -> reverts BodyTooLong(16385) inside Intake; state stays Matched. 4) bob: topUpFee(id, 1 ether); resolve(id) -> still reverts BodyTooLong. settle(id) and cancel(id) revert WrongState(Matched). 5) warp to resolveAfter + 3 days: abandon(id) -> TooEarly; +1 s: abandon(id) succeeds, alice gets stake + 0.5 fee + bob's 1 IMD top-up back, bob gets 1 IMD. Expected: step 1 reverts BadTerms. Actual: create succeeds and both stakes are immobilised until resolveAfter + 3 days (up to 368 days with resolveAfter = now + MAX_TERM). Verified: the attached proof (copied to test/scratch/ and run with forge test --match-path) fails on the current code with 'next call did not revert as expected' and 'create accepted a body the Intake rejects on-chain (BodyTooLong)'.","severity":"low","snippet":"            body.length == 0 || stake == 0 || joinBy <= block.timestamp || resolveAfter < joinBy","title":"create accepts a body longer than Intake's 16,384-byte cap, so a matched wager can never be resolved and both stakes stay locked until abandon"},{"citation":"resolved","description":"From audit_math, reproduced. The only strength test settle applies is the strict majority agreed * 2 > panelSize read from the attestation the registry stored; the registry itself marks an attestation verified on agreed >= quorum alone. Nothing compares the signed panelSize or quorum with what the body both parties staked on (15/11 in the shipped tests), and the inequality degenerates at the bottom of the domain: panelSize 1 / agreed 1 (2 > 1) and panelSize 0 / quorum 0 / agreed 1 (2 > 0) both count. The oracle-consumer reference this launch targets says a consumer that moves value must require 'that the panel and quorum are at least what the contract asked for' because 'a small panel is cheap to fill with seats one holder controls'. Precondition: the attestation must carry the oracle signer's signature, so no outside caller can trigger it; the exposure is to a plane rerun or signing path that reports a smaller panel than the body requested. Impact under that precondition: 2 x stake paid on a one-seat or zero-seat 'majority' instead of a refund. The shipped fuzz test testFuzz_onlyCanonicalMajorityBoolPays asserts this payout as intended. Minimal fix within the design: take minPanel and minQuorum (uint16) at create, store them beside the wager, and add a.panelSize >= minPanel && a.quorum >= minQuorum to `usable`; the body is opaque so the contract cannot derive them from it.","line":247,"path":"src/SwarmWager.sol","reproduction":"Offline with test/helpers/RegistryTestSupport.sol (PaymentToken, RecordingIntake, fresh AskSwarmRegistry signed by key 0xA11CE) and SwarmWager(registry, token): (1) alice create(body with \"panelSize\":15,\"quorum\":11, true, 3e18, START+1h, START+2h); bob join(id); warp START+2h; resolve(id). (2) writer delivers an attestation for w.requestId with answerType 0, answer abi.encode(true), panelSize 1, quorum 1, agreed 1, issuedAt now, expiresAt now+1d, signed by the registry's SIGNER; registry.get reads Answered/verified. (3) settle(id). Expected (the body asked for 15/11): refund both stakes. Actual: state Paid, winner alice, alice balance 100e18 + 3e18 - 0.5e18, bob 97e18. Same with panelSize 0, quorum 0, agreed 1 and answer abi.encode(false): state Paid, winner bob. Both ran in test/scratch/PanelMinimum.t.sol (test_panelOfOnePaysThePot, test_panelOfZeroAgreedOnePaysThePot) and pass against the current code, i.e. the pot is paid.","severity":"low","snippet":"            && a.answer.length == 32 && uint256(a.agreed) * 2 > a.panelSize;","title":"settle enforces no minimum panel or quorum: a verified bool with panelSize 1/agreed 1 or panelSize 0/agreed 1 pays the whole pot"},{"citation":"resolved","description":"Merged from audit_permissions (low) and audit_economics (info, lever 1). resolve is permissionless with only a lower time bound; abandon only becomes possible at resolveAfter + ANSWER_WINDOW and resolve stays callable until someone abandons, so the moment the body is sent to the swarm is chosen unilaterally by whoever calls first, within a window of at least 3 days. For a body with \"window\":{\"hours\":N} the plane resolves the observation window from the ask time, so for a time-varying question the resolver (normally one of the two parties) picks the state of the world that is judged, and the pot flows to the side that moment favours. The NatSpec (lines 47-48) tells parties to agree on a fixed fact, but create cannot enforce it and the contract cannot parse the body. Severity low: it is documented, it only affects parties who chose a question shape the documentation warns against, and it never pays a stake to anyone other than one of the two sides. Minimal fix preserving the design: a resolveBy term on create (resolveAfter <= resolveBy <= resolveAfter + ANSWER_WINDOW) after which resolve reverts and abandon is allowed, so the pick window is bounded by the parties' agreement rather than by the abandonment deadline.","line":205,"path":"src/SwarmWager.sol","reproduction":"alice: create(body {\"v\":1,\"question\":\"Is the ETH/USD price above 4000 USD?\",\"chainId\":1,\"window\":{\"hours\":1},\"answerType\":\"bool\",\"evidence\":\"panel\",\"panelSize\":15,\"quorum\":11,\"validForSeconds\":86400}, true, 3e18, T, T); bob joins (no). Expected by the parties: judged at or about T. Actual: from T until abandon (earliest T + 3 days + 1 s) any caller may resolve; test/SwarmWagerReview.t.sol test_resolveCallerChoosesAskTimeForRelativeWindows shows w.askedAt and the registry's askedAt equal the caller-chosen START + 2 hours + 2 days with the body forwarded unchanged. If ETH is below 4000 at T and above 4000 at any point in the next 3 days, alice resolves then and wins 3e18; had bob resolved at T he would have won instead. The outcome depends on who called resolve when, not on the fact staked on.","severity":"low","snippet":"        if (block.timestamp < w.resolveAfter) revert TooEarly();","title":"resolve has no upper deadline, so for a relative-window body the first caller picks the observation window anywhere in a span of at least 3 days"},{"citation":"resolved","description":"Merged from audit_permissions and audit_economics; documented in the NatSpec and asserted as intended by test_writerPairingOfAnotherQuestionsAnswerIsTrusted, so recorded as a trust statement, not a defect. settle pays on registry.get(requestId) being Answered + verified with a canonical bool and strict majority. The live registry (bytecode at 0x53e1e2f33f05086086adf618ca92c3cb0ab111cd compared with the compiled src/AskSwarmRegistry.sol: 10,226 bytes, zero non-immutable byte differences; INTAKE, IMD and SIGNER read back as 0xa43e...de82, 0xd34a...63b7 and 0x5598...2982) verifies only that SIGNER signed the attestation for the registry's own EIP-712 domain, never compares a.questionHash or a.requestId with the ask, and Intake v2 forwards the writer's arguments to the callback unchecked. SwarmWager cannot pin a question hash either, because the hash is the plane's normalized document and the body may use a relative window. Hence the Intake writer key can settle any wager either way by delivering, to the wager's request id, a valid signed bool attestation bought for another question, and the oracle signer key can sign any bool answer. Both are IMD-operated hot keys outside the author's control; users should size stakes to that trust, as the oracle-consumer reference says.","line":51,"path":"src/SwarmWager.sol","reproduction":"test/SwarmWagerReview.t.sol test_writerPairingOfAnotherQuestionsAnswerIsTrusted: wager idA is resolved (alice yes, bob no, 3e18 each). bob calls registry.ask(\"a different question\") and receives ridB. The writer calls intake.complete(ridA, 0, abi.encode(ridA, attestationB, signatureB)) where attestationB carries questionHash keccak256(\"different question's canonical document\"), answerType 0, answer abi.encode(true), signed by SIGNER. If the pairing were enforced the registry would record Unverified and settle would refund; actually the registry records Answered/verified under ridA, settle(idA) pays 6e18 to alice and ridB stays Pending. Only the writer can do this (Intake.complete is writer-only), so there is no public bypass.","severity":"info","snippet":"/// It trusts the Intake writer's pairing of the request and signed question, and the oracle signer.","title":"Trust assumption: the Intake writer's pairing and the oracle signer decide every wager; SwarmWager binds nothing about its question to the answer it pays on"},{"citation":"resolved","description":"Merged from audit_permissions and audit_economics (lever 2). Documented at lines 235-236 and tested by test_timeoutSettlementBeforeLateAnswerRemainsRefunded. settle is permissionless and, once the registry has been Pending for more than 3 days after askedAt, the first call refunds both stakes finally; a later delivery is then ignored by the wager. The two parties have opposite incentives at that moment, so when the swarm is late the side expecting to lose can lock in a refund by racing the delivery. The alternative (waiting indefinitely) would let an unanswered request lock stakes forever, so the choice is defensible; no change required unless the author wants a longer window.","line":243,"path":"src/SwarmWager.sol","reproduction":"alice yes, bob no, 3e18 each; resolve at time A. No delivery for 3 days. At A + 3 days + 1 s bob calls settle(id): both stakes return (reason 2), state Refunded. Then the writer delivers a verified bool true (alice should have won 6e18); settle(id) reverts WrongState(Refunded). Expected by alice: payout; actual: refund.","severity":"info","snippet":"            if (block.timestamp <= uint256(w.askedAt) + ANSWER_WINDOW) revert StillPending();","title":"Documented race: after ANSWER_WINDOW the party that would lose can refund a still-pending wager before the late answer lands"}],"hash":"baf582fb72745eb192265c33b89cd71a2b7aa0926941f471a90c005632bcd976","nodeId":"341f1129-6500-43a1-a0bb-c3139c0ef7d4","outcome":"completed","summary":"Review complete. The findings file is at the repository root and every snippet, line and coverage reference checks out against the tree.\n\n**Outcome:** no critical, high or medium defects. SwarmWager's state machine, checks-effects-interactions ordering, bounds and payout rule all hold. The launch manifest is correct, and I confirmed over mainnet RPC that the live registry at the manifest's address is byte-identical to the source and that its IMD, Intake and signer immutables match the brief.\n\n**Findings kept, after reproduction and merging:**\n\n1. **Low, create (line 139).** A body longer than Intake's cap can be matched but never resolved, locking both stakes until abandon. Two specialists reported it; merged into one. I read `MAX_BODY_BYTES` from the live Intake to confirm the cap, and the specialist's proof fails on the current code, so it is attached.\n2. **Low, settle (line 247).** No minimum panel or quorum is enforced, so a signed bool with a one-seat or zero-seat panel pays the pot. Reproduced in a scratch test against the real registry source.\n3. **Low, resolve (line 205).** No upper deadline, so the first caller picks the observation window of a relative-window question across at least three days. One specialist rated it low, one info; kept at low since it decides who wins and the documentation cannot enforce the warning.\n4. **Info.** Trust assumption on the Intake writer's pairing and the oracle signer. Two reports merged.\n5. **Info.** Documented timeout race after the three-day window. Two reports merged.\n\n**Dropped:** the math specialist's test-coverage note, because the boundaries, review and atomicity suites in the tree already cover nearly everything it listed. The remaining gap is finding 2.\n\n**Coverage:** all 13 entry points answered, plus the funds-conservation invariant and the manifest. The full suite passes, 157 tests.\n\n**Not verified:** the IMD token's full transfer semantics. It has an owner and about 23 KB of code. The manifest already names its transfer behaviour as a trust assumption, and I found no pause or blocklist function to reproduce a failure against.","treeHash":null,"usage":{"cachedInputTokens":946758,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":26293,"runtime":"claude","turns":26,"wallClockMs":428374}},{"artifacts":[],"attempt":1,"bundleHash":"5138ccf9381d72ea5b3c4ea5896b6d93b9286f3fca3fc777531d4f8d1e3bee1a","device":"fef70a876212b4f0","findings":[],"hash":"cf7a5219af907dde922f683e4135a67fb618ec2f344fe888f5b2055999ae7f55","nodeId":"2c0e360a-61d9-4a15-b5e3-aa812772fbd4","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/b34bbf68-48c5-4271-af67-49b3bc522e6c/2c0e360a-61d9-4a15-b5e3-aa812772fbd4/launch.json) naming only SwarmWager, with the exact constructor addresses and review notes.\n\nValidation passed: manifest structure, compiled ABI, `forge build`, and **142 tests** using the supplied fuzz seed. Only the manifest changed outside scratch artifacts.\n\nNo transaction was broadcast. Live explorer verification returned HTTP 403.","treeHash":"60b35af445f8da81d2aa7bb71b2d18678d51d1e6","usage":{"cachedInputTokens":1086080,"inputTokens":67929,"model":"gpt-6-astra","outputTokens":6171,"runtime":"codex","turns":6,"wallClockMs":230082}}],"verification":[{"checks":[{"durationMs":63384,"exitCode":0,"name":"build","output":"Compiling 43 files with Solc 0.8.26\nSolc 0.8.26 finished in 63.29s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/AskSwarmRegistry.t.sol:613:5:\n    |\n613 |     function _delivered() internal returns (bool d) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":16557,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 416566)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 429075)\n[PASS] test_callbackSelectorIsCanonical() (gas: 691)\n[PASS] test_digestMatchesTheProtocol() (gas: 10377)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.66ms (1.63ms CPU time)\n\nRan 2 tests for test/SwarmWagerLiveRegistry.t.sol:SwarmWagerLiveRegistryTest\n[PASS] test_launchAddressesAndLiveAskGetAndUnverifiedRefund() (gas: 1147131)\n[PASS] test_liveLostOutcomeRefunds() (gas: 913967)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 6.26ms (2.09ms CPU time)\n\nRan 4 tests for test/SwarmWagerDeployment.t.sol:SwarmWagerDeploymentTest\n[PASS] test_constructorRejectsZeroDependenciesAndNativeValue() (gas: 3966)\n[PASS] test_factoryDeploysOnlyWagerOnEmptyChainWithStaticArguments() (gas: 3410212)\n[PASS] test_projectScriptRejectsOtherChains() (gas: 2009226)\n[PASS] test_projectScriptUsesExistingMainnetRegistry() (gas: 3539625)\nLogs:\n  SwarmWager 0x34A1D3fff3958843C43aD80F30b94c510645C316 chain 1\n\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 8.76ms (8.73ms CPU time)\n\nRan 26 tests for test/SwarmWagerReview.t.sol:SwarmWagerReviewTest\n[PASS] testFuzz_allAcceptedTermsHaveBoundedExit(uint64,uint64,bool) (runs: 256, μ: 377608, ~: 422369)\n[PASS] testFuzz_onlyCanonicalMajorityBoolPays(uint256,uint16,uint16) (runs: 256, μ: 1004784, ~: 1017295)\n[PASS] testFuzz_topUpFeeConservation(uint96,uint96,bool) (runs: 256, μ: 858778, ~: 535475)\n[PASS] testFuzz_wrongBoolLengthRefunds(uint8) (runs: 256, μ: 993577, ~: 987288)\n[PASS] test_abandonBeforeLateResolvePreventsAnAsk() (gas: 473416)\n[PASS] test_abandonReturnsAllTopUpsToCreator() (gas: 433654)\n[PASS] test_badSignatureRefundsBothStakes() (gas: 1009930)\n[PASS] test_creatorTopUpRecoversWagerAfterPriceRise() (gas: 1191517)\n[PASS] test_exactJoinAndResolveBoundaryRemainsSupported() (gas: 977893)\n[PASS] test_expiredAtDeliveryRefundsBothStakes() (gas: 979775)\n[PASS] test_lateAnswerBeforeTimeoutSettlementStillPaysWinner() (gas: 1049816)\n[PASS] test_lostCallbackRefundsBothStakes() (gas: 884685)\n[PASS] test_maximumFeeEscrowCanBeFundedAndAbandoned() (gas: 531708)\n[PASS] test_maximumTermCanStillBeMatchedAndUnwound() (gas: 449314)\n[PASS] test_maximumTimestampAndOverlongTermsRejectedBeforePayment() (gas: 102218)\n[PASS] test_priceDecreaseReturnsOnlyRemainderAndApprovesExactPrice() (gas: 808079)\n[PASS] test_priceRiseRevertsWithoutSpendingStakesAndAbandonStillWorks() (gas: 556509)\n[PASS] test_resolutionAfterAbandonDeadlineCanWinTheRace() (gas: 1051298)\n[PASS] test_resolveCallerChoosesAskTimeForRelativeWindows() (gas: 731350)\n[PASS] test_resolveWaitsThroughGapAfterJoinDeadline() (gas: 731606)\n[PASS] test_thirdPartyTopUpIsExplicitAndUnusedFeeGoesToCreator() (gas: 1177687)\n[PASS] test_timeoutIsStrictlyAfterAnswerWindow() (gas: 838828)\n[PASS] test_timeoutSettlementBeforeLateAnswerRemainsRefunded() (gas: 1057759)\n[PASS] test_topUpRefusesUnknownOpenAskedAndTerminalWagers() (gas: 1345614)\n[PASS] test_topUpRefusesZeroOverflowAndRollsBackFailedPayment() (gas: 573580)\n[PASS] test_writerPairingOfAnotherQuestionsAnswerIsTrusted() (gas: 1164208)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 197.01ms (360.30ms CPU time)\n\nRan 10 tests for test/SwarmWagerBoundaries.t.sol:SwarmWagerBoundariesTest\n[PASS] testFuzz_majorityBoundaryAcrossUint16Range(uint16,bool,bool,bool) (runs: 1000, μ: 996347, ~: 989999)\n[PASS] testFuzz_nonBoolTypeCannotPayEvenWithCanonicalBoolBytes(uint8,bool) (runs: 1000, μ: 996481, ~: 1006187)\n[PASS] test_failedCreateAndJoinDoNotLeavePhantomPositionsOrParticipants() (gas: 855348)\n[PASS] test_maximumStakeAndMaximumFeeDoNotNarrowCombinedAmounts() (gas: 1126236)\n[PASS] test_missingRegistryRecordUsesTimeoutInsteadOfPayingEmbeddedAnswer() (gas: 825603)\n[PASS] test_oversizedBodyRejectedByTransportLeavesFeeAndStakesRefundable() (gas: 4252869)\n[PASS] test_retiredActionRollsBackApprovalAndCanBeAbandoned() (gas: 546125)\n[PASS] test_sharedQuestionIndexCannotSubstituteAnotherWagersAnswer() (gas: 1849034)\n[PASS] test_unavailablePriceDoesNotChargeCreateOrTrapMatchedEscrow() (gas: 674356)\n[PASS] test_zeroAndUnrepresentableFeesRejectBeforeFunding() (gas: 233192)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 205.97ms (420.72ms CPU time)\n\nRan 23 tests for test/AskSwarmRegistry.t.sol:AskSwarmRegistryTest\n[PASS] testFuzz_indexedAnswersAreMajorities(uint16,uint16,uint16,uint32,uint32,uint32) (runs: 256, μ: 429041, ~: 425934)\n[PASS] test_answerDeliveredWithinStipendAndVerified() (gas: 480527)\n[PASS] test_askAtMostAgainstTheQuotedPrice() (gas: 307456)\n[PASS] test_askPullsPriceAndRegisters() (gas: 289885)\n[PASS] test_badSignatureStoredUnverifiedAndNotIndexed() (gas: 433697)\n[PASS] test_callbackGasMargin() (gas: 730555)\nLogs:\n  onOracleResult gas, bytes32 answer: 148282\n  onOracleResult gas, 352-byte answer: 135951\n\n[PASS] test_constructorMakesNoCallsAndAskLeavesNoAllowance() (gas: 2566003)\n[PASS] test_digestMatchesPlaneSignature() (gas: 15161)\n[PASS] test_domainIsTheCallbackContract() (gas: 398151)\n[PASS] test_expiredAtDeliveryAndAnswerBoundaries() (gas: 2957963)\n[PASS] test_expiryBoundaryAtDelivery() (gas: 449389)\n[PASS] test_failureHookStatusesAndUnknownIds() (gas: 384242)\n[PASS] test_failureRecorded() (gas: 316821)\n[PASS] test_indexRespectsValidityWindowAndReindexRecovers() (gas: 1493990)\n[PASS] test_largeAnswerStillWithinStipend() (gas: 516572)\n[PASS] test_markLostReadsIntakeCompletionRecord() (gas: 801557)\n[PASS] test_minorityAnswerNotIndexedEvenWhenNothingHeld() (gas: 779775)\n[PASS] test_minorityOfLargePanelCannotDisplaceSupermajority() (gas: 1155889)\n[PASS] test_onlyIntakeCanDeliver() (gas: 301915)\n[PASS] test_quorumAndExpiryGateVerified() (gas: 393137)\n[PASS] test_settledAskRefusesRedeliveryThroughAnotherOpenAsk() (gas: 789628)\n[PASS] test_signatureEdges() (gas: 1310064)\n[PASS] test_weakPanelCannotOverwriteStrongAnswer() (gas: 1129046)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 206.01ms (90.18ms CPU time)\n\nRan 3 tests for test/SwarmWagerAtomicity.t.sol:SwarmWagerAtomicityTest\n[PASS] testFuzz_failedPaymentPreservesConcurrentEscrow(uint8,uint8,uint8,uint96) (runs: 1000, μ: 1378009, ~: 1294234)\n[PASS] test_everyPaymentLegRejectsFalseRevertAndMalformedReturns() (gas: 93507466)\n[PASS] test_noReturnTokenCompletesWinsRefundsCancellationAndAbandonment() (gas: 2560329)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 206.10ms (240.78ms CPU time)\n\nRan 19 tests for test/AskSwarmRegistryPayments.t.sol:AskSwarmRegistryPaymentsTest\n[PASS] testFuzz_badTokenReturnRollsBackBothPaymentLegs(uint8,bool) (runs: 1000, μ: 210602, ~: 221751)\n[PASS] testFuzz_exactPriceIsForwardedAndBodyIsUnchanged(uint128,bytes) (runs: 1000, μ: 567526, ~: 574358)\n[PASS] test_askDoesNotSpendPreexistingDonation() (gas: 399320)\n[PASS] test_constructorRejectsEveryZeroDependency() (gas: 7544)\n[PASS] test_donationCannotSubsidizeAnUnfundedAsk() (gas: 154696)\n[PASS] test_fullCallerBalanceAndMaximumBody() (gas: 2954509)\n[PASS] test_insufficientBalanceRollsBackConsumedAllowance() (gas: 192998)\n[PASS] test_intakeBodyBoundsRollBackThePayment() (gas: 434697)\n[PASS] test_noApprovalAndOneWeiShortApprovalBothRevert() (gas: 323043)\n[PASS] test_noReturnTokenIsSupportedOnTransferAndApproval() (gas: 394401)\n[PASS] test_notSoldDoesNotChargeOrRegister() (gas: 143386)\n[PASS] test_oneWeiPrice() (gas: 384542)\n[PASS] test_plainEthAndPayableAskAreRejectedWithoutTakingFunds() (gas: 145470)\n[PASS] test_priceChangesAreReadOnEveryAsk() (gas: 561725)\n[PASS] test_priceIncreaseBeyondApprovalCannotChargeOldQuote() (gas: 187170)\n[PASS] test_priceLookupFailureDoesNotChargeOrRegister() (gas: 163271)\n[PASS] test_rejectionAfterIntakePullRollsBackRecipientPayment() (gas: 343199)\n[PASS] test_rejectionBeforeIntakePullRollsBackCallerPayment() (gas: 227757)\n[PASS] test_tokenRejectsOnlyIntakePullAndEntireAskRollsBack() (gas: 317064)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 221.22ms (335.14ms CPU time)\n\nRan 26 tests for test/AskSwarmRegistryCallbacks.t.sol:AskSwarmRegistryCallbacksTest\n[PASS] testFuzz_longAnswerHashAndEventPreserveEveryByte(uint16,bytes32) (runs: 1000, μ: 833024, ~: 700811)\n[PASS] testFuzz_non65ByteSignaturesNeverVerify(uint16,bytes32) (runs: 1000, μ: 505677, ~: 494531)\n[PASS] testFuzz_shortAnswerRoundTripsIncludingZeros(bytes32,uint8) (runs: 1000, μ: 517533, ~: 523377)\n[PASS] testFuzz_verifiedRequiresIssuedAtWithinTolerance(uint32,uint32) (runs: 1000, μ: 505854, ~: 517466)\n[PASS] test_bothFailureStatusesPreserveFeeAndEmitReasonAndCounts() (gas: 1041103)\n[PASS] test_bothHooksRefuseEverySettledStatus() (gas: 2315241)\n[PASS] test_bothPanelSizeAndAgreementMustBeAtLeastAsStrong() (gas: 1886869)\n[PASS] test_eachOfTheFifteenFieldsIsBoundByTheSignature() (gas: 5586715)\n[PASS] test_falseIsAVerifiedAnswerAndNotAFailure() (gas: 504554)\n[PASS] test_firstByteOverCapIsUnverifiedAndDoesNotDisplaceHeldAnswer() (gas: 800971)\n[PASS] test_intakeAndOracleRequestIdsMayDiffer() (gas: 524108)\n[PASS] test_invalidVAndZeroRecoveryAreRejected() (gas: 2238504)\n[PASS] test_issuedAtToleranceBoundary() (gas: 1279965)\n[PASS] test_maximumAcceptedAnswerFitsColdCallbackStipend() (gas: 1152530)\n[PASS] test_nonzeroAbiPaddingCannotLeakIntoShortAnswer() (gas: 509578)\n[PASS] test_recordsWithoutAStoredAnswerReportZeroAnswerHash() (gas: 1858663)\n[PASS] test_registeredCallbackWithForeignRequestIdCannotCreateAnAsk() (gas: 93390)\n[PASS] test_settledAskIsNotRewrittenByAnotherRequestsCompletion() (gas: 1119030)\n[PASS] test_signatureForAnotherConsumerIsNotReusable() (gas: 500205)\n[PASS] test_thirdPartyCannotCompleteOrCallEitherHook() (gas: 448513)\n[PASS] test_timeAndMinimumFiltersDoNotDeleteHistoricalRecord() (gas: 604618)\n[PASS] test_transportWillNotRetrySuccessOrFailure() (gas: 867496)\n[PASS] test_unknownReadsDoNotLookAnswered() (gas: 48342)\n[PASS] test_weakerMajorityCanReplaceOnlyAfterHeldAnswerExpires() (gas: 1216157)\n[PASS] test_wrongDomainChainNameAndVersionAreRejected() (gas: 1164726)\n[PASS] test_wrongSignerCannotReplaceHeldAnswer() (gas: 852582)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 221.20ms (866.76ms CPU time)\n\nRan 15 tests for test/SwarmWager.t.sol:SwarmWagerTest\n[PASS] test_abandonWhenNeverResolved() (gas: 526475)\n[PASS] test_anyoneCancelsAfterJoinBy() (gas: 431549)\n[PASS] test_badTerms() (gas: 117795)\n[PASS] test_cancelUnmatched() (gas: 468784)\n[PASS] test_creatorCannotTakeBothSides() (gas: 385876)\n[PASS] test_minorityAnswerRefunds() (gas: 1003852)\n[PASS] test_noWins() (gas: 1031853)\n[PASS] test_nonBoolAnswerRefunds() (gas: 1029900)\n[PASS] test_nonCanonicalBoolRefunds() (gas: 1030322)\n[PASS] test_pendingThenTimeoutRefunds() (gas: 786321)\n[PASS] test_refusedRefunds() (gas: 842526)\n[PASS] test_resolveWaitsAndOnlyOnce() (gas: 730962)\n[PASS] test_settleOnlyOnce() (gas: 1064491)\n[PASS] test_splitPanelRefunds() (gas: 859479)\n[PASS] test_yesWins() (gas: 1095859)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 221.21ms (4.14ms CPU time)\n\nRan 11 tests for test/AskSwarmRegistryReview.t.sol:AskSwarmRegistryReviewTest\n[PASS] test_askAtMostRefusesAPriceAboveTheCeiling() (gas: 764549)\n[PASS] test_askWithoutCeilingStillPaysTheLivePrice() (gas: 363602)\n[PASS] test_deliveryEmitsIndexedOnlyWhenTheIndexMoves() (gas: 831136)\n[PASS] test_markLostAfterAFailureCompletionWithEmptyArguments() (gas: 413455)\n[PASS] test_markLostSettlesAnAskIntakeCompletedWithoutDelivering() (gas: 1024141)\n[PASS] test_reindexFallsBackToAValidAnswerAfterTheHeldOneExpires() (gas: 1047052)\n[PASS] test_reindexRefusesEveryIneligibleRecord() (gas: 2185211)\n[PASS] test_reindexReplacesAFallbackOnlyByStrictDominance() (gas: 1703927)\n[PASS] test_shortLivedEqualAnswerCannotCutHeldValidityShort() (gas: 1618364)\n[PASS] test_staleOrShorterLivedEqualAnswerDoesNotDisplaceOnDelivery() (gas: 3309315)\n[PASS] test_statusCodesAreAppendedNotRenumbered() (gas: 580)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 221.25ms (38.15ms CPU time)\n\nRan 9 tests for test/AskSwarmRegistryAdversarial.t.sol:AskSwarmRegistryAdversarialTest\n[PASS] testFuzz_oversizedAnswersOfAnySizeSettleInsideStipend(uint24) (runs: 300, μ: 998852, ~: 948792)\n[PASS] testFuzz_readsOfUntouchedKeysAreEmpty(bytes32,uint16,uint16) (runs: 256, μ: 47590, ~: 47590)\n[PASS] testFuzz_unexpectedFailureStatusesSettleAsNoResult(uint8,bytes32,uint16) (runs: 512, μ: 839256, ~: 839429)\n[PASS] testFuzz_verifiedExactlyWhenEveryConditionHolds(uint16,uint16,uint16,uint32,uint32,uint8) (runs: 1000, μ: 500044, ~: 497893)\n[PASS] test_callbackGasAtTheStipendBoundary() (gas: 1848958)\nLogs:\n  onOracleResult gas, one-word answer, cold: 118568\n  onOracleResult gas, 4096-byte answer, cold: 156201\n\n[PASS] test_contractAskerIsRecordedNotTxOrigin() (gas: 639024)\n[PASS] test_highSTwinIsUnverifiedWhileZeroOneVAreNormalised() (gas: 857211)\n[PASS] test_identicalBodiesAreDistinctPaidAsks() (gas: 524043)\n[PASS] test_maximumAnswerDisplacingAHeldAnswerFitsColdStipend() (gas: 1592155)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 221.28ms (576.60ms CPU time)\n\nRan 2 tests for test/AskSwarmRegistryIndexInvariant.t.sol:AskSwarmRegistryIndexInvariantTest\n[PASS]\nAskSwarmRegistryIndexInvariantTest invariants:\n[PASS] invariant_everyAskIsPendingOrSettledOnce\n[PASS] invariant_indexOnlyHoldsVerifiedMajoritiesOfTheirOwnQuestion\n[PASS] invariant_registryHoldsNothingAndForwardsEveryFee\n AskSwarmRegistryIndexInvariantTest invariants (runs: 192, calls: 12288, reverts: 0)\n\n╭------------------------+------------+-------+---------+----------╮\n| Contract               | Selector   | Calls | Reverts | Discards |\n+==================================================================+\n| IndexTransitionHandler | ask        | 1332  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | deliver    | 1328  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | directHook | 1369  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | fail       | 1393  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | markLost   | 1370  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | reindex    | 1325  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | replay     | 1406  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | strand     | 1339  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | warp       | 1426  | 0       | 0        |\n╰------------------------+------------+-------+---------+----------╯\n\n[PASS] test_handlersReachLostAndReindexMoves() (gas: 1787105)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.19s (7.18s CPU time)\n\nRan 1 test for test/AskSwarmRegistryInvariant.t.sol:AskSwarmRegistryInvariantTest\n[PASS]\nAskSwarmRegistryInvariantTest invariants:\n[PASS] invariant_paymentsAreConservedAndNoFeeIsRetained\n[PASS] invariant_requestsAndCanonicalAnswersStayConsistent\n AskSwarmRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭-------------------------+---------------------------------+-------+---------+----------╮\n| Contract                | Selector                        | Calls | Reverts | Discards |\n+========================================================================================+\n| RegistrySequenceHandler | advanceTime                     | 2154  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | answer                          | 2238  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | ask                             | 2151  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | donate                          | 2264  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | failingAsk                      | 2324  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | markLost                        | 2225  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | refuse                          | 2309  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | reindex                         | 2251  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | replaySettledThroughOpenRequest | 2240  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | retryCompletedRequest           | 2178  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | unauthorizedCallback            | 2242  | 0       | 0        |\n╰-------------------------+---------------------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.54s (12.53s CPU time)\n\nRan 2 tests for test/SwarmWagerInvariant.t.sol:SwarmWagerInvariantTest\n[PASS]\nSwarmWagerInvariantTest invariants:\n[PASS] invariant_escrowAndEveryActorBalanceReconcile\n[PASS] invariant_termsRequestsAndTerminalStatesStayConsistent\n SwarmWagerInvariantTest invariants (runs: 256, calls: 32768, reverts: 0)\n\n╭-------------------+----------------+-------+---------+----------╮\n| Contract          | Selector       | Calls | Reverts | Discards |\n+=================================================================+\n| SwarmWagerHandler | abandon        | 2531  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | advanceTime    | 2535  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | cancel         | 2442  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | changePrice    | 2458  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | create         | 2504  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | deliver        | 2597  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | donate         | 2483  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | failingResolve | 2562  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | join           | 2582  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | resolve        | 2591  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | settle         | 2466  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | topUp          | 2494  | 0       | 0        |\n|-------------------+----------------+-------+---------+----------|\n| SwarmWagerHandler | wrongState     | 2523  | 0       | 0        |\n╰-------------------+----------------+-------+---------+----------╯\n\n[PASS] test_handlerReachesEveryOutcomeAndAllExitPaths() (gas: 38042355)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 16.46s (16.45s CPU time)\n\nRan 15 test suites in 16.46s (38.13s CPU time): 157 tests passed, 0 failed, 0 skipped (157 total tests)\n","passed":true},{"durationMs":207,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"AskSwarmRegistry.ask(bytes)\",\"AskSwarmRegistry.askAtMost(bytes,uint256)\",\"AskSwarmRegistry.markLost(bytes32)\",\"AskSwarmRegistry.onFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"AskSwarmRegistry.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"AskSwarmRegistry.reindex(bytes32)\",\"SwarmWager.abandon(uint256)\",\"SwarmWager.cancel(uint256)\",\"SwarmWager.create(bytes,bool,uint96,uint64,uint64)\",\"SwarmWager.join(uint256)\",\"SwarmWager.resolve(uint256)\",\"SwarmWager.settle(uint256)\",\"SwarmWager.topUpFee(uint256,uint96)\"],\"files\":{\".DS_Store\":4,\".env.example\":12,\".gitignore\":9,\"ADAPTATION.md\":167,\"README.md\":303,\"api/answers.mjs\":1,\"api/cpay-webhook.mjs\":1,\"api/hf-sync.mjs\":1,\"api/imd.mjs\":1,\"api/telegram.mjs\":1,\"bun.lock\":458,\"contracts/ADAPTATION-2099.md\":211,\"contracts/ADAPTATION.md\":98,\"contracts/LAUNCH-WAGER.md\":7,\"contracts/LAUNCH.md\":7,\"docs/.DS_Store\":4,\"docs/EVIDENCE.md\":15,\"docs/SUBMISSION.md\":48,\"docs/askswarm-demo.mp4\":11630,\"docs/askswarm.png\":1383,\"docs/brand/.gitignore\":1,\"docs/brand/Battlefin-Black.otf\":864,\"docs/brand/NB_International_Bold_Webfont.ttf\":2797,\"docs/brand/NB_International_Mono_Webfont.ttf\":2749,\"docs/brand/NB_International_Regular_Webfont.ttf\":2728,\"docs/brand/ai.svg\":6,\"docs/brand/data.svg\":5,\"docs/brand/demo.html\":161,\"docs/brand/hand.svg\":3,\"docs/brand/infographic.html\":121,\"docs/brand/lock.svg\":3,\"docs/brand/logo-symbol-light.svg\":4,\"docs/brand/logo-symbol.svg\":4,\"docs/brand/logo-wordmark-dark.svg\":12,\"docs/brand/logo-wordmark-light.svg\":12,\"docs/brand/message.svg\":3,\"docs/brand/miniapp.html\":22,\"docs/brand/star5.svg\":3,\"docs/brand/voiceover.tsv\":7,\"docs/logo-1024.png\":292,\"docs/logo-512.png\":122,\"docs/logo.svg\":7,\"docs/miniapp-640x360.png\":161,\"docs/vids/SCRIPT.md\":11,\"docs/vids/askswarm-demo-silent.mp4\":9487,\"docs/vids/scene1.mp4\":186,\"docs/vids/scene2.mp4\":382,\"docs/vids/scene3.mp4\":791,\"docs/vids/scene4.mp4\":446,\"docs/vids/scene5.mp4\":7161,\"docs/vids/scene6.mp4\":331,\"docs/vids/scene7.mp4\":178,\"foundry.toml\":16,\"functions/answers.ts\":81,\"functions/cpay-webhook.ts\":28,\"functions/hf-sync.ts\":15,\"functions/imd.ts\":58,\"functions/telegram.ts\":24,\"lib/answers.json\":1,\"lib/bot.ts\":269,\"lib/hfsync.ts\":49,\"lib/quick.ts\":21,\"lib/recall.ts\":21,\"lib/risk-model.json\":1,\"lib/risk.ts\":56,\"package.json\":31,\"packages/cpay/src/index.ts\":481,\"packages/imd/src/index.ts\":235,\"packages/imd/src/intake.ts\":133,\"public/ai.svg\":6,\"public/answers.html\":83,\"public/apple-touch-icon.png\":53,\"public/data.svg\":5,\"public/favicon-32.png\":8,\"public/favicon.svg\":7,\"public/fonts/Battlefin-Black.otf\":864,\"public/fonts/NB_International_Bold_Webfont.ttf\":2797,\"public/fonts/NB_International_Mono_Webfont.ttf\":2749,\"public/fonts/NB_International_Regular_Webfont.ttf\":2728,\"public/imd.html\":107,\"public/index.html\":172,\"public/llms.txt\":9,\"public/lock.svg\":3,\"public/logo-wordmark-dark.svg\":12,\"public/logo.svg\":7,\"public/message.svg\":3,\"public/og.png\":1364,\"public/pay.html\":40,\"public/skill.md\":51,\"public/star5.svg\":3,\"script/Deploy.s.sol\":20,\"scripts/approve-permit2.ts\":25,\"scripts/balance.ts\":6,\"scripts/build-answers.ts\":24,\"scripts/dry-run.ts\":13,\"scripts/evidence.ts\":45,\"scripts/hf-sync.ts\":4,\"scripts/launch.ts\":65,\"scripts/spike-sepolia.ts\":50,\"scripts/spike.ts\":58,\"scripts/train-risk.ts\":41,\"scripts/vercel-env.sh\":13,\"src/AskSwarmRegistry.sol\":493,\"src/IIntake.sol\":55,\"src/SwarmWager.sol\":292,\"test/AskSwarmRegistry.t.sol\":643,\"test/AskSwarmRegistryAdversarial.t.sol\":269,\"test/AskSwarmRegistryCallbacks.t.sol\":610,\"test/AskSwarmRegistryIndexInvariant.t.sol\":396,\"test/AskSwarmRegistryInvariant.t.sol\":488,\"test/AskSwarmRegistryPayments.t.sol\":261,\"test/AskSwarmRegistryReview.t.sol\":319,\"test/OracleConsumerConformance.t.sol\":104,\"test/SWARM_WAGER_TESTING.md\":47,\"test/SwarmWager.t.sol\":282,\"test/SwarmWagerAtomicity.t.sol\":268,\"test/SwarmWagerBoundaries.t.sol\":254,\"test/SwarmWagerDeployment.t.sol\":90,\"test/SwarmWagerInvariant.t.sol\":122,\"test/SwarmWagerLiveRegistry.t.sol\":88,\"test/SwarmWagerReview.t.sol\":450,\"test/TESTING.md\":83,\"test/helpers/RegistryTestSupport.sol\":289,\"test/helpers/SwarmWagerHandler.sol\":523,\"test/mocks/IntakeMocks.sol\":100,\"test/mocks/WagerFaultToken.sol\":88,\"tsconfig.json\":8,\"vercel.json\":11},\"excluded\":[\"contracts/lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"3eb1914698faec6ed0d0cc827901e0dac5d979fb05a204fbccd60861980c6c83","verifiedTreeHash":"0a4afc1359caaa4f92c4b45bde808445952f81ad","verifierVersion":"0.1.0+fddeb651"},{"checks":[{"durationMs":53372,"exitCode":0,"name":"build","output":"Compiling 38 files with Solc 0.8.26\nSolc 0.8.26 finished in 53.28s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/AskSwarmRegistry.t.sol:613:5:\n    |\n613 |     function _delivered() internal returns (bool d) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":12974,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 416566)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 429075)\n[PASS] test_callbackSelectorIsCanonical() (gas: 691)\n[PASS] test_digestMatchesTheProtocol() (gas: 10377)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.52ms (1.11ms CPU time)\n\nRan 2 tests for test/SwarmWagerLiveRegistry.t.sol:SwarmWagerLiveRegistryTest\n[PASS] test_launchAddressesAndLiveAskGetAndUnverifiedRefund() (gas: 1147131)\n[PASS] test_liveLostOutcomeRefunds() (gas: 913967)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.59ms (1.12ms CPU time)\n\nRan 4 tests for test/SwarmWagerDeployment.t.sol:SwarmWagerDeploymentTest\n[PASS] test_constructorRejectsZeroDependenciesAndNativeValue() (gas: 3966)\n[PASS] test_factoryDeploysOnlyWagerOnEmptyChainWithStaticArguments() (gas: 3410212)\n[PASS] test_projectScriptRejectsOtherChains() (gas: 2009226)\n[PASS] test_projectScriptUsesExistingMainnetRegistry() (gas: 3539625)\nLogs:\n  SwarmWager 0x34A1D3fff3958843C43aD80F30b94c510645C316 chain 1\n\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 4.88ms (3.36ms CPU time)\n\nRan 15 tests for test/SwarmWager.t.sol:SwarmWagerTest\n[PASS] test_abandonWhenNeverResolved() (gas: 526475)\n[PASS] test_anyoneCancelsAfterJoinBy() (gas: 431549)\n[PASS] test_badTerms() (gas: 117795)\n[PASS] test_cancelUnmatched() (gas: 468784)\n[PASS] test_creatorCannotTakeBothSides() (gas: 385876)\n[PASS] test_minorityAnswerRefunds() (gas: 1003852)\n[PASS] test_noWins() (gas: 1031853)\n[PASS] test_nonBoolAnswerRefunds() (gas: 1029900)\n[PASS] test_nonCanonicalBoolRefunds() (gas: 1030322)\n[PASS] test_pendingThenTimeoutRefunds() (gas: 786321)\n[PASS] test_refusedRefunds() (gas: 842526)\n[PASS] test_resolveWaitsAndOnlyOnce() (gas: 730962)\n[PASS] test_settleOnlyOnce() (gas: 1064491)\n[PASS] test_splitPanelRefunds() (gas: 859479)\n[PASS] test_yesWins() (gas: 1095859)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 7.08ms (5.36ms CPU time)\n\nRan 23 tests for test/AskSwarmRegistry.t.sol:AskSwarmRegistryTest\n[PASS] testFuzz_indexedAnswersAreMajorities(uint16,uint16,uint16,uint32,uint32,uint32) (runs: 256, μ: 429133, ~: 425871)\n[PASS] test_answerDeliveredWithinStipendAndVerified() (gas: 480527)\n[PASS] test_askAtMostAgainstTheQuotedPrice() (gas: 307456)\n[PASS] test_askPullsPriceAndRegisters() (gas: 289885)\n[PASS] test_badSignatureStoredUnverifiedAndNotIndexed() (gas: 433697)\n[PASS] test_callbackGasMargin() (gas: 730555)\nLogs:\n  onOracleResult gas, bytes32 answer: 148282\n  onOracleResult gas, 352-byte answer: 135951\n\n[PASS] test_constructorMakesNoCallsAndAskLeavesNoAllowance() (gas: 2566003)\n[PASS] test_digestMatchesPlaneSignature() (gas: 15161)\n[PASS] test_domainIsTheCallbackContract() (gas: 398151)\n[PASS] test_expiredAtDeliveryAndAnswerBoundaries() (gas: 2957963)\n[PASS] test_expiryBoundaryAtDelivery() (gas: 449389)\n[PASS] test_failureHookStatusesAndUnknownIds() (gas: 384242)\n[PASS] test_failureRecorded() (gas: 316821)\n[PASS] test_indexRespectsValidityWindowAndReindexRecovers() (gas: 1493990)\n[PASS] test_largeAnswerStillWithinStipend() (gas: 516572)\n[PASS] test_markLostReadsIntakeCompletionRecord() (gas: 801557)\n[PASS] test_minorityAnswerNotIndexedEvenWhenNothingHeld() (gas: 779775)\n[PASS] test_minorityOfLargePanelCannotDisplaceSupermajority() (gas: 1155889)\n[PASS] test_onlyIntakeCanDeliver() (gas: 301915)\n[PASS] test_quorumAndExpiryGateVerified() (gas: 393137)\n[PASS] test_settledAskRefusesRedeliveryThroughAnotherOpenAsk() (gas: 789628)\n[PASS] test_signatureEdges() (gas: 1310064)\n[PASS] test_weakPanelCannotOverwriteStrongAnswer() (gas: 1129046)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 152.14ms (170.47ms CPU time)\n\nRan 11 tests for test/AskSwarmRegistryReview.t.sol:AskSwarmRegistryReviewTest\n[PASS] test_askAtMostRefusesAPriceAboveTheCeiling() (gas: 764549)\n[PASS] test_askWithoutCeilingStillPaysTheLivePrice() (gas: 363602)\n[PASS] test_deliveryEmitsIndexedOnlyWhenTheIndexMoves() (gas: 831136)\n[PASS] test_markLostAfterAFailureCompletionWithEmptyArguments() (gas: 413455)\n[PASS] test_markLostSettlesAnAskIntakeCompletedWithoutDelivering() (gas: 1024141)\n[PASS] test_reindexFallsBackToAValidAnswerAfterTheHeldOneExpires() (gas: 1047052)\n[PASS] test_reindexRefusesEveryIneligibleRecord() (gas: 2185211)\n[PASS] test_reindexReplacesAFallbackOnlyByStrictDominance() (gas: 1703927)\n[PASS] test_shortLivedEqualAnswerCannotCutHeldValidityShort() (gas: 1618364)\n[PASS] test_staleOrShorterLivedEqualAnswerDoesNotDisplaceOnDelivery() (gas: 3309315)\n[PASS] test_statusCodesAreAppendedNotRenumbered() (gas: 580)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 163.31ms (16.69ms CPU time)\n\nRan 19 tests for test/AskSwarmRegistryPayments.t.sol:AskSwarmRegistryPaymentsTest\n[PASS] testFuzz_badTokenReturnRollsBackBothPaymentLegs(uint8,bool) (runs: 1000, μ: 210602, ~: 221751)\n[PASS] testFuzz_exactPriceIsForwardedAndBodyIsUnchanged(uint128,bytes) (runs: 1000, μ: 567569, ~: 574322)\n[PASS] test_askDoesNotSpendPreexistingDonation() (gas: 399320)\n[PASS] test_constructorRejectsEveryZeroDependency() (gas: 7544)\n[PASS] test_donationCannotSubsidizeAnUnfundedAsk() (gas: 154696)\n[PASS] test_fullCallerBalanceAndMaximumBody() (gas: 2954509)\n[PASS] test_insufficientBalanceRollsBackConsumedAllowance() (gas: 192998)\n[PASS] test_intakeBodyBoundsRollBackThePayment() (gas: 434697)\n[PASS] test_noApprovalAndOneWeiShortApprovalBothRevert() (gas: 323043)\n[PASS] test_noReturnTokenIsSupportedOnTransferAndApproval() (gas: 394401)\n[PASS] test_notSoldDoesNotChargeOrRegister() (gas: 143386)\n[PASS] test_oneWeiPrice() (gas: 384542)\n[PASS] test_plainEthAndPayableAskAreRejectedWithoutTakingFunds() (gas: 145470)\n[PASS] test_priceChangesAreReadOnEveryAsk() (gas: 561725)\n[PASS] test_priceIncreaseBeyondApprovalCannotChargeOldQuote() (gas: 187170)\n[PASS] test_priceLookupFailureDoesNotChargeOrRegister() (gas: 163271)\n[PASS] test_rejectionAfterIntakePullRollsBackRecipientPayment() (gas: 343199)\n[PASS] test_rejectionBeforeIntakePullRollsBackCallerPayment() (gas: 227757)\n[PASS] test_tokenRejectsOnlyIntakePullAndEntireAskRollsBack() (gas: 317064)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 163.33ms (336.49ms CPU time)\n\nRan 26 tests for test/AskSwarmRegistryCallbacks.t.sol:AskSwarmRegistryCallbacksTest\n[PASS] testFuzz_longAnswerHashAndEventPreserveEveryByte(uint16,bytes32) (runs: 1000, μ: 832940, ~: 701336)\n[PASS] testFuzz_non65ByteSignaturesNeverVerify(uint16,bytes32) (runs: 1000, μ: 505248, ~: 493745)\n[PASS] testFuzz_shortAnswerRoundTripsIncludingZeros(bytes32,uint8) (runs: 1000, μ: 517593, ~: 523377)\n[PASS] testFuzz_verifiedRequiresIssuedAtWithinTolerance(uint32,uint32) (runs: 1000, μ: 505778, ~: 517466)\n[PASS] test_bothFailureStatusesPreserveFeeAndEmitReasonAndCounts() (gas: 1041103)\n[PASS] test_bothHooksRefuseEverySettledStatus() (gas: 2315241)\n[PASS] test_bothPanelSizeAndAgreementMustBeAtLeastAsStrong() (gas: 1886869)\n[PASS] test_eachOfTheFifteenFieldsIsBoundByTheSignature() (gas: 5586715)\n[PASS] test_falseIsAVerifiedAnswerAndNotAFailure() (gas: 504554)\n[PASS] test_firstByteOverCapIsUnverifiedAndDoesNotDisplaceHeldAnswer() (gas: 800971)\n[PASS] test_intakeAndOracleRequestIdsMayDiffer() (gas: 524108)\n[PASS] test_invalidVAndZeroRecoveryAreRejected() (gas: 2238504)\n[PASS] test_issuedAtToleranceBoundary() (gas: 1279965)\n[PASS] test_maximumAcceptedAnswerFitsColdCallbackStipend() (gas: 1152530)\n[PASS] test_nonzeroAbiPaddingCannotLeakIntoShortAnswer() (gas: 509578)\n[PASS] test_recordsWithoutAStoredAnswerReportZeroAnswerHash() (gas: 1858663)\n[PASS] test_registeredCallbackWithForeignRequestIdCannotCreateAnAsk() (gas: 93390)\n[PASS] test_settledAskIsNotRewrittenByAnotherRequestsCompletion() (gas: 1119030)\n[PASS] test_signatureForAnotherConsumerIsNotReusable() (gas: 500205)\n[PASS] test_thirdPartyCannotCompleteOrCallEitherHook() (gas: 448513)\n[PASS] test_timeAndMinimumFiltersDoNotDeleteHistoricalRecord() (gas: 604618)\n[PASS] test_transportWillNotRetrySuccessOrFailure() (gas: 867496)\n[PASS] test_unknownReadsDoNotLookAnswered() (gas: 48342)\n[PASS] test_weakerMajorityCanReplaceOnlyAfterHeldAnswerExpires() (gas: 1216157)\n[PASS] test_wrongDomainChainNameAndVersionAreRejected() (gas: 1164726)\n[PASS] test_wrongSignerCannotReplaceHeldAnswer() (gas: 852582)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 163.40ms (640.19ms CPU time)\n\nRan 26 tests for test/SwarmWagerReview.t.sol:SwarmWagerReviewTest\n[PASS] testFuzz_allAcceptedTermsHaveBoundedExit(uint64,uint64,bool) (runs: 256, μ: 377605, ~: 422369)\n[PASS] testFuzz_onlyCanonicalMajorityBoolPays(uint256,uint16,uint16) (runs: 256, μ: 1004988, ~: 1017301)\n[PASS] testFuzz_topUpFeeConservation(uint96,uint96,bool) (runs: 256, μ: 858856, ~: 535475)\n[PASS] testFuzz_wrongBoolLengthRefunds(uint8) (runs: 256, μ: 993577, ~: 987288)\n[PASS] test_abandonBeforeLateResolvePreventsAnAsk() (gas: 473416)\n[PASS] test_abandonReturnsAllTopUpsToCreator() (gas: 433654)\n[PASS] test_badSignatureRefundsBothStakes() (gas: 1009930)\n[PASS] test_creatorTopUpRecoversWagerAfterPriceRise() (gas: 1191517)\n[PASS] test_exactJoinAndResolveBoundaryRemainsSupported() (gas: 977893)\n[PASS] test_expiredAtDeliveryRefundsBothStakes() (gas: 979775)\n[PASS] test_lateAnswerBeforeTimeoutSettlementStillPaysWinner() (gas: 1049816)\n[PASS] test_lostCallbackRefundsBothStakes() (gas: 884685)\n[PASS] test_maximumFeeEscrowCanBeFundedAndAbandoned() (gas: 531708)\n[PASS] test_maximumTermCanStillBeMatchedAndUnwound() (gas: 449314)\n[PASS] test_maximumTimestampAndOverlongTermsRejectedBeforePayment() (gas: 102218)\n[PASS] test_priceDecreaseReturnsOnlyRemainderAndApprovesExactPrice() (gas: 808079)\n[PASS] test_priceRiseRevertsWithoutSpendingStakesAndAbandonStillWorks() (gas: 556509)\n[PASS] test_resolutionAfterAbandonDeadlineCanWinTheRace() (gas: 1051298)\n[PASS] test_resolveCallerChoosesAskTimeForRelativeWindows() (gas: 731350)\n[PASS] test_resolveWaitsThroughGapAfterJoinDeadline() (gas: 731606)\n[PASS] test_thirdPartyTopUpIsExplicitAndUnusedFeeGoesToCreator() (gas: 1177687)\n[PASS] test_timeoutIsStrictlyAfterAnswerWindow() (gas: 838828)\n[PASS] test_timeoutSettlementBeforeLateAnswerRemainsRefunded() (gas: 1057759)\n[PASS] test_topUpRefusesUnknownOpenAskedAndTerminalWagers() (gas: 1345614)\n[PASS] test_topUpRefusesZeroOverflowAndRollsBackFailedPayment() (gas: 573580)\n[PASS] test_writerPairingOfAnotherQuestionsAnswerIsTrusted() (gas: 1164208)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 163.37ms (581.67ms CPU time)\n\nRan 9 tests for test/AskSwarmRegistryAdversarial.t.sol:AskSwarmRegistryAdversarialTest\n[PASS] testFuzz_oversizedAnswersOfAnySizeSettleInsideStipend(uint24) (runs: 300, μ: 998852, ~: 948792)\n[PASS] testFuzz_readsOfUntouchedKeysAreEmpty(bytes32,uint16,uint16) (runs: 256, μ: 47590, ~: 47590)\n[PASS] testFuzz_unexpectedFailureStatusesSettleAsNoResult(uint8,bytes32,uint16) (runs: 512, μ: 839252, ~: 839429)\n[PASS] testFuzz_verifiedExactlyWhenEveryConditionHolds(uint16,uint16,uint16,uint32,uint32,uint8) (runs: 1000, μ: 500001, ~: 497931)\n[PASS] test_callbackGasAtTheStipendBoundary() (gas: 1848958)\nLogs:\n  onOracleResult gas, one-word answer, cold: 118568\n  onOracleResult gas, 4096-byte answer, cold: 156201\n\n[PASS] test_contractAskerIsRecordedNotTxOrigin() (gas: 639024)\n[PASS] test_highSTwinIsUnverifiedWhileZeroOneVAreNormalised() (gas: 857211)\n[PASS] test_identicalBodiesAreDistinctPaidAsks() (gas: 524043)\n[PASS] test_maximumAnswerDisplacingAHeldAnswerFitsColdStipend() (gas: 1592155)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 165.19ms (474.89ms CPU time)\n\nRan 2 tests for test/AskSwarmRegistryIndexInvariant.t.sol:AskSwarmRegistryIndexInvariantTest\n[PASS]\nAskSwarmRegistryIndexInvariantTest invariants:\n[PASS] invariant_everyAskIsPendingOrSettledOnce\n[PASS] invariant_indexOnlyHoldsVerifiedMajoritiesOfTheirOwnQuestion\n[PASS] invariant_registryHoldsNothingAndForwardsEveryFee\n AskSwarmRegistryIndexInvariantTest invariants (runs: 192, calls: 12288, reverts: 0)\n\n╭------------------------+------------+-------+---------+----------╮\n| Contract               | Selector   | Calls | Reverts | Discards |\n+==================================================================+\n| IndexTransitionHandler | ask        | 1332  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | deliver    | 1328  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | directHook | 1369  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | fail       | 1393  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | markLost   | 1370  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | reindex    | 1325  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | replay     | 1406  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | strand     | 1339  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | warp       | 1426  | 0       | 0        |\n╰------------------------+------------+-------+---------+----------╯\n\n[PASS] test_handlersReachLostAndReindexMoves() (gas: 1787105)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.31s (7.32s CPU time)\n\nRan 1 test for test/AskSwarmRegistryInvariant.t.sol:AskSwarmRegistryInvariantTest\n[PASS]\nAskSwarmRegistryInvariantTest invariants:\n[PASS] invariant_paymentsAreConservedAndNoFeeIsRetained\n[PASS] invariant_requestsAndCanonicalAnswersStayConsistent\n AskSwarmRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭-------------------------+---------------------------------+-------+---------+----------╮\n| Contract                | Selector                        | Calls | Reverts | Discards |\n+========================================================================================+\n| RegistrySequenceHandler | advanceTime                     | 2154  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | answer                          | 2238  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | ask                             | 2151  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | donate                          | 2264  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | failingAsk                      | 2324  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | markLost                        | 2225  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | refuse                          | 2309  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | reindex                         | 2251  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | replaySettledThroughOpenRequest | 2240  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | retryCompletedRequest           | 2178  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | unauthorizedCallback            | 2242  | 0       | 0        |\n╰-------------------------+---------------------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.86s (12.86s CPU time)\n\nRan 12 test suites in 12.87s (21.16s CPU time): 142 tests passed, 0 failed, 0 skipped (142 total tests)\n","passed":true},{"durationMs":218,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"AskSwarmRegistry.ask(bytes)\",\"AskSwarmRegistry.askAtMost(bytes,uint256)\",\"AskSwarmRegistry.markLost(bytes32)\",\"AskSwarmRegistry.onFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"AskSwarmRegistry.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"AskSwarmRegistry.reindex(bytes32)\",\"SwarmWager.abandon(uint256)\",\"SwarmWager.cancel(uint256)\",\"SwarmWager.create(bytes,bool,uint96,uint64,uint64)\",\"SwarmWager.join(uint256)\",\"SwarmWager.resolve(uint256)\",\"SwarmWager.settle(uint256)\",\"SwarmWager.topUpFee(uint256,uint96)\"],\"files\":{\".DS_Store\":4,\".env.example\":12,\".gitignore\":9,\"ADAPTATION.md\":167,\"README.md\":303,\"api/answers.mjs\":1,\"api/cpay-webhook.mjs\":1,\"api/hf-sync.mjs\":1,\"api/imd.mjs\":1,\"api/telegram.mjs\":1,\"bun.lock\":458,\"contracts/ADAPTATION-2099.md\":211,\"contracts/ADAPTATION.md\":98,\"contracts/LAUNCH-WAGER.md\":7,\"contracts/LAUNCH.md\":7,\"docs/.DS_Store\":4,\"docs/EVIDENCE.md\":15,\"docs/SUBMISSION.md\":48,\"docs/askswarm-demo.mp4\":11630,\"docs/askswarm.png\":1383,\"docs/brand/.gitignore\":1,\"docs/brand/Battlefin-Black.otf\":864,\"docs/brand/NB_International_Bold_Webfont.ttf\":2797,\"docs/brand/NB_International_Mono_Webfont.ttf\":2749,\"docs/brand/NB_International_Regular_Webfont.ttf\":2728,\"docs/brand/ai.svg\":6,\"docs/brand/data.svg\":5,\"docs/brand/demo.html\":161,\"docs/brand/hand.svg\":3,\"docs/brand/infographic.html\":121,\"docs/brand/lock.svg\":3,\"docs/brand/logo-symbol-light.svg\":4,\"docs/brand/logo-symbol.svg\":4,\"docs/brand/logo-wordmark-dark.svg\":12,\"docs/brand/logo-wordmark-light.svg\":12,\"docs/brand/message.svg\":3,\"docs/brand/miniapp.html\":22,\"docs/brand/star5.svg\":3,\"docs/brand/voiceover.tsv\":7,\"docs/logo-1024.png\":292,\"docs/logo-512.png\":122,\"docs/logo.svg\":7,\"docs/miniapp-640x360.png\":161,\"docs/vids/SCRIPT.md\":11,\"docs/vids/askswarm-demo-silent.mp4\":9487,\"docs/vids/scene1.mp4\":186,\"docs/vids/scene2.mp4\":382,\"docs/vids/scene3.mp4\":791,\"docs/vids/scene4.mp4\":446,\"docs/vids/scene5.mp4\":7161,\"docs/vids/scene6.mp4\":331,\"docs/vids/scene7.mp4\":178,\"foundry.toml\":16,\"functions/answers.ts\":81,\"functions/cpay-webhook.ts\":28,\"functions/hf-sync.ts\":15,\"functions/imd.ts\":58,\"functions/telegram.ts\":24,\"lib/answers.json\":1,\"lib/bot.ts\":269,\"lib/hfsync.ts\":49,\"lib/quick.ts\":21,\"lib/recall.ts\":21,\"lib/risk-model.json\":1,\"lib/risk.ts\":56,\"package.json\":31,\"packages/cpay/src/index.ts\":481,\"packages/imd/src/index.ts\":235,\"packages/imd/src/intake.ts\":133,\"public/ai.svg\":6,\"public/answers.html\":83,\"public/apple-touch-icon.png\":53,\"public/data.svg\":5,\"public/favicon-32.png\":8,\"public/favicon.svg\":7,\"public/fonts/Battlefin-Black.otf\":864,\"public/fonts/NB_International_Bold_Webfont.ttf\":2797,\"public/fonts/NB_International_Mono_Webfont.ttf\":2749,\"public/fonts/NB_International_Regular_Webfont.ttf\":2728,\"public/imd.html\":107,\"public/index.html\":172,\"public/llms.txt\":9,\"public/lock.svg\":3,\"public/logo-wordmark-dark.svg\":12,\"public/logo.svg\":7,\"public/message.svg\":3,\"public/og.png\":1364,\"public/pay.html\":40,\"public/skill.md\":51,\"public/star5.svg\":3,\"script/Deploy.s.sol\":20,\"scripts/approve-permit2.ts\":25,\"scripts/balance.ts\":6,\"scripts/build-answers.ts\":24,\"scripts/dry-run.ts\":13,\"scripts/evidence.ts\":45,\"scripts/hf-sync.ts\":4,\"scripts/launch.ts\":65,\"scripts/spike-sepolia.ts\":50,\"scripts/spike.ts\":58,\"scripts/train-risk.ts\":41,\"scripts/vercel-env.sh\":13,\"src/AskSwarmRegistry.sol\":493,\"src/IIntake.sol\":55,\"src/SwarmWager.sol\":292,\"test/AskSwarmRegistry.t.sol\":643,\"test/AskSwarmRegistryAdversarial.t.sol\":269,\"test/AskSwarmRegistryCallbacks.t.sol\":610,\"test/AskSwarmRegistryIndexInvariant.t.sol\":396,\"test/AskSwarmRegistryInvariant.t.sol\":488,\"test/AskSwarmRegistryPayments.t.sol\":261,\"test/AskSwarmRegistryReview.t.sol\":319,\"test/OracleConsumerConformance.t.sol\":104,\"test/SwarmWager.t.sol\":282,\"test/SwarmWagerDeployment.t.sol\":90,\"test/SwarmWagerLiveRegistry.t.sol\":88,\"test/SwarmWagerReview.t.sol\":450,\"test/TESTING.md\":83,\"test/helpers/RegistryTestSupport.sol\":289,\"test/mocks/IntakeMocks.sol\":100,\"tsconfig.json\":8,\"vercel.json\":11},\"excluded\":[\"contracts/lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1558,"exitCode":0,"name":"slither","output":"[medium/medium] reentrancy-no-eth at src/SwarmWager.sol:202: Reentrancy in SwarmWager.resolve(uint256) (src/SwarmWager.sol#202-217):\n[medium/medium] unused-return at src/AskSwarmRegistry.sol:322: AskSwarmRegistry.markLost(bytes32) (src/AskSwarmRegistry.sol#322-330) ignores return value by (None,None,None,completed) = INTAKE.requests(requestId) (src/AskSwarmRegistry.sol#326)\n[low/medium] reentrancy-benign at src/AskSwarmRegistry.sol:203: Reentrancy in AskSwarmRegistry._ask(bytes,uint256) (src/AskSwarmRegistry.sol#203-216):\n[low/medium] reentrancy-events at src/SwarmWager.sol:237: Reentrancy in SwarmWager.settle(uint256) (src/SwarmWager.sol#237-259):\n[low/medium] reentrancy-events at src/SwarmWager.sol:164: Reentrancy in SwarmWager.join(uint256) (src/SwarmWager.sol#164-174):\n[low/medium] reentrancy-events at src/SwarmWager.sol:221: Reentrancy in SwarmWager.abandon(uint256) (src/SwarmWager.sol#221-230):\n[low/medium] reentrancy-events at src/SwarmWager.sol:202: Reentrancy in SwarmWager.resolve(uint256) (src/SwarmWager.sol#202-217):\n[low/medium] reentrancy-events at src/SwarmWager.sol:269: Reentrancy in SwarmWager._refund(SwarmWager.Wager,uint256,uint8) (src/SwarmWager.sol#269-274):\n[low/medium] reentrancy-events at src/AskSwarmRegistry.sol:203: Reentrancy in AskSwarmRegistry._ask(bytes,uint256) (src/AskSwarmRegistry.sol#203-216):\n[low/medium] reentrancy-events at src/SwarmWager.sol:189: Reentrancy in SwarmWager.topUpFee(uint256,uint96) (src/SwarmWager.sol#189-196):\n[low/medium] reentrancy-events at src/SwarmWager.sol:134: Reentrancy in SwarmWager.create(bytes,bool,uint96,uint64,uint64) (src/SwarmWager.sol#134-161):\n[low/medium] reentrancy-events at src/SwarmWager.sol:177: Reentrancy in SwarmWager.cancel(uint256) (src/SwarmWager.sol#177-184):\n[low/medium] timestamp at src/SwarmWager.sol:134: SwarmWager.create(bytes,bool,uint96,uint64,uint64) (src/SwarmWager.sol#134-161) uses timestamp for comparisons\n[low/medium] timestamp at src/AskSwarmRegistry.sol:226: AskSwarmRegistry.onOracleResult(bytes32,OracleAttestation,bytes) (src/AskSwarmRegistry.sol#226-295) uses timestamp for comparisons\n[low/medium] timestamp at src/AskSwarmRegistry.sol:354: AskSwarmRegistry._mayDisplace(AskSwarmRegistry.Stored,uint16,uint16,uint64,uint64,bool) (src/AskSwarmRegistry.sol#354-368) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmWager.sol:177: SwarmWager.cancel(uint256) (src/SwarmWager.sol#177-184) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmWager.sol:202: SwarmWager.resolve(uint256) (src/SwarmWager.sol#202-217) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmWager.sol:164: SwarmWager.join(uint256) (src/SwarmWager.sol#164-174) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmWager.sol:221: SwarmWager.abandon(uint256) (src/SwarmWager.sol#221-230) uses timestamp for comparisons\n[low/medium] timestamp at src/AskSwarmRegistry.sol:339: AskSwarmRegistry.reindex(bytes32) (src/AskSwarmRegistry.sol#339-348) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmWager.sol:288: SwarmWager._call(bytes) (src/SwarmWager.sol#288-291) uses timestamp for comparisons\n[low/medium] timestamp at src/AskSwarmRegistry.sol:392: AskSwarmRegistry.isCurrent(bytes32) (src/AskSwarmRegistry.sol#392-395) uses timestamp for comparisons\n[low/medium] timestamp at src/AskSwarmRegistry.sol:380: AskSwarmRegistry.answerOf(bytes32,uint16,uint16) (src/AskSwarmRegistry.sol#380-389) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmWager.sol:237: SwarmWager.settle(uint256) (src/SwarmWager.sol#237-259) uses timestamp for comparisons","passed":true},{"durationMs":286,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/AskSwarmRegistry.sol:326: Reentrancy: State change after external call (5 places)\n[low] ecrecover at src/AskSwarmRegistry.sol:477: `ecrecover` Signature Malleability\n[low] literal-instead-of-constant at src/AskSwarmRegistry.sol:255: Literal Instead of Constant (7 places)\n[low] missing-inheritance at src/AskSwarmRegistry.sol:46: Missing Inheritance\n[low] push-zero-opcode at src/AskSwarmRegistry.sol:2: PUSH0 Opcode (3 places)\n[low] unspecific-solidity-pragma at src/AskSwarmRegistry.sol:2: Unspecific Solidity Pragma (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"92de674ceadae96ec3a9ff5dfcdd327eb9163722a9cd1f235a65cbed0f24103c","verifiedTreeHash":"c394c0c28c7ce8e2fcd45c60fd7aaddc3cc4d154","verifierVersion":"0.1.0+5921f9e9"},{"checks":[{"durationMs":50386,"exitCode":0,"name":"build","output":"Compiling 38 files with Solc 0.8.26\nSolc 0.8.26 finished in 50.29s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/AskSwarmRegistry.t.sol:613:5:\n    |\n613 |     function _delivered() internal returns (bool d) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":12552,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 416566)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 429075)\n[PASS] test_callbackSelectorIsCanonical() (gas: 691)\n[PASS] test_digestMatchesTheProtocol() (gas: 10377)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.74ms (1.40ms CPU time)\n\nRan 2 tests for test/SwarmWagerLiveRegistry.t.sol:SwarmWagerLiveRegistryTest\n[PASS] test_launchAddressesAndLiveAskGetAndUnverifiedRefund() (gas: 1147131)\n[PASS] test_liveLostOutcomeRefunds() (gas: 913967)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 6.61ms (2.11ms CPU time)\n\nRan 15 tests for test/SwarmWager.t.sol:SwarmWagerTest\n[PASS] test_abandonWhenNeverResolved() (gas: 526475)\n[PASS] test_anyoneCancelsAfterJoinBy() (gas: 431549)\n[PASS] test_badTerms() (gas: 117795)\n[PASS] test_cancelUnmatched() (gas: 468784)\n[PASS] test_creatorCannotTakeBothSides() (gas: 385876)\n[PASS] test_minorityAnswerRefunds() (gas: 1003852)\n[PASS] test_noWins() (gas: 1031853)\n[PASS] test_nonBoolAnswerRefunds() (gas: 1029900)\n[PASS] test_nonCanonicalBoolRefunds() (gas: 1030322)\n[PASS] test_pendingThenTimeoutRefunds() (gas: 786321)\n[PASS] test_refusedRefunds() (gas: 842526)\n[PASS] test_resolveWaitsAndOnlyOnce() (gas: 730962)\n[PASS] test_settleOnlyOnce() (gas: 1064491)\n[PASS] test_splitPanelRefunds() (gas: 859479)\n[PASS] test_yesWins() (gas: 1095859)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 10.74ms (8.41ms CPU time)\n\nRan 11 tests for test/AskSwarmRegistryReview.t.sol:AskSwarmRegistryReviewTest\n[PASS] test_askAtMostRefusesAPriceAboveTheCeiling() (gas: 764549)\n[PASS] test_askWithoutCeilingStillPaysTheLivePrice() (gas: 363602)\n[PASS] test_deliveryEmitsIndexedOnlyWhenTheIndexMoves() (gas: 831136)\n[PASS] test_markLostAfterAFailureCompletionWithEmptyArguments() (gas: 413455)\n[PASS] test_markLostSettlesAnAskIntakeCompletedWithoutDelivering() (gas: 1024141)\n[PASS] test_reindexFallsBackToAValidAnswerAfterTheHeldOneExpires() (gas: 1047052)\n[PASS] test_reindexRefusesEveryIneligibleRecord() (gas: 2185211)\n[PASS] test_reindexReplacesAFallbackOnlyByStrictDominance() (gas: 1703927)\n[PASS] test_shortLivedEqualAnswerCannotCutHeldValidityShort() (gas: 1618364)\n[PASS] test_staleOrShorterLivedEqualAnswerDoesNotDisplaceOnDelivery() (gas: 3309315)\n[PASS] test_statusCodesAreAppendedNotRenumbered() (gas: 580)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 84.30ms (31.34ms CPU time)\n\nRan 4 tests for test/SwarmWagerDeployment.t.sol:SwarmWagerDeploymentTest\n[PASS] test_constructorRejectsZeroDependenciesAndNativeValue() (gas: 3966)\n[PASS] test_factoryDeploysOnlyWagerOnEmptyChainWithStaticArguments() (gas: 3410212)\n[PASS] test_projectScriptRejectsOtherChains() (gas: 2009226)\n[PASS] test_projectScriptUsesExistingMainnetRegistry() (gas: 3539625)\nLogs:\n  SwarmWager 0x34A1D3fff3958843C43aD80F30b94c510645C316 chain 1\n\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 89.48ms (7.61ms CPU time)\n\nRan 19 tests for test/AskSwarmRegistryPayments.t.sol:AskSwarmRegistryPaymentsTest\n[PASS] testFuzz_badTokenReturnRollsBackBothPaymentLegs(uint8,bool) (runs: 1000, μ: 210602, ~: 221751)\n[PASS] testFuzz_exactPriceIsForwardedAndBodyIsUnchanged(uint128,bytes) (runs: 1000, μ: 567569, ~: 574322)\n[PASS] test_askDoesNotSpendPreexistingDonation() (gas: 399320)\n[PASS] test_constructorRejectsEveryZeroDependency() (gas: 7544)\n[PASS] test_donationCannotSubsidizeAnUnfundedAsk() (gas: 154696)\n[PASS] test_fullCallerBalanceAndMaximumBody() (gas: 2954509)\n[PASS] test_insufficientBalanceRollsBackConsumedAllowance() (gas: 192998)\n[PASS] test_intakeBodyBoundsRollBackThePayment() (gas: 434697)\n[PASS] test_noApprovalAndOneWeiShortApprovalBothRevert() (gas: 323043)\n[PASS] test_noReturnTokenIsSupportedOnTransferAndApproval() (gas: 394401)\n[PASS] test_notSoldDoesNotChargeOrRegister() (gas: 143386)\n[PASS] test_oneWeiPrice() (gas: 384542)\n[PASS] test_plainEthAndPayableAskAreRejectedWithoutTakingFunds() (gas: 145470)\n[PASS] test_priceChangesAreReadOnEveryAsk() (gas: 561725)\n[PASS] test_priceIncreaseBeyondApprovalCannotChargeOldQuote() (gas: 187170)\n[PASS] test_priceLookupFailureDoesNotChargeOrRegister() (gas: 163271)\n[PASS] test_rejectionAfterIntakePullRollsBackRecipientPayment() (gas: 343199)\n[PASS] test_rejectionBeforeIntakePullRollsBackCallerPayment() (gas: 227757)\n[PASS] test_tokenRejectsOnlyIntakePullAndEntireAskRollsBack() (gas: 317064)\nSuite result: ok. 19 passed; 0 failed; 0 skipped; finished in 150.48ms (295.85ms CPU time)\n\nRan 26 tests for test/SwarmWagerReview.t.sol:SwarmWagerReviewTest\n[PASS] testFuzz_allAcceptedTermsHaveBoundedExit(uint64,uint64,bool) (runs: 256, μ: 377605, ~: 422369)\n[PASS] testFuzz_onlyCanonicalMajorityBoolPays(uint256,uint16,uint16) (runs: 256, μ: 1004988, ~: 1017301)\n[PASS] testFuzz_topUpFeeConservation(uint96,uint96,bool) (runs: 256, μ: 858856, ~: 535475)\n[PASS] testFuzz_wrongBoolLengthRefunds(uint8) (runs: 256, μ: 993577, ~: 987288)\n[PASS] test_abandonBeforeLateResolvePreventsAnAsk() (gas: 473416)\n[PASS] test_abandonReturnsAllTopUpsToCreator() (gas: 433654)\n[PASS] test_badSignatureRefundsBothStakes() (gas: 1009930)\n[PASS] test_creatorTopUpRecoversWagerAfterPriceRise() (gas: 1191517)\n[PASS] test_exactJoinAndResolveBoundaryRemainsSupported() (gas: 977893)\n[PASS] test_expiredAtDeliveryRefundsBothStakes() (gas: 979775)\n[PASS] test_lateAnswerBeforeTimeoutSettlementStillPaysWinner() (gas: 1049816)\n[PASS] test_lostCallbackRefundsBothStakes() (gas: 884685)\n[PASS] test_maximumFeeEscrowCanBeFundedAndAbandoned() (gas: 531708)\n[PASS] test_maximumTermCanStillBeMatchedAndUnwound() (gas: 449314)\n[PASS] test_maximumTimestampAndOverlongTermsRejectedBeforePayment() (gas: 102218)\n[PASS] test_priceDecreaseReturnsOnlyRemainderAndApprovesExactPrice() (gas: 808079)\n[PASS] test_priceRiseRevertsWithoutSpendingStakesAndAbandonStillWorks() (gas: 556509)\n[PASS] test_resolutionAfterAbandonDeadlineCanWinTheRace() (gas: 1051298)\n[PASS] test_resolveCallerChoosesAskTimeForRelativeWindows() (gas: 731350)\n[PASS] test_resolveWaitsThroughGapAfterJoinDeadline() (gas: 731606)\n[PASS] test_thirdPartyTopUpIsExplicitAndUnusedFeeGoesToCreator() (gas: 1177687)\n[PASS] test_timeoutIsStrictlyAfterAnswerWindow() (gas: 838828)\n[PASS] test_timeoutSettlementBeforeLateAnswerRemainsRefunded() (gas: 1057759)\n[PASS] test_topUpRefusesUnknownOpenAskedAndTerminalWagers() (gas: 1345614)\n[PASS] test_topUpRefusesZeroOverflowAndRollsBackFailedPayment() (gas: 573580)\n[PASS] test_writerPairingOfAnotherQuestionsAnswerIsTrusted() (gas: 1164208)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 157.93ms (284.05ms CPU time)\n\nRan 23 tests for test/AskSwarmRegistry.t.sol:AskSwarmRegistryTest\n[PASS] testFuzz_indexedAnswersAreMajorities(uint16,uint16,uint16,uint32,uint32,uint32) (runs: 256, μ: 429133, ~: 425871)\n[PASS] test_answerDeliveredWithinStipendAndVerified() (gas: 480527)\n[PASS] test_askAtMostAgainstTheQuotedPrice() (gas: 307456)\n[PASS] test_askPullsPriceAndRegisters() (gas: 289885)\n[PASS] test_badSignatureStoredUnverifiedAndNotIndexed() (gas: 433697)\n[PASS] test_callbackGasMargin() (gas: 730555)\nLogs:\n  onOracleResult gas, bytes32 answer: 148282\n  onOracleResult gas, 352-byte answer: 135951\n\n[PASS] test_constructorMakesNoCallsAndAskLeavesNoAllowance() (gas: 2566003)\n[PASS] test_digestMatchesPlaneSignature() (gas: 15161)\n[PASS] test_domainIsTheCallbackContract() (gas: 398151)\n[PASS] test_expiredAtDeliveryAndAnswerBoundaries() (gas: 2957963)\n[PASS] test_expiryBoundaryAtDelivery() (gas: 449389)\n[PASS] test_failureHookStatusesAndUnknownIds() (gas: 384242)\n[PASS] test_failureRecorded() (gas: 316821)\n[PASS] test_indexRespectsValidityWindowAndReindexRecovers() (gas: 1493990)\n[PASS] test_largeAnswerStillWithinStipend() (gas: 516572)\n[PASS] test_markLostReadsIntakeCompletionRecord() (gas: 801557)\n[PASS] test_minorityAnswerNotIndexedEvenWhenNothingHeld() (gas: 779775)\n[PASS] test_minorityOfLargePanelCannotDisplaceSupermajority() (gas: 1155889)\n[PASS] test_onlyIntakeCanDeliver() (gas: 301915)\n[PASS] test_quorumAndExpiryGateVerified() (gas: 393137)\n[PASS] test_settledAskRefusesRedeliveryThroughAnotherOpenAsk() (gas: 789628)\n[PASS] test_signatureEdges() (gas: 1310064)\n[PASS] test_weakPanelCannotOverwriteStrongAnswer() (gas: 1129046)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 164.27ms (106.43ms CPU time)\n\nRan 9 tests for test/AskSwarmRegistryAdversarial.t.sol:AskSwarmRegistryAdversarialTest\n[PASS] testFuzz_oversizedAnswersOfAnySizeSettleInsideStipend(uint24) (runs: 300, μ: 998852, ~: 948792)\n[PASS] testFuzz_readsOfUntouchedKeysAreEmpty(bytes32,uint16,uint16) (runs: 256, μ: 47590, ~: 47590)\n[PASS] testFuzz_unexpectedFailureStatusesSettleAsNoResult(uint8,bytes32,uint16) (runs: 512, μ: 839252, ~: 839429)\n[PASS] testFuzz_verifiedExactlyWhenEveryConditionHolds(uint16,uint16,uint16,uint32,uint32,uint8) (runs: 1000, μ: 500001, ~: 497931)\n[PASS] test_callbackGasAtTheStipendBoundary() (gas: 1848958)\nLogs:\n  onOracleResult gas, one-word answer, cold: 118568\n  onOracleResult gas, 4096-byte answer, cold: 156201\n\n[PASS] test_contractAskerIsRecordedNotTxOrigin() (gas: 639024)\n[PASS] test_highSTwinIsUnverifiedWhileZeroOneVAreNormalised() (gas: 857211)\n[PASS] test_identicalBodiesAreDistinctPaidAsks() (gas: 524043)\n[PASS] test_maximumAnswerDisplacingAHeldAnswerFitsColdStipend() (gas: 1592155)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 182.55ms (733.31ms CPU time)\n\nRan 26 tests for test/AskSwarmRegistryCallbacks.t.sol:AskSwarmRegistryCallbacksTest\n[PASS] testFuzz_longAnswerHashAndEventPreserveEveryByte(uint16,bytes32) (runs: 1000, μ: 832940, ~: 701336)\n[PASS] testFuzz_non65ByteSignaturesNeverVerify(uint16,bytes32) (runs: 1000, μ: 505248, ~: 493745)\n[PASS] testFuzz_shortAnswerRoundTripsIncludingZeros(bytes32,uint8) (runs: 1000, μ: 517593, ~: 523377)\n[PASS] testFuzz_verifiedRequiresIssuedAtWithinTolerance(uint32,uint32) (runs: 1000, μ: 505778, ~: 517466)\n[PASS] test_bothFailureStatusesPreserveFeeAndEmitReasonAndCounts() (gas: 1041103)\n[PASS] test_bothHooksRefuseEverySettledStatus() (gas: 2315241)\n[PASS] test_bothPanelSizeAndAgreementMustBeAtLeastAsStrong() (gas: 1886869)\n[PASS] test_eachOfTheFifteenFieldsIsBoundByTheSignature() (gas: 5586715)\n[PASS] test_falseIsAVerifiedAnswerAndNotAFailure() (gas: 504554)\n[PASS] test_firstByteOverCapIsUnverifiedAndDoesNotDisplaceHeldAnswer() (gas: 800971)\n[PASS] test_intakeAndOracleRequestIdsMayDiffer() (gas: 524108)\n[PASS] test_invalidVAndZeroRecoveryAreRejected() (gas: 2238504)\n[PASS] test_issuedAtToleranceBoundary() (gas: 1279965)\n[PASS] test_maximumAcceptedAnswerFitsColdCallbackStipend() (gas: 1152530)\n[PASS] test_nonzeroAbiPaddingCannotLeakIntoShortAnswer() (gas: 509578)\n[PASS] test_recordsWithoutAStoredAnswerReportZeroAnswerHash() (gas: 1858663)\n[PASS] test_registeredCallbackWithForeignRequestIdCannotCreateAnAsk() (gas: 93390)\n[PASS] test_settledAskIsNotRewrittenByAnotherRequestsCompletion() (gas: 1119030)\n[PASS] test_signatureForAnotherConsumerIsNotReusable() (gas: 500205)\n[PASS] test_thirdPartyCannotCompleteOrCallEitherHook() (gas: 448513)\n[PASS] test_timeAndMinimumFiltersDoNotDeleteHistoricalRecord() (gas: 604618)\n[PASS] test_transportWillNotRetrySuccessOrFailure() (gas: 867496)\n[PASS] test_unknownReadsDoNotLookAnswered() (gas: 48342)\n[PASS] test_weakerMajorityCanReplaceOnlyAfterHeldAnswerExpires() (gas: 1216157)\n[PASS] test_wrongDomainChainNameAndVersionAreRejected() (gas: 1164726)\n[PASS] test_wrongSignerCannotReplaceHeldAnswer() (gas: 852582)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 182.51ms (763.80ms CPU time)\n\nRan 2 tests for test/AskSwarmRegistryIndexInvariant.t.sol:AskSwarmRegistryIndexInvariantTest\n[PASS]\nAskSwarmRegistryIndexInvariantTest invariants:\n[PASS] invariant_everyAskIsPendingOrSettledOnce\n[PASS] invariant_indexOnlyHoldsVerifiedMajoritiesOfTheirOwnQuestion\n[PASS] invariant_registryHoldsNothingAndForwardsEveryFee\n AskSwarmRegistryIndexInvariantTest invariants (runs: 192, calls: 12288, reverts: 0)\n\n╭------------------------+------------+-------+---------+----------╮\n| Contract               | Selector   | Calls | Reverts | Discards |\n+==================================================================+\n| IndexTransitionHandler | ask        | 1332  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | deliver    | 1328  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | directHook | 1369  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | fail       | 1393  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | markLost   | 1370  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | reindex    | 1325  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | replay     | 1406  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | strand     | 1339  | 0       | 0        |\n|------------------------+------------+-------+---------+----------|\n| IndexTransitionHandler | warp       | 1426  | 0       | 0        |\n╰------------------------+------------+-------+---------+----------╯\n\n[PASS] test_handlersReachLostAndReindexMoves() (gas: 1787105)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.34s (7.33s CPU time)\n\nRan 1 test for test/AskSwarmRegistryInvariant.t.sol:AskSwarmRegistryInvariantTest\n[PASS]\nAskSwarmRegistryInvariantTest invariants:\n[PASS] invariant_paymentsAreConservedAndNoFeeIsRetained\n[PASS] invariant_requestsAndCanonicalAnswersStayConsistent\n AskSwarmRegistryInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭-------------------------+---------------------------------+-------+---------+----------╮\n| Contract                | Selector                        | Calls | Reverts | Discards |\n+========================================================================================+\n| RegistrySequenceHandler | advanceTime                     | 2154  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | answer                          | 2238  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | ask                             | 2151  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | donate                          | 2264  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | failingAsk                      | 2324  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | markLost                        | 2225  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | refuse                          | 2309  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | reindex                         | 2251  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | replaySettledThroughOpenRequest | 2240  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | retryCompletedRequest           | 2178  | 0       | 0        |\n|-------------------------+---------------------------------+-------+---------+----------|\n| RegistrySequenceHandler | unauthorizedCallback            | 2242  | 0       | 0        |\n╰-------------------------+---------------------------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.45s (12.45s CPU time)\n\nRan 12 test suites in 12.45s (20.82s CPU time): 142 tests passed, 0 failed, 0 skipped (142 total tests)\n","passed":true},{"durationMs":209,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"AskSwarmRegistry.ask(bytes)\",\"AskSwarmRegistry.askAtMost(bytes,uint256)\",\"AskSwarmRegistry.markLost(bytes32)\",\"AskSwarmRegistry.onFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"AskSwarmRegistry.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"AskSwarmRegistry.reindex(bytes32)\",\"SwarmWager.abandon(uint256)\",\"SwarmWager.cancel(uint256)\",\"SwarmWager.create(bytes,bool,uint96,uint64,uint64)\",\"SwarmWager.join(uint256)\",\"SwarmWager.resolve(uint256)\",\"SwarmWager.settle(uint256)\",\"SwarmWager.topUpFee(uint256,uint96)\"],\"files\":{\".DS_Store\":4,\".env.example\":12,\".gitignore\":9,\"ADAPTATION.md\":167,\"README.md\":303,\"api/answers.mjs\":1,\"api/cpay-webhook.mjs\":1,\"api/hf-sync.mjs\":1,\"api/imd.mjs\":1,\"api/telegram.mjs\":1,\"bun.lock\":458,\"contracts/ADAPTATION-2099.md\":211,\"contracts/ADAPTATION.md\":98,\"contracts/LAUNCH-WAGER.md\":7,\"contracts/LAUNCH.md\":7,\"docs/.DS_Store\":4,\"docs/EVIDENCE.md\":15,\"docs/SUBMISSION.md\":48,\"docs/askswarm-demo.mp4\":11630,\"docs/askswarm.png\":1383,\"docs/brand/.gitignore\":1,\"docs/brand/Battlefin-Black.otf\":864,\"docs/brand/NB_International_Bold_Webfont.ttf\":2797,\"docs/brand/NB_International_Mono_Webfont.ttf\":2749,\"docs/brand/NB_International_Regular_Webfont.ttf\":2728,\"docs/brand/ai.svg\":6,\"docs/brand/data.svg\":5,\"docs/brand/demo.html\":161,\"docs/brand/hand.svg\":3,\"docs/brand/infographic.html\":121,\"docs/brand/lock.svg\":3,\"docs/brand/logo-symbol-light.svg\":4,\"docs/brand/logo-symbol.svg\":4,\"docs/brand/logo-wordmark-dark.svg\":12,\"docs/brand/logo-wordmark-light.svg\":12,\"docs/brand/message.svg\":3,\"docs/brand/miniapp.html\":22,\"docs/brand/star5.svg\":3,\"docs/brand/voiceover.tsv\":7,\"docs/logo-1024.png\":292,\"docs/logo-512.png\":122,\"docs/logo.svg\":7,\"docs/miniapp-640x360.png\":161,\"docs/vids/SCRIPT.md\":11,\"docs/vids/askswarm-demo-silent.mp4\":9487,\"docs/vids/scene1.mp4\":186,\"docs/vids/scene2.mp4\":382,\"docs/vids/scene3.mp4\":791,\"docs/vids/scene4.mp4\":446,\"docs/vids/scene5.mp4\":7161,\"docs/vids/scene6.mp4\":331,\"docs/vids/scene7.mp4\":178,\"foundry.toml\":16,\"functions/answers.ts\":81,\"functions/cpay-webhook.ts\":28,\"functions/hf-sync.ts\":15,\"functions/imd.ts\":58,\"functions/telegram.ts\":24,\"launch.json\":13,\"lib/answers.json\":1,\"lib/bot.ts\":269,\"lib/hfsync.ts\":49,\"lib/quick.ts\":21,\"lib/recall.ts\":21,\"lib/risk-model.json\":1,\"lib/risk.ts\":56,\"package.json\":31,\"packages/cpay/src/index.ts\":481,\"packages/imd/src/index.ts\":235,\"packages/imd/src/intake.ts\":133,\"public/ai.svg\":6,\"public/answers.html\":83,\"public/apple-touch-icon.png\":53,\"public/data.svg\":5,\"public/favicon-32.png\":8,\"public/favicon.svg\":7,\"public/fonts/Battlefin-Black.otf\":864,\"public/fonts/NB_International_Bold_Webfont.ttf\":2797,\"public/fonts/NB_International_Mono_Webfont.ttf\":2749,\"public/fonts/NB_International_Regular_Webfont.ttf\":2728,\"public/imd.html\":107,\"public/index.html\":172,\"public/llms.txt\":9,\"public/lock.svg\":3,\"public/logo-wordmark-dark.svg\":12,\"public/logo.svg\":7,\"public/message.svg\":3,\"public/og.png\":1364,\"public/pay.html\":40,\"public/skill.md\":51,\"public/star5.svg\":3,\"script/Deploy.s.sol\":20,\"scripts/approve-permit2.ts\":25,\"scripts/balance.ts\":6,\"scripts/build-answers.ts\":24,\"scripts/dry-run.ts\":13,\"scripts/evidence.ts\":45,\"scripts/hf-sync.ts\":4,\"scripts/launch.ts\":65,\"scripts/spike-sepolia.ts\":50,\"scripts/spike.ts\":58,\"scripts/train-risk.ts\":41,\"scripts/vercel-env.sh\":13,\"src/AskSwarmRegistry.sol\":493,\"src/IIntake.sol\":55,\"src/SwarmWager.sol\":292,\"test/AskSwarmRegistry.t.sol\":643,\"test/AskSwarmRegistryAdversarial.t.sol\":269,\"test/AskSwarmRegistryCallbacks.t.sol\":610,\"test/AskSwarmRegistryIndexInvariant.t.sol\":396,\"test/AskSwarmRegistryInvariant.t.sol\":488,\"test/AskSwarmRegistryPayments.t.sol\":261,\"test/AskSwarmRegistryReview.t.sol\":319,\"test/OracleConsumerConformance.t.sol\":104,\"test/SwarmWager.t.sol\":282,\"test/SwarmWagerDeployment.t.sol\":90,\"test/SwarmWagerLiveRegistry.t.sol\":88,\"test/SwarmWagerReview.t.sol\":450,\"test/TESTING.md\":83,\"test/helpers/RegistryTestSupport.sol\":289,\"test/mocks/IntakeMocks.sol\":100,\"tsconfig.json\":8,\"vercel.json\":11},\"excluded\":[\"contracts/lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"cf7a5219af907dde922f683e4135a67fb618ec2f344fe888f5b2055999ae7f55","verifiedTreeHash":"60b35af445f8da81d2aa7bb71b2d18678d51d1e6","verifierVersion":"0.1.0+fddeb651"}]}