{"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":"d6381850-9beb-42ad-bf3f-f36b2deb97af","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"7a6f119b69e36a3ea9607eb873c0b9650d387569ba1972ee03c60e495d05667a","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"40fa1bcb5a83cfd90154f9e88b5c55f0bee552233895ed8b22edf33ebee3c1b0","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"d48762691560b73b22c1165b8ca4e64f6d945f15e4545a1ac66705aa8dfd1a2a","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"f2669761f495dcdb3e5cfca516d556d089b2f2d7fd71509af20a9a720510b404","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"7adf89190c88aa96b6c7a1d16cc2164d41293790f78dc21db051832bed23d117","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"2f3ea3c1bd88ad9fa9259f45d5dd6228d1e4c20cc95e452e1be178796590e627","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"104d4961c218724813af93bef024353978c088c20ca7eb8f4b7963b2576cb579","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"4bbc6fb923533b4ec32ae037bf62b51f30d909fbc5fd57cd5b2cf7543ba24a4e","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"A custom token: HAMSTER (HAMSTER).\nToken name: HAMSTER\nToken symbol: HAMSTER\nToken supply: 1,000,000,000 with 18 decimals, all minted once to the deployer in the constructor.\nWhat it does: hamster-hour-bet-on-the-wheel.sites.imd.fun\nBet\nLose\nWin $HAMSTER","parentJobId":null,"planHash":"eb2d352d4a10fd5930db34932758ed227ca28a455eb9acafea997922ae10c7c4","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"d6381850-9beb-42ad-bf3f-f36b2deb97af","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1993-hamster"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51225","feedbackHash":"b39b389e9fb8006a51bac745e3a3ac1c7751b9fbb4c86d4a5de73bf268f72ed4","nodeKey":"audit_economics","submissionHash":"7a6f119b69e36a3ea9607eb873c0b9650d387569ba1972ee03c60e495d05667a","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52138","feedbackHash":"667ae012c3e112a9e1bb9e2d9422bb65168d194890a5bee1fc6a7470345eea72","nodeKey":"audit_flow","submissionHash":"40fa1bcb5a83cfd90154f9e88b5c55f0bee552233895ed8b22edf33ebee3c1b0","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52270","feedbackHash":"0ca7e69640e2d99f7d5332c90c58c12f149aae5b54ddf88d75364e3d4cfb5599","nodeKey":"audit_judge","submissionHash":"d48762691560b73b22c1165b8ca4e64f6d945f15e4545a1ac66705aa8dfd1a2a","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52681","feedbackHash":"4baf66251cb72e119a0800cae38ad4383416d3c00fcadec16cfc099275e314b4","nodeKey":"audit_math","submissionHash":"f2669761f495dcdb3e5cfca516d556d089b2f2d7fd71509af20a9a720510b404","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51534","feedbackHash":"73ee2f20cc19eaa9616d3e4dcd51355ce85aed03d8349f2f3623d6826da8a9b5","nodeKey":"audit_permissions","submissionHash":"7adf89190c88aa96b6c7a1d16cc2164d41293790f78dc21db051832bed23d117","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52670","feedbackHash":"c27791099767de9315aeaf926d32b0f4bc9370621ae85e0d171bcb5477ad7e7d","nodeKey":"build_contract_project","submissionHash":"2f3ea3c1bd88ad9fa9259f45d5dd6228d1e4c20cc95e452e1be178796590e627","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52205","feedbackHash":"5c550e2dede5853db0cce72f2571d8013aa6de791e760abdd9d3f132161f2c0f","nodeKey":"manifest","submissionHash":"104d4961c218724813af93bef024353978c088c20ca7eb8f4b7963b2576cb579","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52607","feedbackHash":"bd89f74c1d12636f65a4d33c09f490b7af6ffbdab672eaaf448b0875199001cd","nodeKey":"write_foundry_tests","submissionHash":"4bbc6fb923533b4ec32ae037bf62b51f30d909fbc5fd57cd5b2cf7543ba24a4e","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"9708a1226e5b90e06d606ef5b0d3cfa7e9d9967285b067b495435b0061284a1c","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"3cbee987b7d1635654b69559c223413817f0ff08bf3484ea81ca22ab463885bf","device":"fa5c50e7abe46571","findings":[],"hash":"104d4961c218724813af93bef024353978c088c20ca7eb8f4b7963b2576cb579","nodeId":"1d12c429-527f-404d-bc81-0353d7726201","outcome":"completed","summary":"Done. `launch.json` is written at the repository root and is the only changed file.\n\n**What it describes**\n\n- **Token:** `HamsterToken`, name and symbol HAMSTER, 18 decimals, no constructor arguments. The constructor mints the full supply once to msg.sender, so totalSupply is 1000000000000000000000000000 minor units.\n- **Application contract:** `HamsterRewards` with constructor arguments `$token` and `$requester`. The second argument is the Ownable2Step owner, so it resolves to the economics remainder recipient rather than the factory, which satisfies the protected owners check.\n- **Pool and economics:** copied verbatim from the launch terms. The pair is IMD, fee 12500, tick spacing 60, the one-to-one provenance price, and the requester's economics object exactly as given.\n- **Notes:** 1670 characters explaining the token's plain ERC-20 behaviour, the reward contract's single one-time owner power, that it receives no supply at launch, and that no initialization calls are needed.\n\n**Verification**\n\n- `forge build` compiles cleanly.\n- `forge test` with the verifier's fuzz seed passed all 56 tests across 6 suites, including the invariant suite.\n- A scratch script confirmed the manifest uses only schema keys, matches the required economics and pool objects, and that each constructorArgs list length matches the compiled ABI for both contracts.\n\nThe README's deployment table calls the owner argument `$owner`. That is not a manifest placeholder, so the manifest uses `$requester` as the schema requires. No other file was touched.","treeHash":"2d43ea8864b68fe6ef6a3b4f1990531539811f22","usage":{"cachedInputTokens":243029,"inputTokens":162,"model":"claude-fable-5-1","outputTokens":4043,"runtime":"claude","turns":10,"wallClockMs":83343}},{"artifacts":[],"attempt":1,"bundleHash":"454e6c4a0a2d24c43ee5e73b1f54dcb199195e72d8177cbd85841244cc07cc20","device":"a09316cd893b3b67","findings":[],"hash":"2f3ea3c1bd88ad9fa9259f45d5dd6228d1e4c20cc95e452e1be178796590e627","nodeId":"79065a4e-59f9-4270-8ba6-ef8f5a4b41d2","outcome":"completed","summary":"Implemented HAMSTER with 1 billion tokens, 18 decimals, minted once to the deployer, plus funded rewards for eligible losing bets.\n\nValidation passed: `forge build`, 56 tests with the supplied fuzz seed, and `forge fmt --check`.\n\nDeployment assumptions and operating steps are in [README.md](/home/ubuntu/.identitymd/work/d6381850-9beb-42ad-bf3f-f36b2deb97af/79065a4e-59f9-4270-8ba6-ef8f5a4b41d2/README.md). Rewards require game configuration, funding, and site integration after launch.","treeHash":"83d4783cd7b47a0f01102c69e584183ee9134c87","usage":{"cachedInputTokens":1069056,"inputTokens":95505,"model":"gpt-6-astra","outputTokens":32152,"runtime":"codex","turns":6,"wallClockMs":911750}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"62491201fe455e89","findings":[{"citation":"resolved","description":"Documentation only, not a code defect. The launch reference for this task states that application contracts in a custom_token launch.json take `$token`, `$requester` (economics.remainderTo) or `$contract:EarlierName` as address arguments. README.md line 13 instructs the manifest writer to pass `$owner` for `owner_`. The code itself is correct: HamsterRewards(address hamster_, address owner_) with Ownable(owner_) is two static address words, and the owner holds only the one-shot configureGame plus Ownable2Step transfer/renounce; after configureGame succeeds the owner has no reward, withdrawal, pause or rate power (verified by reading src/HamsterRewards.sol lines 57-68 and 129-133). The only risk is that a manifest copied from the README is refused at admission or resolves to an unintended owner.","line":13,"path":"README.md","reproduction":"State: the manifest step writes launch.json with contracts[0] = {\"contract\":\"HamsterRewards\",\"constructorArgs\":[\"$token\",\"$owner\"]} exactly as README.md line 13 says. Expected per the task's launch reference: the second argument should be \"$requester\" (0xee2aaa315cf7ed169f93148d30d24af9318dbb66, economics.remainderTo). Actual: `$owner` is not among the substitutions the custom_token reference lists, so the manifest is either refused or resolved by a rule the README does not describe. Fix: README line 13 should say `$requester`; no Solidity change is needed.","severity":"info","snippet":"| `HamsterRewards` | `address hamster_`, `address owner_` | Pass the newly deployed token (`$token`) and the requester's launch owner (`$owner`). |","title":"README names the HamsterRewards owner argument as $owner; the custom_token manifest vocabulary is $requester"}],"hash":"40fa1bcb5a83cfd90154f9e88b5c55f0bee552233895ed8b22edf33ebee3c1b0","nodeId":"a0b78815-571a-4667-a1f1-1ef7420d3842","outcome":"completed","summary":"Review complete. The findings file is written at `.imd-findings.json`, no tracked file was changed, and `test/scratch/` holds only my throwaway differential test.\n\n**Result: no reproducible defect in the assigned area.** One documentation note was recorded at info level.\n\n**What I covered (Execution Trace, Periphery, First Principles)**\n\n- **Every assumption `eligibleLoss` makes about the external game was checked against the real game source.** I fetched HamsterHour.sol at the commit the site's deployment record names and confirmed the status encoding, the UNDER/OVER and RUNNING/SLEEPING index order, how `marketVoided` is set at settlement, that `rankCount` is at least one whenever an exact pool exists, that every used `ties[i]` is at least one, and that positions survive the game's own claim.\n- **Differential fuzz against the real game logic.** I compiled a copy of the game with only the oracle verifier stubbed, placed real bets, settled, and claimed. Across 3000 runs, `eligibleLoss` equalled the losing stake exactly when the game paid nothing on a non-voided market, and zero for winners, refunds and voided windows. Claiming in the game did not change eligibility.\n- **Execution flow.** Claims set the replay flag and counter before the transfer under a reentrancy guard. Failed or underfunded claims consume nothing. Game reads compile to static calls, so the aderyn reentrancy lead on `configureGame` cannot execute. The two slither timestamp leads are deadline checks only.\n- **Periphery.** All vendored OpenZeppelin v5.1.0 and forge-std v1.9.6 files match upstream apart from formatter line wrapping. The read interface matches the published ABI, whose hash I recomputed. On-chain reads confirmed IMD has 18 decimals and the deployed game's constants match the source.\n\n**The one note** is that README line 13 tells the manifest writer to pass `$owner` for the rewards owner, while the custom_token reference for this task only lists `$token`, `$requester` and `$contract:Name`. The code is correct either way.\n\n**Not a defect, but worth the requester's attention:** the reward rate is one HAMSTER base unit per IMD base unit lost. At the 888 IMD opening cap for one billion tokens, a lost minimum bet earns HAMSTER worth well under a millionth of an IMD. That is the stated design and is documented, so I did not report it.","treeHash":null,"usage":{"cachedInputTokens":2660141,"inputTokens":674,"model":"claude-fable-5-1","outputTokens":36132,"runtime":"claude","turns":45,"wallClockMs":545650}},{"artifacts":[],"attempt":1,"bundleHash":"b16f5c6c5ae72ea0aaeba31f8d91da46945ac85b4d0b04847e898a7ce79bf690","device":"dc176559ff153c37","findings":[],"hash":"4bbc6fb923533b4ec32ae037bf62b51f30d909fbc5fd57cd5b2cf7543ba24a4e","nodeId":"165f0408-3a03-4824-bf6d-f3fb80de9ba3","outcome":"completed","summary":"The full suite passes with the verifier's seed: 92 deliverable tests plus 2 scratch checks, 0 failures, total runtime about 110 seconds.\n\n**What I added** (all under `test/`, building on the existing suite rather than rewriting it):\n\n- **`test/HamsterToken.invariant.t.sol`**: an ERC-20 invariant suite for the token. A handler with six holders runs transfer, approve and transferFrom in random order, deliberately over-asking a quarter of the time and asserting the exact ERC-6093 error at the call. Invariants check fixed supply, sum of balances against a ghost ledger, allowances against a ghost ledger including unlimited allowances, and unchanged metadata.\n- **`test/HamsterRewards.lifecycle.invariant.t.sol`**: a lifecycle invariant suite for the rewards contract. Unlike the existing invariant test, which runs against frozen settled records, this handler settles windows with varied results and refund flags, voids open windows, advances time so the end-of-window guard matters, funds from two donors by both paths, shuffles two-step ownership, and attempts reconfiguration. Every claim's outcome is predicted from an independent model of the README's eligibility table before the call. Invariants check inventory equals donations minus payouts, nobody is paid more than they wagered or twice, nothing is paid on voided or unfinished windows, quotes match the model, owners never receive tokens, and configuration is permanent.\n- **`test/HamsterRewards.edge.t.sol`**: 34 unit and property tests for paths the first suite skipped. Rewards side: pending-window quotes revert, ineligible-but-voided windows, voided windows before their end, unknown status values, binary-only wallets when the exact market had no ranks, voided exact market skipping rank validation, each refund flag in isolation, ties beyond the rank count, a zero-tie last rank, zero-line boundaries, overflowing stakes failing closed, a one-wei loss, a maximal single stake, relayer self-claims, contracts that half-implement the game interface, scheduling boundaries, strict current-window comparison, ownership after configuration, pending transfer cancelled by renounce, and funding from wallets without balance or allowance. Token side: exact-allowance spend, approve overwrite, no Approval event on transferFrom, full-balance moves, self transferFrom, and ether rejection. Two fuzz properties bound the loss by the wager and by the non-refunded markets, and check that a claim pays exactly the quote or changes nothing.\n\n**Verification.** I confirmed with a scratch driver that the lifecycle handler reaches successful claims, rejected claims, settlements, voids and ownership moves, so the invariants are not vacuous. Fuzz run counts are set with inline forge-config, and no configuration file was touched.\n\n**Defects.** I found none that needed reporting, so no findings file was written. The one open risk is outside this repository: the contract reverts with InvalidGameState for any wallet holding an exact ticket if the real game ever records a rank with zero ties, which the README already lists as an owner verification duty before configuration.","treeHash":"c5690cdbdc42ec4406d73af70e8163bad1d6ccee","usage":{"cachedInputTokens":1296203,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":47763,"runtime":"claude","turns":34,"wallClockMs":786588}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4dd74fd7c315da80","findings":[{"citation":"resolved","description":"Economic Security guide, 'Break dependencies': HamsterRewards has exactly one outflow, the safeTransfer in _claim, and _claim only runs when game.window(windowId).status == SETTLED (2) for a windowId >= firstEligibleWindow. `game` and `firstEligibleWindow` are write-once (configureGame reverts AlreadyConfigured), fund() is an irrevocable pull with no withdrawal, and the owner has no sweep. The dependency is a single externally operated contract whose settlement needs an off-chain oracle attestation: on mainnet it has created 89 windows and settledWindows() is still 0, and its ABI exposes team-only reconfiguration (scheduleGenesisTimestamp, scheduleSourceUrl). If the site migrates HamsterHour to a new address, or the oracle stops and every window ends VOIDED via voidWindow after the 48 h TIMEOUT, every HAMSTER already in the reward contract is locked forever: no claim can ever satisfy status == SETTLED again. The README documents 'Donations cannot be withdrawn, even if the game fails' as intentional, so this is reported as the design decision's concrete failure state for the author to confirm, not as a permission bypass. A minimal preserving fix is an owner-callable or anyone-callable sweep to economics.remainderTo gated on an objective dead-game condition (e.g. no window SETTLED for N days past firstEligibleWindow), which keeps claims permissionless and the owner unable to touch funds while the game is alive.","line":146,"path":"src/HamsterRewards.sol","reproduction":"State: HamsterRewards configured with game G and firstEligibleWindow F; donor calls fund(1_000e18) (or transfers directly). Then G never returns status 2 for any window >= F: either every window is voided (status 3, which eligibleLoss maps to 0 so _claim reverts NothingToClaim), or G is abandoned and window() reverts, or G reports status 1 forever. Expected: some path returns the 1_000e18 HAMSTER to the requester/donor. Actual: claim/claimFor revert for every (windowId, account), fund() only adds more, configureGame reverts AlreadyConfigured, renounceOwnership/transferOwnership move no tokens; hamster.balanceOf(rewards) stays 1_000e18 permanently. In the existing test fixture: after setUp, call game.setReadsRevert(true) (or set every window to status 3) and observe there is no call sequence by any actor that reduces token.balanceOf(address(rewards)).","severity":"low","snippet":"        hamster.safeTransfer(account, reward);","title":"Donated HAMSTER is permanently stranded if the configured game stops settling or is replaced (no recovery path for a dead dependency)"},{"citation":"resolved","description":"Flow Gap guide, execution x first principles across the launch flow: HamsterRewards.constructor(address hamster_, address owner_) sets the Ownable owner from owner_, and configureGame is onlyOwner and one-shot. The only address placeholders a custom-token manifest may use in application contractorArgs are $token, $requester (economics.remainderTo) and $contract:EarlierName. The README's deployment table, which is the manifest step's instruction for this tree, names `$owner`. A manifest copied from it is either refused by admission (unknown placeholder) or, if a writer substitutes a literal, risks an owner that is not the requester, after which nobody can run configureGame and the contract is unusable (claims and fund() revert NotConfigured forever, renounceOwnership also reverts NotConfigured). The protected Owners check only rejects the factory and IMD as owners, so a wrong literal would pass it. Fix: state `$requester` explicitly in README.md line 13 (and the 'After launch' section), matching the economics.remainderTo address 0xee2aaa315cf7ed169f93148d30d24af9318dbb66 already quoted on line 26.","line":13,"path":"README.md","reproduction":"Input: a launch.json entry {\"contract\":\"HamsterRewards\",\"constructorArgs\":[\"$token\",\"$owner\"]} written from README line 13. Expected: the deployer resolves the second argument to the requester. Actual: `$owner` is not among $token/$requester/$contract:Name, so the manifest is refused; if instead a non-requester literal is substituted, deploy succeeds, owner() != requester, and the requester's configureGame(game, F) reverts OwnableUnauthorizedAccount(requester), leaving every state-changing function except ownership handoff reverting NotConfigured.","severity":"low","snippet":"| `HamsterRewards` | `address hamster_`, `address owner_` | Pass the newly deployed token (`$token`) and the requester's launch owner (`$owner`). |","title":"README tells the manifest writer to pass `$owner`, a placeholder the launch.json schema does not define; following it yields an invalid manifest or a wrong owner"},{"citation":"resolved","description":"Economic Security guide, 'Every finding needs concrete economics'. The reward is one HAMSTER base unit per IMD base unit lost and cannot be changed after deployment (constant; no setter; configuration is one-shot). Pricing from the launch economics in README line 26 (initial market cap 888 IMD for 1e27 base units): 1 HAMSTER = 8.88e-7 IMD. (a) Incentive side: the game's MIN_BET is 0.5 IMD; losing it earns 0.5 HAMSTER worth 4.4e-7 IMD, i.e. 0.00009 % of the stake, so the advertised 'Lose -> Win $HAMSTER' loop has no measurable value unless the requester funds and the market reprices HAMSTER by >1e5x. (b) Extraction side (checked because the README warns about it): a hedger betting X on both OVER and UNDER in one window is guaranteed one losing leg of X and receives X HAMSTER, at a net IMD cost equal to the game's fee split (Split event: winners/stakers/oracle/team) on X, i.e. f*X IMD, versus X*8.88e-7 IMD of HAMSTER; draining a reserve of R HAMSTER costs at least f*R IMD, so at launch prices nobody profits and the reserve is only spent by genuine losers. Neither direction is a code defect; it is recorded so the author decides the constant deliberately before deployment, since it cannot be tuned afterwards and a later price appreciation flips (b) into a profitable drain of whatever is funded.","line":19,"path":"src/HamsterRewards.sol","reproduction":"State from the live game: MIN_BET() = 500000000000000000. A wallet bets 0.5 IMD UNDER in window F, result > line, window settled. eligibleLoss(F, wallet) = 5e17; claim(F) transfers 5e17 HAMSTER. At the manifest economics (888e18 wei of IMD cap / 1e27 supply) that is 4.44e-7 IMD for 0.5 IMD lost. Conversely, with the reward contract funded with 1e26 HAMSTER (10 % of supply), draining it needs 1e26 base units of losing stakes = 1e8 IMD lost gross, costing at least the game's fee share of that; at the opening cap the drained HAMSTER is worth 88.8 IMD.","severity":"info","snippet":"    uint256 public constant REWARD_PER_IMD = 1;","title":"REWARD_PER_IMD = 1 is immutable and, at the launch's own opening cap, pays about 0.00000089 IMD of HAMSTER per IMD lost; the same constant makes hedge farming unprofitable by roughly five orders of ma"}],"hash":"7a6f119b69e36a3ea9607eb873c0b9650d387569ba1972ee03c60e495d05667a","nodeId":"416e7879-7d50-40aa-9482-28978be1ce1f","outcome":"completed","summary":"The findings file is valid, every snippet matches its line, and the working tree holds nothing but `.imd-findings.json`. Nothing else is needed.\n\n**Review complete.** The reward contract is economically sound in its area. I found no path that pays HAMSTER for a refunded or winning stake, no double payment, and no break in the funded-equals-paid-plus-balance conservation law. Three low-impact items are reported.\n\n**What I checked**\n- Traced all ten entry points and three invariants from the Economic Security, Invariant and Flow Gap guides. The existing 56 tests and the stateful invariant suite pass.\n- Verified the contract's assumptions against the live Hamster Hour game on mainnet and the site's own JavaScript payout math. The status encoding, OVER/UNDER and SLEEP winner rules, the exact-rank distance logic, and the refund flags all match what the reward contract encodes.\n- The game has created 89 windows and settled none, and its source is not verified anywhere public. One lead stays unverified for that reason: whether the game can still settle a window after timeout refunds were already paid.\n\n**Findings written to `.imd-findings.json`**\n1. **Low. Stranded donations.** The contract's only outflow requires a window to reach settled status. If the game migrates, dies, or voids every window, all funded HAMSTER is locked forever. The README documents this as intentional, so it is reported as the concrete failure state of that decision.\n2. **Low. README names `$owner`.** The deployment table tells the manifest writer to use a placeholder the launch schema does not define. Following it yields a refused manifest or, with a substituted literal, an owner that can never configure the game.\n3. **Info. Reward rate economics.** One HAMSTER per IMD lost is immutable. At the opening cap it pays about 0.00009 percent of the stake, and by the same arithmetic hedge farming cannot drain the reserve at launch prices. Recorded so the author sets the constant deliberately.\n\n**Coverage** has 15 rows, all answered, none unreached.","treeHash":null,"usage":{"cachedInputTokens":1064228,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":30576,"runtime":"claude","turns":34,"wallClockMs":557191}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"739094f0e08668ee","findings":[{"citation":"resolved","description":"Application-contract constructor arguments in launch.json may only be static words, `$token`, `$requester` or `$contract:EarlierName`. The project's deployment table instructs `$owner` for the only privileged role in the system (the one-time `configureGame` caller). A manifest written from this table is refused at admission, or, if a manifest author substitutes a different value by guesswork, the sole configuration power goes to an unintended address. The intended value is `$requester` (economics.remainderTo, 0xee2aaa315cf7ed169f93148d30d24af9318dbb66), which also satisfies the protected OwnerChecks (not the factory, not IMD).","line":13,"path":"README.md","reproduction":"Write launch.json contracts entry {\"contract\":\"HamsterRewards\",\"constructorArgs\":[\"$token\",\"$owner\"]} as the README directs -> manifest validation rejects the unknown placeholder `$owner`; expected: README names `$requester` so the manifest resolves owner_ to the requester. Fix: change `$owner` to `$requester` in README.md:13 (no code change).","severity":"low","snippet":"| `HamsterRewards` | `address hamster_`, `address owner_` | Pass the newly deployed token (`$token`) and the requester's launch owner (`$owner`). |","title":"README tells the manifest step to pass `$owner` for HamsterRewards.owner_, a placeholder the launch manifest does not accept"}],"hash":"7adf89190c88aa96b6c7a1d16cc2164d41293790f78dc21db051832bed23d117","nodeId":"6b882a8c-19f9-4100-aa37-4fbc6b9e1b08","outcome":"completed","summary":"I found no access-control defect in the contracts, and wrote one low-severity documentation finding to `.imd-findings.json`. The file also has a coverage row for all 10 entry points (each marked `holds`) plus one row for the supply invariant. No other files were changed, and the existing 56 tests pass.\n\n**Finding (low):** `README.md:13` tells whoever writes the manifest to pass `$owner` as the `HamsterRewards` owner. The manifest has no `$owner` value: application contracts can only use plain values, `$token`, `$requester` or `$contract:EarlierName`. A manifest written from that line would be refused, or someone would guess a value for the only privileged role in the system. The fix is a one-word change to `$requester` (the requester's address, `0xee2a…bb66`), which also passes the supplied owner checks.\n\n**Access Control, Trust Gap and Asymmetry**\n- **The token (`HamsterToken`)** is an unchanged OpenZeppelin ERC-20. It has no owner, no extra minting, no tax, and nothing that can freeze or move a holder's balance. The full supply is minted once, to the deployer, in the constructor.\n- **The reward contract (`HamsterRewards`):**\n  - **What the owner can do:** set the game address once, choosing a window that hasn't started yet. Once set, the owner cannot withdraw, change the rate or pause. Ownership hand-over needs the new owner to accept, and the owner cannot give up ownership before the game is set.\n  - **The trust gap:** the owner could point it at a fake game that invents losses and pays out every donation. This is the project's own stated trust assumption, already written up in `docs/SECURITY.md`. Donors can see which game was set before giving, because `fund()` is blocked until then, so I did not count it as a defect. One gap remains: HAMSTER sent directly to the contract before the game is set relies entirely on that owner.\n- **Claims:** `claimFor` lets anyone trigger a claim, but the tokens always go to the bettor, and each wallet can claim once per window. Funding is first-come-first-served by design.\n- **Static-analysis leads:** I rejected the high-severity \"reentrancy\" warning at `HamsterRewards.sol:61`. The calls there only read from the game, so nothing can call back in. The timestamp warnings are start/end deadline checks, not a source of randomness.\n\n**What I couldn't verify:** the deployed Hamster Hour game's source isn't published (Sourcify has no match). I checked the site's front-end code and it agrees with the reward contract on which side loses in the Over/Under and Sleeping/Running markets. Two edge cases depend on the game itself, and I left them out because I can't prove them:\n- whether a result exactly equal to the line is refunded or counted as a win for Under;\n- whether a market where nobody bet on the winning side is voided.\n\nIf the game does neither, some real losers would get no HAMSTER.","treeHash":null,"usage":{"cachedInputTokens":451532,"inputTokens":20,"model":"claude-opus-5-5","outputTokens":8980,"runtime":"claude","turns":10,"wallClockMs":119952}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f9a12c57a094ca8d","findings":[{"citation":"resolved","description":"Merged from audit_permissions, audit_flow and audit_economics (same root cause, three reports). The custom_token manifest accepts only static words, $token, $requester or $contract:EarlierName in application-contract constructor arguments; `$owner` is not a placeholder. The launch.json already in the tree (line 16) correctly passes \"$requester\", so the manifest itself is not defective and admission is not blocked by this. What remains is a documentation defect: the README's deployment table, which is the instruction a manifest writer or operator copies from, disagrees with the committed manifest and with the launch vocabulary. A manifest regenerated from the README would be refused (unknown placeholder) or, if a literal were substituted by guesswork, would hand the one-shot configureGame power to an address other than the requester; after that nobody could configure the contract and every state-changing function except ownership handoff would revert NotConfigured. No Solidity change is needed: the fix is to write `$requester` (economics.remainderTo, 0xee2aaa315cf7ed169f93148d30d24af9318dbb66) in README.md line 13.","line":13,"path":"README.md","reproduction":"Compare README.md line 13 (`$owner`) with launch.json lines 14-17 (constructorArgs [\"$token\", \"$requester\"]) and with the custom_token launch vocabulary ($token, $requester, $contract:Name). Expected: the README names the same placeholder the manifest uses. Actual: the README names `$owner`, which no manifest rule resolves. If a manifest were written from the README, {\"contract\":\"HamsterRewards\",\"constructorArgs\":[\"$token\",\"$owner\"]} would be refused at validation.","severity":"low","snippet":"| `HamsterRewards` | `address hamster_`, `address owner_` | Pass the newly deployed token (`$token`) and the requester's launch owner (`$owner`). |","title":"README deployment table names `$owner` for HamsterRewards.owner_; the manifest vocabulary and the tree's launch.json use `$requester`"},{"citation":"resolved","description":"Reproduced the audit_economics finding. HamsterRewards has exactly one outflow, the safeTransfer in _claim (line 146), and _claim pays only when game.window(windowId).status == 2 for a windowId >= firstEligibleWindow and the position has a losing stake. game and firstEligibleWindow are write-once (configureGame reverts AlreadyConfigured at line 58), fund() is an irrevocable pull, and there is no sweep, no owner withdrawal and no expiry. The dependency is a single externally operated contract (HamsterHour at 0xc5217f129da200a8e86229de4eabf3686eef64b1, source commit 7ab2a01b) whose settle() needs a signed oracle attestation within 48 h of each window end, after which anyone can voidWindow (status 3) and eligibleLoss returns 0 (line 94). Read on mainnet during this review: currentWindow() = 89, settledWindows() = 0, window 85 status 1 (Open) with endsAt 1792157400 and no settlement about 3.6 hours later, imdLiability 0.5 IMD, oracleReserve 0. The game is live but has never settled a window. If the oracle never produces results, or the operators migrate the game to a new address (the README itself says the game address is not hardcoded and must be chosen at configure time), every HAMSTER already funded is locked forever. The README documents 'Donations are irrevocable' as intentional, so this is reported as the design decision's concrete failure state for the requester to confirm, not as a permission bypass. A fix that preserves the agreed trust model (owner never touches funds while the game is alive) is a sweep to economics.remainderTo gated on an objective dead-game condition, e.g. no window >= firstEligibleWindow has reached status 2 within N days after firstEligibleWindow's endsAt. If the requester accepts the lock as designed, no code change is needed.","line":70,"path":"src/HamsterRewards.sol","reproduction":"State: HamsterRewards configured with game G and firstEligibleWindow 1; fund(1_000e18). Then G reports status 3 (voided) for window 1 (or reverts on window(), or stays at status 1 forever). Calls tried: claimFor(1, bettor) with bettor.over = [100e18, 0] -> revert NothingToClaim (status 3 maps to loss 0); configureGame(G2, 5) from owner -> revert AlreadyConfigured; renounceOwnership() from owner -> succeeds and moves nothing; transferOwnership moves nothing; fund() only adds. Expected (if recovery were intended): some actor can return the 1_000e18 to the requester. Actual: hamster.balanceOf(rewards) stays 1_000e18 under every reachable call sequence. Verified with a scratch Foundry test against MockHamsterHour (set window 1 status 3, assert claimFor reverts NothingToClaim, configureGame reverts AlreadyConfigured, renounceOwnership succeeds, balance == 1_000 ether).","severity":"low","snippet":"    /// @notice Donate HAMSTER from an exact allowance. There is no administrative withdrawal.\n    function fund(uint256 amount) external nonReentrant {","title":"Donated HAMSTER has no recovery path if the configured game never reaches a Settled window (design risk, live game has 0 settlements)"},{"citation":"resolved","description":"Merged from audit_math and audit_economics (same mechanism: gross per-side loss, no netting of the same wallet's winning side, constant REWARD_PER_IMD = 1 at line 19). eligibleLoss adds the gross stake on each losing side without netting the wallet's winning side of the same market. In the real game (HamsterHour.settle, source at the recorded commit) a contested binary market pays winners pool - 5% stakers - 3% oracle - 1% team = 91% of the pool pro rata. A wallet staking X on both UNDER and OVER of one window is guaranteed one losing leg and therefore X HAMSTER per window, at a net IMD cost of 0.18X when it is alone in the market (pays 2X, wins back 0.91*2X) and less as others join its winning side. At the launch economics in launch.json (888 IMD cap for 1e27 base units, 8.88e-7 IMD per HAMSTER) the hedge costs about 0.18 IMD per HAMSTER earned, so it is unprofitable by roughly five orders of magnitude at the opening price and becomes profitable only if HAMSTER trades above about 0.18 IMD. Conversely a genuine 0.5 IMD loser (MIN_BET) earns 0.5 HAMSTER worth 4.4e-7 IMD. Both directions are consequences of the documented per-ticket rule (README 'Hedging opposing bets ... can farm losing-stake rewards') and of a constant that cannot be changed after deployment; they are recorded so the requester sizes the funded inventory and the rate deliberately. If netting is wanted, loss for a binary market = losing-side stake minus the same wallet's winning-side stake, floored at zero; single-side semantics are unchanged by that.","line":101,"path":"src/HamsterRewards.sol","reproduction":"MockHamsterHour window 1: status 2, line 1000, result 1200, over = [100e18, 100e18], rewards[0] = 182e18; position of wallet H: over = [100e18, 100e18] (100 UNDER, 100 OVER), no other bettors. rewardFor(1, H) == 100e18 and claim(1) from H transfers 100e18 HAMSTER (scratch Foundry test, passes). In the game H would reclaim 0.91 * 200e18 = 182e18 IMD, a net IMD loss of 18e18. Expected under the README's per-ticket rule: 100e18 (the code does what the document says); the ratio of HAMSTER earned to IMD actually lost is 100:18 for a lone hedger and approaches 100:0 as other bettors join the winning side.","severity":"info","snippet":"            loss += p.over[w.result > w.line ? 0 : 1];","title":"Opposite-side hedges in one binary market always earn the full losing-side stake in HAMSTER; the 1:1 rate is immutable, so the farm's profitability is set by HAMSTER's price alone"}],"hash":"d48762691560b73b22c1165b8ca4e64f6d945f15e4545a1ac66705aa8dfd1a2a","nodeId":"683b081c-8f81-4464-9247-c172fd7ab7df","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the result. The scratch test is removed and the working tree is otherwise untouched.\n\n**Outcome: no code defect in HamsterToken or HamsterRewards.** Three findings survive, all low or informational.\n\n- **Low, README.md line 13.** The deployment table tells the manifest writer to pass `$owner`, which is not a manifest placeholder. The committed launch.json already uses `$requester`, so this is a documentation inconsistency, not a blocked launch. Three specialists reported it; merged into one.\n- **Low, HamsterRewards fund().** Donations have no recovery path if the configured game never produces a Settled window. The live game on mainnet has created 89 windows and settled none, and window 85 is still Open hours past its end. The README documents the lock as intentional, so this is a design risk for the requester to confirm.\n- **Info, eligibleLoss line 101.** A wallet hedging both sides of one binary market always earns its full losing-side stake, while its real IMD loss is only the 9% fee share. The 1:1 rate is immutable. At the opening cap this is unprofitable by about five orders of magnitude. Two specialists' notes merged.\n\n**What I verified beyond the specialists.** I pulled the actual HamsterHour source at the commit the site's deployment record names and compared it line by line with eligibleLoss. Status codes, side indices, market-void indices, the result-equals-line refund, one-sided refunds, exact-rank matching and position persistence after claim all agree. The site bundle agrees too. All 92 project tests pass, formatting and the ABI check pass, and the manifest's keys, types, lowercase addresses, name lengths and constructor arity are correct. The static-analysis leads (timestamp checks, reentrancy in configureGame, loop revert, uninitialized local) are false positives: the game reads are staticcalls and the local is initialized.\n\n**Coverage:** all 10 entry points answered. Nine hold; fund() points at the stranded-donation finding. Three extra rows record the game-semantics comparison, the manifest shape, and CREATE2 deployability. The protected owner and token floor harness could not be run here because its helper files are not in the tree; its conditions were checked by reading.","treeHash":null,"usage":{"cachedInputTokens":1360111,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":25743,"runtime":"claude","turns":34,"wallClockMs":562861}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1a7606be97f168d4","findings":[{"citation":"resolved","description":"eligibleLoss adds the gross stake of each losing side per market without netting the same wallet's winning side. The game (HamsterHour.sol at the recorded commit, settle(): rewards[i] = pool - 5% - 3% - 1%) returns 91% of a contested pool to the winning side. A wallet that stakes X on both OVER and UNDER of one window is guaranteed one losing side, so it always receives X HAMSTER, while its IMD cost is only the fee share of the pool it did not win back. This is documented in README (\"Hedging opposing bets ... can farm losing-stake rewards\") and is a design property, not a code defect; it is recorded here with concrete numbers so the author can size the HAMSTER inventory and rate (REWARD_PER_IMD = 1, immutable) against it. At the launch cap of 888 IMD for 1e9 HAMSTER (8.88e-7 IMD per HAMSTER) the farm costs about 0.18 IMD of fees per HAMSTER earned when the hedger is the only bettor, so it is unprofitable at launch price and becomes profitable only if HAMSTER trades above roughly 0.18 IMD, or earlier when other bettors' stakes dilute the hedger's fee loss. No fix is required to preserve the agreed design; if the author wants to limit it, netting a wallet's two sides of the same binary market (loss = max(side0, side1) - min(side0, side1) on the losing side) would remove the guaranteed component without changing single-side semantics.","line":101,"path":"src/HamsterRewards.sol","reproduction":"Game settled window k, result != line, over = [100e18 from wallet A on UNDER, 100e18 from wallet A on OVER], no other bettors, status 2, marketVoided[0] false. In the game A claims 0.91 * 200e18 = 182e18 IMD back (net IMD loss 18e18). HamsterRewards.rewardFor(k, A) returns 100e18 and claim(k) pays 100e18 HAMSTER. Reproduced against MockHamsterHour with position over = [100 ether, 100 ether] and the fixture window (line 1000, result 1200): rewardFor == 100 ether. Expected under the documented per-ticket rule: 100e18 (the code does what the README says); flagged because the ratio of HAMSTER earned to IMD actually lost is 100:18 for a lone hedger and approaches 100:0 as other bettors join the winning side's pool.","severity":"info","snippet":"            loss += p.over[w.result > w.line ? 0 : 1];","title":"Hedged OVER+UNDER (or SLEEPING+RUNNING) stakes always earn the full losing-side stake in HAMSTER while the net IMD loss is only the 9% fee share"}],"hash":"f2669761f495dcdb3e5cfca516d556d089b2f2d7fd71509af20a9a720510b404","nodeId":"9d272e1b-ef6e-424c-a279-58ad9b9a1599","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the result. No source file was changed and the scratch tests were removed.\n\n**Outcome:** no defect of medium or higher severity in the math, boundary or numerical-gap area. The file records one info-level item and a 14-row coverage record answering all ten listed entry points plus four invariants.\n\n**What I verified**\n\n- **Reward arithmetic.** Reward equals loss times a constant of one. IMD on mainnet reports 18 decimals, as does HAMSTER, so the base-unit rate is exact. There is no division, downcast or scale mixing. A one-wei loss pays one wei and absurd stakes revert through checked addition rather than wrapping.\n- **Game semantics.** I fetched the game's source at the commit recorded in the site's deployment file and compared it line by line with `eligibleLoss`. Status codes, market and side indices, the sleeping rule, the one-sided and equal-to-line refunds, the three-rank distance logic, and position persistence all match. The exact market is never voided by the game, and a rank count of zero with an exact entry cannot occur, so the fail-closed reverts are unreachable for the honest game.\n- **Boundaries.** First-window configuration requires a future start and an id above the current window. Window times for out-of-range ids revert in the game before any overflow. Settlement in the game requires the window to have ended, so the contract's end-time check never blocks an honest settled window.\n- **Token.** The supply constant evaluates to the manifest's string exactly, minted once in the constructor, with unmodified OpenZeppelin transfer and allowance code, so every launch flow moves the stated amount.\n\n**The one recorded item** is informational. A wallet that stakes equally on both sides of a binary market always earns the full losing side in HAMSTER while losing only the fee share in IMD. The README already documents this as a design property, so I quantified it for the author's funding decision rather than proposing a change. At the launch price the farm is far from profitable.\n\nStatic-analysis leads (timestamp comparisons, state change after an owner-only external view call, the require inside the bounded rank loop) were each traced and none reproduced as a defect.","treeHash":null,"usage":{"cachedInputTokens":1310155,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":31874,"runtime":"claude","turns":37,"wallClockMs":545536}}],"verification":[{"checks":[{"durationMs":2360,"exitCode":0,"name":"build","output":"Compiling 40 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.29s\nCompiler run successful!\n","passed":true},{"durationMs":3808,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 10 tests for test/HamsterRewards.t.sol:HamsterRewardsSetupTest\n[PASS] test_AdminCannotWithdrawPauseOrChangeRate() (gas: 379538)\n[PASS] test_ConfigurationCannotChangeEvenWithoutFundingOrClaims() (gas: 120467)\n[PASS] test_ConstructorValidatesAddressesButMakesNoExternalCalls() (gas: 6086)\n[PASS] test_FirstWindowMustBeFutureAndNotCurrent() (gas: 214396)\n[PASS] test_InvalidGameAndWrongWagerTokenRejected() (gas: 196310)\n[PASS] test_InvalidGameTimesRejected() (gas: 47792)\n[PASS] test_OnlyExplicitOwnerConfigures() (gas: 153930)\n[PASS] test_RenounceAfterConfigurationDoesNotStopClaims() (gas: 306747)\n[PASS] test_TwoStepOwnershipTransferBeforeConfiguration() (gas: 238399)\n[PASS] test_UnconfiguredOperationsHaveClearErrors() (gas: 152367)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 27.56ms (3.37ms CPU time)\n\nRan 4 tests for test/HamsterRewards.t.sol:HamsterRewardsAdversarialTest\n[PASS] test_FailedTokenTransferRollsBackClaimAndAccounting() (gas: 635065)\n[PASS] test_FeeOnTransferFundingRejectedAtomically() (gas: 203549)\n[PASS] test_FundingCallbackCannotReenterClaim() (gas: 254863)\n[PASS] test_TransferCallbackCannotReenterClaim() (gas: 396573)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 27.55ms (1.28ms CPU time)\n\nRan 18 tests for test/HamsterRewards.t.sol:HamsterRewardsEligibilityTest\n[PASS] testFuzz_BinaryLosersAndRefunds(uint128,uint128,uint128,uint128,uint8) (runs: 512, μ: 381988, ~: 383550)\n[PASS] testFuzz_ExactRanking(uint256,uint256,uint128) (runs: 512, μ: 344188, ~: 344246)\n[PASS] test_ExactAllThreeRanksAndTiesAreWinners() (gas: 1536508)\n[PASS] test_ExactDistanceWorksAtUint256Extremes() (gas: 690975)\n[PASS] test_ExactSingleRankAndNoUnusedRankMatch() (gas: 560984)\n[PASS] test_IMDAndJackpotClaimStateCannotChangeEligibility() (gas: 749869)\n[PASS] test_InvalidRankDataFailsClosed() (gas: 947569)\n[PASS] test_LineEqualityRefundsBothBinarySides() (gas: 452826)\n[PASS] test_LosingBetsAcrossMarketsEarnExistingTokens() (gas: 596313)\n[PASS] test_MarketRefundFlagsExcludeAllRefundedBets() (gas: 494343)\n[PASS] test_OldWindowsExcludedAndNoRewardExpiryAfterFinality() (gas: 785085)\n[PASS] test_PrematureSettledResultRejectedUntilEnd() (gas: 411750)\n[PASS] test_UncontestedBinaryMarketsNeverEarnRewards() (gas: 621363)\n[PASS] test_UnderResultAndZeroResultChooseCorrectLosers() (gas: 896350)\n[PASS] test_UnknownOpenAndUnsettledWindowsCannotClaim() (gas: 767648)\n[PASS] test_VoidedWindowHasNoRewardEvenWithLosingLookingPositions() (gas: 441594)\n[PASS] test_WalletWithBothWinningAndLosingBetsOnlyEarnsLosingStake() (gas: 350830)\n[PASS] test_WinnersAndNonBettorsReceiveNoLossReward() (gas: 490495)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 27.60ms (62.03ms CPU time)\n\nRan 10 tests for test/HamsterRewards.t.sol:HamsterRewardsPaymentTest\n[PASS] testFuzz_ClaimsConserveTokens(uint128,uint128) (runs: 512, μ: 940047, ~: 938252)\nLogs:\n  Bound result 3\n  Bound result 13\n\n[PASS] test_ClaimForPaysBettorNeverCaller() (gas: 338464)\n[PASS] test_DirectDonationsAreUsable() (gas: 341919)\n[PASS] test_ExternalGameFailureDoesNotConsumeClaim() (gas: 409958)\n[PASS] test_InsufficientInventoryDoesNotConsumeClaimAndTopUpAllowsRetry() (gas: 632848)\n[PASS] test_MalformedGameResponseFailsClosed() (gas: 67381)\n[PASS] test_NoAccidentalEtherAccepted() (gas: 36058)\n[PASS] test_NoDoubleClaimAndIndependentWindows() (gas: 1190789)\n[PASS] test_PermissionlessFundingWithExactAllowanceAndEvent() (gas: 193264)\n[PASS] test_ZeroFundingAndFundingWithoutAllowanceFail() (gas: 85804)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 31.74ms (34.13ms CPU time)\n\nRan 13 tests for test/HamsterToken.t.sol:HamsterTokenTest\n[PASS] testFuzz_ConservationAndAllowance(uint256,uint256) (runs: 512, μ: 245853, ~: 248540)\nLogs:\n  Bound result 163180084878773170784918813\n  Bound result 140979614315091927206736116\n\n[PASS] test_ApproveTransferFromAndRevoke() (gas: 257395)\n[PASS] test_ConstructorEmitsSingleMint() (gas: 5545)\n[PASS] test_FactoryOwnsEntireSupplyAndAppHasExplicitOwner() (gas: 378736)\n[PASS] test_InsufficientBalanceAndAllowanceAreAtomic() (gas: 151369)\n[PASS] test_LaunchDistributionAndClaimArriveExactly() (gas: 672061)\n[PASS] test_MetadataAndWholeSupply() (gas: 71461)\n[PASS] test_NoForbiddenRuntimeOpcodes() (gas: 784813)\n[PASS] test_NoMintFreezeSeizeOrUpgradeEndpoints() (gas: 425487)\n[PASS] test_StandardUnlimitedAllowanceBehavior() (gas: 120596)\n[PASS] test_TransferAndEvents() (gas: 81161)\n[PASS] test_ZeroAddressesRejected() (gas: 83730)\n[PASS] test_ZeroAndSelfTransfersAreStandard() (gas: 127169)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 31.75ms (21.61ms CPU time)\n\nRan 1 test for test/HamsterRewards.invariant.t.sol:HamsterRewardsInvariantTest\n[PASS]\nHamsterRewardsInvariantTest invariants:\n[PASS] invariant_EachWalletWindowPaysAtMostOnce\n[PASS] invariant_FixedSupplyAndReserveConservation\n HamsterRewardsInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------+-------+---------+----------╮\n| Contract       | Selector | Calls | Reverts | Discards |\n+========================================================+\n| RewardsHandler | claim    | 4115  | 0       | 0        |\n|----------------+----------+-------+---------+----------|\n| RewardsHandler | fund     | 4077  | 0       | 0        |\n╰----------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 479821422010289616521622\n  Bound result 2\n  Bound result 885710097\n  Bound result 315360000\n  Bound result 50000000000000000000\n  Bound result 1901074597\n  Bound result 1\n  Bound result 8\n  Bound result 8\n  Bound result 70000000000000000000\n  Bound result 2\n  Bound result 8640000\n  Bound result 8\n  Bound result 1\n  Bound result 4\n  Bound result 5\n  Bound result 7\n  Bound result 4\n  Bound result 367078845005893502975085\n  Bound result 3013170592\n  Bound result 3237\n  Bound result 15999999999999999999\n  Bound result 1\n  Bound result 8\n  Bound result 8\n  Bound result 8\n  Bound result 7\n  Bound result 8\n  Bound result 2111799\n  Bound result 138649887167543885672875\n  Bound result 8\n  Bound result 1000000000000000000000\n  Bound result 8\n  Bound result 10354586011754298099754\n  Bound result 8\n  Bound result 8\n  Bound result 350218202752168428711\n  Bound result 8\n  Bound result 90000000000000000000\n  Bound result 1\n  Bound result 3\n  Bound result 8\n  Bound result 7\n  Bound result 255\n  Bound result 395415285134322081059\n  Bound result 642543083648670723946\n  Bound result 8\n  Bound result 11\n  Bound result 2829\n  Bound result 1158957869146037950623\n  Bound result 223937631186045234066\n  Bound result 6\n  Bound result 58503792798076760620\n  Bound result 1000000000\n  Bound result 9203\n  Bound result 4\n  Bound result 1541\n  Bound result 3\n  Bound result 7\n  Bound result 8\n  Bound result 9\n  Bound result 2\n  Bound result 4\n  Bound result 8892572210366801193\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.73s (3.72s CPU time)\n\nRan 6 test suites in 3.73s (3.87s CPU time): 56 tests passed, 0 failed, 0 skipped (56 total tests)\n","passed":true},{"durationMs":41,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRewards.acceptOwnership()\",\"HamsterRewards.claim(uint256)\",\"HamsterRewards.claimFor(uint256,address)\",\"HamsterRewards.configureGame(address,uint256)\",\"HamsterRewards.fund(uint256)\",\"HamsterRewards.renounceOwnership()\",\"HamsterRewards.transferOwnership(address)\",\"HamsterToken.approve(address,uint256)\",\"HamsterToken.transfer(address,uint256)\",\"HamsterToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":138,\"docs/REFERENCES.md\":42,\"docs/SECURITY.md\":38,\"docs/reference/HamsterHour.reads.abi.json\":269,\"foundry.toml\":21,\"launch.json\":32,\"remappings.txt\":2,\"src/HamsterRewards.sol\":153,\"src/HamsterToken.sol\":13,\"src/interfaces/IHamsterHour.sol\":52,\"test/HamsterRewards.invariant.t.sol\":149,\"test/HamsterRewards.t.sol\":654,\"test/HamsterToken.t.sol\":203,\"test/mocks/MockHamsterHour.sol\":53,\"tools/check_game_abi.py\":24},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"104d4961c218724813af93bef024353978c088c20ca7eb8f4b7963b2576cb579","verifiedTreeHash":"2d43ea8864b68fe6ef6a3b4f1990531539811f22","verifierVersion":"0.1.0+d952fceb"},{"checks":[{"durationMs":2321,"exitCode":0,"name":"build","output":"Compiling 40 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.25s\nCompiler run successful!\n","passed":true},{"durationMs":3817,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 18 tests for test/HamsterRewards.t.sol:HamsterRewardsEligibilityTest\n[PASS] testFuzz_BinaryLosersAndRefunds(uint128,uint128,uint128,uint128,uint8) (runs: 512, μ: 381988, ~: 383550)\n[PASS] testFuzz_ExactRanking(uint256,uint256,uint128) (runs: 512, μ: 344188, ~: 344246)\n[PASS] test_ExactAllThreeRanksAndTiesAreWinners() (gas: 1536508)\n[PASS] test_ExactDistanceWorksAtUint256Extremes() (gas: 690975)\n[PASS] test_ExactSingleRankAndNoUnusedRankMatch() (gas: 560984)\n[PASS] test_IMDAndJackpotClaimStateCannotChangeEligibility() (gas: 749869)\n[PASS] test_InvalidRankDataFailsClosed() (gas: 947569)\n[PASS] test_LineEqualityRefundsBothBinarySides() (gas: 452826)\n[PASS] test_LosingBetsAcrossMarketsEarnExistingTokens() (gas: 596313)\n[PASS] test_MarketRefundFlagsExcludeAllRefundedBets() (gas: 494343)\n[PASS] test_OldWindowsExcludedAndNoRewardExpiryAfterFinality() (gas: 785085)\n[PASS] test_PrematureSettledResultRejectedUntilEnd() (gas: 411750)\n[PASS] test_UncontestedBinaryMarketsNeverEarnRewards() (gas: 621363)\n[PASS] test_UnderResultAndZeroResultChooseCorrectLosers() (gas: 896350)\n[PASS] test_UnknownOpenAndUnsettledWindowsCannotClaim() (gas: 767648)\n[PASS] test_VoidedWindowHasNoRewardEvenWithLosingLookingPositions() (gas: 441594)\n[PASS] test_WalletWithBothWinningAndLosingBetsOnlyEarnsLosingStake() (gas: 350830)\n[PASS] test_WinnersAndNonBettorsReceiveNoLossReward() (gas: 490495)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 28.99ms (58.09ms CPU time)\n\nRan 10 tests for test/HamsterRewards.t.sol:HamsterRewardsSetupTest\n[PASS] test_AdminCannotWithdrawPauseOrChangeRate() (gas: 379538)\n[PASS] test_ConfigurationCannotChangeEvenWithoutFundingOrClaims() (gas: 120467)\n[PASS] test_ConstructorValidatesAddressesButMakesNoExternalCalls() (gas: 6086)\n[PASS] test_FirstWindowMustBeFutureAndNotCurrent() (gas: 214396)\n[PASS] test_InvalidGameAndWrongWagerTokenRejected() (gas: 196310)\n[PASS] test_InvalidGameTimesRejected() (gas: 47792)\n[PASS] test_OnlyExplicitOwnerConfigures() (gas: 153930)\n[PASS] test_RenounceAfterConfigurationDoesNotStopClaims() (gas: 306747)\n[PASS] test_TwoStepOwnershipTransferBeforeConfiguration() (gas: 238399)\n[PASS] test_UnconfiguredOperationsHaveClearErrors() (gas: 152367)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 29.52ms (2.29ms CPU time)\n\nRan 13 tests for test/HamsterToken.t.sol:HamsterTokenTest\n[PASS] testFuzz_ConservationAndAllowance(uint256,uint256) (runs: 512, μ: 245853, ~: 248540)\nLogs:\n  Bound result 163180084878773170784918813\n  Bound result 140979614315091927206736116\n\n[PASS] test_ApproveTransferFromAndRevoke() (gas: 257395)\n[PASS] test_ConstructorEmitsSingleMint() (gas: 5545)\n[PASS] test_FactoryOwnsEntireSupplyAndAppHasExplicitOwner() (gas: 378736)\n[PASS] test_InsufficientBalanceAndAllowanceAreAtomic() (gas: 151369)\n[PASS] test_LaunchDistributionAndClaimArriveExactly() (gas: 672061)\n[PASS] test_MetadataAndWholeSupply() (gas: 71461)\n[PASS] test_NoForbiddenRuntimeOpcodes() (gas: 784813)\n[PASS] test_NoMintFreezeSeizeOrUpgradeEndpoints() (gas: 425487)\n[PASS] test_StandardUnlimitedAllowanceBehavior() (gas: 120596)\n[PASS] test_TransferAndEvents() (gas: 81161)\n[PASS] test_ZeroAddressesRejected() (gas: 83730)\n[PASS] test_ZeroAndSelfTransfersAreStandard() (gas: 127169)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 29.57ms (36.34ms CPU time)\n\nRan 4 tests for test/HamsterRewards.t.sol:HamsterRewardsAdversarialTest\n[PASS] test_FailedTokenTransferRollsBackClaimAndAccounting() (gas: 635065)\n[PASS] test_FeeOnTransferFundingRejectedAtomically() (gas: 203549)\n[PASS] test_FundingCallbackCannotReenterClaim() (gas: 254863)\n[PASS] test_TransferCallbackCannotReenterClaim() (gas: 396573)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 30.35ms (1.27ms CPU time)\n\nRan 10 tests for test/HamsterRewards.t.sol:HamsterRewardsPaymentTest\n[PASS] testFuzz_ClaimsConserveTokens(uint128,uint128) (runs: 512, μ: 940047, ~: 938252)\nLogs:\n  Bound result 91609316869910335227155\n  Bound result 42224548777802\n\n[PASS] test_ClaimForPaysBettorNeverCaller() (gas: 338464)\n[PASS] test_DirectDonationsAreUsable() (gas: 341919)\n[PASS] test_ExternalGameFailureDoesNotConsumeClaim() (gas: 409958)\n[PASS] test_InsufficientInventoryDoesNotConsumeClaimAndTopUpAllowsRetry() (gas: 632848)\n[PASS] test_MalformedGameResponseFailsClosed() (gas: 67381)\n[PASS] test_NoAccidentalEtherAccepted() (gas: 36058)\n[PASS] test_NoDoubleClaimAndIndependentWindows() (gas: 1190789)\n[PASS] test_PermissionlessFundingWithExactAllowanceAndEvent() (gas: 193264)\n[PASS] test_ZeroFundingAndFundingWithoutAllowanceFail() (gas: 85804)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 30.44ms (32.30ms CPU time)\n\nRan 1 test for test/HamsterRewards.invariant.t.sol:HamsterRewardsInvariantTest\n[PASS]\nHamsterRewardsInvariantTest invariants:\n[PASS] invariant_EachWalletWindowPaysAtMostOnce\n[PASS] invariant_FixedSupplyAndReserveConservation\n HamsterRewardsInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------+-------+---------+----------╮\n| Contract       | Selector | Calls | Reverts | Discards |\n+========================================================+\n| RewardsHandler | claim    | 4115  | 0       | 0        |\n|----------------+----------+-------+---------+----------|\n| RewardsHandler | fund     | 4077  | 0       | 0        |\n╰----------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 479821422010289616521622\n  Bound result 2\n  Bound result 885710097\n  Bound result 315360000\n  Bound result 50000000000000000000\n  Bound result 1901074597\n  Bound result 1\n  Bound result 8\n  Bound result 8\n  Bound result 70000000000000000000\n  Bound result 2\n  Bound result 8640000\n  Bound result 8\n  Bound result 1\n  Bound result 4\n  Bound result 5\n  Bound result 7\n  Bound result 4\n  Bound result 367078845005893502975085\n  Bound result 3013170592\n  Bound result 3237\n  Bound result 15999999999999999999\n  Bound result 1\n  Bound result 8\n  Bound result 8\n  Bound result 8\n  Bound result 7\n  Bound result 8\n  Bound result 2111799\n  Bound result 138649887167543885672875\n  Bound result 8\n  Bound result 1000000000000000000000\n  Bound result 8\n  Bound result 10354586011754298099754\n  Bound result 8\n  Bound result 8\n  Bound result 350218202752168428711\n  Bound result 8\n  Bound result 90000000000000000000\n  Bound result 1\n  Bound result 3\n  Bound result 8\n  Bound result 7\n  Bound result 255\n  Bound result 395415285134322081059\n  Bound result 642543083648670723946\n  Bound result 8\n  Bound result 11\n  Bound result 2829\n  Bound result 1158957869146037950623\n  Bound result 223937631186045234066\n  Bound result 6\n  Bound result 58503792798076760620\n  Bound result 1000000000\n  Bound result 9203\n  Bound result 4\n  Bound result 1541\n  Bound result 3\n  Bound result 7\n  Bound result 8\n  Bound result 9\n  Bound result 2\n  Bound result 4\n  Bound result 8892572210366801193\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.74s (3.74s CPU time)\n\nRan 6 test suites in 3.74s (3.89s CPU time): 56 tests passed, 0 failed, 0 skipped (56 total tests)\n","passed":true},{"durationMs":34,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRewards.acceptOwnership()\",\"HamsterRewards.claim(uint256)\",\"HamsterRewards.claimFor(uint256,address)\",\"HamsterRewards.configureGame(address,uint256)\",\"HamsterRewards.fund(uint256)\",\"HamsterRewards.renounceOwnership()\",\"HamsterRewards.transferOwnership(address)\",\"HamsterToken.approve(address,uint256)\",\"HamsterToken.transfer(address,uint256)\",\"HamsterToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":138,\"docs/REFERENCES.md\":42,\"docs/SECURITY.md\":38,\"docs/reference/HamsterHour.reads.abi.json\":269,\"foundry.toml\":21,\"remappings.txt\":2,\"src/HamsterRewards.sol\":153,\"src/HamsterToken.sol\":13,\"src/interfaces/IHamsterHour.sol\":52,\"test/HamsterRewards.invariant.t.sol\":149,\"test/HamsterRewards.t.sol\":654,\"test/HamsterToken.t.sol\":203,\"test/mocks/MockHamsterHour.sol\":53,\"tools/check_game_abi.py\":24},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":752,"exitCode":0,"name":"slither","output":"[low/medium] timestamp at src/HamsterRewards.sol:90: HamsterRewards.eligibleLoss(uint256,address) (src/HamsterRewards.sol#90-117) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRewards.sol:57: HamsterRewards.configureGame(address,uint256) (src/HamsterRewards.sol#57-68) uses timestamp for comparisons","passed":true},{"durationMs":295,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/HamsterRewards.sol:61: Reentrancy: State change after external call (3 places)\n[low] centralization-risk at src/HamsterRewards.sol:14: Centralization Risk (3 places)\n[low] large-numeric-literal at src/HamsterToken.sol:8: Large Numeric Literal\n[low] require-revert-in-loop at src/HamsterRewards.sol:111: Loop Contains `require`/`revert`\n[low] uninitialized-local-variable at src/HamsterRewards.sol:111: Uninitialized Local Variable","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"2f3ea3c1bd88ad9fa9259f45d5dd6228d1e4c20cc95e452e1be178796590e627","verifiedTreeHash":"83d4783cd7b47a0f01102c69e584183ee9134c87","verifierVersion":"0.1.0+d952fceb"},{"checks":[{"durationMs":6022,"exitCode":0,"name":"build","output":"Compiling 43 files with Solc 0.8.26\nSolc 0.8.26 finished in 5.89s\nCompiler run successful!\n","passed":true},{"durationMs":90526,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/HamsterRewards.t.sol:HamsterRewardsAdversarialTest\n[PASS] test_FailedTokenTransferRollsBackClaimAndAccounting() (gas: 635065)\n[PASS] test_FeeOnTransferFundingRejectedAtomically() (gas: 203549)\n[PASS] test_FundingCallbackCannotReenterClaim() (gas: 254863)\n[PASS] test_TransferCallbackCannotReenterClaim() (gas: 396573)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 4.72ms (991.17µs CPU time)\n\nRan 10 tests for test/HamsterRewards.t.sol:HamsterRewardsSetupTest\n[PASS] test_AdminCannotWithdrawPauseOrChangeRate() (gas: 379538)\n[PASS] test_ConfigurationCannotChangeEvenWithoutFundingOrClaims() (gas: 120467)\n[PASS] test_ConstructorValidatesAddressesButMakesNoExternalCalls() (gas: 6086)\n[PASS] test_FirstWindowMustBeFutureAndNotCurrent() (gas: 214396)\n[PASS] test_InvalidGameAndWrongWagerTokenRejected() (gas: 196310)\n[PASS] test_InvalidGameTimesRejected() (gas: 47792)\n[PASS] test_OnlyExplicitOwnerConfigures() (gas: 153930)\n[PASS] test_RenounceAfterConfigurationDoesNotStopClaims() (gas: 306747)\n[PASS] test_TwoStepOwnershipTransferBeforeConfiguration() (gas: 238399)\n[PASS] test_UnconfiguredOperationsHaveClearErrors() (gas: 152367)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 12.21ms (2.26ms CPU time)\n\nRan 7 tests for test/HamsterRewards.edge.t.sol:HamsterTokenEdgeTest\n[PASS] testFuzz_TransferChainConservesSupply(uint256,uint256,uint256) (runs: 1000, μ: 200573, ~: 203001)\nLogs:\n  Bound result 10799\n  Bound result 72\n  Bound result 67\n\n[PASS] test_ApproveOverwritesInsteadOfAccumulating() (gas: 128059)\n[PASS] test_FullBalanceMovesAndOneMoreWeiFails() (gas: 162908)\n[PASS] test_SpendingTheExactAllowanceLeavesZero() (gas: 219190)\n[PASS] test_TokenHoldsNoEtherAndHasNoReceive() (gas: 68304)\n[PASS] test_TransferFromEmitsTransferButNoApproval() (gas: 117748)\n[PASS] test_TransferFromRequiresAllowanceEvenForSelf() (gas: 212161)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 110.10ms (109.47ms CPU time)\n\nRan 13 tests for test/HamsterToken.t.sol:HamsterTokenTest\n[PASS] testFuzz_ConservationAndAllowance(uint256,uint256) (runs: 512, μ: 246047, ~: 248540)\nLogs:\n  Bound result 388698765804027818991252101\n  Bound result 388698765804027818991252101\n\n[PASS] test_ApproveTransferFromAndRevoke() (gas: 257395)\n[PASS] test_ConstructorEmitsSingleMint() (gas: 5545)\n[PASS] test_FactoryOwnsEntireSupplyAndAppHasExplicitOwner() (gas: 378736)\n[PASS] test_InsufficientBalanceAndAllowanceAreAtomic() (gas: 151369)\n[PASS] test_LaunchDistributionAndClaimArriveExactly() (gas: 672061)\n[PASS] test_MetadataAndWholeSupply() (gas: 71461)\n[PASS] test_NoForbiddenRuntimeOpcodes() (gas: 784813)\n[PASS] test_NoMintFreezeSeizeOrUpgradeEndpoints() (gas: 425487)\n[PASS] test_StandardUnlimitedAllowanceBehavior() (gas: 120596)\n[PASS] test_TransferAndEvents() (gas: 81161)\n[PASS] test_ZeroAddressesRejected() (gas: 83730)\n[PASS] test_ZeroAndSelfTransfersAreStandard() (gas: 127169)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 118.12ms (112.73ms CPU time)\n\nRan 18 tests for test/HamsterRewards.t.sol:HamsterRewardsEligibilityTest\n[PASS] testFuzz_BinaryLosersAndRefunds(uint128,uint128,uint128,uint128,uint8) (runs: 512, μ: 382018, ~: 383549)\n[PASS] testFuzz_ExactRanking(uint256,uint256,uint128) (runs: 512, μ: 344220, ~: 344230)\n[PASS] test_ExactAllThreeRanksAndTiesAreWinners() (gas: 1536508)\n[PASS] test_ExactDistanceWorksAtUint256Extremes() (gas: 690975)\n[PASS] test_ExactSingleRankAndNoUnusedRankMatch() (gas: 560984)\n[PASS] test_IMDAndJackpotClaimStateCannotChangeEligibility() (gas: 749869)\n[PASS] test_InvalidRankDataFailsClosed() (gas: 947569)\n[PASS] test_LineEqualityRefundsBothBinarySides() (gas: 452826)\n[PASS] test_LosingBetsAcrossMarketsEarnExistingTokens() (gas: 596313)\n[PASS] test_MarketRefundFlagsExcludeAllRefundedBets() (gas: 494343)\n[PASS] test_OldWindowsExcludedAndNoRewardExpiryAfterFinality() (gas: 785085)\n[PASS] test_PrematureSettledResultRejectedUntilEnd() (gas: 411750)\n[PASS] test_UncontestedBinaryMarketsNeverEarnRewards() (gas: 621363)\n[PASS] test_UnderResultAndZeroResultChooseCorrectLosers() (gas: 896350)\n[PASS] test_UnknownOpenAndUnsettledWindowsCannotClaim() (gas: 767648)\n[PASS] test_VoidedWindowHasNoRewardEvenWithLosingLookingPositions() (gas: 441594)\n[PASS] test_WalletWithBothWinningAndLosingBetsOnlyEarnsLosingStake() (gas: 350830)\n[PASS] test_WinnersAndNonBettorsReceiveNoLossReward() (gas: 490495)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 126.03ms (216.33ms CPU time)\n\nRan 10 tests for test/HamsterRewards.t.sol:HamsterRewardsPaymentTest\n[PASS] testFuzz_ClaimsConserveTokens(uint128,uint128) (runs: 512, μ: 939006, ~: 903444)\nLogs:\n  Bound result 93506142610470977187526\n  Bound result 105214\n\n[PASS] test_ClaimForPaysBettorNeverCaller() (gas: 338464)\n[PASS] test_DirectDonationsAreUsable() (gas: 341919)\n[PASS] test_ExternalGameFailureDoesNotConsumeClaim() (gas: 409958)\n[PASS] test_InsufficientInventoryDoesNotConsumeClaimAndTopUpAllowsRetry() (gas: 632848)\n[PASS] test_MalformedGameResponseFailsClosed() (gas: 67381)\n[PASS] test_NoAccidentalEtherAccepted() (gas: 36058)\n[PASS] test_NoDoubleClaimAndIndependentWindows() (gas: 1190789)\n[PASS] test_PermissionlessFundingWithExactAllowanceAndEvent() (gas: 193264)\n[PASS] test_ZeroFundingAndFundingWithoutAllowanceFail() (gas: 85804)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 126.12ms (127.96ms CPU time)\n\nRan 27 tests for test/HamsterRewards.edge.t.sol:HamsterRewardsEdgeTest\n[PASS] testFuzz_ClaimPaysExactlyTheQuoteOrLeavesEverythingUntouched(uint96,uint96) (runs: 1000, μ: 1100944, ~: 1132545)\nLogs:\n  Bound result 7006\n\n[PASS] testFuzz_LossNeverExceedsStakeAndRespectsRefunds(uint64[5],uint256,uint256,uint8,bool,bool) (runs: 1000, μ: 628264, ~: 635075)\n[PASS] test_BinaryOnlyWalletClaimsWhenExactMarketHadNoRanks() (gas: 659478)\n[PASS] test_ClaimConsumesExactlyTheInventoryItNeeds() (gas: 1117802)\n[PASS] test_ContractWithoutTheGameInterfaceIsRejected() (gas: 191174)\n[PASS] test_CurrentWindowBoundaryUsesStrictComparison() (gas: 151676)\n[PASS] test_EachMarketRefundFlagRemovesOnlyThatMarket() (gas: 1066595)\n[PASS] test_ExcessiveStakesFailClosedInsteadOfWrapping() (gas: 426839)\n[PASS] test_FirstWindowSchedulingBoundaries() (gas: 209956)\n[PASS] test_FundingFromWalletsThatCannotPayIsAtomic() (gas: 285752)\n[PASS] test_FundingWithUnlimitedAllowanceLeavesItUnlimited() (gas: 111363)\n[PASS] test_IneligibleWindowRejectedEvenWhenVoided() (gas: 626415)\n[PASS] test_LastRankWithZeroTiesFailsClosed() (gas: 652466)\n[PASS] test_NoUnexpectedFunctionsOnRewards() (gas: 161140)\n[PASS] test_NonOwnerCannotRenounceBeforeOrAfterConfiguration() (gas: 72897)\n[PASS] test_OneWeiLossPaysOneBaseUnit() (gas: 343405)\n[PASS] test_OwnershipTransferAfterConfigurationGrantsNoPowers() (gas: 620262)\n[PASS] test_PendingTransferIsCancelledByRenounce() (gas: 127177)\n[PASS] test_RelayerClaimingForItselfIsAnOrdinaryClaim() (gas: 470968)\n[PASS] test_RewardQuoteRevertsForPendingWindowRatherThanQuotingZero() (gas: 967142)\n[PASS] test_SameWalletDifferentWindowsAreIndependentEvenWhenOneIsVoided() (gas: 1155205)\n[PASS] test_SingleMaximalStakeIsQuotedButNeverPayable() (gas: 404214)\n[PASS] test_TiesBeyondRankCountAreIgnored() (gas: 673369)\n[PASS] test_UnknownStatusValuesAreNotSettled() (gas: 1358142)\n[PASS] test_VoidedExactMarketSkipsRankValidation() (gas: 469121)\n[PASS] test_VoidedWindowQuotesZeroEvenBeforeItsEnd() (gas: 608843)\n[PASS] test_ZeroLineBoundaries() (gas: 743582)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 126.21ms (241.46ms CPU time)\n\nRan 1 test for test/HamsterRewards.invariant.t.sol:HamsterRewardsInvariantTest\n[PASS]\nHamsterRewardsInvariantTest invariants:\n[PASS] invariant_EachWalletWindowPaysAtMostOnce\n[PASS] invariant_FixedSupplyAndReserveConservation\n HamsterRewardsInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭----------------+----------+-------+---------+----------╮\n| Contract       | Selector | Calls | Reverts | Discards |\n+========================================================+\n| RewardsHandler | claim    | 4115  | 0       | 0        |\n|----------------+----------+-------+---------+----------|\n| RewardsHandler | fund     | 4077  | 0       | 0        |\n╰----------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 479821422010289616521622\n  Bound result 8\n  Bound result 885710097\n  Bound result 150\n  Bound result 80000000000000000000\n  Bound result 1901074597\n  Bound result 1\n  Bound result 8\n  Bound result 8\n  Bound result 356400\n  Bound result 2\n  Bound result 80\n  Bound result 1\n  Bound result 8\n  Bound result 1\n  Bound result 6\n  Bound result 2\n  Bound result 1\n  Bound result 136974254911285501964283\n  Bound result 3013170593\n  Bound result 2854\n  Bound result 96760098931873322463627\n  Bound result 1\n  Bound result 8\n  Bound result 3\n  Bound result 8\n  Bound result 4\n  Bound result 1\n  Bound result 2111799\n  Bound result 274778437464134763448276\n  Bound result 8\n  Bound result 255\n  Bound result 8\n  Bound result 1000000000000000000\n  Bound result 8\n  Bound result 8\n  Bound result 1287492210002729654847\n  Bound result 2\n  Bound result 1005000000000000000000\n  Bound result 1\n  Bound result 3\n  Bound result 8\n  Bound result 4\n  Bound result 244\n  Bound result 7088178945741252365324\n  Bound result 456423817679655880570\n  Bound result 8\n  Bound result 8\n  Bound result 2830\n  Bound result 954463301588600082871\n  Bound result 340634001793145655172\n  Bound result 6\n  Bound result 178568338751167909402\n  Bound result 10\n  Bound result 178467480900727615026\n  Bound result 6\n  Bound result 1553\n  Bound result 3\n  Bound result 8\n  Bound result 5\n  Bound result 69414140462859924960\n  Bound result 5\n  Bound result 6\n  Bound result 17302953811178550865\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.14s (5.13s CPU time)\n\nRan 1 test for test/HamsterToken.invariant.t.sol:HamsterTokenInvariantTest\n[PASS]\nHamsterTokenInvariantTest invariants:\n[PASS] invariant_AllowancesMatchTheGhostLedger\n[PASS] invariant_BalancesMatchTheGhostLedger\n[PASS] invariant_MetadataNeverChanges\n[PASS] invariant_SupplyIsFixedAndFullyAccountedFor\n HamsterTokenInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------+-------+---------+----------╮\n| Contract     | Selector     | Calls | Reverts | Discards |\n+==========================================================+\n| TokenHandler | approve      | 5376  | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| TokenHandler | transfer     | 5506  | 0       | 0        |\n|--------------+--------------+-------+---------+----------|\n| TokenHandler | transferFrom | 5502  | 0       | 0        |\n╰--------------+--------------+-------+---------+----------╯\n\nLogs:\n  Bound result 24\n  Bound result 16\n  Bound result 1632297502364845445815\n  Bound result 7920\n  Bound result 4228666474\n  Bound result 5400\n  Bound result 0\n  Bound result 115792089237316195423570985008687907853269984665640563039457584007913129640143\n  Bound result 1\n  Bound result 878\n  Bound result 1371946897577267636629\n  Bound result 1\n  Bound result 128\n  Bound result 159701961144927917712\n  Bound result 617\n  Bound result 0\n  Bound result 59801308941837782593\n  Bound result 115792089237316195423570985008687907853269984665640564038680087277995666674383\n  Bound result 1811905364692322960748\n  Bound result 859261652642429671873\n  Bound result 36000\n  Bound result 1005000000000000000000\n  Bound result 57\n  Bound result 43\n  Bound result 121\n  Bound result 11\n  Bound result 253\n  Bound result 641\n  Bound result 127\n  Bound result 818443534216735278359\n  Bound result 4866\n  Bound result 18\n  Bound result 0\n  Bound result 1999999999999999999999\n  Bound result 908350897442665701420\n  Bound result 22\n  Bound result 95\n  Bound result 5316\n  Bound result 3\n  Bound result 372385078961832103\n  Bound result 16424317964958956475\n  Bound result 36000\n  Bound result 115792089237316195423570985008687907853269984665640564038689087277995666674390\n  Bound result 7867\n  Bound result 115792089237316195423570985008687907853269984665640064039440787304873437525079\n  Bound result 527\n  Bound result 6266\n  Bound result 2669\n  Bound result 0\n  Bound result 0\n  Bound result 733\n  Bound result 317\n  Bound result 6706\n  Bound result 1916692634923705890646\n  Bound result 115792089237316195423570985008687907853269984665640563039297882046768839939856\n  Bound result 2233625730\n  Bound result 2546\n  Bound result 120\n  Bound result 214457162972337789\n  Bound result 0\n  Bound result 0\n  Bound result 23\n  Bound result 10000000000000000000\n  Bound result 115792089237316195423570985008687907853269984665640563039298667589605229391729\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.82s (8.82s CPU time)\n\nRan 1 test for test/HamsterRewards.lifecycle.invariant.t.sol:HamsterRewardsLifecycleInvariantTest\n[PASS]\nHamsterRewardsLifecycleInvariantTest invariants:\n[PASS] invariant_ConfigurationIsPermanentAndOwnerPowerless\n[PASS] invariant_GameRecordsStayFinal\n[PASS] invariant_InventoryEqualsDonationsMinusPayouts\n[PASS] invariant_NobodyIsPaidMoreThanTheyWageredOrTwice\n HamsterRewardsLifecycleInvariantTest invariants (runs: 256, calls: 24576, reverts: 0)\n\n╭------------------+-------------+-------+---------+----------╮\n| Contract         | Selector    | Calls | Reverts | Discards |\n+=============================================================+\n| LifecycleHandler | claim       | 3503  | 0       | 0        |\n|------------------+-------------+-------+---------+----------|\n| LifecycleHandler | fund        | 3434  | 0       | 0        |\n|------------------+-------------+-------+---------+----------|\n| LifecycleHandler | ownership   | 3460  | 0       | 0        |\n|------------------+-------------+-------+---------+----------|\n| LifecycleHandler | reconfigure | 3514  | 0       | 0        |\n|------------------+-------------+-------+---------+----------|\n| LifecycleHandler | settle      | 3535  | 0       | 0        |\n|------------------+-------------+-------+---------+----------|\n| LifecycleHandler | voidWindow  | 3583  | 0       | 0        |\n|------------------+-------------+-------+---------+----------|\n| LifecycleHandler | warp        | 3547  | 0       | 0        |\n╰------------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4\n  Bound result 5\n  Bound result 4\n  Bound result 200000000000000000000\n  Bound result 150\n  Bound result 2\n  Bound result 100000000000000000000\n  Bound result 2\n  Bound result 6\n  Bound result 4\n  Bound result 3\n  Bound result 242\n  Bound result 3\n  Bound result 1\n  Bound result 12\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 4029\n  Bound result 6\n  Bound result 2799\n  Bound result 6\n  Bound result 2290\n  Bound result 1\n  Bound result 12575172431989636687\n  Bound result 40\n  Bound result 3\n  Bound result 6\n  Bound result 3\n  Bound result 4228\n  Bound result 4\n  Bound result 4797\n  Bound result 1\n  Bound result 16\n  Bound result 5400\n  Bound result 6\n  Bound result 2\n  Bound result 2379\n  Bound result 5\n  Bound result 0\n  Bound result 4\n  Bound result 25000000000000000000\n  Bound result 0\n  Bound result 4229\n  Bound result 7\n  Bound result 2357\n  Bound result 153421692348902872654\n  Bound result 4\n  Bound result 5\n  Bound result 3997\n  Bound result 4\n  Bound result 40\n  Bound result 2\n  Bound result 0\n  Bound result 51202758911834328448\n  Bound result 4\n  Bound result 48\n  Bound result 5400\n  Bound result 7\n  Bound result 4\n  Bound result 2211\n  Bound result 4536\n  Bound result 1403\n  Bound result 1\n  Bound result 3990\n  Bound result 4\n  Bound result 6\n  Bound result 4\n  Bound result 0\n  Bound result 3\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 90.38s (90.38s CPU time)\n\nRan 10 test suites in 90.39s (104.97s CPU time): 92 tests passed, 0 failed, 0 skipped (92 total tests)\n","passed":true},{"durationMs":91,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRewards.acceptOwnership()\",\"HamsterRewards.claim(uint256)\",\"HamsterRewards.claimFor(uint256,address)\",\"HamsterRewards.configureGame(address,uint256)\",\"HamsterRewards.fund(uint256)\",\"HamsterRewards.renounceOwnership()\",\"HamsterRewards.transferOwnership(address)\",\"HamsterToken.approve(address,uint256)\",\"HamsterToken.transfer(address,uint256)\",\"HamsterToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":138,\"docs/REFERENCES.md\":42,\"docs/SECURITY.md\":38,\"docs/reference/HamsterHour.reads.abi.json\":269,\"foundry.toml\":21,\"remappings.txt\":2,\"src/HamsterRewards.sol\":153,\"src/HamsterToken.sol\":13,\"src/interfaces/IHamsterHour.sol\":52,\"test/HamsterRewards.edge.t.sol\":582,\"test/HamsterRewards.invariant.t.sol\":149,\"test/HamsterRewards.lifecycle.invariant.t.sol\":381,\"test/HamsterRewards.t.sol\":654,\"test/HamsterToken.invariant.t.sol\":158,\"test/HamsterToken.t.sol\":203,\"test/mocks/MockHamsterHour.sol\":53,\"tools/check_game_abi.py\":24},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"4bbc6fb923533b4ec32ae037bf62b51f30d909fbc5fd57cd5b2cf7543ba24a4e","verifiedTreeHash":"c5690cdbdc42ec4406d73af70e8163bad1d6ccee","verifierVersion":"0.1.0+d952fceb"}]}