{"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":"76506bc8-6d8a-4fe0-95cb-6384a0801040","kind":"skill:build-contract-project","nodes":[{"acceptedSubmissionHash":"54c88f5217b7c46bef940d8aac425bad59b6d70e66710e18be95fe86c6e25401","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","state":"accepted"}],"objective":"Sorphera - contract hardening, integration tests and deployment preparation\n\nTagline: Weekly ETH & NFT lottery ball jackpots. Powered by FWA.\nRepo: Sorphera repository\nIMD launch: 961\nParent job: a3707b79-51b8-4d04-9e32-3e786d91c1d9\nReviewed commit: b06997d42012b7ad7ffe943b3acdd816b2092c4e\n\nContinue from the current repo head; check changes since the reviewed commit. Keep this contracts-only: implement contracts, tests, deployment scripts, docs and integration artifacts. Target Ethereum mainnet, testing FWA on a pinned mainnet fork. Do not broadcast mainnet transactions, spend real funds or enable public sales.\n\nPRESERVE PRODUCT RULES\n\nTwo separate weekly lottery-ball games:\n\nETH Jackpot: settle FWA acquisitions to ETH. Winning tickets split distributable ETH equally; no winners means rollover.\n\nNFT Jackpot: take the NFTs. No winners means inventory rollover; one winning ticket receives all inventory. Multiple winning tickets trigger a separate verifiable random tie-break selecting ONE winning ticket for all inventory.\n\nKeep three distinct unordered main numbers 1-20 plus bonus 1-5, existing ticket ownership, 0.005 ETH default tickets and 10% operator fee / 90% acquisition defaults.\n\nTotal ticket sales remain uncapped; transaction batches and processing remain bounded.\n\nCompany builder rewards stay separate from purchaser reward entitlements, prizes and refunds.\n\nPreserve custody/refund/claim/rollover guarantees and economics; explain necessary changes.\n\nUse verifiable randomness and expose draw/tie-break events for future animations. No website work.\n\nFIX THE FAILED DEPLOYMENT REHEARSAL\n\nLaunch was parked after 6/7 gates passed. protected_invariants failed with \"application constructor failed\" in setUp(), gas 0. Sorphera checks for code at the factory and VRF coordinator; the factory checks router code.\n\nCapture the failing contract, resolved constructor arguments, chain state and revert trace. Check dependency order, $owner/$contract substitutions and coordinator code. Match IMD compiler/optimizer/EVM settings. Local tests passed 64/64 on Forge 1.7.1; IMD reported 1.8.3. Investigate, rather than assume, the cause.\n\nFix the cause without weakening safeguards or mocking production dependencies. If IMD's private harness is unavailable, supply a public reproduction and exact platform follow-up. Never claim its gate passed without evidence.\n\nVERIFY MAINNET INTEGRATION AND NETWORK CONFIGURATION\n\nPrimary references:\n\nFWA deployments\n\nBuilder revenue\n\nFWA testing\n\nBuilder examples\n\nChainlink networks\n\nPublished mainnet pool: 0x958C41181182e76F221331b2755b77D9e1426A98\nPublished mainnet rewards: 0xA54b44C7a894AA19C49734A753D01f9B8C5f6516\n\nReviewed Sepolia lacked builder attribution. Mainnet source/ABI includes it; an explorer read reported builderRewardBps() = 1500. Reverify compatibility and current settings; the rate can change.\n\nRecord chain/block, bytecode, ABIs and pool/rewards/token/randomness bindings. Verify the transfer helper, Permit2, distributor/deposit permissions and liquidity. Prove router builder attribution as immediate acquire caller, with round vaults retaining purchaser rights.\n\nReplace the Sepolia-only restriction with validated network configuration: chain ID, dependencies, coordinator, key hash and subscription. Fail closed on wrong chains/incompatible dependencies. Separate production and test-only simulation.\n\nRead live quotes, VRF charges, gas-price assumptions, slippage limits and settlement windows. Do not hardcode 0.06 ETH pulls or source defaults.\n\nTEST COMPLETE LIFECYCLES AND FAILURE PATHS\n\nRun existing tests and add pinned mainnet-fork tests using deployed FWA code unchanged. Record commands/RPC requirements; disclose fork-only balances, impersonation and oracle simulation.\n\nCover both games: tickets -> FWA requests -> allocation -> ETH/NFT settlement -> draw -> finalization -> claims. Verify real builder allowance accounting, eligible acquisition/settlement credits, reward purchase, transfer-helper queueing and next-block treasury delivery. Test purchaser rewards separately.\n\nRequired coverage:\n\nETH prize splits, duplicate winning tickets, no-winner rollover and rounding dust.\n\nNFT single winner, multiwinner tie-break, rollover and bounded delivery/recovery.\n\nFailed/expired acquisitions, immediate/deferred refunds, stale/slipping quotes, unavailable inventory, delayed allocation and missed settlement windows.\n\nCross-round isolation, conservation of funds/inventory, locked liabilities, correct fee accounting and prevention of operator withdrawal of prizes/refunds/purchaser rewards.\n\nNumber validation/canonical ordering, quick-pick/draw sampling bias, bonus independence, cutoff boundaries and immutable terms for sold tickets.\n\nUnauthorized, duplicate, delayed and out-of-order VRF callbacks; request-to-round binding and separate tie-break requests.\n\nReentrancy, reverting recipients, NFT receiver failures, unauthorized administration, paused paths and changed dependency/helper permissions.\n\nLarge ticket/inventory counts: demonstrate bounded gas and progress without processing every ticket in one transaction.\n\nForks receive no automatic live Chainlink callbacks. Document test-only fulfillment for FWA and lottery VRF. Separately test lottery VRF on Sepolia with controlled FWA test dependencies and the real coordinator if test funding/access exists. Otherwise deliver scripts, exact prerequisites and a NOT RUN result. Never label simulation as live VRF verification.\n\nReview lockups from permanent VRF failure, pending acquisitions and missed settlement windows. Document fair recovery options; prohibit discretionary rerolls, winner replacement and post-sale rule changes.\n\nPREPARE DEPLOYMENT AND OPERATIONS\n\nDeliver build/deployment rehearsals, owner/treasury inputs, dependency order, factory binding, router setup, company VRF subscription/consumer setup and funding/preflight checks. Sales default to disabled.\n\nSeparate mainnet/Sepolia/fork artifacts. Check current IMD rules: a continuation may update code without redeploying or retargeting the parked Sepolia launch. Document the supported mainnet route and any new launch/platform action required.\n\nProvide keeper/operations scripts and a runbook for acquisitions, allocation processing, timely settlement, closing rounds, randomness requests, finalization and reward claims. Specify permissions, funding, monitoring and safe retries.\n\nDELIVER EVIDENCE\n\nCommit fixes/tests to the existing project and summarize the changes. Update dependency records, test reports, manifests, ABIs, events and configuration schemas. Leave undeployed addresses null and label simulated/example artifacts.\n\nReport:\n\nRoot cause, fix, files changed and protected-gate status.\n\nExact commands and passed/failed/skipped test counts.\n\nMainnet fork block/dependencies and real vs simulated oracle coverage.\n\nGas/scaling results and supported deployment procedure.\n\nRemaining blockers, each with the exact external input/action required.\n\nComplete all unblocked work. Distinguish verified, unrun and blocked steps. State readiness for independent security review/deployment rehearsal; passing tests is not an audit or approval for public sales.","parentJobId":"a3707b79-51b8-4d04-9e32-3e786d91c1d9","planHash":"0b54eb006d2e967aa43d6bd7f0e45e867d64eecd463679d2c51e84852756cf08","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"a3707b79-51b8-4d04-9e32-3e786d91c1d9","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-961-build-sorphera-smart-contracts"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52208","feedbackHash":"5a760cffb36f5155cbc0fb295bbb9fc0f1ff588ff85c876e482f3120b134ab94","nodeKey":"build_contract_project","submissionHash":"54c88f5217b7c46bef940d8aac425bad59b6d70e66710e18be95fe86c6e25401","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"2a7bfbdd114b2e241f0a17e76955456872b3b06909739f743b43467ff80ca9c9","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"f1a613658983bf86ed451c843a78ccf9aa806886a1fcec6dd2a42c422535d246","device":"9676188abd3783f2","findings":[],"hash":"54c88f5217b7c46bef940d8aac425bad59b6d70e66710e18be95fe86c6e25401","nodeId":"997b83e3-4ec8-4e3f-80c3-86059a7b75f3","outcome":"completed","summary":"Implemented contract hardening, independent NFT tie-break VRF requests, validated network configuration, constructor diagnostics, fork integration tests, deployment scripts and operations artifacts.\n\nValidation passed with Solidity **0.8.26**:\n\n- `forge build` and both formatting checks.\n- Offline suite: **65 passed**.\n- Mainnet fork at block **26,145,236**: **11 passed**.\n- Sepolia fork: **3 passed**.\n- Empty-chain constructor reproduction: **1 passed**.\n\nNo failures or skips in these runs. [Test report and exact commands](/root/.identitymd/work/76506bc8-6d8a-4fe0-95cb-6384a0801040/997b83e3-4ec8-4e3f-80c3-86059a7b75f3/docs/TESTING.md).\n\nThe constructor failure is reproducible when coordinator code is absent; genuine Sepolia fork state succeeds. **IMD’s private root cause remains unconfirmed, and its protected gate remains failed/not rerun.** Safeguards were preserved. [Investigation and required platform follow-up](/root/.identitymd/work/76506bc8-6d8a-4fe0-95cb-6384a0801040/997b83e3-4ec8-4e3f-80c3-86059a7b75f3/docs/REHEARSAL.md).\n\nMainnet tests use unchanged deployed FWA code; oracle fulfillment is explicitly simulated. Live Sepolia VRF still requires company funding/access. Owner inputs, independent review and a separate authorized mainnet launch remain required. [Deployment procedure and blockers](/root/.identitymd/work/76506bc8-6d8a-4fe0-95cb-6384a0801040/997b83e3-4ec8-4e3f-80c3-86059a7b75f3/docs/DEPLOYMENT.md).\n\nNo transactions broadcast or sales enabled. Ready for independent security review and deployment rehearsal—not public release. Changes remain uncommitted because your rules prohibit touching `.git/`.","treeHash":"aeab25608608f7786b37314529eeec51c4c3982c","usage":{"cachedInputTokens":15529088,"inputTokens":299295,"model":"gpt-6-astra","outputTokens":70199,"runtime":"codex","turns":13,"wallClockMs":2516694}}],"verification":[{"checks":[{"durationMs":64524,"exitCode":0,"name":"build","output":"Compiling 39 files with Solc 0.8.26\nSolc 0.8.26 finished in 64.40s\nCompiler run successful!\nwarning[missing-events-arithmetic]: `budget` is changed without an event but is used in arithmetic\n    ╭▸ src/SorpheraVault.sol:102:9\n    │\n102 │         budget += msg.value;\n    │         ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SorpheraVault.sol:80:9\n   │\n80 │         address lottery_,\n   │         ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SorpheraVaultFactory.sol:22:25\n   │\n22 │     function setLottery(address lottery_) external onlyOwner {\n   │                         ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/SorpheraVaultFactory.sol:37:9\n   │\n37 │         emit VaultCreated(msg.sender, game, round, address(vault));\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/lib/Networks.sol:21:17\n   │\n21 │         require(valid, \"Sorphera: network configuration\");\n   │                 ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n   ╭▸ src/lib/Security.sol:15:22\n   │\n15 │         (bool ok,) = to.call{value: amount}(\"\");\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/lib/RewardTransfer.sol:19:32\n   │\n19 │         require(amount != 0 && block.timestamp <= deadline, \"Sorphera: reward bounds\");\n   │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/lib/RewardTransfer.sol:45:9\n   │\n45 │         emit RewardQueued(token, recipient, amount, nonce);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/lib/RewardTransfer.sol:36:9\n   │\n36 │ ┏         ITransferHelper(helper)\n37 │ ┃             .depositWithPermit2(\n38 │ ┃                 ITransferHelper.PermitTransferFrom(\n39 │ ┃                     ITransferHelper.TokenPermissions(token, amount), nonce, deadline\n   ‡ ┃\n42 │ ┃                 recipient\n43 │ ┃             );\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SorpheraVault.sol:107:64\n    │\n107 │             ISorphera(lottery).acquisitionOpen(game, round) && block.timestamp < settings.cutoff\n    │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SorpheraVault.sol:111:44\n    │\n111 │         require(count > 0 && count <= 8 && block.timestamp <= deadline, \"Sorphera: acquisition batch\");\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SorpheraVault.sol:130:51\n    │\n130 │             IFWA.Acquisition memory acquisition = pool.acquisitions(ids[i]);\n    │                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:134:13\n    │\n134 │             emit Acquisition(game, round, ids[i], acquisition.priceEscrowed, vrf, sw, fw);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/SorpheraVault.sol:129:13\n    │\n129 │             require(ids[i] != 0 && requestState[ids[i]] == 0, \"Sorphera: duplicate request\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/SorpheraVault.sol:131:13\n    │\n131 │             require(acquisition.purchaser == address(this), \"Sorphera: purchaser\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SorpheraRouter.sol:26:39\n   │\n26 │     function configure(address pool_, address helper_) external onlyOwner {\n   │                                       ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/SorpheraRouter.sol:26:24\n   │\n26 │     function configure(address pool_, address helper_) external onlyOwner {\n   │                        ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestState` is updated\n    ╭▸ src/SorpheraVault.sol:150:17\n    │\n150 │                 pool.acceptDepositorBid(a.listingId);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestState` is updated\n    ╭▸ src/SorpheraVault.sol:152:17\n    │\n152 │                 pool.keepNFT(a.listingId);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestState` is updated\n    ╭▸ src/SorpheraVault.sol:191:21\n    │\n191 │                     ISorphera(lottery).recordNFT(game, round, securedAt);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/SorpheraRouter.sol:106:15\n    │\n106 │         ids = IFWA(p).acquire{value: msg.value}(msg.sender, count, maxFee, minValue, slippage);\n    │               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:192:21\n    │\n192 │                     emit CustodySecured(index, l.collection, l.tokenId, id, a.listingId);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:198:21\n    │\n198 │                     emit DeliveryStuck(id, a.listingId);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:205:13\n    │\n205 │             emit Reconciled(id, a.listingId, a.status);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/SorpheraVault.sol:160:9\n    │\n160 │         pool.processAcquisitions(count);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/SorpheraVault.sol:160:9\n    │\n160 │         pool.processAcquisitions(count);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-eth]: uncapped ETH transfer can be reentered before `entered` is updated\n   ╭▸ src/lib/Security.sol:15:22\n   │\n15 │         (bool ok,) = to.call{value: amount}(\"\");\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-eth\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n  ╭▸ src/lib/Balls.sol:9:13\n  │\n9 │             require(a[i] >= 1 && a[i] <= 20, \"Sorphera: ball\");\n  │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SorpheraRouter.sol:102:13\n    │\n102 │             block.timestamp <= deadline && maxFee > 0 && minValue > 0 && slippage <= 1000,\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SorpheraVault.sol:172:37\n    │\n172 │         IFWA.Acquisition memory a = pool.acquisitions(id);\n    │                                     ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/lib/Balls.sol:23:68\n   │\n23 │             uint256 x = uint256(keccak256(abi.encode(seed, domain, counter)));\n   │                                                                    ━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SorpheraVault.sol:176:37\n    │\n176 │             IFWA.Listing memory l = pool.listings(a.listingId);\n    │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SorpheraVault.sol:181:21\n    │\n181 │                 try IERC721(l.collection).ownerOf(l.tokenId) returns (address holder) {\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/lib/Balls.sol:20:9\n   │\n20 │         require(n != 0, \"Sorphera: empty sample\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/lib/Balls.sol:26:9\n   │\n26 │         revert(\"unreachable\");\n   │         ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraRouter.sol:110:9\n    │\n110 │         emit AcquisitionForwarded(msg.sender, p, ids, refund);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SorpheraVault.sol:191:21\n    │\n191 │                     ISorphera(lottery).recordNFT(game, round, securedAt);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SorpheraVault.sol:193:28\n    │\n193 │                 } else if (pool.stuckNFTRecipient(a.listingId) == address(this)) {\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/lib/Balls.sol:43:17\n   │\n43 │         bonus = uint8(uniform(seed, keccak256(\"Sorphera bonus\"), 5) + 1);\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/SorpheraVault.sol:171:9\n    │\n171 │         require(requestState[id] != 0, \"Sorphera: unknown acquisition\");\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/SorpheraVault.sol:173:9\n    │\n173 │         require(a.purchaser == address(this), \"Sorphera: purchaser\");\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/SorpheraVault.sol:177:13\n    │\n177 │             require(l.purchaser == address(this), \"Sorphera: purchaser\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SorpheraVault.sol:184:21\n    │\n184 │                 if (held) {\n    │                     ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-no-eth]: external call can be reentered before `requestState` is updated\n    ╭▸ src/SorpheraVault.sol:213:9\n    │\n213 │         pool.recoverStuckNFT(a.listingId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/SorpheraVault.sol:223:9\n    │\n223 │         pool.withdrawAcquisitionRefund();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:224:9\n    │\n224 │         emit RefundRecovered(address(this).balance - beforeBalance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/SorpheraVault.sol:223:9\n    │\n223 │         pool.withdrawAcquisitionRefund();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SorpheraVault.sol:232:13\n    │\n232 │         if (block.timestamp >= settings.cutoff) budget = 0;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:237:13\n    │\n237 │             emit ETHExported(amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/SorpheraVault.sol:244:9\n    │\n244 │         rewards.claimEpochTokens(epochs);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:245:9\n    │\n245 │         emit PurchaserRewardsClaimed(prizeToken.balanceOf(address(this)) - beforeBalance);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/SorpheraVault.sol:244:9\n    │\n244 │         rewards.claimEpochTokens(epochs);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n   ╭▸ src/lib/RewardTransfer.sol:36:9\n   │\n36 │ ┏         ITransferHelper(helper)\n37 │ ┃             .depositWithPermit2(\n38 │ ┃                 ITransferHelper.PermitTransferFrom(\n39 │ ┃                     ITransferHelper.TokenPermissions(token, amount), nonce, deadline\n   ‡ ┃\n42 │ ┃                 recipient\n43 │ ┃             );\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/SorpheraVault.sol:281:17\n    │\n281 │             try this.deliver{gas: 500000}(index, recipient) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SorpheraVault.sol:281:17\n    │\n281 │             try this.deliver{gas: 500000}(index, recipient) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:282:17\n    │\n282 │                 emit NFTClaimed(index, recipient);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:285:17\n    │\n285 │                 emit NFTClaimFailed(index, recipient);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraVault.sol:276:21\n    │\n276 │                     emit SharedAssetVote(index, ticket, recipient);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/SorpheraVault.sol:269:13\n    │\n269 │             require(!a.claimed, \"Sorphera: NFT claimed\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/Sorphera.sol:244:26\n    │\n244 │         (bool active,) = coordinator.s_provingKeys(c.keyHash);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/Sorphera.sol:245:67\n    │\n245 │         (uint16 minimumConfirmations, uint32 maximumGas,,,,,,,) = coordinator.s_config();\n    │                                                                   ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Sorphera.sol:268:17\n    │\n268 │         require(present, \"Sorphera: VRF consumer missing\");\n    │                 ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/Sorphera.sol:262:13\n    │\n262 │             coordinator.getSubscription(c.subscription);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/SorpheraRouter.sol:123:26\n    │\n123 │         uint256 amount = r.claimAccruedTokens(minOut);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/SorpheraRouter.sol:116:9\n    │\n116 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SorpheraRouter.sol:119:31\n    │\n119 │         require(minOut > 0 && block.timestamp <= deadline, \"Sorphera: reward bounds\");\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SorpheraRouter.sol:126:9\n    │\n126 │         emit BuilderRewardClaimed(address(r), allowance, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `latestRound` is updated\n    ╭▸ src/Sorphera.sol:300:13\n    │\n300 │ ┏             factory.create(\n301 │ ┃                 game,\n302 │ ┃                 id,\n303 │ ┃                 SorpheraVault.Settings(rules.maxFee, rules.maxTotal, rules.minValue, rules.slippage, cutoff)\n304 │ ┃             )\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Sorphera.sol:290:17\n    │\n290 │         require(block.timestamp >= cutoff - WEEK, \"Sorphera: window not started\");\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:311:9\n    │\n311 │ ┏         emit RoundOpened(\n312 │ ┃             game, id, r.group, r.vault, r.start, cutoff, r.earliestDraw, r.settlementDeadline, r.price\n313 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/Sorphera.sol:339:9\n    │\n339 │         SorpheraVault(payable(r.vault)).fund{value: msg.value - fee}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/SorpheraRouter.sol:132:9\n    │\n132 │         IRewards(rewardsForPool[p]).withdrawTokenBuyAllowanceAsETH();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/SorpheraRouter.sol:129:87\n    │\n129 │     function recoverBuilderAllowance(address p, address recipient) external onlyOwner nonReentrant {\n    │                                                                                       ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/SorpheraRouter.sol:132:9\n    │\n132 │         IRewards(rewardsForPool[p]).withdrawTokenBuyAllowanceAsETH();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Sorphera.sol:319:57\n    │\n319 │             salesEnabled && r.status == Status.Sales && block.timestamp >= r.start\n    │                                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Sorphera.sol:320:20\n    │\n320 │                 && block.timestamp < r.cutoff,\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n  ╭▸ src/lib/Balls.sol:7:9\n  │\n7 │         require(bonus >= 1 && bonus <= 5, \"Sorphera: bonus\");\n  │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/lib/Balls.sol:14:9\n   │\n14 │         require(a[0] != a[1] && a[1] != a[2], \"Sorphera: distinct balls\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Sorphera.sol:344:44\n    │\n344 │         return r.status == Status.Sales && block.timestamp < r.cutoff;\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Sorphera.sol:349:45\n    │\n349 │         require(r.status == Status.Sales && block.timestamp >= r.cutoff, \"Sorphera: cannot close\");\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/Sorphera.sol:386:9\n    │\n386 │         v.syncETH();\n    │         ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/Sorphera.sol:411:21\n    │\n411 │           requestId = coordinator.requestRandomWords(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━┛\n412 │ ┃             IVRF.Request(\n413 │ ┃                 c.keyHash,\n414 │ ┃                 c.subscription,\n    ‡ ┃\n420 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Sorphera.sol:392:49\n    │\n392 │         if (game == 1 && r.eligibleNFTs == 0 && block.timestamp >= r.settlementDeadline) {\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Sorphera.sol:397:13\n    │\n397 │             block.timestamp >= r.earliestDraw && v.pending() == 0 && v.budget() == 0 && v.refundCredit() == 0,\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:524:9\n    │\n524 │         emit Rollover(game, id, r.group, g.cash, g.nftCount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:536:9\n    │\n536 │         emit Cancelled(game, id, g.cash, r.sold);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:558:13\n    │\n558 │             emit DustCarried(game, currentGroup[game], dust);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:405:9\n    │\n405 │         emit DrawRequested(game, id, r.requestId, r.frozenNFTs);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Sorphera.sol:418:40\n    │\n418 │                 abi.encodeWithSelector(bytes4(keccak256(\"VRF ExtraArgsV1\")), c.nativePayment)\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes4' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:431:9\n    │\n431 │         emit TieBreakRequested(game, id, r.tieBreakRequestId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/Sorphera.sol:552:19\n    │\n552 │         g.cash -= share * g.divisor;\n    │                   ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Sorphera.sol:596:13\n    │\n596 │             amount += delta;\n    │             ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:601:9\n    │\n601 │         emit Claimed(game, g.terminalRound, ids[0], recipient, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Sorphera.sol:569:9\n    │\n569 │         require(terminal != 0, \"Sorphera: prize not finalized\");\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Sorphera.sol:572:9\n    │\n572 │         require(t.player == claimant && claimant != address(0), \"Sorphera: ticket owner\");\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Sorphera.sol:574:13\n    │\n574 │ ┏             require(\n575 │ ┃                 t.combination == r.winningKey && (game == 0 || ticket == r.winningTicket),\n576 │ ┃                 \"Sorphera: not winning ticket\"\n577 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Sorphera.sol:579:13\n    │\n579 │             require(r.status == Status.Cancelled, \"Sorphera: prize state\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/Sorphera.sol:604:85\n    │\n604 │     function withdrawOperator(address recipient, uint256 amount) external onlyOwner nonReentrant {\n    │                                                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Sorphera.sol:609:9\n    │\n609 │         emit OperatorWithdrawal(recipient, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\n","passed":true},{"durationMs":12972,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/SorpheraHardening.t.sol:SorpheraHardeningTest\n[PASS] testChangedChainStopsSalesAndRequests() (gas: 3807473)\n[PASS] testChangedHelperPermissionsStopNewRiskButPreserveCashClaims() (gas: 4930556)\n[PASS] testConstructorDiagnosticsEmptyChainAndUnresolvedDependencies() (gas: 6162)\n[PASS] testIndependentTieBreakLocksPrizesFeesAndNextRound() (gas: 6780695)\n[PASS] testProductionRejectsSimulationAndIncorrectGasLane() (gas: 150171)\n[PASS] testUnavailableInventoryDoesNotConsumeBudget() (gas: 5015857)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 129.03ms (5.75ms CPU time)\n\nRan 40 tests for test/Sorphera.t.sol:SorpheraTest\n[PASS] testApplicationSizeAndNoEscapeOpcodes() (gas: 17413995)\n[PASS] testBlackoutSlippageBudgetDeadlineAndFailedAcquireRollback() (gas: 4159147)\n[PASS] testBuilderAttributionOverpaymentAndPurchaserRewardsSeparated() (gas: 6036677)\n[PASS] testCallbackAuthenticationBindingDuplicateNoRerollOrCancellation() (gas: 4504947)\n[PASS] testCallbacksOutOfOrderAreBoundToSeparateGamesAndZeroWordValid() (gas: 10061082)\nLogs:\n  tie-break finalize gas: 224049\n\n[PASS] testCustodyBeforeDeadlineCountsEvenWhenReconciledAfter() (gas: 6169361)\nLogs:\n  tie-break finalize gas: 224049\n\n[PASS] testDelayedCashoutNFTGameRemainsIncidentalETHAndCancels() (gas: 4752977)\n[PASS] testETHForcedNFTCustodyIsReservedForWinners() (gas: 5853253)\n[PASS] testETHOneMatchFullPrizeAndOperatorReserve() (gas: 5844820)\n[PASS] testETHRolloverOldTicketsExpireCarryNeverSpent() (gas: 9174099)\n[PASS] testExpiredAcquisitionBlocksDrawUntilReconciled() (gas: 5284240)\n[PASS] testFactoryOnlyRegisteredLotteryCreatesVaults() (gas: 3461015)\n[PASS] testFixedETHSettlementEvenAfterExclusiveWindow() (gas: 4451218)\n[PASS] testForcedDeliveryAfterDeadlineStillCancels() (gas: 5061080)\n[PASS] testFuzzConservationAfterFWAChargesCashoutAndLateFunds(uint8,uint64) (runs: 256, μ: 6869508, ~: 6480146)\nLogs:\n  Bound result 3\n\n[PASS] testFuzzConservationUnusedBudget(uint8,uint64) (runs: 256, μ: 6767896, ~: 5949290)\nLogs:\n  Bound result 51\n\n[PASS] testFuzzSamplingRangeDistinctAndReplay(uint256) (runs: 256, μ: 33232, ~: 33276)\n[PASS] testLargeSalesConstantFinalizationAndPartialLargeInventory() (gas: 187917463)\nLogs:\n  draw finalize gas, 2000 tickets / 104 NFTs: 138634\n  tie-break finalize gas: 224049\n\n[PASS] testLateAllocationAfterCancellationSettlesToDivisibleETHRefund() (gas: 5238234)\n[PASS] testLateETHRecoveryGoesToOriginalWinnerNotNextRound() (gas: 8060968)\n[PASS] testLateNFTDoesNotRescueCancelledRoundAndSharedRecovery() (gas: 5469308)\n[PASS] testMultipleETHMatchesDuplicatesAndRounding() (gas: 4907160)\n[PASS] testNFTCancellationFeesPartialRefundAndLateRecovery() (gas: 5243476)\n[PASS] testNFTFeeReserveCannotBeWithdrawnUntilSuccess() (gas: 6029694)\nLogs:\n  tie-break finalize gas: 224049\n\n[PASS] testNFTOneWinnerAllAssetsAndFunds() (gas: 7870845)\n[PASS] testNFTRolloverInventoryAndResidualCannotRespin() (gas: 10027365)\n[PASS] testNFTTieBreakIncludesEveryDuplicateAndIsDomainSeparated() (gas: 7002333)\n[PASS] testNFTTransferFailuresAreIsolatedAndRetryable() (gas: 7401769)\n[PASS] testNoLateEntryAndBoundedTickets() (gas: 3535951)\n[PASS] testPermanentlyStuckNFTNeverFreezesETHGameAndLateRecoveryFollowsWinner() (gas: 9509260)\n[PASS] testRejectedETHAndReentrancyRetainLiabilities() (gas: 4872276)\n[PASS] testRewardHelperFailureRollsBackAllowanceAndClaims() (gas: 4972391)\n[PASS] testStartsDisabledUnconfiguredAndOwnerSettings() (gas: 5539745)\n[PASS] testStuckNFTCustodyRequiredAndRecoveryAfterWindow() (gas: 6705854)\n[PASS] testStuckOnlyNFTCancelsRoundAndLateRecoveryIsSharedByRefundCohort() (gas: 8716889)\n[PASS] testUnclaimedWinningsStayReservedAcrossNewRoundAndWithdrawals() (gas: 9236913)\n[PASS] testUnorderedNumbersIndexedNoTicketTransfer() (gas: 4010512)\n[PASS] testUnwithdrawnFWARefundPreventsDraw() (gas: 4681304)\n[PASS] testWeeklyGamesIndependentFreezeAndPauseClaims() (gas: 8411688)\n[PASS] testZeroTicketsSkipRandomnessAndSeparateGameDoesNotBlock() (gas: 9836119)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 129.19ms (552.32ms CPU time)\n\nRan 17 tests for test/SorpheraAdversarial.t.sol:SorpheraAdversarialTest\n[PASS] testBadCallbackShapeUnknownRequestAndFutureRulesCannotMutateActiveRound() (gas: 7770199)\n[PASS] testCancellationAccumulatesSubTicketLateRecoveriesWithoutFees() (gas: 4653514)\n[PASS] testDuplicateClaimIdsNeverMultiplyPayoutAndMixedOwnerBatchRollsBack() (gas: 4869145)\n[PASS] testEmptyAndOversizedMaintenanceAndClaimBatchesReject() (gas: 3765455)\n[PASS] testEmptyAndUnderpaidAndOverpaidSalesAreAtomic() (gas: 3496820)\n[PASS] testEveryCombinationHasUniqueKeyAndAllSixOrdersMatch() (gas: 354117209)\n[PASS] testForgedReceiptStampCannotRescueLateDeliveryAndDeadlineBoundaryIsStrict() (gas: 5492047)\n[PASS] testFuzzPriceEdgesKeepExactSplitAndFullBatchRefund(uint256,uint8) (runs: 1000, μ: 6052834, ~: 5067690)\nLogs:\n  Bound result 2595\n  Bound result 41\n\n[PASS] testFuzzReceiptTimeNotReconcileTimeDecidesCancellation(uint256,bool) (runs: 512, μ: 5245246, ~: 5309909)\nLogs:\n  Bound result 1715526\n\n[PASS] testInvalidTicketAtEndRollsBackEntireBatchAndBothAccounts() (gas: 8735804)\n[PASS] testMaximumTicketPriceFullBatchRefundsAllUnspentFunds() (gas: 11884810)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 100\n\n[PASS] testMinimumTicketPriceSingleEntryRefundsAllUnspentFunds() (gas: 4042211)\nLogs:\n  Bound result 1\n  Bound result 1\n\n[PASS] testNFTReceiverCannotReenterClaimAnotherAsset() (gas: 7070312)\n[PASS] testPauseBlocksSaleButPreservesPermissionlessSettlement() (gas: 6342559)\n[PASS] testSecondLotteryCannotValidateAgainstBoundFactoryOrCreateVaults() (gas: 8524550)\n[PASS] testStuckAssetRecoveredIntoRolledRoundJoinsCarryoverForNextWinnerOnly() (gas: 11493087)\n[PASS] testVaultPrivilegeAndCrossRoundRequestBoundaries() (gas: 7565053)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 271.22ms (561.93ms CPU time)\n\nRan 2 tests for test/SorpheraInvariant.t.sol:SorpheraInvariantTest\n[PASS]\nSorpheraInvariantTest invariants:\n[PASS] invariant_externalFlowsConserveETH\n[PASS] invariant_gameAssetsNeverCrossSubsidize\n[PASS] invariant_liabilitiesEqualReservedFeesCashAndUnpaidTickets\n[PASS] invariant_purchaserAndBuilderTokensStayConserved\n[PASS] invariant_roundOutcomesFollowFixedRules\n[PASS] invariant_vaultRequestsAndCustodyRemainBacked\n SorpheraInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭-----------------+-----------------+-------+---------+----------╮\n| Contract        | Selector        | Calls | Reverts | Discards |\n+================================================================+\n| SorpheraHandler | acquire         | 1013  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | advance         | 986   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | builderReward   | 1079  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | buy             | 2067  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | claim           | 1001  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | claimNFT        | 980   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | forceSettlement | 1021  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | pause           | 1077  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | queueTokens     | 1033  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | receiveTokens   | 1021  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | recoverStuck    | 1036  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | resolve         | 1012  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | rewardEpoch     | 1039  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | syncOrDonate    | 982   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | withdraw        | 1037  | 0       | 0        |\n╰-----------------+-----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 8\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 20000000000000000\n  Bound result 2\n  Bound result 20000000000000000\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 103\n  Bound result 1\n  Bound result 1\n  Bound result 101\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 10\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 95\n  Bound result 1\n  Bound result 1\n  Bound result 2663753875\n  Bound result 3\n  Bound result 1\n  Bound result 1\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 777\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 7056117010503631\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 6476347572076484054\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n\n[PASS] testHandlerPinnedLifecycleExercisesClaimsAndLateRecoveries() (gas: 15166352)\nLogs:\n  Bound result 0\n  Bound result 8\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 20000000000000000\n  Bound result 2\n  Bound result 20000000000000000\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 103\n  Bound result 1\n  Bound result 1\n  Bound result 101\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 17\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 4000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 8\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 1\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 12.90s (12.90s CPU time)\n\nRan 4 test suites in 12.90s (13.43s CPU time): 65 tests passed, 0 failed, 0 skipped (65 total tests)\n","passed":true},{"durationMs":46,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Sorphera.acceptOwner()\",\"Sorphera.buy(uint8,uint256,(uint8[3],uint8)[])\",\"Sorphera.claimETH(uint8,uint256,uint256[],address)\",\"Sorphera.close(uint8,uint256)\",\"Sorphera.configureRandomness((uint256,bytes32,uint16,uint32,bool))\",\"Sorphera.configureRules(uint8,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))\",\"Sorphera.credit(uint8,uint256)\",\"Sorphera.finalize(uint8,uint256)\",\"Sorphera.finalizeTieBreak(uint8,uint256)\",\"Sorphera.openRound(uint8)\",\"Sorphera.proposeOwner(address)\",\"Sorphera.rawFulfillRandomWords(uint256,uint256[])\",\"Sorphera.recordNFT(uint8,uint256,uint256)\",\"Sorphera.requestDraw(uint8,uint256)\",\"Sorphera.requestTieBreak(uint8,uint256)\",\"Sorphera.setSalesEnabled(bool)\",\"Sorphera.validateLaunch()\",\"Sorphera.withdrawOperator(address,uint256)\",\"SorpheraRouter.acceptOwner()\",\"SorpheraRouter.acquire(address,uint256,uint256,uint256,uint256,uint256)\",\"SorpheraRouter.claimBuilderRewards(address,address,uint256,uint256)\",\"SorpheraRouter.configure(address,address)\",\"SorpheraRouter.proposeOwner(address)\",\"SorpheraRouter.receive()\",\"SorpheraRouter.recoverBuilderAllowance(address,address)\",\"SorpheraVault.acquire(uint256,uint256)\",\"SorpheraVault.claimEpochRewards(uint256[])\",\"SorpheraVault.claimNFTs(uint256,uint256[],address)\",\"SorpheraVault.claimTokens(uint256,address,uint256)\",\"SorpheraVault.deliver(uint256,address)\",\"SorpheraVault.fund()\",\"SorpheraVault.onERC721Received(address,address,uint256,bytes)\",\"SorpheraVault.process(uint256)\",\"SorpheraVault.receive()\",\"SorpheraVault.reconcile(uint256[])\",\"SorpheraVault.recoverNFT(uint256)\",\"SorpheraVault.recoverRefund()\",\"SorpheraVault.settle(uint256)\",\"SorpheraVault.syncETH()\",\"SorpheraVaultFactory.acceptOwner()\",\"SorpheraVaultFactory.create(uint8,uint256,(uint256,uint256,uint256,uint256,uint256))\",\"SorpheraVaultFactory.proposeOwner(address)\",\"SorpheraVaultFactory.setLottery(address)\"],\"files\":{\".gitignore\":3,\"README.md\":90,\"deployments/config.schema.json\":168,\"deployments/fork.json\":13,\"deployments/mainnet.json\":28,\"deployments/mainnet.launch.json\":27,\"deployments/sepolia.json\":28,\"docs/DEPENDENCIES.md\":46,\"docs/DEPLOYMENT.md\":42,\"docs/MAINNET.md\":46,\"docs/OPERATIONS.md\":58,\"docs/REHEARSAL.md\":43,\"docs/TESTING.md\":66,\"docs/evidence/baseline.txt\":125,\"docs/evidence/build.txt\":834,\"docs/evidence/commands.json\":49,\"docs/evidence/compiler-settings.json\":8,\"docs/evidence/constructor-empty.txt\":31,\"docs/evidence/fmt-check.txt\":0,\"docs/evidence/gas-scaling.txt\":252,\"docs/evidence/imd-launch-961.json\":168,\"docs/evidence/imd-launch-capabilities.json\":144,\"docs/evidence/integration-fmt-check.txt\":0,\"docs/evidence/mainnet-builder-trace.txt\":853,\"docs/evidence/mainnet-fork.txt\":22,\"docs/evidence/offline-tests.txt\":134,\"docs/evidence/sepolia-fork-and-constructor.txt\":121,\"docs/reference/FWAV2.sepolia.abi.json\":1,\"docs/reference/FWAV2Rewards.sepolia.abi.json\":1,\"docs/reference/mainnet/buyback.runtime.hex\":1,\"docs/reference/mainnet/coordinator.abi.json\":1750,\"docs/reference/mainnet/coordinator.runtime.hex\":1,\"docs/reference/mainnet/floorOracle.abi.json\":1439,\"docs/reference/mainnet/floorOracle.runtime.hex\":1,\"docs/reference/mainnet/helper.abi.json\":591,\"docs/reference/mainnet/helper.runtime.hex\":1,\"docs/reference/mainnet/hook.abi.json\":1352,\"docs/reference/mainnet/hook.runtime.hex\":1,\"docs/reference/mainnet/notifier.runtime.hex\":1,\"docs/reference/mainnet/permit2.abi.json\":901,\"docs/reference/mainnet/permit2.runtime.hex\":1,\"docs/reference/mainnet/pool.abi.json\":2979,\"docs/reference/mainnet/pool.runtime.hex\":1,\"docs/reference/mainnet/poolManager.abi.json\":1366,\"docs/reference/mainnet/poolManager.runtime.hex\":1,\"docs/reference/mainnet/rewards.abi.json\":1623,\"docs/reference/mainnet/rewards.runtime.hex\":1,\"docs/reference/mainnet/service.runtime.hex\":1,\"docs/reference/mainnet/snapshot.json\":956,\"docs/reference/mainnet/source-bindings.json\":29,\"docs/reference/mainnet/token.abi.json\":1214,\"docs/reference/mainnet/token.runtime.hex\":1,\"docs/reference/sepolia-readback.json\":46,\"docs/reference/verification.json\":21,\"docs/validation.json\":91,\"foundry.toml\":20,\"frontend/README.md\":7,\"frontend/abi/Sorphera.json\":2110,\"frontend/abi/SorpheraRouter.json\":468,\"frontend/abi/SorpheraVault.json\":1020,\"frontend/abi/SorpheraVaultFactory.json\":245,\"frontend/bytecode-sizes.json\":18,\"frontend/configuration.json\":58,\"frontend/deployment.json\":29,\"integration/Sepolia.t.sol\":42,\"integration/mainnet/Mainnet.t.sol\":425,\"integration/rehearsal/Constructor.t.sol\":61,\"launch.json\":9,\"script/Operations.s.sol\":149,\"script/Rehearse.s.sol\":43,\"script/SepoliaCanary.s.sol\":32,\"src/Sorphera.sol\":635,\"src/SorpheraRouter.sol\":136,\"src/SorpheraVault.sol\":307,\"src/SorpheraVaultFactory.sol\":39,\"src/interfaces/External.sol\":126,\"src/lib/Balls.sol\":46,\"src/lib/Networks.sol\":23,\"src/lib/RewardTransfer.sol\":54,\"src/lib/Security.sol\":47,\"test/README.md\":7,\"test/Sorphera.t.sol\":988,\"test/SorpheraAdversarial.t.sol\":458,\"test/SorpheraHardening.t.sol\":150,\"test/SorpheraInvariant.t.sol\":666,\"test/helpers/SimulatedSorphera.sol\":14,\"test/helpers/SorpheraFixture.sol\":128,\"test/mocks/ExternalMocks.sol\":416,\"tools/export.py\":19,\"tools/preflight.py\":52,\"tools/read-only-rpc.py\":36,\"tools/snapshot-mainnet.py\":65},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":5876,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/SorpheraVault.sol:231: SorpheraVault._sync() (src/SorpheraVault.sol#231-239) sends eth to arbitrary user\n[medium/medium] divide-before-multiply at src/Sorphera.sol:548: Sorphera._distribute(uint8,uint256) (src/Sorphera.sol#548-560) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/Sorphera.sol:376: Sorphera.isCancelled(uint8,uint256) (src/Sorphera.sol#376-378) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Sorphera.sol:548: Sorphera._distribute(uint8,uint256) (src/Sorphera.sol#548-560) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/Sorphera.sol:381: Reentrancy in Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#381-406):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:209: Reentrancy in SorpheraVault.recoverNFT(uint256) (src/SorpheraVault.sol#209-215):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:170: Reentrancy in SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207):\n[medium/medium] reentrancy-no-eth at src/Sorphera.sol:381: Reentrancy in Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#381-406):\n[medium/medium] reentrancy-no-eth at src/Sorphera.sol:277: Reentrancy in Sorphera.openRound(uint8) (src/Sorphera.sol#277-314):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:142: Reentrancy in SorpheraVault.settle(uint256) (src/SorpheraVault.sol#142-156):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:259: Reentrancy in SorpheraVault.claimNFTs(uint256,uint256[],address) (src/SorpheraVault.sol#259-288):\n[medium/medium] uninitialized-local at src/Sorphera.sol:591: Sorphera.claimETH(uint8,uint256,uint256[],address).amount (src/Sorphera.sol#591) is a local variable never initialized\n[medium/medium] uninitialized-local at src/SorpheraVault.sol:180: SorpheraVault._reconcile(uint256).held (src/SorpheraVault.sol#180) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Sorphera.sol:264: Sorphera._checkFunding(Sorphera.RandomConfig).present (src/Sorphera.sol#264) is a local variable never initialized\n[medium/medium] unused-return at src/SorpheraVault.sol:241: SorpheraVault.claimEpochRewards(uint256[]) (src/SorpheraVault.sol#241-246) ignores return value by rewards.claimEpochTokens(epochs) (src/SorpheraVault.sol#244)\n[medium/medium] unused-return at src/SorpheraVault.sol:158: SorpheraVault.process(uint256) (src/SorpheraVault.sol#158-161) ignores return value by pool.processAcquisitions(count) (src/SorpheraVault.sol#160)\n[medium/medium] unused-return at src/Sorphera.sol:241: Sorphera._validateNetwork(Sorphera.RandomConfig) (src/Sorphera.sol#241-253) ignores return value by (active,None) = coordinator.s_provingKeys(c.keyHash) (src/Sorphera.sol#244)\n[medium/medium] unused-return at src/Sorphera.sol:241: Sorphera._validateNetwork(Sorphera.RandomConfig) (src/Sorphera.sol#241-253) ignores return value by (minimumConfirmations,maximumGas,None,None,None,None,None,None,None) = coordinator.s_config() (src/Sorphera.sol#245)\n[medium/medium] unused-return at src/SorpheraRouter.sol:129: SorpheraRouter.recoverBuilderAllowance(address,address) (src/SorpheraRouter.sol#129-134) ignores return value by IRewards(rewardsForPool[p]).withdrawTokenBuyAllowanceAsETH() (src/SorpheraRouter.sol#132)\n[medium/medium] unused-return at src/Sorphera.sol:259: Sorphera._checkFunding(Sorphera.RandomConfig) (src/Sorphera.sol#259-269) ignores return value by (link,nativeBalance,None,None,consumers) = coordinator.getSubscription(c.subscription) (src/Sorphera.sol#261-262)\n[medium/medium] unused-return at src/SorpheraVault.sol:221: SorpheraVault.recoverRefund() (src/SorpheraVault.sol#221-225) ignores return value by pool.withdrawAcquisitionRefund() (src/SorpheraVault.sol#223)\n[low/medium] events-maths at src/SorpheraVault.sol:101: SorpheraVault.fund() (src/SorpheraVault.sol#101-103) should emit an event for: \n[low/medium] missing-zero-check at src/SorpheraVault.sol:80: SorpheraVault.constructor(address,SorpheraRouter,uint8,uint256,SorpheraVault.Settings).lottery_ (src/SorpheraVault.sol#80) lacks a zero-check on :\n[low/medium] calls-loop at src/SorpheraVault.sol:170: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207) has external calls inside a loop: ISorphera(lottery).recordNFT(game,round,securedAt) (src/SorpheraVault.sol#191)\n[low/medium] calls-loop at src/SorpheraVault.sol:170: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207) has external calls inside a loop: l = pool.listings(a.listingId) (src/SorpheraVault.sol#176)\n[low/medium] calls-loop at src/SorpheraVault.sol:105: SorpheraVault.acquire(uint256,uint256) (src/SorpheraVault.sol#105-137) has external calls inside a loop: acquisition = pool.acquisitions(ids[i]) (src/SorpheraVault.sol#130)\n[low/medium] calls-loop at src/SorpheraVault.sol:259: SorpheraVault.claimNFTs(uint256,uint256[],address) (src/SorpheraVault.sol#259-288) has external calls inside a loop: this.deliver{gas: 500000}(index,recipient) (src/SorpheraVault.sol#281-286)\n[low/medium] calls-loop at src/SorpheraVault.sol:170: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207) has external calls inside a loop: a = pool.acquisitions(id) (src/SorpheraVault.sol#172)\n[low/medium] calls-loop at src/SorpheraVault.sol:170: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207) has external calls inside a loop: pool.stuckNFTRecipient(a.listingId) == address(this) (src/SorpheraVault.sol#193)\n[low/medium] calls-loop at src/SorpheraVault.sol:170: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207) has external calls inside a loop: holder = IERC721(l.collection).ownerOf(l.tokenId) (src/SorpheraVault.sol#181-183)\n[low/medium] reentrancy-benign at src/SorpheraVault.sol:170: Reentrancy in SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207):\n[low/medium] reentrancy-benign at src/SorpheraVault.sol:105: Reentrancy in SorpheraVault.acquire(uint256,uint256) (src/SorpheraVault.sol#105-137):\n[low/medium] reentrancy-benign at src/Sorphera.sol:408: Reentrancy in Sorphera._request(uint8,uint256,bool) (src/Sorphera.sol#408-423):\n[low/medium] reentrancy-benign at src/Sorphera.sol:277: Reentrancy in Sorphera.openRound(uint8) (src/Sorphera.sol#277-314):\n[low/medium] reentrancy-benign at src/Sorphera.sol:381: Reentrancy in Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#381-406):\n[low/medium] timestamp at src/SorpheraVault.sol:105: SorpheraVault.acquire(uint256,uint256) (src/SorpheraVault.sol#105-137) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:354: Sorphera.credit(uint8,uint256) (src/Sorphera.sol#354-362) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:434: Sorphera.rawFulfillRandomWords(uint256,uint256[]) (src/Sorphera.sol#434-453) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:316: Sorphera.buy(uint8,uint256,Sorphera.Pick[]) (src/Sorphera.sol#316-340) uses timestamp for comparisons\n[low/medium] timestamp at src/SorpheraRouter.sol:113: SorpheraRouter.claimBuilderRewards(address,address,uint256,uint256) (src/SorpheraRouter.sol#113-127) uses timestamp for comparisons\n[low/medium] timestamp at src/SorpheraVault.sol:170: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#170-207) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:277: Sorphera.openRound(uint8) (src/Sorphera.sol#277-314) uses timestamp for comparisons\n[low/medium] timestamp at src/SorpheraVault.sol:231: SorpheraVault._sync() (src/SorpheraVault.sol#231-239) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:347: Sorphera.close(uint8,uint256) (src/Sorphera.sol#347-352) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:376: Sorphera.isCancelled(uint8,uint256) (src/Sorphera.sol#376-378) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:366: Sorphera.recordNFT(uint8,uint256,uint256) (src/Sorphera.sol#366-374) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:548: Sorphera._distribute(uint8,uint256) (src/Sorphera.sol#548-560) uses timestamp for comparisons\n[low/medium] timestamp at src/SorpheraRouter.sol:91: SorpheraRouter.acquire(address,uint256,uint256,uint256,uint256,uint256) (src/SorpheraRouter.sol#91-111) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:342: Sorphera.acquisitionOpen(uint8,uint256) (src/Sorphera.sol#342-345) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:496: Sorphera.finalizeTieBreak(uint8,uint256) (src/Sorphera.sol#496-507) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:459: Sorphera.finalize(uint8,uint256) (src/Sorphera.sol#459-476) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:562: Sorphera.entitlement(uint8,uint256,uint256,address) (src/Sorphera.sol#562-582) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:426: Sorphera.requestTieBreak(uint8,uint256) (src/Sorphera.sol#426-432) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:381: Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#381-406) uses timestamp for comparisons","passed":true},{"durationMs":351,"exitCode":0,"name":"aderyn","output":"[high] contract-locks-ether at src/SorpheraVault.sol:10: Contract locks Ether without a withdraw function\n[high] reentrancy-state-change at src/Sorphera.sol:233: Reentrancy: State change after external call (25 places)\n[high] storage-array-memory-edit at src/Sorphera.sol:232: Storage Array Edited with Memory (4 places)\n[low] centralization-risk at src/Sorphera.sol:12: Centralization Risk (12 places)\n[low] costly-loop at src/Sorphera.sol:332: Costly operations inside loop (5 places)\n[low] large-numeric-literal at src/Sorphera.sol:221: Large Numeric Literal (2 places)\n[low] literal-instead-of-constant at src/Sorphera.sol:202: Literal Instead of Constant (13 places)\n[low] modifier-used-only-once at src/SorpheraVault.sol:96: Modifier Invoked Only Once\n[low] non-reentrant-not-first at src/Sorphera.sol:604: `nonReentrant` is Not the First Modifier (3 places)\n[low] require-revert-in-loop at src/Sorphera.sol:332: Loop Contains `require`/`revert` (5 places)\n[low] state-change-without-event at src/SorpheraRouter.sol:129: State Change Without Event (4 places)\n[low] unchecked-return at src/Sorphera.sol:593: Unchecked Return (5 places)\n[low] uninitialized-local-variable at src/Sorphera.sol:265: Uninitialized Local Variable (4 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"54c88f5217b7c46bef940d8aac425bad59b6d70e66710e18be95fe86c6e25401","verifiedTreeHash":"aeab25608608f7786b37314529eeec51c4c3982c","verifierVersion":"0.1.0+ad90ce4c"}]}