{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"c41faf15-e12c-4910-97fb-e23fe03fe778","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":"86dac7d2d3334bbc17ab793822634a17f2f1d1d6b493e630cd11c5291e242156","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"failed"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"waiting"},{"acceptedSubmissionHash":"dfd530473b38d6d8a314fc78ac0e48e915aed8fe0158709ac7ad6932d5dad413","dependsOn":["build_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":"waiting"}],"objective":"SIMD Vault on Robinhood Chain: the contract that pays for and owns the fees of the \"Test\" token launch, and splits everything it receives every 7 days. Three linked contracts, no owner, no admin, no upgrade, no pause.\n\nFixed addresses (Robinhood Chain):\n- IMD token: 0x5f7bb59365ce557c26dbcaa4ee9d39a4b95b7127\n- Identity.md Intake: 0xa43e6f75ee006411f79ac1c84120606c2330de82 (request(bytes32 action, bytes body, (address target, bytes4 selector) callback, address asset, uint256 amount); price from priceOf(action, asset))\n- Identity.md launch factory: 0x9c9d2fcb75c2c132c0ac0c42df3819a42347265e (claimFees(uint64 launchNumber) can be called by anyone and pays the launch's requester; positionOf(uint64) returns (PoolKey key, int24 tickLower, int24 tickUpper, address requester))\n- Dev wallet: 0xdfa1f1f6feaa04f7874eff0b7754b7ffaebd8bc0\n- Marketing wallet: 0xdfa1f1f6feaa04f7874eff0b7754b7ffaebd8bc0\n\n1. SIMDVault\n   - launch(bytes body): callable only by the dev wallet, only once. Approves Intake for exactly priceOf(\"launch.open@launch-1\", IMD) and calls Intake.request(\"launch.open@launch-1\", body, no callback, IMD, that price), paid from the vault's own IMD. This makes the vault the launch's requester, so the factory pays it the launch's creator fees for good.\n   - bindLaunch(uint64 launchNumber, address token): callable only by the dev wallet, only once, and only if factory.positionOf(launchNumber).requester == address(this). Stores both for good and passes the token to HolderRewards and JobsVault (their one-time setToken, callable only by the vault).\n   - distribute(): anyone, at most once every 7 days, only after bindLaunch. First calls factory.claimFees(launchNumber). Then splits the vault's whole IMD balance: 40% to HolderRewards, 25.72% to JobsVault, 17.14% to the dev wallet, 17.14% to the marketing wallet (rounding dust stays for next week). The vault's whole balance of the launched token is burned (sent to 0x000000000000000000000000000000000000dEaD).\n   - No other way for IMD or tokens to leave.\n   SIMDVault deploys HolderRewards and JobsVault in its own constructor and exposes them as immutable public getters.\n2. HolderRewards: receives IMD each week and pays it to holders of the launched token pro rata to a weekly snapshot, so it cannot be gamed by buying just before a claim. On each IMD deposit from the vault it opens a new epoch and asks the swarm, through Intake.request(\"oracle.request@oracle-1\", ...), paid from its own IMD, for a Merkle root of every holder's balance at the deposit block, excluding pools, the PoolManager, the factory and these three contracts; the root arrives in the oracle callback (only Intake can call it). claim(epoch, amount, proof) pays each holder once. Unclaimed IMD rolls into the next epoch after 28 days.\n3. JobsVault: receives IMD each week and pays Identity.md swarm jobs for holders. Any wallet holding at least 1,000,000 of the launched token can call requestJob(bytes body) at most once per 24 hours; the vault pays Intake.request(\"job.open@job-1\", body, no callback, IMD, priceOf) from its own IMD. No withdraw.\n\nTests: fork tests against Robinhood Chain with the real Intake and factory addresses; launch and bindLaunch only by the dev wallet and only once; bindLaunch rejects a launch whose requester is not the vault; the 40 / 25.72 / 17.14 / 17.14 split and the token burn; the 7-day limit; JobsVault holding and daily limits; only Intake can deliver oracle answers.\n","parentJobId":null,"planHash":"5740033696160d3259dce78f27fb4bf540a71ae7e06af36135bb89d5f17d0de8","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"c41faf15-e12c-4910-97fb-e23fe03fe778","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2354-simd-vault-robinhood-chain"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52681","feedbackHash":"60566fd52a6c713c5cc17463339d50c903b27290f6c296ff6206a99f0ec8366e","nodeKey":"build_contract_project","submissionHash":"86dac7d2d3334bbc17ab793822634a17f2f1d1d6b493e630cd11c5291e242156","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52210","feedbackHash":"31fc9f0d3247cb6c2d34db9b430fbad221a549bdb1eb8c3ad227ebb3b7edd9a2","nodeKey":"write_foundry_tests","submissionHash":"dfd530473b38d6d8a314fc78ac0e48e915aed8fe0158709ac7ad6932d5dad413","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"38ae598f02cdece32c16fcb82a76cd9d7f5f30b65ecc068075aa55140724d183","state":"blocked","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"ba691021e70bb66b8592bd177ea4cd40af9ccfee33bfed6dd53d03009acc8e00","device":"1a7606be97f168d4","findings":[],"hash":"86dac7d2d3334bbc17ab793822634a17f2f1d1d6b493e630cd11c5291e242156","nodeId":"1b301417-dd6a-47e0-82ad-49759259cb31","outcome":"completed","summary":"The deliverable is complete and committed. A clean rebuild, the full test run with the verifier's fuzz seed, and `forge fmt --check` all pass.\n\n**What was built** (Foundry project at the repository root, solc 0.8.26, `bytecode_hash = \"none\"`, forge-std 1.9.7 and OpenZeppelin 5.7.0 vendored as plain files under `lib/`, no submodules):\n\n- `src/SIMDVault.sol`: `launch` (dev only, once, pays exactly `priceOf` for `launch.open@launch-1` from its own IMD, no callback), `bindLaunch` (dev only, once, requires the factory's requester to be the vault and the token to be in the pool key, then calls the one-time `setToken` on both children), `distribute` (anyone, every 7 days, after binding: `claimFees` in a try, then the 40 / 25.72 / 17.14 / 17.14 split in basis points with dust kept, and the whole launched-token balance burned to `0x…dEaD`). It deploys `HolderRewards` and `JobsVault` in its constructor as immutable getters, calls no other contract there, and has no owner, receive, or withdraw.\n- `src/HolderRewards.sol`: each deposit rolls closed epochs, opens a new one pinned to block `head() - 8`, builds the oracle question on chain with the canonical `OracleQuestion` library, stores its hash, and buys `oracle.request@oracle-1` from its own IMD. The callback accepts only the Intake, only a pending request, only the pinned question hash, a panel of at least 5 with quorum 4 and `agreed >= quorum`, and a signature in its own EIP-712 domain. Claims pay `pool * balance / total` once per holder for 28 days; the leaf carries the total so proofs fix the denominator. Unclaimed IMD rolls forward; failed asks can be retried daily by anyone.\n- `src/JobsVault.sol`: `requestJob(body)` for wallets holding at least 1,000,000 tokens, once per 24 hours per wallet, paid from its own IMD with no callback. No withdraw.\n\n**Tests**: 59 local tests pass across the vault, HolderRewards, JobsVault and the protocol's oracle conformance vectors (digest, selector, question hash, delivery under the 200,000 gas stipend). `test/Fork.t.sol` holds the Robinhood Chain fork tests with the real Intake, IMD and factory addresses; they skip cleanly without `ROBINHOOD_RPC_URL`.\n\n**Documented in README.md**: the 7 constructor arguments with their Robinhood Chain values, every named constant, the assumptions, and the operational steps after launch.\n\n**Still owed, stated plainly**:\n- The fork tests could not run here because this machine has no Robinhood Chain RPC URL. The live checks (actions priced in IMD, `launch` against the real Intake, `bindLaunch` against a real position, `head()` via ArbSys) remain to be run with the URL.\n- The oracle question was not sent to the plane's `POST /requests/check` from this machine. It should be checked with the real token address before the first `distribute`.\n- Two deliberate deviations from the brief's wording, both explained in the README: the snapshot sits 8 blocks before the deposit block because the oracle protocol requires an absolute window to be five blocks deep when read, and `claimFees` runs inside a try so a reverting claim cannot block the weekly split.\n- The brief assumes the launch's fees arrive in IMD. The vault has no `receive()`, so if the launch pool were native-coin paired, an ETH payout from `claimFees` would revert and be logged rather than received. The requester should confirm the pool's currencies before binding.","treeHash":"7380eb8b186a9de06ece48793ac101fc016eb725","usage":{"cachedInputTokens":3092538,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":80661,"runtime":"claude","turns":42,"wallClockMs":976473}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7eb57f222fe63696","findings":[],"hash":"8d736c73a6b533b9ca7bbf54a5ec8ec9ec350ad8cf04bd2a78b2b03bf34a360c","nodeId":"1b301417-dd6a-47e0-82ad-49759259cb31","outcome":"failed","summary":"needs input: The supplied ETH-fee proof reproduces: SIMDVault rejects the factory's native transfer, leaving both ETH and TEST fees uncollected. Completing this repair requires a native-ETH settlement policy. The brief specifies IMD distributions and TEST burning, but no ETH-to-IMD conversion route or alternative ETH payout policy. Intake does not accept native ETH for jobs or oracle requests, so simply accepting ETH or forwarding its shares to the child vaults leaves funds unusable. No owner/admin setter is permitted. The separate epoch-overpayment proof also reproduces; no contract changes have been made, as required when blocked on requester input. — How should native ETH creator fees be handled: converted to IMD before the existing split (specify the approved conversion route and pricing/slippage rule), or paid out as ETH (specify the recipients and shares)?","treeHash":null,"usage":{"cachedInputTokens":565632,"inputTokens":75757,"model":"gpt-6-astra","outputTokens":4721,"runtime":"codex","turns":4,"wallClockMs":162653}},{"artifacts":[],"attempt":1,"bundleHash":"9a7f92d0a72f873c222cdabd8f63b863b7f50e44f58729c0c93c90ae895b011b","device":"dff6c0d3de4aa913","findings":[{"description":"The intake-client reference says the launch factory's claimFees pays the requester its LP fee share 'in ETH and in tokens', and the launch body is a custom_token launch priced in wei (initialMarketCapWei), i.e. a native-ETH / TEST pool (currency0 = address(0)). SIMDVault has no receive() or fallback, so the factory's native transfer to the vault reverts, the whole claimFees reverts, and distribute() swallows it in try/catch (FeesClaimFailed) every week. Result: neither the ETH fees nor the TEST-side fees are ever collected (so nothing is ever burned), and the fees stay at the factory forever because the vault also has no setRequester path. Even with a receive() added, the brief's split only moves IMD and nothing lets ETH leave the vault, so ETH would be stranded instead; the fix needs both a way to accept ETH and a defined way to distribute it (or convert it to IMD). The existing mocks register an IMD/TEST pool, which is why the current suite does not catch this. I could not verify the live pool pairing from this machine (no reachable Robinhood Chain RPC); a fork run of factory.positionOf on a live custom_token launch is still owed.","line":169,"path":"src/SIMDVault.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SIMDVault} from \"src/SIMDVault.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\nimport {ILaunchFactory} from \"src/interfaces/ILaunchFactory.sol\";\n\ncontract Tok is ERC20 {\n    constructor(string memory n) ERC20(n, n) {}\n\n    function mint(address to, uint256 a) external {\n        _mint(to, a);\n    }\n}\n\n/// @dev Intake stand-in: pulls the price and forwards it, as the live one does.\ncontract Intake {\n    uint256 public nonce;\n\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0.5 ether;\n    }\n\n    function request(bytes32, bytes calldata, IIntake.Callback calldata, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32)\n    {\n        IERC20(asset).transferFrom(msg.sender, address(0xBEEF), amount);\n        return keccak256(abi.encode(++nonce));\n    }\n}\n\n/// @dev Launch factory stand-in for a `custom_token` launch: the pool is native ETH / token\n/// (currency0 = address(0)), and `claimFees` pays the requester in ETH and in tokens, reverting\n/// when the native transfer fails, as Uniswap v4's `CurrencyLibrary.transfer` does.\ncontract EthFactory {\n    address public requester;\n    address public tok;\n    uint256 public feesEth;\n    uint256 public feesTok;\n\n    constructor(address requester_, address tok_) {\n        requester = requester_;\n        tok = tok_;\n    }\n\n    function accrue(uint256 tokAmount) external payable {\n        feesEth += msg.value;\n        feesTok += tokAmount;\n    }\n\n    function claimFees(uint64) external {\n        (uint256 e, uint256 t) = (feesEth, feesTok);\n        (feesEth, feesTok) = (0, 0);\n        (bool ok,) = requester.call{value: e}(\"\");\n        require(ok, \"NativeTransferFailed\");\n        IERC20(tok).transfer(requester, t);\n    }\n\n    function positionOf(uint64)\n        external\n        view\n        returns (ILaunchFactory.PoolKey memory key, int24, int24, address)\n    {\n        key = ILaunchFactory.PoolKey(address(0), tok, 10_000, 200, address(0));\n        return (key, -887200, 887200, requester);\n    }\n}\n\ncontract EthFeesProof is Test {\n    function test_theVaultCanCollectTheLaunchsEthAndTokenFees() public {\n        vm.roll(1000);\n        Tok imd = new Tok(\"IMD\");\n        Tok token = new Tok(\"TEST\");\n        Intake intake = new Intake();\n        address dev = makeAddr(\"dev\");\n        address predicted = vm.computeCreateAddress(address(this), vm.getNonce(address(this)) + 1);\n        EthFactory factory = new EthFactory(predicted, address(token));\n        SIMDVault vault = new SIMDVault(\n            IERC20(address(imd)),\n            IIntake(address(intake)),\n            ILaunchFactory(address(factory)),\n            dev,\n            makeAddr(\"marketing\"),\n            makeAddr(\"signer\"),\n            false\n        );\n        assertEq(address(vault), predicted);\n        imd.mint(address(vault), 10 ether);\n        vm.startPrank(dev);\n        vault.launch(\"{}\");\n        vault.bindLaunch(1, IERC20(address(token)));\n        vm.stopPrank();\n\n        token.mint(address(factory), 1000 ether);\n        factory.accrue{value: 1 ether}(1000 ether);\n        vault.distribute();\n\n        // The creator fees the vault was built to own must actually be collected.\n        assertEq(factory.feesEth(), 0, \"ETH fee share never leaves the factory\");\n        assertEq(address(factory).balance, 0, \"ETH fee share never leaves the factory\");\n        assertEq(token.balanceOf(vault.BURN()), 1000 ether, \"token fee share never burned\");\n    }\n}","reproduction":"Factory stand-in with PoolKey(currency0=address(0), currency1=TEST) whose claimFees sends ETH with call and requires success (as Uniswap v4 CurrencyLibrary.transfer does). launch, bindLaunch, accrue 1 ETH + 1000 TEST, distribute(). Expected: factory fees go to 0 and 1000 TEST reach 0x...dEaD. Actual: distribute emits FeesClaimFailed(NativeTransferFailed); factory still holds 1 ETH and 1000 TEST; burn address receives 0.","severity":"high","title":"SIMDVault cannot receive the launch's ETH fee share, so claimFees always fails and no creator fees are ever collected"},{"description":"claim pays e.pool * balance / total where total comes from the leaf, and never checks e.claimed + amount <= e.pool. If a delivered root's leaves carry a total smaller than the sum of their balances (an oracle mistake, or different totals in different leaves), the epoch pays out more than its pool, taken from IMD reserved for other epochs. When the earlier epoch's claim window closes, _rollClosed computes reserved -= unclaimed, which underflows, so every later deposit reverts; deposit is called from SIMDVault.distribute, so distribute reverts forever and all IMD in the vault is frozen (distribute is its only exit). One bad answer turns into permanent loss of liveness for the whole system rather than a loss bounded to one epoch.","line":427,"path":"src/HolderRewards.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {HolderRewards} from \"src/HolderRewards.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\nimport {OracleAttestation} from \"src/oracle/OracleAttestation.sol\";\n\ncontract Tok is ERC20 {\n    constructor(string memory n) ERC20(n, n) {}\n\n    function mint(address to, uint256 a) external {\n        _mint(to, a);\n    }\n}\n\ncontract Intake {\n    uint256 public nonce;\n\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0.5 ether;\n    }\n\n    function request(bytes32, bytes calldata, IIntake.Callback calldata, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32)\n    {\n        IERC20(asset).transferFrom(msg.sender, address(0xBEEF), amount);\n        return keccak256(abi.encode(++nonce));\n    }\n}\n\n/// @notice One answered root whose leaves carry a `total` smaller than the sum of their balances\n/// lets an epoch pay out more than its pool, out of earlier epochs' reserve. When the earlier\n/// epoch then closes, `_rollClosed` underflows on `reserved -= unclaimed` and every later\n/// `deposit` (so every `SIMDVault.distribute`) reverts forever.\ncontract OverclaimProof is Test {\n    uint256 internal constant KEY = 0xA11CE;\n    Tok imd;\n    Tok token;\n    Intake intake;\n    HolderRewards rewards;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.roll(1000);\n        imd = new Tok(\"IMD\");\n        token = new Tok(\"TEST\");\n        intake = new Intake();\n        rewards = new HolderRewards(\n            address(this), IERC20(address(imd)), IIntake(address(intake)), makeAddr(\"factory\"), makeAddr(\"jobs\"),\n            vm.addr(KEY), false\n        );\n        rewards.setToken(IERC20(address(token)));\n        imd.mint(address(this), 100 ether);\n        imd.approve(address(rewards), type(uint256).max);\n    }\n\n    function _answer(uint256 epoch, bytes32 root) internal {\n        HolderRewards.Epoch memory e = rewards.epochs(epoch);\n        OracleAttestation.Attestation memory a = OracleAttestation.Attestation({\n            requestId: keccak256(abi.encode(\"att\", epoch)),\n            chainId: block.chainid,\n            questionHash: e.questionHash,\n            answerType: OracleAttestation.ANSWER_BYTES32,\n            answer: abi.encode(root),\n            figure: 0,\n            fromBlock: e.snapshotBlock,\n            toBlock: e.snapshotBlock,\n            blockHash: bytes32(uint256(1)),\n            panelJobId: bytes32(uint256(2)),\n            panelSize: 5,\n            quorum: 4,\n            agreed: 5,\n            issuedAt: uint64(block.timestamp),\n            expiresAt: uint64(block.timestamp + 1 hours)\n        });\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY, rewards.attestationDigest(a));\n        bytes32 requestId = keccak256(abi.encode(intake.nonce()));\n        vm.prank(address(intake));\n        rewards.onOracleResult(requestId, a, abi.encodePacked(r, s, v));\n    }\n\n    function test_oneOverpayingRootCannotBrickLaterEpochs() public {\n        rewards.deposit(10 ether); // epoch 1, pool 9.5\n        vm.warp(block.timestamp + 7 days);\n        rewards.deposit(10 ether); // epoch 2, pool 9.5\n\n        // Epoch 2's answered leaves: alice (1 of 1) and bob (1 of 1).\n        bytes32 lA = rewards.leaf(alice, 1, 1);\n        bytes32 lB = rewards.leaf(bob, 1, 1);\n        bytes32 root = lA < lB ? keccak256(abi.encodePacked(lA, lB)) : keccak256(abi.encodePacked(lB, lA));\n        _answer(2, root);\n        bytes32[] memory pA = new bytes32[](1);\n        pA[0] = lB;\n        bytes32[] memory pB = new bytes32[](1);\n        pB[0] = lA;\n        vm.prank(alice);\n        rewards.claim(2, 1, 1, pA);\n        vm.prank(bob);\n        try rewards.claim(2, 1, 1, pB) {} catch {}\n\n        // No epoch may pay more than its pool.\n        HolderRewards.Epoch memory e2 = rewards.epochs(2);\n        assertLe(e2.claimed, e2.pool, \"epoch 2 paid more than its pool\");\n\n        // And the week must keep running once epoch 1 closes.\n        vm.warp(block.timestamp + 28 days);\n        rewards.deposit(10 ether);\n        assertGe(imd.balanceOf(address(rewards)), rewards.reserved());\n    }\n}","reproduction":"Two deposits of 10 IMD (pools 9.5 each). Epoch 2 answered with leaves (alice,1,1) and (bob,1,1). alice and bob each claim 9.5 IMD: epoch 2 claimed = 19 > pool 9.5, epoch 1 holders now unfunded. Warp 28 days and deposit again: expected success; actual panic 0x11 (arithmetic underflow) in _rollClosed, on every future call.","severity":"medium","title":"HolderRewards.claim does not cap an epoch's payouts at its pool; one inconsistent root drains earlier epochs and permanently bricks deposit/distribute"},{"description":"requestJob checks token.balanceOf(msg.sender) at call time and a per-address cooldown. The same 1,000,000 tokens can be moved to a fresh address after each call (or borrowed from the pool / Uniswap v4 flash accounting inside one transaction by a throwaway contract), so the daily limit does not limit anyone and the JobsVault's whole weekly IMD can be spent by one actor in one block. The brief's wording ('any wallet holding ... at most once per 24 hours') is met literally, so this is reported as a design weakness for the requester rather than asserted as correct or wrong in the suite; a holding snapshot (e.g. HolderRewards' epoch root) or a minimum holding period would close it.","line":641,"path":"src/JobsVault.sol","reproduction":"Holder A with exactly 1,000,000 TEST calls requestJob, transfers the tokens to fresh address B, B calls requestJob, B transfers to C, ... in the same block. Expected under the brief's intent: one job per holder per 24h. Actual: one job per transfer, each paid 0.5 IMD by JobsVault, until JobsVault is empty.","severity":"medium","title":"JobsVault's 1,000,000-token gate and 24-hour limit are per address and read the live balance, so one holder (or a flash borrower) can open unlimited jobs per day"},{"description":"bindLaunch only checks that token_ is one of the pool's two currencies. If the launch pool were IMD-paired, the dev wallet could bind IMD as the 'launched token' once and for good: distribute would then send the IMD dust to the burn address, JobsVault would gate on holding 1,000,000 IMD and HolderRewards would snapshot IMD holders. It is a one-shot dev-wallet mistake with no recovery, so a check token_ != imd (and != address(0) native) would be cheap.","line":142,"path":"src/SIMDVault.sol","reproduction":"With the existing MockLaunchFactory (IMD/TEST pool) call bindLaunch(7, IMD) from the dev wallet: expected revert, actual success and jobsVault.token() == IMD.","severity":"low","title":"bindLaunch accepts IMD itself (or any pool currency) as the launched token"}],"hash":"dfd530473b38d6d8a314fc78ac0e48e915aed8fe0158709ac7ad6932d5dad413","nodeId":"5ba50337-7ed2-4215-9868-ad896531de88","outcome":"completed","summary":"`forge test` passes: 65 tests pass and 5 are skipped. The run used the verifier's fuzz seed and left out `test/scratch/`. Before adding tests I found four defects, two of which come with failing proofs. They're in `.imd-findings.json` and not written up as correct behaviour.\n\n**What I added** (the earlier contributor's 59 tests are unchanged):\n- **`test/Invariant.t.sol`**: invariant tests over random call sequences across all three contracts (128 runs, depth 60). The random calls are:\n  - fees building up and anyone claiming them;\n  - IMD sent straight to the vault, and time passing;\n  - `distribute` from random callers;\n  - Intake retries and the writer delivering signed roots;\n  - holder claims, holder job requests, and strangers trying privileged calls or delivering oracle answers directly.\n\n  The invariants that hold after every sequence:\n  - HolderRewards always holds at least what it owes, and what it owes equals what open epochs still have to pay.\n  - No IMD ends up anywhere unexpected.\n  - The dev, marketing and JobsVault wallets get exactly their 17.14% / 17.14% / 25.72% shares each round.\n  - JobsVault spends only on job prices, and holders get only what they claim, once each.\n  - Every launched-token fee the vault receives is burned.\n  - The 7-day limit holds and the launch binding never changes.\n  - Strangers never get a privileged call through, and only Intake can deliver an answer.\n- **`test/Edges.t.sol`**: fuzzed boundaries (1000 runs each) for the 1,000,000-token holding threshold and every offset around the 7-day and 24-hour limits. It also checks that a JobsVault with too little IMD for a job refuses without using up the holder's daily turn, and that a request the Intake refuses moves no IMD.\n\n**Findings in `.imd-findings.json`:**\n1. **High – the vault can't collect the launch's fees.** The intake-client reference says the factory pays creator fees \"in ETH and in tokens\", and this launch's pool is ETH / TEST. `SIMDVault` has no `receive()`, so `claimFees` reverts. `distribute` catches the error every week and carries on, so neither the ETH nor the TEST fees are ever collected or burned. Even with a `receive()` added, nothing lets ETH leave the vault. The proof test fails on the current code: the factory still holds 1 ETH and the burn address receives 0. The existing mocks use an IMD / TEST pool, which is why the suite missed it.\n2. **Medium – one bad oracle root freezes everything.** `HolderRewards.claim` never caps an epoch's payouts at its pool. If one root has leaves whose stated total is smaller than the balances they add up to, that epoch pays out more than it holds, taking IMD meant for other epochs. When the earlier epoch's 28-day window closes, the next deposit hits an arithmetic underflow (panic `0x11`). Every later `distribute` then reverts, and the vault's IMD is stuck for good. A proof test is included.\n3. **Medium – the JobsVault limits are easy to get around.** It checks the caller's live balance and keeps one limit per address. Moving the same 1,000,000 tokens to a fresh address after each request, or borrowing them for one transaction, lets one person open unlimited jobs in a single block. This matches the brief's wording, so it's reported as a design weakness.\n4. **Low – `bindLaunch` accepts IMD as the launched token.** It accepts either pool currency, so if a pool were paired with IMD the dev wallet could bind IMD itself, permanently and with no way back.\n\n**Still owed:** none of the fork tests have run against live state. I couldn't reach a Robinhood Chain RPC from this machine. The tests skip when `ROBINHOOD_RPC_URL` isn't set, and finding 1 especially needs a live check of how a real launch's pool is paired. I haven't committed anything.","treeHash":"04dfee15988ff71a9b1e7e483c401fc447e122e5","usage":{"cachedInputTokens":2227609,"inputTokens":50,"model":"claude-opus-5-5","outputTokens":34638,"runtime":"claude","turns":26,"wallClockMs":621680}}],"verification":[{"checks":[{"durationMs":2798,"exitCode":0,"name":"build","output":"Compiling 63 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.71s\nCompiler run successful!\n","passed":true},{"durationMs":216,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 5 tests for test/Fork.t.sol:RobinhoodForkTest\n[SKIP] test_fork_bindLaunchRejectsALaunchTheVaultDidNotRequest() (gas: 0)\n[SKIP] test_fork_headReadsTheChainsOwnBlockNumber() (gas: 0)\n[SKIP] test_fork_jobsVaultRefusesBeforeBinding() (gas: 0)\n[SKIP] test_fork_launchPaysTheLivePriceFromTheVaultOnlyByDevOnlyOnce() (gas: 0)\n[SKIP] test_fork_theFixedAddressesHaveCodeAndSellTheActionsInImd() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 5 skipped; finished in 502.38µs (381.70µs CPU time)\n\nRan 9 tests for test/JobsVault.t.sol:JobsVaultTest\n[PASS] test_aHolderOpensAJobPaidByTheVaultWithNoCallback() (gas: 412507)\n[PASS] test_holdingBelowOneMillionIsRefused() (gas: 439261)\n[PASS] test_noWithdraw() (gas: 98931)\n[PASS] test_onceEvery24Hours() (gas: 746710)\n[PASS] test_refusedBeforeTheTokenIsBound() (gas: 54996)\n[PASS] test_refusesAnEmptyBodyAnUnsoldActionAndAnEmptyVault() (gas: 292342)\n[PASS] test_theHoldingScalesWithTheTokensDecimals() (gas: 627543)\n[PASS] test_theLimitIsPerWallet() (gas: 694194)\n[PASS] test_vaultHoldsItsWeeklyShare() (gas: 13007)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 3.76ms (1.14ms CPU time)\n\nRan 5 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKeyAsDelivered() (gas: 2280011)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3591)\n[PASS] test_digestMatchesTheProtocol() (gas: 13709)\n[PASS] test_questionHashMatchesTheProtocolVector() (gas: 37673)\n[PASS] test_theProtocolSignatureRecoversTheVectorSigner() (gas: 16881)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 3.92ms (3.58ms CPU time)\n\nRan 25 tests for test/SIMDVault.t.sol:SIMDVaultTest\n[PASS] testFuzz_splitConservesTheBalance(uint256) (runs: 256, μ: 2229154, ~: 2914485)\nLogs:\n  Bound result 615746248078388375607473153257\n\n[PASS] test_bindLaunchOnlyByTheDevWallet() (gas: 34931)\n[PASS] test_bindLaunchOnlyOnce() (gas: 765777)\n[PASS] test_bindLaunchRejectsALaunchWhoseRequesterIsNotTheVault() (gas: 202637)\n[PASS] test_bindLaunchRejectsATokenThatIsNotInTheLaunchPool() (gas: 75981)\n[PASS] test_bindLaunchStoresAndPassesTheTokenOn() (gas: 702482)\n[PASS] test_childrenTakeTheTokenOnlyFromTheVaultAndOnlyOnce() (gas: 746989)\n[PASS] test_constructorDeploysChildrenBoundToTheVault() (gas: 128527)\n[PASS] test_constructorDoesNotCallAnyOtherContract() (gas: 22571)\n[PASS] test_constructorRefusesZeroAddresses() (gas: 12720)\n[PASS] test_distributeAtMostOnceEverySevenDays() (gas: 2887154)\n[PASS] test_distributeByAnyoneAndWithNothingToSplit() (gas: 809211)\n[PASS] test_distributeClaimsFeesSplitsTheWholeBalanceAndBurnsTheToken() (gas: 3197272)\n[PASS] test_distributeNeedsBindLaunch() (gas: 544448)\n[PASS] test_distributeRoundingDustStaysForNextWeek() (gas: 1347703)\n[PASS] test_distributeSplitIsExactInBasisPoints() (gas: 2827716)\n[PASS] test_distributeSurvivesAFailingClaimFees() (gas: 2812811)\n[PASS] test_feesLandOnTheVaultBecauseItIsTheRequester() (gas: 947919)\n[PASS] test_launchFollowsAMovedPrice() (gas: 538556)\n[PASS] test_launchNeedsTheVaultToHoldThePrice() (gas: 127617)\n[PASS] test_launchOnlyByTheDevWallet() (gas: 98734)\n[PASS] test_launchOnlyOnce() (gas: 527698)\n[PASS] test_launchPaysExactlyThePriceFromTheVaultAsPayerWithNoCallback() (gas: 608784)\n[PASS] test_launchRefusesAnEmptyBodyAndAnUnsoldAction() (gas: 150198)\n[PASS] test_noOtherExitForFundsAndNoOwner() (gas: 1151024)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 106.24ms (98.59ms CPU time)\n\nRan 20 tests for test/HolderRewards.t.sol:HolderRewardsTest\n[PASS] testFuzz_claimsNeverExceedThePool(uint128,uint128,uint128) (runs: 256, μ: 2699797, ~: 2720388)\n[PASS] test_aLateAnswerToAClosedEpochChangesNothingClaimable() (gas: 2415584)\n[PASS] test_aTamperedExpiredOrForeignSignatureIsRefused() (gas: 2596755)\n[PASS] test_aWeakPanelIsRefused() (gas: 2339642)\n[PASS] test_anAnswerToAnotherQuestionIsRefused() (gas: 2238471)\n[PASS] test_anEpochThatNeverGotARootRollsItsWholePool() (gas: 4289494)\n[PASS] test_anIntakeThatRevertsDoesNotBlockTheWeek() (gas: 2663082)\n[PASS] test_anUnknownOrSettledRequestIsRefused() (gas: 2365488)\n[PASS] test_anUnsoldOrUnaffordableAskIsSkippedNotReverted() (gas: 721766)\n[PASS] test_buyingAfterTheSnapshotEarnsNothing() (gas: 2452762)\n[PASS] test_claimNeedsAnAnsweredEpochWithHolders() (gas: 2410939)\n[PASS] test_claimRefusesABadProofAWrongBalanceOrSomeoneElsesLeaf() (gas: 2561761)\n[PASS] test_depositOnlyFromTheVaultAndOnlyWithAToken() (gas: 67369)\n[PASS] test_depositOpensAnEpochPinnedEightBlocksBackAndAsksTheOracle() (gas: 3253567)\n[PASS] test_holdersClaimProRataOnce() (gas: 2887825)\n[PASS] test_onlyTheIntakeDeliversAnswers() (gas: 2311388)\n[PASS] test_requestRootIsRateLimitedAndRefusedOnceAnsweredOrClosed() (gas: 6119180)\n[PASS] test_theAnswerArrivesThroughTheIntakeWithinTheStipend() (gas: 2384878)\n[PASS] test_theQuestionNamesTheTokenTheBlockAndTheExclusionsInLowercaseHex() (gas: 2278297)\n[PASS] test_unclaimedRollsIntoTheNextEpochAfter28Days() (gas: 11116783)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 127.33ms (202.53ms CPU time)\n\nRan 5 test suites in 128.40ms (241.76ms CPU time): 59 tests passed, 0 failed, 5 skipped (64 total tests)\n","passed":true},{"durationMs":45,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HolderRewards.claim(uint256,uint256,uint256,bytes32[])\",\"HolderRewards.deposit(uint256)\",\"HolderRewards.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"HolderRewards.requestRoot(uint256)\",\"HolderRewards.setToken(address)\",\"JobsVault.requestJob(bytes)\",\"JobsVault.setToken(address)\",\"SIMDVault.bindLaunch(uint64,address)\",\"SIMDVault.distribute()\",\"SIMDVault.launch(bytes)\"],\"files\":{\".gitignore\":4,\"README.md\":195,\"foundry.toml\":16,\"remappings.txt\":2,\"src/HolderRewards.sol\":364,\"src/JobsVault.sol\":108,\"src/SIMDVault.sol\":198,\"src/interfaces/IIntake.sol\":20,\"src/interfaces/ILaunchFactory.sol\":23,\"src/oracle/OracleAttestation.sol\":221,\"src/oracle/OracleQuestion.sol\":255,\"test/Base.t.sol\":164,\"test/Fork.t.sol\":102,\"test/HolderRewards.t.sol\":464,\"test/JobsVault.t.sol\":131,\"test/OracleConsumerConformance.t.sol\":165,\"test/SIMDVault.t.sol\":369,\"test/mocks/MockERC20.sol\":20,\"test/mocks/MockIntake.sol\":100,\"test/mocks/MockLaunchFactory.sol\":63},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":2664,"exitCode":0,"name":"slither","output":"[medium/high] incorrect-equality at src/SIMDVault.sol:159: SIMDVault.distribute() (src/SIMDVault.sol#159-192) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/SIMDVault.sol:195: SIMDVault.nextDistributionAt() (src/SIMDVault.sol#195-197) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/HolderRewards.sol:315: Reentrancy in HolderRewards._ask(uint256,HolderRewards.Epoch) (src/HolderRewards.sol#315-340):\n[medium/medium] unused-return at src/SIMDVault.sol:159: SIMDVault.distribute() (src/SIMDVault.sol#159-192) ignores return value by holderRewards.deposit(toHolders) (src/SIMDVault.sol#182)\n[medium/medium] unused-return at src/SIMDVault.sol:136: SIMDVault.bindLaunch(uint64,IERC20) (src/SIMDVault.sol#136-151) ignores return value by (key,None,None,requester) = factory.positionOf(launchNumber_) (src/SIMDVault.sol#140)\n[low/medium] reentrancy-benign at src/HolderRewards.sol:315: Reentrancy in HolderRewards._ask(uint256,HolderRewards.Epoch) (src/HolderRewards.sol#315-340):\n[low/medium] reentrancy-benign at src/SIMDVault.sol:121: Reentrancy in SIMDVault.launch(bytes) (src/SIMDVault.sol#121-132):\n[low/medium] reentrancy-events at src/JobsVault.sol:75: Reentrancy in JobsVault.requestJob(bytes) (src/JobsVault.sol#75-92):\n[low/medium] reentrancy-events at src/SIMDVault.sol:136: Reentrancy in SIMDVault.bindLaunch(uint64,IERC20) (src/SIMDVault.sol#136-151):\n[low/medium] reentrancy-events at src/SIMDVault.sol:121: Reentrancy in SIMDVault.launch(bytes) (src/SIMDVault.sol#121-132):\n[low/medium] reentrancy-events at src/HolderRewards.sol:315: Reentrancy in HolderRewards._ask(uint256,HolderRewards.Epoch) (src/HolderRewards.sol#315-340):\n[low/medium] reentrancy-events at src/SIMDVault.sol:159: Reentrancy in SIMDVault.distribute() (src/SIMDVault.sol#159-192):\n[low/medium] reentrancy-events at src/SIMDVault.sol:159: Reentrancy in SIMDVault.distribute() (src/SIMDVault.sol#159-192):\n[low/medium] timestamp at src/SIMDVault.sol:195: SIMDVault.nextDistributionAt() (src/SIMDVault.sol#195-197) uses timestamp for comparisons\n[low/medium] timestamp at src/JobsVault.sol:75: JobsVault.requestJob(bytes) (src/JobsVault.sol#75-92) uses timestamp for comparisons\n[low/medium] timestamp at src/HolderRewards.sol:217: HolderRewards.claim(uint256,uint256,uint256,bytes32[]) (src/HolderRewards.sol#217-234) uses timestamp for comparisons\n[low/medium] timestamp at src/JobsVault.sol:95: JobsVault.canRequest(address) (src/JobsVault.sol#95-100) uses timestamp for comparisons\n[low/medium] timestamp at src/oracle/OracleAttestation.sol:157: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/oracle/OracleAttestation.sol#157-165) uses timestamp for comparisons\n[low/medium] timestamp at src/HolderRewards.sol:177: HolderRewards.requestRoot(uint256) (src/HolderRewards.sol#177-186) uses timestamp for comparisons\n[low/medium] timestamp at src/SIMDVault.sol:159: SIMDVault.distribute() (src/SIMDVault.sol#159-192) uses timestamp for comparisons\n[low/medium] timestamp at src/HolderRewards.sol:344: HolderRewards._rollClosed() (src/HolderRewards.sol#344-358) uses timestamp for comparisons\n[low/medium] timestamp at src/HolderRewards.sol:303: HolderRewards.claimable(uint256,address,uint256,uint256) (src/HolderRewards.sol#303-309) uses timestamp for comparisons","passed":true},{"durationMs":604,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/HolderRewards.sol:162: Reentrancy: State change after external call (5 places)\n[high] unsafe-casting at src/HolderRewards.sol:166: Unsafe Casting of integers (2 places)\n[low] costly-loop at src/HolderRewards.sol:347: Costly operations inside loop\n[low] internal-function-used-once at src/oracle/OracleAttestation.sol:195: Internal Function Used Only Once (2 places)\n[low] large-numeric-literal at src/JobsVault.sol:38: Large Numeric Literal (2 places)\n[low] literal-instead-of-constant at src/oracle/OracleQuestion.sol:117: Literal Instead of Constant (13 places)\n[low] require-revert-in-loop at src/oracle/OracleQuestion.sol:114: Loop Contains `require`/`revert` (2 places)\n[low] unchecked-return at src/HolderRewards.sol:171: Unchecked Return (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"86dac7d2d3334bbc17ab793822634a17f2f1d1d6b493e630cd11c5291e242156","verifiedTreeHash":"7380eb8b186a9de06ece48793ac101fc016eb725","verifierVersion":"0.1.0+a26ee00d"},{"checks":[{"durationMs":3541,"exitCode":0,"name":"build","output":"Compiling 65 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.46s\nCompiler run successful!\n","passed":true},{"durationMs":2352,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 5 tests for test/Fork.t.sol:RobinhoodForkTest\n[SKIP] test_fork_bindLaunchRejectsALaunchTheVaultDidNotRequest() (gas: 0)\n[SKIP] test_fork_headReadsTheChainsOwnBlockNumber() (gas: 0)\n[SKIP] test_fork_jobsVaultRefusesBeforeBinding() (gas: 0)\n[SKIP] test_fork_launchPaysTheLivePriceFromTheVaultOnlyByDevOnlyOnce() (gas: 0)\n[SKIP] test_fork_theFixedAddressesHaveCodeAndSellTheActionsInImd() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 5 skipped; finished in 446.81µs (309.76µs CPU time)\n\nRan 9 tests for test/JobsVault.t.sol:JobsVaultTest\n[PASS] test_aHolderOpensAJobPaidByTheVaultWithNoCallback() (gas: 412507)\n[PASS] test_holdingBelowOneMillionIsRefused() (gas: 439261)\n[PASS] test_noWithdraw() (gas: 98931)\n[PASS] test_onceEvery24Hours() (gas: 746710)\n[PASS] test_refusedBeforeTheTokenIsBound() (gas: 54996)\n[PASS] test_refusesAnEmptyBodyAnUnsoldActionAndAnEmptyVault() (gas: 292342)\n[PASS] test_theHoldingScalesWithTheTokensDecimals() (gas: 627543)\n[PASS] test_theLimitIsPerWallet() (gas: 694194)\n[PASS] test_vaultHoldsItsWeeklyShare() (gas: 13007)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 6.02ms (1.46ms CPU time)\n\nRan 20 tests for test/HolderRewards.t.sol:HolderRewardsTest\n[PASS] testFuzz_claimsNeverExceedThePool(uint128,uint128,uint128) (runs: 256, μ: 2698900, ~: 2720388)\n[PASS] test_aLateAnswerToAClosedEpochChangesNothingClaimable() (gas: 2415584)\n[PASS] test_aTamperedExpiredOrForeignSignatureIsRefused() (gas: 2596755)\n[PASS] test_aWeakPanelIsRefused() (gas: 2339642)\n[PASS] test_anAnswerToAnotherQuestionIsRefused() (gas: 2238471)\n[PASS] test_anEpochThatNeverGotARootRollsItsWholePool() (gas: 4289494)\n[PASS] test_anIntakeThatRevertsDoesNotBlockTheWeek() (gas: 2663082)\n[PASS] test_anUnknownOrSettledRequestIsRefused() (gas: 2365488)\n[PASS] test_anUnsoldOrUnaffordableAskIsSkippedNotReverted() (gas: 721766)\n[PASS] test_buyingAfterTheSnapshotEarnsNothing() (gas: 2452762)\n[PASS] test_claimNeedsAnAnsweredEpochWithHolders() (gas: 2410939)\n[PASS] test_claimRefusesABadProofAWrongBalanceOrSomeoneElsesLeaf() (gas: 2561761)\n[PASS] test_depositOnlyFromTheVaultAndOnlyWithAToken() (gas: 67369)\n[PASS] test_depositOpensAnEpochPinnedEightBlocksBackAndAsksTheOracle() (gas: 3253567)\n[PASS] test_holdersClaimProRataOnce() (gas: 2887825)\n[PASS] test_onlyTheIntakeDeliversAnswers() (gas: 2311388)\n[PASS] test_requestRootIsRateLimitedAndRefusedOnceAnsweredOrClosed() (gas: 6119180)\n[PASS] test_theAnswerArrivesThroughTheIntakeWithinTheStipend() (gas: 2384878)\n[PASS] test_theQuestionNamesTheTokenTheBlockAndTheExclusionsInLowercaseHex() (gas: 2278297)\n[PASS] test_unclaimedRollsIntoTheNextEpochAfter28Days() (gas: 11116783)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 258.09ms (324.75ms CPU time)\n\nRan 5 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKeyAsDelivered() (gas: 2280011)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3591)\n[PASS] test_digestMatchesTheProtocol() (gas: 13709)\n[PASS] test_questionHashMatchesTheProtocolVector() (gas: 37673)\n[PASS] test_theProtocolSignatureRecoversTheVectorSigner() (gas: 16881)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 278.11ms (2.58ms CPU time)\n\nRan 5 tests for test/Edges.t.sol:EdgesTest\n[PASS] testFuzz_distributeOnlyAfterSevenDays(uint256) (runs: 1000, μ: 2176560, ~: 2156026)\nLogs:\n  Bound result 9725\n\n[PASS] testFuzz_jobNeedsExactlyOneMillionTokens(uint256) (runs: 1000, μ: 2316694, ~: 2247461)\nLogs:\n  Bound result 2594\n\n[PASS] testFuzz_jobOnlyAfter24Hours(uint256) (runs: 1000, μ: 2601667, ~: 2502039)\nLogs:\n  Bound result 88342\n\n[PASS] test_aDrainedJobsVaultRefusesWithoutSpendingTheTurn() (gas: 18297938)\n[PASS] test_aRefusedJobRequestMovesNoImd() (gas: 2380048)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 278.36ms (820.74ms CPU time)\n\nRan 25 tests for test/SIMDVault.t.sol:SIMDVaultTest\n[PASS] testFuzz_splitConservesTheBalance(uint256) (runs: 256, μ: 2223547, ~: 2912369)\nLogs:\n  Bound result 615746248078388375607473153257\n\n[PASS] test_bindLaunchOnlyByTheDevWallet() (gas: 34931)\n[PASS] test_bindLaunchOnlyOnce() (gas: 765777)\n[PASS] test_bindLaunchRejectsALaunchWhoseRequesterIsNotTheVault() (gas: 202637)\n[PASS] test_bindLaunchRejectsATokenThatIsNotInTheLaunchPool() (gas: 75981)\n[PASS] test_bindLaunchStoresAndPassesTheTokenOn() (gas: 702482)\n[PASS] test_childrenTakeTheTokenOnlyFromTheVaultAndOnlyOnce() (gas: 746989)\n[PASS] test_constructorDeploysChildrenBoundToTheVault() (gas: 128527)\n[PASS] test_constructorDoesNotCallAnyOtherContract() (gas: 22571)\n[PASS] test_constructorRefusesZeroAddresses() (gas: 12720)\n[PASS] test_distributeAtMostOnceEverySevenDays() (gas: 2887154)\n[PASS] test_distributeByAnyoneAndWithNothingToSplit() (gas: 809211)\n[PASS] test_distributeClaimsFeesSplitsTheWholeBalanceAndBurnsTheToken() (gas: 3197272)\n[PASS] test_distributeNeedsBindLaunch() (gas: 544448)\n[PASS] test_distributeRoundingDustStaysForNextWeek() (gas: 1347703)\n[PASS] test_distributeSplitIsExactInBasisPoints() (gas: 2827716)\n[PASS] test_distributeSurvivesAFailingClaimFees() (gas: 2812811)\n[PASS] test_feesLandOnTheVaultBecauseItIsTheRequester() (gas: 947919)\n[PASS] test_launchFollowsAMovedPrice() (gas: 538556)\n[PASS] test_launchNeedsTheVaultToHoldThePrice() (gas: 127617)\n[PASS] test_launchOnlyByTheDevWallet() (gas: 98734)\n[PASS] test_launchOnlyOnce() (gas: 527698)\n[PASS] test_launchPaysExactlyThePriceFromTheVaultAsPayerWithNoCallback() (gas: 608784)\n[PASS] test_launchRefusesAnEmptyBodyAndAnUnsoldAction() (gas: 150198)\n[PASS] test_noOtherExitForFundsAndNoOwner() (gas: 1151024)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 278.36ms (259.04ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:SystemInvariantTest\n[PASS]\nSystemInvariantTest invariants:\n[PASS] invariant_imdIsConserved\n[PASS] invariant_recipientsGetExactlyTheirShare\n[PASS] invariant_rewardsHoldWhatTheyOwe\n[PASS] invariant_rulesHold\n[PASS] invariant_tokenFeesAreBurned\n SystemInvariantTest invariants (runs: 128, calls: 7680, reverts: 0)\n\n╭---------------+-------------------+-------+---------+----------╮\n| Contract      | Selector          | Calls | Reverts | Discards |\n+================================================================+\n| SystemHandler | accrueFees        | 696   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | claim             | 686   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | claimFeesDirectly | 654   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | deliver           | 725   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | distribute        | 697   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | donate            | 678   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | requestJob        | 716   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | requestRoot       | 710   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | strangerAdmin     | 663   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | strangerDeliver   | 754   | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| SystemHandler | warp              | 701   | 0       | 0        |\n╰---------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1796568207831344569181\n  Bound result 15\n  Bound result 5199\n  Bound result 972673544849629798096930038646268148460323425401\n  Bound result 3880\n  Bound result 13297\n  Bound result 0\n  Bound result 504\n  Bound result 1\n  Bound result 9876\n  Bound result 887220\n  Bound result 2\n  Bound result 112811662\n  Bound result 1\n  Bound result 340282366920938463463374677802659872768\n  Bound result 1\n  Bound result 1000000000000000000000\n  Bound result 0\n  Bound result 100\n  Bound result 742045715467293283364846401879868355290465904129\n  Bound result 1\n  Bound result 1\n  Bound result 1683\n  Bound result 0\n  Bound result 99\n  Bound result 1\n  Bound result 0\n  Bound result 415972814\n  Bound result 12336\n  Bound result 2096\n  Bound result 999999999000000000000000\n  Bound result 11000000000000000000\n  Bound result 4267757869\n  Bound result 7870\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 599290589\n  Bound result 1\n  Bound result 0\n  Bound result 4023\n  Bound result 0\n  Bound result 1\n  Bound result 4823\n  Bound result 1\n  Bound result 691200\n  Bound result 1\n  Bound result 615733\n  Bound result 15\n  Bound result 157198258\n  Bound result 0\n  Bound result 7220\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 222\n  Bound result 1\n  Bound result 31391154128120194439916053875\n  Bound result 2\n  Bound result 3443\n  Bound result 2\n  Bound result 3880\n  Bound result 1\n  Bound result 691804932678249084598636\n  Bound result 0\n  Bound result 1\n  Bound result 172\n  Bound result 2\n  Bound result 2419200\n  Bound result 0\n  Bound result 1\n  Bound result 0\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.25s (2.24s CPU time)\n\nRan 7 test suites in 2.25s (3.35s CPU time): 65 tests passed, 0 failed, 5 skipped (70 total tests)\n","passed":true},{"durationMs":48,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HolderRewards.claim(uint256,uint256,uint256,bytes32[])\",\"HolderRewards.deposit(uint256)\",\"HolderRewards.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"HolderRewards.requestRoot(uint256)\",\"HolderRewards.setToken(address)\",\"JobsVault.requestJob(bytes)\",\"JobsVault.setToken(address)\",\"SIMDVault.bindLaunch(uint64,address)\",\"SIMDVault.distribute()\",\"SIMDVault.launch(bytes)\"],\"files\":{\".gitignore\":4,\"README.md\":195,\"foundry.toml\":16,\"remappings.txt\":2,\"src/HolderRewards.sol\":364,\"src/JobsVault.sol\":108,\"src/SIMDVault.sol\":198,\"src/interfaces/IIntake.sol\":20,\"src/interfaces/ILaunchFactory.sol\":23,\"src/oracle/OracleAttestation.sol\":221,\"src/oracle/OracleQuestion.sol\":255,\"test/Base.t.sol\":164,\"test/Edges.t.sol\":102,\"test/Fork.t.sol\":102,\"test/HolderRewards.t.sol\":464,\"test/Invariant.t.sol\":446,\"test/JobsVault.t.sol\":131,\"test/OracleConsumerConformance.t.sol\":165,\"test/SIMDVault.t.sol\":369,\"test/mocks/MockERC20.sol\":20,\"test/mocks/MockIntake.sol\":100,\"test/mocks/MockLaunchFactory.sol\":63},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"dfd530473b38d6d8a314fc78ac0e48e915aed8fe0158709ac7ad6932d5dad413","verifiedTreeHash":"04dfee15988ff71a9b1e7e483c401fc447e122e5","verifierVersion":"0.1.0+a26ee00d"}]}