{"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":"b99b441b-44dd-4aa7-b7da-cc88c49b8f49","kind":"skill:build-contract-project","nodes":[{"acceptedSubmissionHash":"41f5e4c2f5006f82f2eb08c22883d4130ffe5cd5fbed54601549d58d057e5119","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","state":"accepted"}],"objective":"CONTRACTS: Sorphera Passport - buy 12 paid tickets, earn 1 free\n\nContinue the EXISTING project:\nhttps://github.com/identity-md-launches/launch-961-build-sorphera-smart-contracts\nStart from latest main after PR #8; preserve newer work.\nRead docs/PASSPORT-HANDOFF.md and current contracts/tests. These rules settle its finality/refund questions.\n\nONE Contracts task: implement/test rewards, regenerate interfaces and provide a handoff. No website work. Never import simulated browser Passport data as real entitlements.\n\n1. PRODUCT RULES\n\nOne qualifying paid ticket earns one stamp. Every 12 stamps earns one free entry. Carry remainders across purchases, weeks and ETH/NFT games. No expiry, weekly cap, enrollment, NFT, token, tier, streak or transferable rewards.\n\nUse one positive, immutable qualifying ticket price set for the deployment; local fixtures use 0.005 ETH. Production price remains a pre-deployment owner input. Earning/redemption requires the round's frozen price to equal it. Other-priced rounds are ineligible; cheap purchases cannot earn expensive entries. No later admin repricing of rewards.\n\nOnly fully paid eligible tickets count; rewards earn no stamps. No admin mint or discretionary grants. Transaction splitting cannot change rewards; wallet splitting cannot increase them.\n\nBoundaries: 11+1 => 1 reward/0 stamps; 11+3 => 1/2; 24 => 2/0. Redemption leaves carried stamps intact.\n\n2. FINALITY WITHOUT REWARD DEBT\n\nPaid purchases remain pending until THEIR OWN round reaches Won or Rolled. For this version, cutoff, block confirmations, an accepted VRF request or an unfinished NFT tie-break are insufficient. Cancelled/refunded rounds earn zero. A Rolled round counts once; its old tickets do not enter later draws. Indefinitely pending rounds stay pending for rewards.\n\nCredit each wallet/game/round at most once through bounded, idempotent finalization. Permissionless processing may credit only the rightful wallet. Never iterate every player or an entire wallet history. Allow bounded finalization alongside redemption where practical to avoid requiring a separate user transaction.\n\nDerive rewards/remainders from cumulative finalized paid counts, independent of processing order. Never trust client counts or add refund clawbacks/reward debt. Preserve oracle policy.\n\n3. REDEMPTION\n\nOne earned reward creates one zero-entry-price ticket in a qualifying open ETH or NFT round. No additional purchase is required; gas still applies. Support free-only redemption and an atomic mixed paid/reward batch matching the existing basket. Preserve ordinary paid-buy compatibility where practical.\n\nValidate balance, owner, picks, game/round, chain, sales pause, start and strict block.timestamp < cutoff, with existing relevant launch/dependency guards. Reverts preserve state. Consume credit atomically; prevent overspending, replay, reentrancy and double processing. Helpers must not own player tickets. Avoid delegated signatures.\n\nFree entries join the same matching index and have equal winning-number eligibility, ETH share per matching ticket, NFT tie-break chance and winner claim rights. Retain duplicate combinations, unique IDs across all entries, independent NFT tie randomness and immutable accepted requests.\n\n4. ACCOUNTING AND CANCELLATION\n\nTrack paid, reward and total entries separately. Trace all uses of sold, zero-ticket checks and denominators; do not globally substitute paid counts for total entries.\n\nKeep fees at 10% of actual paid ETH and the 90% acquisition allocation. Free entries create no revenue, fees, budget or extra FWA pulls. No treasury subsidy or fixed cash-value promise. Charge only paid entries. Free-only batches pay zero; do not fake funding to pass vault checks.\n\nCRITICAL: _cancel currently uses r.sold as its refund divisor, and entitlement is shared by ETH, FWA token and exceptional NFT claims. Merely inserting free tickets would dilute paid refunds and allocate them cancellation proceeds.\n\nSeparate winning eligibility from cancellation eligibility:\n- Won: paid/reward winning tickets share normal prize rights, including existing associated FWA token and late-asset entitlements.\n- Cancelled: only the entitled PAID-ticket cohort shares the recovery pool. Reward tickets get NO cancellation cash, FWA tokens, late-recovery shares or exceptional NFT release votes.\n- Restore each reward redeemed in a cancelled round exactly once to its original owner. Restoration earns no stamp and leaves no active entry. Losing/rolled-over entries are not restored; no ticket may both win and regain its reward.\n\nHandle reward-only rounds, zero paid refund recipients, carryover, dust and late ETH/token/NFT arrivals without division by zero, orphaned funds, unpaid liabilities or operator windfalls. Preserve legitimate group/origin-round rights. Where zero-recipient recovery requires routing, implement/document same-game carry-forward for this new deployment, including later recoveries; no owner sweep.\n\nUpdate liabilities, claims, vault/helper denominators and events consistently. Cancellation payouts remain shares of actual recoveries, not a new guaranteed full-price refund. State and test the invariants.\n\n5. INTERFACES AND HANDOFF\n\nExpose authoritative views/events for qualifying price, paid/reward/total counts, wallet pending/finalized credit, stamps, available rewards, processed rounds, redemptions and restorations. Use bounded views/indexed events, not unbounded history scans. Distinguish paid purchases from reward issuance; include owner/game/round/ticket.\n\nSupply example reads/calls for finalization, redemption and restoration, with confirmation/reorg handling. Optimistic UI state is not spendable authority.\n\nRegenerate canonical ABIs using the permitted workflow. Document compatibility/deployment changes and required hash regeneration; never falsify protected release hashes or activate the existing site's writes. UI wiring is a later Website task.\n\nUpdate PASSPORT-HANDOFF.md with rules, accounting, ABI changes and customer-copy implications: \"Rewards become available after the qualifying round completes. A cancelled reward entry returns your free ticket.\"\n\n6. VERIFICATION\n\nAdd meaningful unit, fuzz/invariant and integration coverage:\n- Thresholds/remainders, batch/order equivalence, mixed games, price exclusion.\n- Pending/Won/Rolled/Cancelled finality, duplicate finalization, wallet isolation.\n- Free-only/mixed batches, cutoff/pause, invalid picks, insufficient credits, reentrancy and failure rollback.\n- Paid/reward winners and NFT ties; no recursive stamp earning.\n- One-time cancellation restoration; no free-ticket recovery/voting rights.\n- Zero paid recipients, carryover and late ETH/token/NFT recoveries.\n- Bounded gas as history grows; rewards/liabilities cannot be inflated.\nInclude a regression exposing the all-ticket refund-divisor error when free entries are introduced.\n\nRun build/format/contract suites and relevant fork/tooling regressions. Pin inputs; distinguish simulated callback","parentJobId":"204f31bc-a49e-463b-9843-bc0853dbbbd4","planHash":"80e5b307e46b89583be20d02010523ce336398ab9fd1b20a19add0923232ed82","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":"52678","feedbackHash":"e75aac488aea97b0867d707c1109795e9e2722ffed83b68caaa67d05b6199365","nodeKey":"build_contract_project","submissionHash":"41f5e4c2f5006f82f2eb08c22883d4130ffe5cd5fbed54601549d58d057e5119","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"e8c106973460ae58bcfa2e41d48120afc80873e2e50313b74c40c922f8560d87","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"ec4014a98e5aa1719508d4c53d15bf52aa1347ebb7d55a6b8d7ea1934f01934c","device":"96eeb8eb2acdbbf1","findings":[],"hash":"41f5e4c2f5006f82f2eb08c22883d4130ffe5cd5fbed54601549d58d057e5119","nodeId":"d5813c3b-b48d-452f-9e33-6907a5f28eef","outcome":"completed","summary":"The work is complete and verified. Summary:\n\n**What was built**\n\n- **New `src/SorpheraPassport.sol`** (no owner, 4.6 KB). It derives all credit from the lottery's own per-wallet counts: one stamp per paid ticket once *that* round is Won or Rolled, 12 stamps per reward, remainders carried across purchases, weeks and both games. `process(wallet, keys[])` is permissionless, bounded to 50 rounds and idempotent. `enter(game, round, picks, rewards, finalizeFirst)` does free-only, mixed or plain paid batches atomically, optionally finalizing the caller's terminal rounds in the same transaction. Rewards redeemed into a cancelled round are restored exactly once and earn nothing. The qualifying price is an immutable constructor argument.\n- **`src/Sorphera.sol` changes.** `buy` is unchanged and now shares `_enter` with a passport-only `enter(player, ...)`. `Round` gained `paidEntries`/`rewardEntries` while `sold` stays the total entry count for matching and draw checks. `Ticket` gained a `reward` flag. `entitlement` rejects reward tickets in cancelled rounds, so they get no refund cash, FWA tokens or NFT release votes. `_cancel` now divides by the paid cohort instead of `sold`, and a zero-paid cancelled group carries any cash forward to the game's current group rather than dividing by zero or sweeping to the owner. `setPassport` binds the Passport once.\n- **Size constraint.** Sorphera is at 24,366 bytes against the 24,576 EIP-170 limit, which is why the rewards logic lives in a satellite contract and the lottery exposes only the minimal counters.\n\n**Verification**\n\n| Check | Result |\n| --- | --- |\n| `forge build` | passes |\n| `forge fmt --check` | passes |\n| `forge test` with the verifier's fuzz seed | 103 tests, 0 failures |\n\nThe new `test/SorpheraPassport.t.sol` has 27 tests (including a 256-run fuzz for batch/order equivalence) covering thresholds, finality states, wallet isolation, price exclusion, redemption failures with rollback, paid and reward winners sharing ETH, a reward ticket winning an NFT tie-break, one-time restoration, and the refund-divisor regression. `test/SorpheraPassportInvariant.t.sol` adds two stateful properties over 2,560 handler calls. Fork and integration suites were not re-run because there is no network here; they exercise `buy`, whose behaviour is unchanged.\n\n**Documentation and artifacts**\n\n- `docs/PASSPORT-HANDOFF.md` is rewritten with the rules, accounting, invariants, full ABI change list, example reads and calls with confirmation handling, deployment steps and the required customer copy.\n- ABIs were regenerated with `tools/export.py` (now also exporting `SorpheraPassport.json`); README, `frontend/README.md`, `frontend/configuration.json`, `test/README.md` and `docs/TESTING.md` were updated.\n\n**Open items for the requester**\n\n- The production qualifying price is an owner input decided before deployment.\n- `launch.json` was deliberately left untouched. The manifest step must add `SorpheraPassport` with `[\"$contract:Sorphera\", <priceWei>]`, and the owner must call `setPassport` after deployment.\n- Protected release hashes must be regenerated by the release process because the Sorphera bytecode changed. Nothing here activates the site's writes; UI wiring is a later Website task.","treeHash":"cdaa264cc22d6d3f52ac840d87dd051fd0fe8c59","usage":{"cachedInputTokens":2993646,"inputTokens":770,"model":"claude-fable-5-1","outputTokens":85504,"runtime":"claude","turns":50,"wallClockMs":2345923}}],"verification":[{"checks":[{"durationMs":124701,"exitCode":0,"name":"build","output":"Compiling 45 files with Solc 0.8.26\nSolc 0.8.26 finished in 124.62s\nCompiler run successful with warnings:\nWarning (8760): This declaration has the same name as another declaration.\n   --> src/SorpheraPassport.sol:155:13:\n    |\n155 |             uint256 stamps,\n    |             ^^^^^^^^^^^^^^\nNote: The other declaration is here:\n   --> src/SorpheraPassport.sol:177:5:\n    |\n177 |     function stamps(address wallet) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/helpers/SorpheraFixture.sol:104:9:\n    |\n104 |         uint256 rewards,\n    |         ^^^^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> test/helpers/SorpheraFixture.sol:29:5:\n   |\n29 |     MockRewards internal rewards;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/SorpheraPassport.t.sol:66:33:\n   |\n66 |     function _earn(address who, uint256 n) internal returns (uint256 id) {\n   |                                 ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:150:10:\n    |\n150 |         (uint256 n, SorpheraVault v) = _openNFT();\n    |          ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:169:10:\n    |\n169 |         (uint256 n, SorpheraVault v) = _openNFT();\n    |          ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:189:46:\n    |\n189 |     function _repeat(Sorphera.Pick memory p, uint256 n) internal pure returns (Sorphera.Pick[] memory picks) {\n    |                                              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:460:10:\n    |\n460 |         (uint256 n, SorpheraVault v) = _openNFT();\n    |          ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\n","passed":true},{"durationMs":14226,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 8 tests for test/SorpheraReviewRegression.t.sol:SorpheraReviewRegressionTest\n[PASS] testFrozenReserveRejectsRequestBeforeAcceptanceThenTopupAllowsSameRound() (gas: 5262030)\n[PASS] testHostileOwnerOfCannotExhaustCancellationSweepGas() (gas: 5186683)\n[PASS] testInsufficientCallbackGasIsBilledAndCannotReplaceAcceptedDraw() (gas: 4374598)\n[PASS] testLargePendingCancellationReviewCommitsBoundedProgress() (gas: 21198769)\n[PASS] testPermanentTieNonfulfillmentLocksUntilOriginalDelayedCallback() (gas: 6627071)\n[PASS] testPredeadlineCustodyInLastCancellationBatchPreservesDraw() (gas: 24103543)\n[PASS] testReservePermissionsCurrencyAndConsumerRecheckedBeforeRequest() (gas: 4446862)\n[PASS] testUnreconciledPredeadlineCustodyCannotBeFrontRunByCancellation() (gas: 5540005)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 189.67ms (12.70ms CPU time)\n\nRan 40 tests for test/Sorphera.t.sol:SorpheraTest\n[PASS] testApplicationSizeAndNoEscapeOpcodes() (gas: 18758562)\n[PASS] testBlackoutSlippageBudgetDeadlineAndFailedAcquireRollback() (gas: 4313410)\n[PASS] testBuilderAttributionOverpaymentAndPurchaserRewardsSeparated() (gas: 6209830)\n[PASS] testCallbackAuthenticationBindingDuplicateNoRerollOrCancellation() (gas: 4664381)\n[PASS] testCallbacksOutOfOrderAreBoundToSeparateGamesAndZeroWordValid() (gas: 10411891)\nLogs:\n  tie-break finalize gas: 224262\n\n[PASS] testCustodyBeforeDeadlineCountsEvenWhenReconciledAfter() (gas: 6361078)\nLogs:\n  tie-break finalize gas: 224262\n\n[PASS] testDelayedCashoutNFTGameRemainsIncidentalETHAndCancels() (gas: 4995724)\n[PASS] testETHForcedNFTCustodyIsReservedForWinners() (gas: 6026534)\n[PASS] testETHOneMatchFullPrizeAndOperatorReserve() (gas: 6055569)\n[PASS] testETHRolloverOldTicketsExpireCarryNeverSpent() (gas: 9525131)\n[PASS] testExpiredAcquisitionBlocksDrawUntilReconciled() (gas: 5457545)\n[PASS] testFactoryOnlyRegisteredLotteryCreatesVaults() (gas: 3564731)\n[PASS] testFixedETHSettlementEvenAfterExclusiveWindow() (gas: 4604870)\n[PASS] testForcedDeliveryAfterDeadlineStillCancels() (gas: 5305526)\n[PASS] testFuzzConservationAfterFWAChargesCashoutAndLateFunds(uint8,uint64) (runs: 256, μ: 7134205, ~: 6744673)\nLogs:\n  Bound result 13\n\n[PASS] testFuzzConservationUnusedBudget(uint8,uint64) (runs: 256, μ: 6937417, ~: 6152887)\nLogs:\n  Bound result 5\n\n[PASS] testFuzzSamplingRangeDistinctAndReplay(uint256) (runs: 256, μ: 33454, ~: 33499)\n[PASS] testLargeSalesConstantFinalizationAndPartialLargeInventory() (gas: 188655233)\nLogs:\n  draw finalize gas, 2000 tickets / 104 NFTs: 138860\n  tie-break finalize gas: 224262\n\n[PASS] testLateAllocationAfterCancellationSettlesToDivisibleETHRefund() (gas: 5490498)\n[PASS] testLateETHRecoveryGoesToOriginalWinnerNotNextRound() (gas: 8387603)\n[PASS] testLateNFTDoesNotRescueCancelledRoundAndSharedRecovery() (gas: 5741901)\n[PASS] testMultipleETHMatchesDuplicatesAndRounding() (gas: 5117369)\n[PASS] testNFTCancellationFeesPartialRefundAndLateRecovery() (gas: 5495758)\n[PASS] testNFTFeeReserveCannotBeWithdrawnUntilSuccess() (gas: 6208600)\nLogs:\n  tie-break finalize gas: 224262\n\n[PASS] testNFTOneWinnerAllAssetsAndFunds() (gas: 8087674)\n[PASS] testNFTRolloverInventoryAndResidualCannotRespin() (gas: 10378000)\n[PASS] testNFTTieBreakIncludesEveryDuplicateAndIsDomainSeparated() (gas: 7222931)\n[PASS] testNFTTransferFailuresAreIsolatedAndRetryable() (gas: 7590118)\n[PASS] testNoLateEntryAndBoundedTickets() (gas: 3642884)\n[PASS] testPermanentlyStuckNFTNeverFreezesETHGameAndLateRecoveryFollowsWinner() (gas: 9823764)\n[PASS] testRejectedETHAndReentrancyRetainLiabilities() (gas: 5045598)\n[PASS] testRewardHelperFailureRollsBackAllowanceAndClaims() (gas: 5125955)\n[PASS] testStartsDisabledUnconfiguredAndOwnerSettings() (gas: 6172885)\n[PASS] testStuckNFTCustodyRequiredAndRecoveryAfterWindow() (gas: 6902807)\n[PASS] testStuckOnlyNFTCancelsRoundAndLateRecoveryIsSharedByRefundCohort() (gas: 9069255)\n[PASS] testUnclaimedWinningsStayReservedAcrossNewRoundAndWithdrawals() (gas: 9583455)\n[PASS] testUnorderedNumbersIndexedNoTicketTransfer() (gas: 4176416)\n[PASS] testUnwithdrawnFWARefundPreventsDraw() (gas: 4840414)\n[PASS] testWeeklyGamesIndependentFreezeAndPauseClaims() (gas: 8752238)\n[PASS] testZeroTicketsSkipRandomnessAndSeparateGameDoesNotBlock() (gas: 10156301)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 189.86ms (547.59ms CPU time)\n\nRan 6 tests for test/SorpheraHardening.t.sol:SorpheraHardeningTest\n[PASS] testChangedChainStopsSalesAndRequests() (gas: 3961458)\n[PASS] testChangedHelperPermissionsStopNewRiskButPreserveCashClaims() (gas: 5104556)\n[PASS] testConstructorDiagnosticsEmptyChainAndUnresolvedDependencies() (gas: 6162)\n[PASS] testIndependentTieBreakLocksPrizesFeesAndNextRound() (gas: 6981909)\n[PASS] testProductionRejectsSimulationAndIncorrectGasLane() (gas: 150346)\n[PASS] testUnavailableInventoryDoesNotConsumeBudget() (gas: 5189775)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 189.91ms (4.72ms CPU time)\n\nRan 17 tests for test/SorpheraAdversarial.t.sol:SorpheraAdversarialTest\n[PASS] testBadCallbackShapeUnknownRequestAndFutureRulesCannotMutateActiveRound() (gas: 8055888)\n[PASS] testCancellationAccumulatesSubTicketLateRecoveriesWithoutFees() (gas: 4837724)\n[PASS] testDuplicateClaimIdsNeverMultiplyPayoutAndMixedOwnerBatchRollsBack() (gas: 5075052)\n[PASS] testEmptyAndOversizedMaintenanceAndClaimBatchesReject() (gas: 3869975)\n[PASS] testEmptyAndUnderpaidAndOverpaidSalesAreAtomic() (gas: 3605994)\n[PASS] testEveryCombinationHasUniqueKeyAndAllSixOrdersMatch() (gas: 356135009)\n[PASS] testForgedReceiptStampCannotRescueLateDeliveryAndDeadlineBoundaryIsStrict() (gas: 5737200)\n[PASS] testFuzzPriceEdgesKeepExactSplitAndFullBatchRefund(uint256,uint8) (runs: 1000, μ: 6393735, ~: 5419494)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 2\n\n[PASS] testFuzzReceiptTimeNotReconcileTimeDecidesCancellation(uint256,bool) (runs: 512, μ: 5449265, ~: 5487086)\nLogs:\n  Bound result 1614038\n\n[PASS] testInvalidTicketAtEndRollsBackEntireBatchAndBothAccounts() (gas: 8811512)\n[PASS] testMaximumTicketPriceFullBatchRefundsAllUnspentFunds() (gas: 12089766)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 100\n\n[PASS] testMinimumTicketPriceSingleEntryRefundsAllUnspentFunds() (gas: 4233456)\nLogs:\n  Bound result 1\n  Bound result 1\n\n[PASS] testNFTReceiverCannotReenterClaimAnotherAsset() (gas: 7281265)\n[PASS] testPauseBlocksSaleButPreservesPermissionlessSettlement() (gas: 6530984)\n[PASS] testSecondLotteryCannotValidateAgainstBoundFactoryOrCreateVaults() (gas: 9250774)\n[PASS] testStuckAssetRecoveredIntoRolledRoundJoinsCarryoverForNextWinnerOnly() (gas: 11863070)\n[PASS] testVaultPrivilegeAndCrossRoundRequestBoundaries() (gas: 7823251)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 289.49ms (691.08ms CPU time)\n\nRan 27 tests for test/SorpheraPassport.t.sol:SorpheraPassportTest\n[PASS] testCancellationDividesRecoveryAmongPaidEntriesOnly() (gas: 14298204)\n[PASS] testCancelledRewardIsRestoredExactlyOnceWithoutStamps() (gas: 21566922)\n[PASS] testCancelledRoundEarnsNothing() (gas: 4729069)\n[PASS] testContractWalletCannotOverspendThroughNestedRedemption() (gas: 10190838)\n[PASS] testFinalizationAlongsideRedemptionInOneTransaction() (gas: 9017906)\n[PASS] testFreeOnlyRedemptionCreatesOwnedZeroPriceTickets() (gas: 9901310)\n[PASS] testFuzzBatchAndOrderEquivalence(uint8,uint8,uint8,uint8) (runs: 256, μ: 15134522, ~: 15232973)\nLogs:\n  Bound result 30\n  Bound result 22\n  Bound result 4\n\n[PASS] testLosingAndWinningRewardEntriesAreNotRestored() (gas: 14284784)\n[PASS] testMixedBatchChargesOnlyPaidEntries() (gas: 9421161)\n[PASS] testMixedGamesShareOneCounter() (gas: 14415998)\n[PASS] testOnlyThePassportCanIssueRewardEntries() (gas: 3523147)\n[PASS] testOtherPriceRoundsEarnNothingAndRefuseRewards() (gas: 15323747)\n[PASS] testPendingUntilOwnRoundIsWonOrRolled() (gas: 5673249)\n[PASS] testProcessingCreditsOnlyTheNamedWalletFromItsOwnEntries() (gas: 5455297)\n[PASS] testProcessingGasDoesNotGrowWithHistory() (gas: 32352221)\n[PASS] testRedemptionFailuresPreserveCredit() (gas: 11063134)\n[PASS] testRewardAndPaidWinnersShareETHEqually() (gas: 11308139)\n[PASS] testRewardOnlyCancelledRoundHasNoDivisionByZeroAndCarriesRecoveries() (gas: 16530047)\n[PASS] testRewardOnlyRoundStillDrawsAndRolls() (gas: 9923067)\n[PASS] testRewardTicketCanWinNFTTieBreakAndClaim() (gas: 15703090)\n[PASS] testRewardTicketHasNoTokenOrNFTRecoveryRights() (gas: 14926836)\n[PASS] testRewardsCannotBeInflatedByRepeatedProcessingOrSelfCalls() (gas: 9374627)\n[PASS] testThresholdsAndRemainders() (gas: 19604006)\n[PASS] testUnboundLotteryRefusesRewardEntriesUntilConfigured() (gas: 5600770)\n[PASS] testUnknownGameOrRoundIsIgnored() (gas: 173745)\n[PASS] testWalletSplittingCannotIncreaseRewards() (gas: 5670194)\n[PASS] testWonRoundCreditsStampsOnce() (gas: 5370891)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 289.55ms (231.88ms CPU time)\n\nRan 2 tests for test/SepoliaCanary.t.sol:SepoliaCanaryTest\n[PASS] testControlledDependenciesAndNoPublicSalesWindow() (gas: 4146881)\n[PASS] testFullCoverageTwoGamesDelayedDrawAndIndependentTieClaims() (gas: 10760653)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 611.79ms (610.97ms CPU time)\n\nRan 1 test for test/SorpheraPassportInvariant.t.sol:SorpheraPassportInvariantTest\n[PASS]\nSorpheraPassportInvariantTest invariants:\n[PASS] invariant_passportCreditIsBoundedByFinalizedPaidTickets\n[PASS] invariant_rewardEntriesCreateNoLiabilityAndFundsConserve\n SorpheraPassportInvariantTest invariants (runs: 64, calls: 2560, reverts: 56)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| PassportHandler | buy      | 650   | 56      | 0        |\n|-----------------+----------+-------+---------+----------|\n| PassportHandler | finish   | 603   | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| PassportHandler | process  | 660   | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| PassportHandler | redeem   | 647   | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 3\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 10\n  Bound result 2\n  Bound result 14\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 4\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 0\n  Bound result 3\n  Bound result 4\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 14\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 9\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.32s (1.32s 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         | 1049  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | advance         | 1035  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | builderReward   | 991   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | buy             | 2010  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | claim           | 984   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | claimNFT        | 1052  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | forceSettlement | 1038  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | pause           | 1007  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | queueTokens     | 1025  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | receiveTokens   | 964   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | recoverStuck    | 1041  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | resolve         | 1033  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | rewardEpoch     | 1037  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | syncOrDonate    | 1047  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | withdraw        | 1071  | 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 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 8\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 99999999999999999998\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 2\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 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 0\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 1\n  Bound result 1\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  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 3\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 1\n\n[PASS] testHandlerPinnedLifecycleExercisesClaimsAndLateRecoveries() (gas: 15801613)\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 14.14s (14.14s CPU time)\n\nRan 8 test suites in 14.14s (17.22s CPU time): 103 tests passed, 0 failed, 0 skipped (103 total tests)\n","passed":true},{"durationMs":239,"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.configureVRFReserve(uint96,uint96)\",\"Sorphera.credit(uint8,uint256)\",\"Sorphera.enter(address,uint8,uint256,(uint8[3],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.setPassport(address)\",\"Sorphera.setSalesEnabled(bool)\",\"Sorphera.validateLaunch()\",\"Sorphera.withdrawOperator(address,uint256)\",\"SorpheraPassport.enter(uint8,uint256,(uint8[3],uint8)[],uint256,(uint8,uint256)[])\",\"SorpheraPassport.process(address,(uint8,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.reviewCancellation(uint256)\",\"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,\"DESIGN.md\":83,\"README.md\":117,\"deployments/canary.example.json\":26,\"deployments/canary.schema.json\":32,\"deployments/config.schema.json\":169,\"deployments/fork.json\":13,\"deployments/mainnet.json\":28,\"deployments/mainnet.launch.json\":27,\"deployments/sepolia.json\":28,\"dist/assets/Chamber-m37PT9hZ.js\":1,\"dist/assets/DrawRoom-CGPqvfiq.js\":2,\"dist/assets/LiveWorkspace-DrRPS7p5.js\":46,\"dist/assets/ccip-C3htbo9-.js\":1,\"dist/assets/index-Bn_J9Yml.js\":73,\"dist/assets/index-DyvbRqjF.css\":1,\"dist/brand/eth-ball.webp\":31,\"dist/brand/hero-world.webp\":399,\"dist/brand/nft-ball.webp\":34,\"dist/brand/plush/albedo.webp\":734,\"dist/brand/plush/surface.webp\":472,\"dist/brand/sorphera-banner-ice-blue.webp\":379,\"dist/brand/sorphera-brand-board-ice-blue.webp\":380,\"dist/brand/sorphera-globe-icon-ice-blue.webp\":18,\"dist/brand/sorphera-wordmark-ice-blue.webp\":226,\"dist/index.html\":31,\"docs/CANARY.md\":118,\"docs/CONTINUATION.md\":47,\"docs/DEPENDENCIES.md\":46,\"docs/DEPLOYMENT.md\":38,\"docs/IMD-SUPPORT-DRAFT.md\":7,\"docs/KEEPER.md\":72,\"docs/MAINNET.md\":46,\"docs/OPERATIONS.md\":60,\"docs/PASSPORT-HANDOFF.md\":96,\"docs/REHEARSAL.md\":43,\"docs/REVIEW-CONTINUATION.md\":79,\"docs/TESTING.md\":70,\"docs/TOOLING-REVIEW.md\":36,\"docs/continuation-validation.json\":174,\"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/continuation/build.log\":858,\"docs/evidence/continuation/canary-dry-run.json\":30,\"docs/evidence/continuation/empty-constructor.log\":9,\"docs/evidence/continuation/forge-tests.log\":154,\"docs/evidence/continuation/keeper-fork-simulation.json\":2408,\"docs/evidence/continuation/keeper-fork-simulation.log\":83,\"docs/evidence/continuation/mainnet-fork.log\":22,\"docs/evidence/continuation/runtime-simulation.json\":17,\"docs/evidence/continuation/sepolia-fork.log\":14,\"docs/evidence/continuation/source-content.json\":97,\"docs/evidence/continuation/tooling-tests.log\":52,\"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\":13,\"frontend/abi/Sorphera.json\":2330,\"frontend/abi/SorpheraPassport.json\":460,\"frontend/abi/SorpheraRouter.json\":468,\"frontend/abi/SorpheraVault.json\":1071,\"frontend/abi/SorpheraVaultFactory.json\":245,\"frontend/bytecode-sizes.json\":22,\"frontend/configuration.json\":71,\"frontend/deployment.json\":29,\"integration/Sepolia.t.sol\":42,\"integration/mainnet/Mainnet.t.sol\":425,\"integration/rehearsal/Constructor.t.sol\":61,\"launch.json\":9,\"ops/keeper.example.json\":27,\"ops/keeper.schema.json\":33,\"ops/sorphera-keeper.service\":33,\"script/CanaryDependencies.sol\":266,\"script/Operations.s.sol\":149,\"script/Rehearse.s.sol\":43,\"script/SepoliaCanary.s.sol\":32,\"src/Sorphera.sol\":719,\"src/SorpheraPassport.sol\":198,\"src/SorpheraRouter.sol\":136,\"src/SorpheraVault.sol\":325,\"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/SepoliaCanary.t.sol\":186,\"test/Sorphera.t.sol\":988,\"test/SorpheraAdversarial.t.sol\":458,\"test/SorpheraHardening.t.sol\":150,\"test/SorpheraInvariant.t.sol\":666,\"test/SorpheraPassport.t.sol\":729,\"test/SorpheraPassportInvariant.t.sol\":238,\"test/SorpheraReviewRegression.t.sol\":259,\"test/helpers/SimulatedSorphera.sol\":14,\"test/helpers/SorpheraFixture.sol\":159,\"test/mocks/ExternalMocks.sol\":416,\"tools/canary.py\":405,\"tools/contracts.py\":50,\"tools/export.py\":19,\"tools/keeper.py\":302,\"tools/keeper_smoke.py\":230,\"tools/preflight.py\":56,\"tools/read-only-rpc.py\":36,\"tools/runtime.py\":366,\"tools/snapshot-mainnet.py\":65,\"tools/source_manifest.py\":32,\"tools/test_canary.py\":221,\"tools/test_keeper.py\":302,\"tools/test_runtime.py\":394,\"web/README.md\":82,\"web/THIRD_PARTY_NOTICES.md\":20,\"web/artwork/README.md\":56,\"web/artwork/plush-source.webp\":1783,\"web/evidence/asset-manifest.json\":62,\"web/evidence/build.txt\":18,\"web/evidence/bundle-report.json\":14,\"web/evidence/claim-mobile.jpg\":97,\"web/evidence/continuity/build.txt\":17,\"web/evidence/continuity/checkout-cutoff.jpg\":86,\"web/evidence/continuity/design-probe-dejavu.json\":116,\"web/evidence/continuity/design-probe.json\":5522,\"web/evidence/continuity/draw-390.jpg\":703,\"web/evidence/continuity/draw-mobile-reduced-after.jpg\":78,\"web/evidence/continuity/globe-away.jpg\":135,\"web/evidence/continuity/globe-bonus-stop.jpg\":136,\"web/evidence/continuity/globe-landed.jpg\":135,\"web/evidence/continuity/globe-mid-turn.jpg\":140,\"web/evidence/continuity/globe-stopped.jpg\":116,\"web/evidence/continuity/home-390-arial.jpg\":297,\"web/evidence/continuity/home-390.jpg\":306,\"web/evidence/continuity/index.html\":48,\"web/evidence/continuity/material-hashes.json\":8,\"web/evidence/continuity/motion-summary.json\":164,\"web/evidence/continuity/offline-export-results.json\":15,\"web/evidence/continuity/packaging.json\":36,\"web/evidence/continuity/paused-checkout-results.json\":8,\"web/evidence/continuity/play-320-eth.jpg\":226,\"web/evidence/continuity/play-320-nft.jpg\":211,\"web/evidence/continuity/play-schedule-390.jpg\":132,\"web/evidence/continuity/plush-comparison.jpg\":438,\"web/evidence/continuity/plush-fallback-comparison.jpg\":414,\"web/evidence/continuity/plush-fallback-full-turn.jpg\":744,\"web/evidence/continuity/plush-fallback-poles.jpg\":355,\"web/evidence/continuity/plush-full-turn.jpg\":824,\"web/evidence/continuity/plush-poles-before.jpg\":347,\"web/evidence/continuity/plush-poles.jpg\":349,\"web/evidence/continuity/plush-results.json\":252,\"web/evidence/continuity/reveal-canvas-results.json\":11,\"web/evidence/continuity/reveal-canvas.mp4\":1173,\"web/evidence/continuity/reveal-webgl-results.json\":11,\"web/evidence/continuity/reveal-webgl.mp4\":1175,\"web/evidence/continuity/revision-reproduction.json\":152,\"web/evidence/continuity/revision-validation.md\":63,\"web/evidence/continuity/schedule-chromium-results.json\":15,\"web/evidence/continuity/schedule-unit-tests.txt\":82,\"web/evidence/continuity/sorphera-nft-42-draw-window.ics\":13,\"web/evidence/continuity/sorphera-nft-42-sales-closing.ics\":13,\"web/evidence/continuity/tickets-390.jpg\":360,\"web/evidence/continuity/typecheck.txt\":3,\"web/evidence/continuity/unit-tests.txt\":290,\"web/evidence/continuity/upcoming-desktop.jpg\":218,\"web/evidence/continuity/validation.md\":84,\"web/evidence/continuity/video-canvas-metadata.txt\":18,\"web/evidence/continuity/video-webgl-metadata.txt\":18,\"web/evidence/draw-finale-desktop.jpg\":596,\"web/evidence/draw-mobile-reduced.jpg\":764,\"web/evidence/iteration/browser-results.json\":14,\"web/evidence/iteration/budget-after.jpg\":134,\"web/evidence/iteration/budget-before.jpg\":134,\"web/evidence/iteration/build.txt\":17,\"web/evidence/iteration/bundle-report.json\":14,\"web/evidence/iteration/claim-after.jpg\":165,\"web/evidence/iteration/contrast.json\":20,\"web/evidence/iteration/draw-mobile-reduced-after.jpg\":81,\"web/evidence/iteration/globe-away.jpg\":133,\"web/evidence/iteration/globe-bonus-stop.jpg\":144,\"web/evidence/iteration/globe-landed.jpg\":148,\"web/evidence/iteration/globe-mid-turn.jpg\":134,\"web/evidence/iteration/globe-stopped.jpg\":129,\"web/evidence/iteration/home-after.jpg\":557,\"web/evidence/iteration/home-before.jpg\":699,\"web/evidence/iteration/index.html\":51,\"web/evidence/iteration/keyboard-focus.jpg\":247,\"web/evidence/iteration/motion-summary.json\":76,\"web/evidence/iteration/play-mobile-after.jpg\":452,\"web/evidence/iteration/publication.json\":12,\"web/evidence/iteration/reveal-normal.mp4\":1967,\"web/evidence/iteration/reveal-results.json\":11,\"web/evidence/iteration/review-after.jpg\":133,\"web/evidence/iteration/review-before.jpg\":139,\"web/evidence/iteration/tests.txt\":260,\"web/evidence/iteration/typecheck.txt\":4,\"web/evidence/iteration/validation.md\":70,\"web/evidence/iteration/video-probe.json\":19,\"web/evidence/iteration2/atlas-390.png\":356,\"web/evidence/iteration2/home-390.png\":994,\"web/evidence/iteration2/receipt-free-1440.png\":559,\"web/evidence/iteration2/validation.md\":46,\"web/evidence/play-desktop.jpg\":146,\"web/evidence/play-mobile.jpg\":1220,\"web/evidence/receipt-desktop.jpg\":280,\"web/evidence/reveal-1-back-facing.jpg\":255,\"web/evidence/reveal-2-stopped-badge.jpg\":223,\"web/evidence/reveal-3-third-ball-hold.png\":753,\"web/evidence/revision/bonus-stop.jpg\":137,\"web/evidence/revision/browser-results.json\":14,\"web/evidence/revision/draw-stop.jpg\":151,\"web/evidence/revision/home-390.jpg\":278,\"web/evidence/revision/plush-comparison.jpg\":254,\"web/evidence/revision/plush-results.json\":37,\"web/evidence/revision/reveal-results.json\":11,\"web/evidence/revision/taste-summary.json\":116,\"web/evidence/revision/validation.md\":99,\"web/evidence/tests.txt\":52,\"web/evidence/typecheck.txt\":5,\"web/evidence/validation.md\":55,\"web/index.html\":30,\"web/licenses/better-interface.txt\":220,\"web/licenses/react-dom.txt\":21,\"web/licenses/react.txt\":21,\"web/licenses/viem.txt\":21,\"web/package-lock.json\":2150,\"web/package.json\":27,\"web/public/brand/eth-ball.webp\":31,\"web/public/brand/hero-world.webp\":399,\"web/public/brand/nft-ball.webp\":34,\"web/public/brand/plush/albedo.webp\":734,\"web/public/brand/plush/surface.webp\":472,\"web/public/brand/sorphera-banner-ice-blue.webp\":379,\"web/public/brand/sorphera-brand-board-ice-blue.webp\":380,\"web/public/brand/sorphera-globe-icon-ice-blue.webp\":18,\"web/public/brand/sorphera-wordmark-ice-blue.webp\":226,\"web/scripts/plush-materials.py\":145,\"web/src/App.tsx\":304,\"web/src/Chamber.tsx\":90,\"web/src/DrawRoom.tsx\":590,\"web/src/LiveWorkspace.tsx\":863,\"web/src/Passport.tsx\":131,\"web/src/Play.tsx\":1164,\"web/src/PlushGlobe.tsx\":66,\"web/src/RoundSchedule.tsx\":145,\"web/src/Sorphera.abi.ts\":1234,\"web/src/SorpheraRouter.abi.ts\":279,\"web/src/SorpheraVault.abi.ts\":647,\"web/src/SorpheraVaultFactory.abi.ts\":158,\"web/src/Tickets.tsx\":512,\"web/src/UpcomingDraw.tsx\":154,\"web/src/budget.ts\":263,\"web/src/components.tsx\":155,\"web/src/contract.ts\":612,\"web/src/core.test.ts\":873,\"web/src/core.ts\":308,\"web/src/demoStorage.ts\":64,\"web/src/deployment.json\":13,\"web/src/earth-land.json\":1,\"web/src/fixtures.ts\":332,\"web/src/helper.abi.ts\":45,\"web/src/indexer.ts\":119,\"web/src/main.tsx\":34,\"web/src/pages.tsx\":457,\"web/src/passport.ts\":280,\"web/src/plushModel.ts\":591,\"web/src/reveal.ts\":99,\"web/src/schedule.test.ts\":197,\"web/src/schedule.ts\":69,\"web/src/styles.css\":3213,\"web/tests/browser.mjs\":527,\"web/tests/paused-checkout.mjs\":217,\"web/tests/plush.mjs\":328,\"web/tests/reveal.mjs\":250,\"web/tests/schedule.mjs\":421,\"web/tsconfig.json\":17,\"web/vite.config.ts\":7},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":8600,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/SorpheraVault.sol:249: SorpheraVault._sync() (src/SorpheraVault.sol#249-257) sends eth to arbitrary user\n[medium/medium] divide-before-multiply at src/Sorphera.sol:628: Sorphera._distribute(uint8,uint256) (src/Sorphera.sol#628-642) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/lib/RewardTransfer.sol:48: RewardTransfer.isValidSignature(bytes32,bytes) (src/lib/RewardTransfer.sol#48-53) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Sorphera.sol:628: Sorphera._distribute(uint8,uint256) (src/Sorphera.sol#628-642) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Sorphera.sol:446: Sorphera.isCancelled(uint8,uint256) (src/Sorphera.sol#446-448) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:227: Reentrancy in SorpheraVault.recoverNFT(uint256) (src/SorpheraVault.sol#227-233):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:277: Reentrancy in SorpheraVault.claimNFTs(uint256,uint256[],address) (src/SorpheraVault.sol#277-306):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:186: Reentrancy in SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225):\n[medium/medium] reentrancy-no-eth at src/Sorphera.sol:313: Reentrancy in Sorphera.openRound(uint8) (src/Sorphera.sol#313-351):\n[medium/medium] reentrancy-no-eth at src/Sorphera.sol:451: Reentrancy in Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#451-483):\n[medium/medium] reentrancy-no-eth at src/Sorphera.sol:451: Reentrancy in Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#451-483):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:144: Reentrancy in SorpheraVault.settle(uint256) (src/SorpheraVault.sol#144-158):\n[medium/medium] reentrancy-no-eth at src/Sorphera.sol:451: Reentrancy in Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#451-483):\n[medium/medium] reentrancy-no-eth at src/SorpheraVault.sol:174: Reentrancy in SorpheraVault.reviewCancellation(uint256) (src/SorpheraVault.sol#174-184):\n[medium/medium] uninitialized-local at src/lib/Balls.sol:34: Balls.draw(bytes32).bag (src/lib/Balls.sol#34) is a local variable never initialized\n[medium/medium] uninitialized-local at src/lib/Networks.sol:11: Networks.validate(uint256,address,bytes32).valid (src/lib/Networks.sol#11) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Sorphera.sol:675: Sorphera.claimETH(uint8,uint256,uint256[],address).amount (src/Sorphera.sol#675) is a local variable never initialized\n[medium/medium] uninitialized-local at src/SorpheraVault.sol:196: SorpheraVault._reconcile(uint256).held (src/SorpheraVault.sol#196) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Sorphera.sol:300: Sorphera._checkFunding(Sorphera.RandomConfig,uint96).present (src/Sorphera.sol#300) is a local variable never initialized\n[medium/medium] unused-return at src/lib/RewardTransfer.sol:12: RewardTransfer._queue(address,address,address,uint256,uint256) (src/lib/RewardTransfer.sol#12-46) ignores return value by ITransferHelper(helper).depositWithPermit2(ITransferHelper.PermitTransferFrom(ITransferHelper.TokenPermissions(token,amount),nonce,deadline),,recipient) (src/lib/RewardTransfer.sol#36-43)\n[medium/medium] unused-return at src/Sorphera.sol:271: Sorphera._validateNetwork(Sorphera.RandomConfig) (src/Sorphera.sol#271-283) ignores return value by (minimumConfirmations,maximumGas,None,None,None,None,None,None,None) = coordinator.s_config() (src/Sorphera.sol#275)\n[medium/medium] unused-return at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) ignores return value by (None,rewards) = lottery.entriesOf(game,round,wallet) (src/SorpheraPassport.sol#98)\n[medium/medium] unused-return at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) ignores return value by (paid,None) = lottery.entriesOf(game,round,wallet) (src/SorpheraPassport.sol#106)\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:271: Sorphera._validateNetwork(Sorphera.RandomConfig) (src/Sorphera.sol#271-283) ignores return value by (active,None) = coordinator.s_provingKeys(c.keyHash) (src/Sorphera.sol#274)\n[medium/medium] unused-return at src/SorpheraVault.sol:160: SorpheraVault.process(uint256) (src/SorpheraVault.sol#160-163) ignores return value by pool.processAcquisitions(count) (src/SorpheraVault.sol#162)\n[medium/medium] unused-return at src/SorpheraVault.sol:259: SorpheraVault.claimEpochRewards(uint256[]) (src/SorpheraVault.sol#259-264) ignores return value by rewards.claimEpochTokens(epochs) (src/SorpheraVault.sol#262)\n[medium/medium] unused-return at src/Sorphera.sol:293: Sorphera._checkFunding(Sorphera.RandomConfig,uint96) (src/Sorphera.sol#293-305) ignores return value by (link,nativeBalance,None,None,consumers) = coordinator.getSubscription(c.subscription) (src/Sorphera.sol#295-296)\n[medium/medium] unused-return at src/SorpheraVault.sol:239: SorpheraVault.recoverRefund() (src/SorpheraVault.sol#239-243) ignores return value by pool.withdrawAcquisitionRefund() (src/SorpheraVault.sol#241)\n[low/high] shadowing-local at src/SorpheraPassport.sol:177: SorpheraPassport.summary(address).stamps (src/SorpheraPassport.sol#155) shadows:\n[low/medium] events-maths at src/SorpheraVault.sol:103: SorpheraVault.fund() (src/SorpheraVault.sol#103-105) should emit an event for: \n[low/medium] missing-zero-check at src/SorpheraVault.sol:82: SorpheraVault.constructor(address,SorpheraRouter,uint8,uint256,SorpheraVault.Settings).lottery_ (src/SorpheraVault.sol#82) lacks a zero-check on :\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: l = pool.listings(a.listingId) (src/SorpheraVault.sol#192)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: r = lottery.getRound(game,round) (src/SorpheraPassport.sol#89)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: ! lottery.isTerminal(r.status) (src/SorpheraPassport.sol#90)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: holder = IERC721(l.collection).ownerOf{gas: 50000}(l.tokenId) (src/SorpheraVault.sol#199-201)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: ISorphera(lottery).recordNFT(game,round,securedAt) (src/SorpheraVault.sol#209)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: l = pool.listings(a.listingId) (src/SorpheraVault.sol#192)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: a = pool.acquisitions(id) (src/SorpheraVault.sol#188)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: (None,rewards) = lottery.entriesOf(game,round,wallet) (src/SorpheraPassport.sol#98)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: holder = IERC721(l.collection).ownerOf{gas: 50000}(l.tokenId) (src/SorpheraVault.sol#199-201)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: r = lottery.getRound(game,round) (src/SorpheraPassport.sol#89)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: pool.stuckNFTRecipient(a.listingId) == address(this) (src/SorpheraVault.sol#211)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: (None,rewards) = lottery.entriesOf(game,round,wallet) (src/SorpheraPassport.sol#98)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: a = pool.acquisitions(id) (src/SorpheraVault.sol#188)\n[low/medium] calls-loop at src/SorpheraVault.sol:277: SorpheraVault.claimNFTs(uint256,uint256[],address) (src/SorpheraVault.sol#277-306) has external calls inside a loop: this.deliver{gas: 500000}(index,recipient) (src/SorpheraVault.sol#299-304)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: (paid,None) = lottery.entriesOf(game,round,wallet) (src/SorpheraPassport.sol#106)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: ISorphera(lottery).recordNFT(game,round,securedAt) (src/SorpheraVault.sol#209)\n[low/medium] calls-loop at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) has external calls inside a loop: pool.stuckNFTRecipient(a.listingId) == address(this) (src/SorpheraVault.sol#211)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: ! lottery.isTerminal(r.status) (src/SorpheraPassport.sol#90)\n[low/medium] calls-loop at src/SorpheraVault.sol:107: SorpheraVault.acquire(uint256,uint256) (src/SorpheraVault.sol#107-139) has external calls inside a loop: acquisition = pool.acquisitions(ids[i]) (src/SorpheraVault.sol#132)\n[low/medium] calls-loop at src/SorpheraPassport.sol:87: SorpheraPassport._processOne(address,uint8,uint256) (src/SorpheraPassport.sol#87-111) has external calls inside a loop: (paid,None) = lottery.entriesOf(game,round,wallet) (src/SorpheraPassport.sol#106)\n[low/medium] reentrancy-benign at src/Sorphera.sol:451: Reentrancy in Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#451-483):\n[low/medium] reentrancy-benign at src/SorpheraVault.sol:107: Reentrancy in SorpheraVault.acquire(uint256,uint256) (src/SorpheraVault.sol#107-139):\n[low/medium] reentrancy-benign at src/Sorphera.sol:313: Reentrancy in Sorphera.openRound(uint8) (src/Sorphera.sol#313-351):\n[low/medium] reentrancy-benign at src/lib/RewardTransfer.sol:12: Reentrancy in RewardTransfer._queue(address,address,address,uint256,uint256) (src/lib/RewardTransfer.sol#12-46):\n[low/medium] reentrancy-benign at src/Sorphera.sol:485: Reentrancy in Sorphera._request(uint8,uint256,bool) (src/Sorphera.sol#485-501):\n[low/medium] reentrancy-benign at src/SorpheraVault.sol:186: Reentrancy in SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225):\n[low/medium] reentrancy-events at src/lib/RewardTransfer.sol:12: Reentrancy in RewardTransfer._queue(address,address,address,uint256,uint256) (src/lib/RewardTransfer.sol#12-46):\n[low/medium] timestamp at src/Sorphera.sol:451: Sorphera.requestDraw(uint8,uint256) (src/Sorphera.sol#451-483) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:424: Sorphera.credit(uint8,uint256) (src/Sorphera.sol#424-432) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:537: Sorphera.finalize(uint8,uint256) (src/Sorphera.sol#537-554) 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/Sorphera.sol:417: Sorphera.close(uint8,uint256) (src/Sorphera.sol#417-422) uses timestamp for comparisons\n[low/medium] timestamp at src/SorpheraVault.sol:249: SorpheraVault._sync() (src/SorpheraVault.sol#249-257) uses timestamp for comparisons\n[low/medium] timestamp at src/lib/RewardTransfer.sol:12: RewardTransfer._queue(address,address,address,uint256,uint256) (src/lib/RewardTransfer.sol#12-46) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:644: Sorphera.entitlement(uint8,uint256,uint256,address) (src/Sorphera.sol#644-666) uses timestamp for comparisons\n[low/medium] timestamp at src/SorpheraVault.sol:186: SorpheraVault._reconcile(uint256) (src/SorpheraVault.sol#186-225) uses timestamp for comparisons\n[low/medium] timestamp at src/SorpheraVault.sol:107: SorpheraVault.acquire(uint256,uint256) (src/SorpheraVault.sol#107-139) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:378: Sorphera._enter(address,uint8,uint256,Sorphera.Pick[],uint256) (src/Sorphera.sol#378-410) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:436: Sorphera.recordNFT(uint8,uint256,uint256) (src/Sorphera.sol#436-444) 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/SorpheraVault.sol:174: SorpheraVault.reviewCancellation(uint256) (src/SorpheraVault.sol#174-184) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:504: Sorphera.requestTieBreak(uint8,uint256) (src/Sorphera.sol#504-510) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:412: Sorphera.acquisitionOpen(uint8,uint256) (src/Sorphera.sol#412-415) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:446: Sorphera.isCancelled(uint8,uint256) (src/Sorphera.sol#446-448) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:512: Sorphera.rawFulfillRandomWords(uint256,uint256[]) (src/Sorphera.sol#512-531) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:574: Sorphera.finalizeTieBreak(uint8,uint256) (src/Sorphera.sol#574-585) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:628: Sorphera._distribute(uint8,uint256) (src/Sorphera.sol#628-642) uses timestamp for comparisons\n[low/medium] timestamp at src/Sorphera.sol:313: Sorphera.openRound(uint8) (src/Sorphera.sol#313-351) uses timestamp for comparisons","passed":true},{"durationMs":467,"exitCode":0,"name":"aderyn","output":"[high] contract-locks-ether at src/SorpheraPassport.sol:13: Contract locks Ether without a withdraw function (2 places)\n[high] reentrancy-state-change at src/Sorphera.sol:263: Reentrancy: State change after external call (26 places)\n[high] storage-array-memory-edit at src/Sorphera.sol:262: Storage Array Edited with Memory (7 places)\n[low] centralization-risk at src/Sorphera.sol:12: Centralization Risk (14 places)\n[low] costly-loop at src/Sorphera.sol:393: Costly operations inside loop (7 places)\n[low] large-numeric-literal at src/Sorphera.sol:243: Large Numeric Literal (2 places)\n[low] literal-instead-of-constant at src/Sorphera.sol:224: Literal Instead of Constant (14 places)\n[low] non-reentrant-not-first at src/Sorphera.sol:688: `nonReentrant` is Not the First Modifier (4 places)\n[low] require-revert-in-loop at src/Sorphera.sol:393: Loop Contains `require`/`revert` (6 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:677: Unchecked Return (6 places)\n[low] uninitialized-local-variable at src/Sorphera.sol:301: Uninitialized Local Variable (5 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"41f5e4c2f5006f82f2eb08c22883d4130ffe5cd5fbed54601549d58d057e5119","verifiedTreeHash":"cdaa264cc22d6d3f52ac840d87dd051fd0fe8c59","verifierVersion":"0.1.0+67c588fa"}]}