{"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":"c20f9b8b-afa2-45f5-abc8-bba3f87f5c47","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"630ea36bd9340b886431026d63f48d7932423f6bcb9161b8c26facb29f5ed00f","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"a3558dec9d5f4ebfbcf99f489043be3386a62d7ec2237661e2d3069c2cb781a4","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"d50dfbeb471df3b27d897e7b09f05a657d85db0e876b4c86c4b65a03892f235e","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"d6fc08086d3a6e8708f9f39515354ff68b550bad30d480b0c295aa5614ad901f","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"52c8868f187ca76d45c690d9357a06cf25d224b13730178caff21f58ceedbb94","dependsOn":["adapt_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"6790453c2d718ebca692ddacc8cd1a668f3d7b426126f8fc5c555f12523b79d9","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"36628033435d347f51e739edbfe2e7d022d6f560559fb939ad5d7488c5a0204f","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"8488fec0d048399d7ebea60af5cf4bd8b800825b9bd0db6fb2cbcae1b78d5845","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"322f3d908dafaaa1972f9da5c6e5dd5d9ac79fb8c076774452fb5690b3727fe1","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Deploy SwarmDerby v2 (src/SwarmDerby.sol) to Robinhood Chain. Deploy only SwarmDerby. Do not deploy DerbyAuction, and do not create a token, distributor or pool. Constructor arguments in order: owner_ = $owner; imd_ = 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127; singlePrice_ = 150000000000000000; packPrice_ = 500000000000000000; houseKey_ = 0x9b7398ccc4834a29c3064efa2b3530e31022109a8dc6a654bfa878ae0059a2a2c3ac9f31916c0a320a2c179109e395905fc821aab91a1136523c1b90bce1536fe5c11ab65de79551875327766c99e74f9243761f0b3c8d323194bd7f3da77086e27991d5ac2e46ec41b36dc3e959b99dfd40e309277beda06980f5d5d59dd86f2d3d01738e7773bfada03634ac9d8611b31f274422bf36137afdf465a406d299433bf548042816d7aa6b6f69e007bc70d5acb0db4a5c8f19cecbaf31728faa399b0b143d34eb956a2230fe75fdaed887cbd68f7154d1abfb62204e928b9c4e9b54ab9cc7bf171f27a16aa37d8a4a7a02f54b7ab2056befbbffcfbdb24506863d (the 256-byte RSA modulus of the house key; pass these exact bytes). IMD audit job f8614c57-0570-4af5-aa6f-85eae302d86b on commit 8b60d1b found 0 critical, 0 high, 1 medium and 6 low. This commit fixes the contract findings (commits single-use per player, house key proposals can be cancelled and lapse after KEY_WINDOW, swings revert NoHouseKey while the key is revoked, _trySend treats a word other than 0 or 1 as a failure) with tests; the medium and two lows were in the off-chain house service (house/), which is fixed too and is not deployed. Keep the code as it is unless the audit finds a critical or high issue. A site, a house service and agent bots call this exact ABI, so do not change function signatures, events, errors, constants, the EIP-712 domain, drawMessage, the split, prices or the payout math, and keep src/DerbyOdds.sol and src/HouseDraw.sol byte-identical: the browser mirrors the odds (test_parityWithBrowser) and the house service signs drawMessage. The constructor deliberately calls no other contract and has no token code check, because the protected deploy rehearsal runs on an empty chain: do not add such a check and do not deploy a token fixture. Accepted by the owner, do not change: the holder of the house key can compute every draw and can withhold draws, which refunds the turn after DRAW_WINDOW, so the key holder does not play (DEPLOY.md, Known limits); purchases have no maxCost argument; session consent signatures have no deadline; swing quality and velo are reported by the client; the arcade cap is per wallet; a grand slam pays 10% of its league's vault. forge test must pass (117 tests, no ffi).","parentJobId":null,"planHash":"861a4a256c0eebe3dc519489781d5341d2e8a93dba352d8e422d8aee28d5aee8","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"c20f9b8b-afa2-45f5-abc8-bba3f87f5c47","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1103-src-swarmderby-sol"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51503","feedbackHash":"c080b869e349bc1db71b38cc508d56ee2a4d2b9ae1185201b1029f3cc53f8689","nodeKey":"adapt_contract_project","submissionHash":"630ea36bd9340b886431026d63f48d7932423f6bcb9161b8c26facb29f5ed00f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51071","feedbackHash":"a72ac8018de7a2aeda4b5154ee194b7b41575ec4d1e7fec76626a20ca096e42c","nodeKey":"audit_economics","submissionHash":"a3558dec9d5f4ebfbcf99f489043be3386a62d7ec2237661e2d3069c2cb781a4","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51145","feedbackHash":"ca51133d6f6c96b10d4c3928a4b5c415e7a797d8012d168922476adfc2bd6110","nodeKey":"audit_flow","submissionHash":"d50dfbeb471df3b27d897e7b09f05a657d85db0e876b4c86c4b65a03892f235e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51512","feedbackHash":"7881c455895d077b238b6744fc09d800b72a093d3bf1efe4acfb6e05fcafcd2c","nodeKey":"audit_imported_code","submissionHash":"d6fc08086d3a6e8708f9f39515354ff68b550bad30d480b0c295aa5614ad901f","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50969","feedbackHash":"23cfddfcf9386c31f12044ed5e505013de9fc205c84a29019ba0197befee1059","nodeKey":"audit_judge","submissionHash":"52c8868f187ca76d45c690d9357a06cf25d224b13730178caff21f58ceedbb94","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51488","feedbackHash":"b394b7a3082b6d02a58dbdc723a728162322c590901bafed43c9440fdf7cff9f","nodeKey":"audit_math","submissionHash":"6790453c2d718ebca692ddacc8cd1a668f3d7b426126f8fc5c555f12523b79d9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52021","feedbackHash":"b3eb7f2d2e6522318f2f5f336049d89b9a63f70295b8d0b477a9b22693b8c791","nodeKey":"audit_permissions","submissionHash":"36628033435d347f51e739edbfe2e7d022d6f560559fb939ad5d7488c5a0204f","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51489","feedbackHash":"ea9983990db5197e676b0e969664715eb8cd3ccb47d12ad9261cac0c39ad52a5","nodeKey":"manifest","submissionHash":"8488fec0d048399d7ebea60af5cf4bd8b800825b9bd0db6fb2cbcae1b78d5845","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51549","feedbackHash":"72f1c58711d53be662ae00f940d52984b38df7a8db868626efcb7c8b0be2e077","nodeKey":"write_foundry_tests","submissionHash":"322f3d908dafaaa1972f9da5c6e5dd5d9ac79fb8c076774452fb5690b3727fe1","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"92f22d90041a76b2d68ad8aa4302e9e0ce4c7be388daceb92cc4ab87ec7aacfd","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"b9cc7e7c60e17d79ca8cf47a596417ec3e6fa8cb9648ba808c745ffb776ef9af","device":"d25fbf67753e5494","findings":[],"hash":"322f3d908dafaaa1972f9da5c6e5dd5d9ac79fb8c076774452fb5690b3727fe1","nodeId":"b085dca8-cf9e-451f-8c94-b7a27658b907","outcome":"completed","summary":"Added [failure-path tests](/home/imd-worker/.identitymd/work/c20f9b8b-afa2-45f5-abc8-bba3f87f5c47/b085dca8-cf9e-451f-8c94-b7a27658b907/test/SwarmDerbyFailures.t.sol) and four stateful invariants.\n\n`forge build` and `forge test` pass: **145 tests, zero failures**. Invariants passed **16,384 randomized calls**.\n\nAll changes are under `test/`. No reproducible contract defect found; live-chain integration remains unverified.","treeHash":"957ef76687f1a671ea19dcf983472b187f5c80a6","usage":{"cachedInputTokens":3113344,"inputTokens":128339,"model":"gpt-6-astra","outputTokens":24448,"runtime":"codex","turns":9,"wallClockMs":921202}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"229c8cb0d9067fbe","findings":[{"citation":"resolved","description":"Asymmetry between the two admin paths that clear a proposal. cancelHouseKey (line 622) clears pendingHouseKey and emits HouseKeyProposed(bytes32(0), 0) so watchers see the proposal withdrawn; revokeHouseKey also clears pendingHouseKey (line 642) but emits only HouseKeySet(bytes32(0)). DEPLOY.md tells operators and players to watch HouseKeyProposed for a coming key change, so an event-driven watcher that saw a proposal and then a revoke keeps a phantom pending proposal with its activeAt in the future, while the contract's pendingHouseKeyAt() view is already 0 and activateHouseKey reverts KeyNotReady. On-chain state is correct and no funds are involved; this is purely an off-chain observability gap. Minimal fix if wanted (does not change any ABI item): in revokeHouseKey, emit HouseKeyProposed(bytes32(0), 0) when pendingHouseKeyAt was nonzero before clearing it.","line":640,"path":"src/SwarmDerby.sol","reproduction":"Owner calls proposeHouseKey(K) (emits HouseKeyProposed(keccak256(K), now + 2 days)), then revokeHouseKey(). Expected (by symmetry with cancelHouseKey): a HouseKeyProposed(bytes32(0), 0) log beside HouseKeySet(bytes32(0)). Actual: only HouseKeySet(bytes32(0)) is logged; pendingHouseKeyAt() == 0. Reproduced in test/scratch/Perm.t.sol test_revokeDropsProposalSilently with vm.recordLogs(): no log with topic keccak256(\"HouseKeyProposed(bytes32,uint256)\") is emitted by revokeHouseKey.","severity":"info","snippet":"    function revokeHouseKey() external onlyOwner {\n        delete houseKey;\n        delete pendingHouseKey;\n        pendingHouseKeyAt = 0;\n        emit HouseKeySet(bytes32(0));\n    }","title":"revokeHouseKey drops a pending proposal without the HouseKeyProposed(0, 0) event that cancelHouseKey emits"},{"citation":"resolved","description":"Not a code defect: a note for the manifest step. The brief lists the constructor as (owner_, imd_, singlePrice_, packPrice_, houseKey_) with houseKey_ a single 256-byte value, but the accepted adaptation (ADAPTATION.md, commit 2c6b03d) replaced the dynamic bytes argument with eight bytes32 words because the factory accepts only static words and each manifest argument is capped at 96 characters. The compiled ABI is constructor(address,address,uint256,uint256,bytes32 x8). I checked that the eight documented words concatenate to exactly the brief's modulus (256 bytes, top bit set, odd, 2048 bits, no small factor), that owner_ is an explicit argument filled by $owner and not msg.sender, and that test/SwarmDerbyLaunch.t.sol rehearses the exact twelve-word CREATE2 encoding with zero value and no token code. The manifest must therefore carry twelve constructorArgs in ADAPTATION.md's order, with contract = SwarmDerby (not the test-only FakeDrawDerby in test/HouseKey.sol).","line":210,"path":"src/SwarmDerby.sol","reproduction":"A launch.json written from the brief's text, e.g. constructorArgs: [\"$owner\", \"0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127\", \"150000000000000000\", \"500000000000000000\", \"0x9b7398cc...06863d\"] (five entries, the last 514 characters), fails twice: the fifth entry exceeds the manifest's 96-character argument limit, and five ABI words do not satisfy the twelve-word constructor (test_constructorRejectsMissingKeyWord shows a truncated argument list makes CREATE2 fail). Expected: twelve entries, the last eight being the bytes32 words listed in ADAPTATION.md, which the launch test deploys successfully and which emit HouseKeySet(keccak256(modulus)) and OwnershipTransferred(0, $owner).","severity":"info","snippet":"    constructor(\n        address owner_,\n        IERC20 imd_,\n        uint256 singlePrice_,\n        uint256 packPrice_,\n        bytes32 houseKey0_,\n        bytes32 houseKey1_,\n        bytes32 houseKey2_,\n        bytes32 houseKey3_,\n        bytes32 houseKey4_,\n        bytes32 houseKey5_,\n        bytes32 houseKey6_,\n        bytes32 houseKey7_\n    ) {","title":"The constructor takes twelve static arguments; the brief's five-argument wording (one 256-byte houseKey_) cannot be used verbatim in launch.json"}],"hash":"36628033435d347f51e739edbfe2e7d022d6f560559fb939ad5d7488c5a0204f","nodeId":"616ff6e1-577b-4e32-a5c9-56f08e47035d","outcome":"completed","summary":"The review is complete and the findings file validates: both snippets match the tree at their cited lines, all 27 listed entry points have a coverage row, and no tracked file changed.\n\n**Outcome: no defect in the assigned area.** I traced every SwarmDerby entry point through the Access Control, Trust Gap and Asymmetry checklists and found the permission model sound. The two items in `.imd-findings.json` are informational only and open no revision.\n\n**What I checked**\n\n- **Access map.** Every writer of every storage variable was traced to its weakest guard. Owner powers are limited to prices (floored), the house-key proposal lifecycle, the 5% ops share, and two-step ownership. Pots, vaults and rollover are unreachable by the owner. `activateHouseKey` is permissionless but can only install the owner's own proposal inside its window.\n- **Sessions.** Binding needs the key's EIP-712 signature with a per-key nonce and the contract's domain. Keys cannot have keys, a player with a key cannot become one, and rebinding the same key needs a fresh signature. Prizes and board credit always go to the player, never the key.\n- **Draw and reveal.** The house message binds the commit, so a player cannot grind salts, and `sig < modulus` plus a full padded-message comparison leaves one valid signature per swing. `draw`, `finalize` and `expire` have complementary time boundaries, so no state exists where the two closing paths disagree.\n- **Admin variants and in-flight value.** Revoke, rotate and price changes were diffed against the user paths. Each either refunds, reverts cleanly, or is a limit the brief already accepts (no maxCost, no consent deadline, outsider-timed activation).\n- **Launch inputs.** The eight key words rebuild the brief's modulus byte for byte, `owner_` is explicit and not the factory, and `DerbyOdds.sol` and `HouseDraw.sol` are identical to the audited commit.\n\n**The two informational notes**\n\n1. `revokeHouseKey` clears a pending proposal without the `HouseKeyProposed(0, 0)` log that `cancelHouseKey` emits. State is correct. Only event-driven watchers are affected.\n2. The constructor now takes twelve static arguments. A manifest written from the brief's five-argument wording would fail, since a single 514-character key exceeds the 96-character argument limit. The manifest must use the twelve values from ADAPTATION.md with `contract` set to `SwarmDerby`.\n\n**Verification.** The full suite passes at 125 tests. Eight scratch probes under `test/scratch/Perm.t.sol` confirm the edge cases above. That directory is mine and is not kept.\n\n**Next.** The manifest step should carry the twelve arguments in ADAPTATION.md's order. The accepted trust limits remain as documented: the key holder must not play, and purchases pay the price in force when they land.","treeHash":null,"usage":{"cachedInputTokens":2478385,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":59732,"runtime":"claude","turns":35,"wallClockMs":1075809}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"93ca4a1020037bf1","findings":[],"hash":"52c8868f187ca76d45c690d9357a06cf25d224b13730178caff21f58ceedbb94","nodeId":"0c525343-3de1-4f4e-9df9-8a80dd7aa941","outcome":"completed","summary":"I found no defects to report, so `.imd-findings.json` holds an empty findings list plus a coverage row for all 27 entry points and two invariants I checked. No tracked files were changed.\n\n**What I checked**\n- **Full test suite:** `forge test` passes with 145 tests and 0 failures. The brief expects 117; the extra 28 come from tester work already accepted into the tree.\n- **Constructor and manifest:** `launch.json` passes 12 arguments. Arguments 5–12 are bytes32 words that join, in order, into exactly the 256-byte modulus from the brief. The owner comes from `$owner`, not the factory, and the constructor calls no other contract and accepts no ETH.\n- **Source changes since the fix commit:** apart from formatting, only two things changed in `src/SwarmDerby.sol`. The constructor now takes the key as eight bytes32 words, and purchases revert `NoHouseKey` while the key is revoked. Function signatures, events, the EIP-712 domain, `drawMessage`, the split and the payout math are unchanged.\n- **Unchanged files:** `src/DerbyOdds.sol` and `src/HouseDraw.sol` have no changes.\n\n**SwarmDerby entry points:** I traced all 17 by hand and each behaves as intended. The ones most worth a second look:\n- A late reveal cannot change a board that has already settled. `finalize` still scores at exactly 10 minutes after the commit, while `dayClosed` only turns true after that moment.\n- Daily payouts keep the pot balanced. A prize the token refuses rolls over to the next day instead of being lost.\n- `expire` cannot underflow the arcade cap counter, because the slot it gives back was taken when the swing was committed.\n- Session binding blocks key chaining and replay: each consent is signed for one player and carries a nonce that changes on every bind.\n\n**Specialist findings, all dropped:**\n- **Five-argument brief vs twelve-argument constructor** (economics low, permissions info): the manifest already uses the correct twelve words, so there is no defect in the code or manifest.\n- **Tokens sent directly to the contract are stuck; turns are stranded while the key is revoked; the IMD token owner can block addresses:** these are by design or already listed as trust assumptions in `DEPLOY.md` under Known limits.\n- **A finalize sent too early leaks the salt:** this needs the player's own client to misbehave, so it is not a contract defect.\n- **`revokeHouseKey` drops a pending proposal without emitting `HouseKeyProposed(0, 0)`:** this does reproduce, but the contract's state is correct and it only affects off-chain watchers. You said to keep the code unless something critical or high turns up, so I noted it in the coverage row rather than as a finding.\n\nI did not trace the 10 DerbyAuction entry points, so they are marked unreached. This launch doesn't deploy DerbyAuction. The static-analysis leads I checked turned out to be safe or deliberate. For example, the \"uninitialized\" `_board`/`_days` are mappings, and the strict equality in `activateHouseKey` is a zero check.","treeHash":null,"usage":{"cachedInputTokens":536876,"inputTokens":16,"model":"claude-opus-5-5","outputTokens":10141,"runtime":"claude","turns":9,"wallClockMs":287685}},{"artifacts":[],"attempt":1,"bundleHash":"f6c8a9c306339fdaaaedff664f77b930dda3cc6f228fa17296a94958de4b935f","device":"c1fc321231608a52","findings":[],"hash":"630ea36bd9340b886431026d63f48d7932423f6bcb9161b8c26facb29f5ed00f","nodeId":"99832602-f724-455b-b6b1-1abfe0307b30","outcome":"completed","summary":"Prepared SwarmDerby for factory deployment with eight static key words preserving the exact modulus. Fixed the reproduced revoked-key purchase issue; runtime ABI and payout math remain unchanged.\n\n`forge build` passed. All 125 tests passed without FFI.\n\nChanges and exact launch arguments are documented in [ADAPTATION.md](/home/seat/.identitymd/work/c20f9b8b-afa2-45f5-abc8-bba3f87f5c47/99832602-f724-455b-b6b1-1abfe0307b30/ADAPTATION.md). No live deployment was performed.","treeHash":"72d676d78e8819af02e87668ec649e0f51011b4e","usage":{"cachedInputTokens":2051456,"inputTokens":133316,"model":"gpt-6-astra","outputTokens":17698,"runtime":"codex","turns":6,"wallClockMs":506605}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"5835e48821d8827d","findings":[],"hash":"6790453c2d718ebca692ddacc8cd1a668f3d7b426126f8fc5c555f12523b79d9","nodeId":"8fc8a5a3-16fe-433f-bc67-5547668c2d73","outcome":"completed","summary":"The review is complete. The findings file holds an empty findings list and 32 coverage rows, and the working tree has no other changes.\n\n**Result: no defect found in the assigned area.** I checked the SwarmDerby arithmetic against the Math Precision, Boundary and Numerical Gap guides and could not produce a failing input for any formula, boundary or seam between them.\n\nWhat I verified, by hand trace and by scratch tests that I ran and then removed:\n\n- **Purchase split.** The 40/45/10 basis-point shares floor and the remainder goes to ops, so the three shares plus ops always equal the cost. The 0.01 IMD price floor keeps every share above zero.\n- **Settlement.** Fuzzed across prices from 0.01 to a trillion IMD with zero to four winners. The tip and each prize equal what the preview reports, the total paid never exceeds the day's amount, and the pot equals the sum of open day pots plus rollover before and after. The divide-before-multiply that slither flagged is the same floor chain on both sides, so the preview and the payout cannot drift.\n- **Odds table.** For every quality from 0 to 100 the five thresholds are strictly ordered and non-increasing in quality. Slam odds are 21 basis points at quality 1 and 80 at quality 100, as documented. The browser twin floors integers below 2^53, so parity holds.\n- **Time boundaries.** The draw window, reveal window, expire and day-closed checks are exact complements of each other. At the boundary second a drawn swing still rolls and the day is still open. One second later it fouls and the day closes.\n- **Board.** Eviction at a full board, tie handling and re-entry of an evicted player keep the list sorted.\n- **Narrowing casts and underflows.** Day fits uint32, timestamps fit uint64, feet never exceed 620, and the arcade slot refund cannot underflow because a refunded swing cannot be expired twice.\n- **House draw.** The PKCS1 padding constant is 205 bytes, giving a 256-byte encoding. The signature must be below the modulus, so adding the modulus is rejected. The modexp input is fixed-length fields, so aderyn's packed-hash lead does not apply.\n- **Launch inputs.** The eight constructor words concatenate to the brief's modulus, whose first byte is 0x9b and last byte 0x3d, so the shape check passes. The live IMD token returns one 32-byte word of 1 and has 18 decimals, so the strict return-data check in the transfer helper matches it.\n\nDerbyAuction is not deployed in this launch. I still traced its basis-point helper, minimum-bid rounding and carry arithmetic and found them exact, so its entry points are marked as holding.\n\nThe static-analysis leads for SwarmDerby all turned out to be false positives: the uninitialized-state lines are mappings, the strict equality on the pending key time is safe because that value is never zero once set, and the reentrancy sites update state before any transfer.","treeHash":null,"usage":{"cachedInputTokens":1608597,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":33930,"runtime":"claude","turns":29,"wallClockMs":547231}},{"artifacts":[],"attempt":1,"bundleHash":"f715e3fb5c0c626f0be227592a71d35f94c36819b8866741f462c69f7a423f3d","device":"e8b60b2d2d013a4d","findings":[],"hash":"8488fec0d048399d7ebea60af5cf4bd8b800825b9bd0db6fb2cbcae1b78d5845","nodeId":"548d92e5-750e-4aa7-a6aa-ef5e32aacc8d","outcome":"completed","summary":"Created [launch.json](/home/imd2/.identitymd/work/c20f9b8b-afa2-45f5-abc8-bba3f87f5c47/548d92e5-750e-4aa7-a6aa-ef5e32aacc8d/launch.json) for SwarmDerby only, using `$owner`, the approved prices and address, and the exact modulus encoded as eight `bytes32` arguments.\n\nValidated against the supplied schema and compiled constructor ABI. `forge build` passed; `forge test` passed all 125 tests with FFI disabled.\n\nOnly `launch.json` changed.","treeHash":"fce13987b9076d4a09efd3695576f9583ef2c70f","usage":{"cachedInputTokens":407552,"inputTokens":34750,"model":"gpt-6-astra","outputTokens":4312,"runtime":"codex","turns":4,"wallClockMs":165406}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"39da99ded7f125c8","findings":[{"citation":"resolved","description":"The assignment text says 'Constructor arguments in order: owner_, imd_, singlePrice_, packPrice_, houseKey_ = 0x9b73...863d (the 256-byte RSA modulus; pass these exact bytes)'. The compiled ABI has 12 constructor arguments: the modulus must be supplied as houseKey0_..houseKey7_, eight consecutive bytes32 words (ADAPTATION.md 'Constructor handoff'). A launch.json with five arguments, or with the 514-character hex string as one argument, is not the accepted ABI (the schema also caps each argument at 96 characters). ABI-encoding the brief's five-argument form puts the dynamic offset word 0x...a0 where houseKey0_ is read, so _checkKey sees a first byte 0x00 < 0x80 and the constructor reverts BadKey; the protected rehearsal would fail with 'application constructor failed'. Not a code defect: the manifest step must use the twelve-argument table in ADAPTATION.md, and the brief wording should be corrected so the deployer and the verifier agree on the argument list.","line":224,"path":"src/SwarmDerby.sol","reproduction":"bytes memory code = bytes.concat(type(SwarmDerby).creationCode, abi.encode(owner, imd, 0.15e18, 0.5e18, modulus /* bytes, 256 long */)); create(0, code) -> returns address(0) (constructor reverts BadKey). Expected per the brief wording: a deployed SwarmDerby with houseKey() == modulus. Actual: deployment fails. With the twelve static words (test/SwarmDerbyLaunch.t.sol _args) the same code deploys and houseKey() equals the modulus. Reproduced in test/scratch/EconProbe.t.sol test_briefEncodingRejected.","severity":"low","snippet":"        bytes memory houseKey_ = abi.encodePacked(\n            houseKey0_, houseKey1_, houseKey2_, houseKey3_, houseKey4_, houseKey5_, houseKey6_, houseKey7_\n        );","title":"Launch brief names one dynamic houseKey_ argument but the compiled constructor takes eight bytes32 words; a manifest written from the brief fails to deploy"},{"citation":"resolved","description":"Every outflow is bounded by a tracked balance: withdrawOps by opsBalance, settlement by pot[league], slams by vault[league]. Tokens that reach the contract outside _pull (a direct IMD transfer, an airdrop) raise balanceOf(derby) above pot[0]+pot[1]+vault[0]+vault[1]+opsBalance and no function can ever move the difference. This is consistent with the stated design (the owner cannot touch pots or vaults) and costs only the sender, so it is informational; a future version could add an owner sweep of exactly balanceOf - (pots + vaults + ops).","line":654,"path":"src/SwarmDerby.sol","reproduction":"imd.transfer(address(derby), 1e18) from any wallet. Then pot(0)+pot(1)+vault(0)+vault(1)+opsBalance() == 0 while imd.balanceOf(derby) == 1e18; withdrawOps(to, 1) reverts (opsBalance underflow) and no other function pays out more than its tracked balance. Expected (if recovery were intended): some path returns the 1e18. Actual: stuck forever. Reproduced in test/scratch/EconProbe.t.sol test_donationStranded.","severity":"info","snippet":"    function withdrawOps(address to, uint256 amount) external onlyOwner {\n        opsBalance -= amount;\n        _send(to, amount);\n    }","title":"IMD sent straight to the contract (or any surplus over pot+vault+ops) is unrecoverable: no sweep path exists"},{"citation":"resolved","description":"Trust assumption, documented in DEPLOY.md Known limits, recorded here as the owner power with the largest player-side economic effect. revokeHouseKey (owner only) empties houseKey; contact swings revert NoHouseKey and purchases revert NoHouseKey, while the whiff path (quality 0, line 354) still spends a turn without checking the key. Turns already paid for (0.15 IMD each, 40% already burned) have no refund path, and a new key needs proposeHouseKey + KEY_DELAY before activateHouseKey, so a revoke is at least a two-day outage for every holder of turns. The owner cannot extract those funds (they sit in pot, vault and ops as before), so this is a liveness/trust note, not a loss to the owner's benefit.","line":360,"path":"src/SwarmDerby.sol","reproduction":"owner: revokeHouseKey(). Alice holds turns(0, alice) == 2 bought earlier. alice: swing(0, 1, 1, commit) -> reverts NoHouseKey; alice: buyTurns(0, 1) -> reverts NoHouseKey; alice: swing(0, 0, 0, 0) succeeds and turns drop to 1 with no roll. No function returns IMD for the remaining turn. Expected (from a player's view): turns remain spendable or refundable; actual: unusable until a new key is active, at the earliest 2 days after a proposal. Reproduced in test/scratch/EconProbe.t.sol test_expireAndWhiff.","severity":"info","snippet":"        if (houseKey.length == 0) revert NoHouseKey(); // revoked: no draw could come","title":"After revokeHouseKey, prepaid turns can only be whiffed: no refund of turns, and purchases/contact swings stay blocked for at least KEY_DELAY (2 days)"}],"hash":"a3558dec9d5f4ebfbcf99f489043be3386a62d7ec2237661e2d3069c2cb781a4","nodeId":"0293d42f-26dd-46e0-9742-9a9e71a6d276","outcome":"completed","summary":"The review is complete. Findings and coverage are in `.imd-findings.json`; no source file was changed.\n\n## Scope\n\nFiles read in full: `src/SwarmDerby.sol`, `src/DerbyOdds.sol`, `src/HouseDraw.sol`, the launch and fixture tests, DEPLOY.md and ADAPTATION.md. `src/DerbyAuction.sol` was read once from line 120 on, since it is not part of this launch. The Economic Security, Invariant and Flow Gap guides were applied against every value-moving path. The existing suite passes with 125 tests, and five scratch probes under `test/scratch/EconProbe.t.sol` all pass.\n\n**Severity counts:** 0 Critical, 0 High, 0 Medium, 1 Low, 2 Info\n\n## Findings\n\n- **[L-1] Brief wording vs constructor ABI.** The assignment says to pass one 256-byte `houseKey_` argument, but the compiled constructor takes eight bytes32 words. ABI-encoding the brief's five-argument form makes the constructor revert BadKey, so a manifest written from the brief literally fails the deploy rehearsal. The twelve-argument table in ADAPTATION.md is the correct input. Reproduced in the probe test.\n- **[I-1] Surplus IMD is unrecoverable.** Every outflow is bounded by a tracked balance, so tokens sent directly to the contract are stuck forever. Consistent with the stated design.\n- **[I-2] Revoking the house key strands prepaid turns.** After `revokeHouseKey`, turns can only be whiffed, and a new key needs at least two days. This is the documented owner power with the largest player-side effect, recorded as a trust note.\n\n## What held\n\n- **Conservation.** Contract balance equals pots plus vaults plus ops after purchases, slams, settlements with blocked winners, and ops withdrawals.\n- **Per-league pot.** The pot always equals the open days' pots plus rollover. Failed prizes return to both.\n- **Settlement boundary.** A finalize at exactly the last commit plus ten minutes still rolls while settlement reverts. One second later settlement succeeds and finalize fouls, so no dinger can land on a settled day.\n- **View vs write.** The tip shown by `nextSettlement` equals the tip paid by `settleNextDay` on odd amounts.\n- **Turn and cap accounting.** Expire refunds exactly one turn and one arcade slot once.\n\n## Static analysis leads\n\nAll slither and aderyn lines were checked. The uninitialized-state, weak-prng, divide-before-multiply, incorrect-equality and encodePacked items are false positives here. The settlement reentrancy line is harmless because every state write precedes the sends and the token is a fixed ERC-20.\n\nThe coverage record has 32 rows: all 27 listed entry points plus the constructor and four invariants. Nothing is marked unreached.","treeHash":null,"usage":{"cachedInputTokens":1377859,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":34002,"runtime":"claude","turns":22,"wallClockMs":799337}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3b9f88f55251764d","findings":[{"citation":"resolved","description":"Control-flow note in the trust model, not a contract defect. finalize(swingId, salt) is only meaningful once the swing is Drawn, but a client that races the house and sends it while the swing is still Committed gets WrongStatus and leaves the salt in public calldata (reverted transactions are included in blocks). The house signature for a swing is deterministic and the key holder can compute it at commit time (drawMessage depends only on stored fields), so with the salt it can evaluate DerbyOdds.roll(swingSeed(salt, keccak256(sig)), swingId, quality, velo) before calling draw. A losing outcome can then simply not be drawn: after DRAW_WINDOW the swing refunds its turn and arcade-cap slot, while winning outcomes are drawn. The contract already treats salt exposure as something to prevent (commitUsed exists because 'a reused salt would show the house a pending result', line 113). DEPLOY.md accepts that the key holder can withhold draws per player; this path turns that into withholding per outcome, but only if the player's own client leaks the salt. No on-chain change is needed; the site and bots must gate finalize on status == Drawn, and a reverted finalize should be treated by the client as a burned salt (the swing can still be revealed later, but its result is now known to the house). Reported for the judge as context; severity info.","line":398,"path":"src/SwarmDerby.sol","reproduction":"State: houseKey set, player has a turn. 1) player: swing(0, 100, 100, commitFor(salt, player)) -> swingId. 2) player (or anyone): finalize(swingId, salt) before any draw -> reverts WrongStatus; the transaction is public with salt in calldata; status stays Committed (test/scratch probe test_finalizeBeforeDrawRevertsAndLeaksNothingOnChain confirmed the revert and state). 3) key holder computes sig = RSA-sign(drawMessage(swingId)) and roll(swingSeed(salt, keccak256(sig)), swingId, 100, 100) off-chain. 4) If the tier is SLAM, holder calls draw; player finalizes and is paid 10% of the vault. If the tier is FOUL/POP, holder never calls draw; after 5 minutes expire(swingId) refunds the turn. Expected per the design: the house cannot know a pending result; actual: it can, for any swing whose salt reached the chain early.","severity":"info","snippet":"        if (s.status != Status.Drawn) revert WrongStatus();","title":"A finalize sent before the draw lands reverts and publishes the salt, letting the key holder compute the pending result and withhold the draw by outcome"},{"citation":"resolved","description":"Periphery trust note on the constructor argument imd_ = 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 (chain 4663). On-chain reads during this review: code present (30,899 bytes hex), symbol IMD, decimals 18, owner() = 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7, transfer() returns the single word 1, transferFrom reverts OZ-v5 style (ERC20InsufficientAllowance), and the runtime exposes setBlocked(address,bool), blocked(address), transfersEnabled(), enableTransfers(), setV4Config(address,address,bool) plus the OFT send/lzReceive surface. Today transfersEnabled() is true and blocked() is false for 0x...dEaD and for SwarmDerby v1. The contract's own handling is sound for the cases it anticipates: a blocked or refusing winner makes _trySend return false and the prize rolls over (settleNextDay lines 578-582) or stays in the vault (finalize lines 414-417), and a blocked settler only blocks that settler. The cases it cannot absorb are external: if the token owner blocks 0x...dEaD or disables transfers, _send(DEAD, burned) reverts TransferFailed and every buyTurns/buyPacks reverts; if the derby address itself is blocked as a sender, settleNextDay, slam payouts, withdrawOps and the burn all revert until it is unblocked. No funds are lost or misdirected (all state updates revert with the call), but the launch should record that liveness of purchases and payouts depends on the IMD owner's blocklist and transfer switch, which the brief's 'exact-transfer, non-rebasing IMD' description does not mention.","line":270,"path":"src/SwarmDerby.sol","reproduction":"Concrete state that triggers it: IMD owner calls setBlocked(0x000000000000000000000000000000000000dEaD, true) (or the transfer switch is turned off). Then any player calling buyTurns(0, 1) with allowance in place: _pull succeeds, _send(DEAD, burned) gets a revert from transfer, _trySend returns false, _send reverts TransferFailed; expected a purchase, actual every purchase reverts for as long as the block lasts. Equivalent for setBlocked(<derby>, true): settleNextDay(league) reverts on the tip transfer, finalize of a SLAM keeps the prize in the vault (payout 0), withdrawOps reverts. Verified against the test suite's MockIMD block_ path for the per-winner cases (test_unpayableWinnerRollsOver, test_unpayableSlamKeepsPrizeAndHomer pass); the DEAD/derby-blocked cases follow from _send at lines 702-704.","severity":"info","snippet":"        _send(DEAD, burned);","title":"Live IMD on Robinhood Chain is an owner-controlled LayerZero OFT with setBlocked and a transfers-enabled switch; blocking DEAD or the derby halts purchases and payouts while it lasts"}],"hash":"d50dfbeb471df3b27d897e7b09f05a657d85db0e876b4c86c4b65a03892f235e","nodeId":"97966a36-a1a6-4b59-93b5-5db5ccccbeba","outcome":"completed","summary":"The review is complete. The findings file is on disk at the repository root, excluded from git by the harness's own exclude rule, and the working tree is otherwise clean with the scratch tests removed.\n\n**Outcome: no critical, high, medium or low defect in the assigned area.** The SwarmDerby v2 control flow holds under the Execution Trace, Periphery and First Principles checklists. Two info-level notes are recorded for the judge, both trust-model observations rather than code defects, and no code change is warranted. The full suite passes with 125 tests and no ffi, which is more than the 117 the brief mentions.\n\n**What was verified beyond reading**\n\n- HouseDraw's PKCS#1 v1.5 padding and DigestInfo were checked byte-for-byte against a real Node `crypto.sign` signature from the test key. The existing suite could not catch a padding error because it signs with modexp on both sides. The parity scratch test passed.\n- The brief's 256-byte house key has the right length, a top bit set and an odd last byte, so it passes the constructor's shape check when split into eight words.\n- The live IMD token on chain 4663 has code, returns the word 1 from transfer, and reverts allowance errors OZ-v5 style, which matches what `_pull` and `_trySend` expect.\n- Scratch probes confirmed the cross-day refund restores the commit day's cap slot, the full-board eviction and re-entry ordering, and the pot and rollover conservation after an empty-day settlement.\n\n**The two info notes**\n\n- A `finalize` sent before the draw lands reverts and leaves the salt in public calldata. The key holder can then compute that swing's result before drawing and withhold a losing draw. This only happens if the player's own client races the house, and the fix is client-side gating on status Drawn.\n- The live IMD is an owner-controlled LayerZero OFT with a blocklist and a transfers-enabled switch. Blocked winners are already handled by rollover. Blocking the dead address or the derby itself would halt purchases and payouts until unblocked, with no loss of funds. Today transfers are enabled and neither address is blocked.\n\n**Coverage** answers all 27 listed entry points plus four invariant rows: 30 hold and one carries the info finding. DerbyAuction rows are marked as light traces since it is not part of this deployment.","treeHash":null,"usage":{"cachedInputTokens":2382642,"inputTokens":642,"model":"claude-fable-5-1","outputTokens":47525,"runtime":"claude","turns":38,"wallClockMs":877122}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8c9c4986ca881107","findings":[{"citation":"resolved","description":"The fifth constructor argument is `bytes memory houseKey_`, a dynamic ABI type holding the 256-byte RSA modulus. The launch recipe this deployment goes through supports only static constructor arguments (address, uint8..uint256, bool, bytes32; 'No dynamic arguments'), and the canonical launch.json schema caps every constructorArgs string at 96 characters. The modulus the brief requires is 0x plus 512 hex digits, 514 characters. So the contract as written cannot be instantiated by the factory with the key the brief names: the manifest is rejected before any bytecode is built, and no static word can stand in for a `bytes` argument. Nothing is wrong with the key itself (checked: 256 bytes, top bit set, odd, no small factors, e coprime). This is a launch policy conflict the adapter must resolve, not a runtime defect. Two constructor-only fixes keep every function signature, event, error, constant, DRAW_TAG, drawMessage and the odds untouched: (a) take the modulus as eight `bytes32` words and concatenate them in the constructor before `_checkKey`, or (b) embed the brief's modulus as a constant and drop the argument. Either leaves the runtime ABI the site, house service and bots use unchanged; `houseKey()` must still return exactly the 256 bytes of the brief. Also note for the adapter: runtime is 17,676 bytes (under EIP-170) and contains no DELEGATECALL/CALLCODE/SELFDESTRUCT, so once the argument shape is fixed the protected rehearsal has nothing else to trip on.","line":194,"path":"src/SwarmDerby.sol","reproduction":"Write launch.json as the brief dictates: {\"kind\":\"evm_contracts\",\"contracts\":[{\"contract\":\"SwarmDerby\",\"constructorArgs\":[\"$owner\",\"0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127\",\"150000000000000000\",\"500000000000000000\",\"0x9b7398cc...24506863d\"]}],\"notes\":\"...\"} with the fifth argument being the full 514-character modulus string. Expected: the manifest validates and the factory's create2 init code ends with the ABI encoding of the five arguments, so `houseKey()` returns the 256 bytes. Actual: LaunchManifest rejects constructorArgs[4] (length 514 > maxLength 96), and even if the length passed, the recipe has no static encoding for a dynamic `bytes` parameter, so no value in the allowed set (static word, $owner, $contract:Name) can fill it. The constructor also reverts BadKey() for any single-word stand-in (length != 256), e.g. passing bytes32(0x9b73...) would be 32 bytes.","severity":"medium","snippet":"    constructor(address owner_, IERC20 imd_, uint256 singlePrice_, uint256 packPrice_, bytes memory houseKey_) {","title":"Constructor takes a dynamic `bytes` house key that the evm_contracts launch manifest cannot carry"},{"citation":"resolved","description":"`swing` refuses every contact swing while `houseKey` is empty (`if (houseKey.length == 0) revert NoHouseKey();`, line 327), but `buyTurns`/`buyPacks` have no such check. A purchase made during a revocation is split and settled immediately: 40% goes to 0xdead in the same transaction, 45% to that day's pot, 10% to the vault, 5% to ops. The turns are credited but no contact swing can use them until a new key is proposed (owner only) and activated at least KEY_DELAY (2 days) later; if the owner never proposes one, the turns are stranded forever while the IMD paid is already burned and distributed. The site can hide the buy button when `houseKey()` is empty, and agent bots that call the ABI directly will not. Consistent with the revoked-key design, the cheap contract fix is to revert in `_buy` when `houseKey.length == 0` (a new error or reuse of NoHouseKey); this changes no existing signature, event or constant. It is low severity because the owner is trusted and turns never expire, so the loss is the time value plus the case where no key is ever restored.","line":221,"path":"src/SwarmDerby.sol","reproduction":"State: fresh deploy with the brief's arguments; player holds IMD and has approved the derby. Owner calls revokeHouseKey() (houseKey() is now empty). Player calls buyTurns(0, 1). Expected (given the stated revoked-key semantics, 'no swing can be drawn'): the purchase reverts so no IMD is burned for a turn that cannot be used. Actual: the call succeeds, 0.06 IMD is transferred to 0xdead at once, turns(0, player) == 1, and the player's next swing(0, 100, 100, commitFor(salt, player)) reverts NoHouseKey(). Confirmed with a scratch Foundry test on this commit (buy succeeds, DEAD balance 0.06 ether, swing reverts NoHouseKey).","severity":"low","snippet":"    function _buy(uint8 league, uint256 count, uint256 cost) internal {","title":"Turns can still be bought while the house key is revoked, burning 40% for turns that cannot be swung"},{"citation":"resolved","description":"By design anyone may activate a proposed key once its delay ends. The switch is immediate: a swing committed seconds earlier, for which the house service has already produced and sent an old-key signature, fails `draw` with BadDraw(), and after DRAW_WINDOW the player expires it for a refund. The house service in house/ only re-reads `houseKey()` every 60 ticks (about a minute), so during a rotation every contact swing in that minute is refunded rather than played. Nobody can steer a roll this way (the old-key signature is useless once the new key is active, so the only outcome is a refund), and no funds are lost, so this is an operating note for the key-rotation runbook: hold both keys and switch on the HouseKeySet event, or activate the key yourself at a quiet moment. No contract change is needed.","line":586,"path":"src/SwarmDerby.sol","reproduction":"Owner calls proposeHouseKey(K2) at time T. At T + 2 days a player calls swing(0, 100, 100, commit) and the house signs drawMessage(id) with the current key K1. Before that draw lands, any address calls activateHouseKey(). The house's draw(id, sigK1) now reverts BadDraw(); after T + 2 days + 5 minutes expire(id) refunds the turn. Expected by the player: a played swing. Actual: a refunded swing. Confirmed with a scratch Foundry test on this commit.","severity":"info","snippet":"    function activateHouseKey() external {","title":"Permissionless activateHouseKey takes effect instantly and refunds every swing the house already signed with the old key"},{"citation":"resolved","description":"Read in full, every external and public state-changing function traced for caller, value moved and trust: src/SwarmDerby.sol (667 lines), src/HouseDraw.sol (45 lines: RSASSA-PKCS1-v1_5 check via the modexp precompile; padding verified to be 00 01 + 202 x ff + 00 + SHA-256 DigestInfo = 256 bytes; sig < modulus enforced, so only the canonical signature of a well-formed key is accepted), src/DerbyOdds.sol (69 lines). Also read: test/HouseKey.sol, test/SwarmDerbyDraw.t.sol, the test list of test/SwarmDerby.t.sol, house/house.mjs, house/keygen.mjs, DEPLOY.md, HANDOFF.md, the pinned protected harness. Not reviewed in depth: src/DerbyAuction.sol (not part of this launch; only its use of dayClosed/board was noted). Not reachable: the Robinhood IMD token at 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 (not in the tree; its blocklist/pause behaviour is taken from DEPLOY.md) and the modexp precompile on Robinhood Chain itself (assumed present, as on Arbitrum Nitro; if absent, every draw fails BadDraw and every swing is refunded). Checks run: the full suite (117 tests pass, no ffi); a scratch invariant fuzz of random buys, swings, draws, reveals, expiries, settlements and ops withdrawals holding (1) imd.balanceOf(derby) == pot[0]+pot[1]+vault[0]+vault[1]+opsBalance and (2) pot[league] == sum of open dayPot + rollover, 64 runs x 150 calls, no violation; runtime size and forbidden-opcode scan of the compiled SwarmDerby (17,676 bytes, none of 0xf4/0xf2/0xff); the brief's modulus shape. Verified sound and not reported: commit single-use per player; commit bound to player so a copied commit only costs the copier; dayClosed implies every swing of the day is past its reveal deadline, so no homer can land after settlement; settlement pays each day once in order with failed prizes rolled over; slam payout reverts into the vault on a refused transfer; _trySend treats any return word other than 1 as failure; session consent is EIP-712 with per-key nonce, keys cannot chain, and every payout goes to the player; two-step ownership; no payable or delegatecall paths; checked arithmetic everywhere with no unchecked blocks. The accepted trust items in the brief (key holder can compute and withhold draws, no maxCost, consent without deadline, client-reported quality and velo, per-wallet arcade cap, 10% slam) were not re-raised.","line":43,"path":"src/SwarmDerby.sol","reproduction":"Not a defect. Listed so the adapter knows what was and was not examined.","severity":"info","snippet":"contract SwarmDerby {","title":"Coverage: contracts read and not reached"}],"hash":"d6fc08086d3a6e8708f9f39515354ff68b550bad30d480b0c295aa5614ad901f","nodeId":"d53737d4-10f0-4648-b15d-0cc361e989bc","outcome":"completed","summary":"The review is complete. The findings file is at the repository root and every quoted snippet matches the tree. The scratch directory has been removed and the tree is otherwise unchanged.\n\n**Result: no critical or high defects in SwarmDerby v2.** The contract, the RSA draw check and the odds library hold up under the Pashov checklist, the existing 117 tests, and a scratch invariant fuzz I ran over random buys, swings, draws, reveals, expiries, settlements and ops withdrawals. Token balance always equalled pots plus vaults plus ops, and each league's pot always equalled its open days plus rollover.\n\nFindings written to `.imd-findings.json`:\n\n- **Medium, launch blocker.** The constructor's fifth argument is a dynamic `bytes` modulus. The launch recipe allows only static argument types, and the manifest schema caps each argument string at 96 characters, while the brief's modulus is 514. The manifest is rejected before any bytecode is built. The adapter can fix this in the constructor alone, either as eight `bytes32` words concatenated before the key check or as an embedded constant. Neither touches the runtime ABI, and `houseKey()` must still return the exact 256 bytes.\n- **Low.** Turns can be bought while the house key is revoked. The purchase burns 40% immediately, yet the turn cannot be swung until a new key activates at least two days later, or ever if none is proposed. A one-line revert in the internal buy path would close this without changing any signature.\n- **Info.** Permissionless key activation is instant, so swings the house already signed with the old key are refunded rather than played. This is a runbook note for rotations, not a code change.\n- **Info, coverage.** Read in full: SwarmDerby, HouseDraw and DerbyOdds. DerbyAuction was only skimmed since it is not in this launch. Not reachable: the live Robinhood IMD token and the chain's modexp precompile, both taken on the documentation's word.\n\nAlso confirmed for the adapter: the compiled runtime is under the EIP-170 limit and contains no DELEGATECALL, CALLCODE or SELFDESTRUCT, and the supplied modulus is a well-formed 2048-bit odd number with no small factors.","treeHash":null,"usage":{"cachedInputTokens":1338528,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":43142,"runtime":"claude","turns":26,"wallClockMs":698594}}],"verification":[{"checks":[{"durationMs":47219,"exitCode":0,"name":"build","output":"Compiling 31 files with Solc 0.8.26\nSolc 0.8.26 finished in 47.06s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:21:5:\n   |\n21 |     function test_validSignatures() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:27:5:\n   |\n27 |     function test_signatureIsDeterministic() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:31:5:\n   |\n31 |     function test_wrongMessage() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:35:5:\n   |\n35 |     function test_flippedBit() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:42:5:\n   |\n42 |     function test_signaturePlusModulusRejected() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:54:5:\n   |\n54 |     function test_wrongLengths() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/SwarmDerbyDraw.t.sol:35:5:\n   |\n35 |     function _sign(uint256 id) internal returns (bytes memory) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:535:48\n    │\n535 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/HouseDraw.sol:21:13\n   │\n21 │             abi.encodePacked(KEY_BYTES, uint256(3), KEY_BYTES, sig, hex\"010001\", modulus)\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:535:55\n    │\n535 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[missing-events-arithmetic]: `singlePrice` is changed without an event but is used in arithmetic\n    ╭▸ src/SwarmDerby.sol:608:9\n    │\n608 │         singlePrice = single;\n    │         ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-arithmetic]: `packPrice` is changed without an event but is used in arithmetic\n    ╭▸ src/SwarmDerby.sol:609:9\n    │\n609 │         packPrice = pack;\n    │         ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/DerbyAuction.sol:301:9\n    │\n301 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `pendingOwner` is changed without an event but is used for access control\n    ╭▸ src/DerbyAuction.sol:302:9\n    │\n302 │         pendingOwner = address(0);\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/DerbyOdds.sol:67:16\n   │\n67 │         feet = uint16(lo + (d % span));\n   │                ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/SwarmDerby.sol:671:9\n    │\n671 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `pendingOwner` is changed without an event but is used for access control\n    ╭▸ src/SwarmDerby.sol:672:9\n    │\n672 │         pendingOwner = address(0);\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:137:13\n    │\n137 │         if (block.timestamp < CLOSE_OFFSET) return 1;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:139:13\n    │\n139 │         if (day > 2 && block.timestamp < _end(day - 1)) return day - 1;\n    │             ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:139:24\n    │\n139 │         if (day > 2 && block.timestamp < _end(day - 1)) return day - 1;\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_entered` is updated\n    ╭▸ src/DerbyAuction.sol:353:13\n    │\n353 │             address(imd).call(abi.encodeCall(IERC20.transferFrom, (from, address(this), amount)));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_entered` is updated\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:168:29\n    │\n168 │         if (sale.settled || block.timestamp < (day - 2) * 1 days + CLOSE_OFFSET || block.timestamp >= end) {\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:168:84\n    │\n168 │         if (sale.settled || block.timestamp < (day - 2) * 1 days + CLOSE_OFFSET || block.timestamp >= end) {\n    │                                                                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:175:13\n    │\n175 │         if (end - block.timestamp < ANTI_SNIPE) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:178:17\n    │\n178 │             if (end > latest) end = latest;\n    │                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:345:13\n    │\n345 │             emit RefundCredited(bidder, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:187:9\n    │\n187 │         emit Bid(day, msg.sender, amount, end, a.creature, a.vibe, a.stadium, a.weather, a.title, a.shoutout);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:209:47\n    │\n209 │         emit Settled(day, a.leader, a.amount, fee, a.bonus);\n    │                                               ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:193:13\n    │\n193 │         if (block.timestamp < _end(day)) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:201:17\n    │\n201 │             if (block.timestamp < day * 1 days) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:209:9\n    │\n209 │         emit Settled(day, a.leader, a.amount, fee, a.bonus);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/DerbyAuction.sol:212:51\n    │\n212 │     function veto(uint256 day) external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:215:13\n    │\n215 │         if (block.timestamp >= day * 1 days) revert BidClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:219:9\n    │\n219 │         emit Vetoed(day, a.leader, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `carry` is updated\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:245:35\n    │\n245 │         uint256 carried = bonus - paid;\n    │                                   ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:247:27\n    │\n247 │         _send(msg.sender, tip);\n    │                           ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:255:9\n    │\n255 │         emit BonusPaid(day, winners, amounts, msg.sender, tip, carried);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/DerbyAuction.sol:229:37\n    │\n229 │         (address[] memory board,) = derby.board(0, day);\n    │                                     ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:265:13\n    │\n265 │         if (block.timestamp <= from + RECLAIM_AFTER) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:269:9\n    │\n269 │         emit Reclaimed(day, a.leader, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:277:9\n    │\n277 │         emit RefundWithdrawn(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:271:9\n    │\n271 │         emit TurnsBought(player, league, count, cost, burned);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:355:91\n    │\n355 │             swings[swingId] = Swing(player, league, 0, velo, Status.Final, 0, bytes32(0), uint32(day), bytes32(0));\n    │                                                                                           ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:364:24\n    │\n364 │         uint64 nowTs = uint64(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:367:97\n    │\n367 │         swings[swingId] = Swing(player, league, quality, velo, Status.Committed, nowTs, commit, uint32(day), bytes32(0));\n    │                                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:382:13\n    │\n382 │         if (block.timestamp > uint256(s.committedAt) + DRAW_WINDOW) revert DrawClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:387:9\n    │\n387 │         emit SwingDrawn(swingId, h);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `vault` is updated\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:402:13\n    │\n402 │         if (block.timestamp > uint256(s.committedAt) + DRAW_WINDOW + REVEAL_WINDOW) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:418:13\n    │\n418 │             emit GrandSlam(swingId, s.player, s.league, feet, payout);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:420:9\n    │\n420 │         emit SwingResolved(swingId, s.player, tier, feet);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:429:17\n    │\n429 │             if (block.timestamp <= committedAt + DRAW_WINDOW) revert NotExpired();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:435:17\n    │\n435 │             if (block.timestamp <= committedAt + DRAW_WINDOW + REVEAL_WINDOW) revert NotExpired();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:519:38\n    │\n519 │         return day < currentDay() && block.timestamp > uint256(dayLastCommit[league][day]) + DRAW_WINDOW + REVEAL_WINDOW;\n    │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:540:51\n    │\n540 │         if (_board[league][day].length > 0) tip = (amount * PAYOUT_BPS / 10_000) * SETTLE_TIP_BPS / 10_000;\n    │                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[reentrancy-no-eth]: external call can be reentered before `rollover` is updated\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:564:19\n    │\n564 │             tip = (distributable * SETTLE_TIP_BPS) / 10_000;\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmDerby.sol:576:27\n    │\n576 │         _send(msg.sender, tip);\n    │                           ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmDerby.sol:574:37\n    │\n574 │         rollover[league] = amount - paid;\n    │                                     ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:584:9\n    │\n584 │         emit DaySettled(league, day, winners, amounts, msg.sender, tip, rollover[league]);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/DerbyAuction.sol:293:32\n    │\n293 │     function transferOwnership(address to) external onlyOwner {\n    │                                ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/DerbyAuction.sol:333:91\n    │\n333 │             if (c < 0x20 || c > 0x7e || c == 0x3c || c == 0x3e || c == 0x22 || c == 0x5c) revert BadAnswers();\n    │                                                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/DerbyAuction.sol:339:16\n    │\n339 │         return amount / 10_000 * bps + (amount % 10_000) * bps / 10_000;\n    │                ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:630:39\n    │\n630 │         if (pendingHouseKeyAt == 0 || block.timestamp < pendingHouseKeyAt) revert KeyNotReady();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:631:13\n    │\n631 │         if (block.timestamp > pendingHouseKeyAt + KEY_WINDOW) revert KeyExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmDerby.sol:662:32\n    │\n662 │     function transferOwnership(address to) external onlyOwner {\n    │                                ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/SwarmDerby.t.sol:145:18\n    │\n145 │         vm.warp((block.timestamp / 1 days + 1) * 1 days + derby.DRAW_WINDOW() + derby.REVEAL_WINDOW() + 1);\n    │         ─────────━━━━━━━━━━━━━━━────────────────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n    ╭▸ test/SwarmDerbyDraw.t.sol:155:21\n    │\n155 │             vm.roll(block.number + i * 7);\n    │             ────────━━━━━━━━━━━━───────── `vm.roll` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockNumber()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/SwarmDerbyDraw.t.sol:158:21\n    │\n158 │             vm.warp(block.timestamp + i);\n    │             ────────━━━━━━━━━━━━━━━───── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":32230,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/HouseDraw.t.sol:HouseDrawTest\n[PASS] test_flippedBit() (gas: 735666)\n[PASS] test_signatureIsDeterministic() (gas: 1402158)\n[PASS] test_signaturePlusModulusRejected() (gas: 2585886)\n[PASS] test_validSignatures() (gas: 1469431)\n[PASS] test_wrongLengths() (gas: 778356)\n[PASS] test_wrongMessage() (gas: 735624)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 350.01ms (80.52ms CPU time)\n\nRan 4 tests for test/SwarmDerbyLaunch.t.sol:SwarmDerbyLaunchTest\n[PASS] test_constructorDoesNotCallToken() (gas: 4405006)\n[PASS] test_constructorIsNonpayable() (gas: 399086)\n[PASS] test_constructorRejectsMissingKeyWord() (gas: 562840)\n[PASS] test_factoryDeploysExactLaunchConfigurationWithoutToken() (gas: 7180274)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 350.00ms (13.38ms CPU time)\n\nRan 59 tests for test/SwarmDerby.t.sol:SwarmDerbyTest\n[PASS] testFuzz_boardsAreTopTen(uint256) (runs: 256, μ: 5050923, ~: 5029485)\n[PASS] testFuzz_settlementConserves(uint256) (runs: 256, μ: 5432591, ~: 5452905)\n[PASS] test_agentLeagueHasNoCap() (gas: 2762548)\n[PASS] test_arcadeCapIsTwentyPerDay() (gas: 2580839)\n[PASS] test_arcadeKeepsLongestAgentKeepsTotal() (gas: 299154)\n[PASS] test_badLeagueRejected() (gas: 32969)\n[PASS] test_boardResetsEachDay() (gas: 216895)\n[PASS] test_buyPackSplitsPerLeague() (gas: 530237)\n[PASS] test_capCountsSessionSwingsForThePlayer() (gas: 2324997)\n[PASS] test_commitBoundToPlayer() (gas: 645220)\n[PASS] test_constructorRejectsZeroAddressesAndFreeTurns() (gas: 1523754)\n[PASS] test_contactNeedsCommit() (gas: 339271)\n[PASS] test_eachDaySettlesOnceInOrder() (gas: 1399451)\n[PASS] test_emptyDayRollsOverWithoutTip() (gas: 1040549)\n[PASS] test_expireUnrevealed() (gas: 675309)\n[PASS] test_finalizeNeedsTheDraw() (gas: 493821)\n[PASS] test_finalizeUpdatesArcadeBoard() (gas: 771376)\n[PASS] test_fullSwingMatchesOdds() (gas: 574094)\n[PASS] test_lateFinalizeScoresOnCommitDay() (gas: 771591)\n[PASS] test_lateRevealIsFoul() (gas: 585987)\n[PASS] test_leagueTurnsAreSeparate() (gas: 300675)\n[PASS] test_leaveSessionFreesTheKey() (gas: 207085)\n[PASS] test_nextSettlementBeforeAnything() (gas: 12117)\n[PASS] test_oddTransferAnswerKeepsSlamPrize() (gas: 9699835)\n[PASS] test_oddsMonotoneInQuality() (gas: 317019)\n[PASS] test_ownerIsConstructorArg() (gas: 4110418)\n[PASS] test_ownerOnlyReachesOps() (gas: 425949)\n[PASS] test_ownershipIsTwoStep() (gas: 171361)\n[PASS] test_ownershipMoveCanBeCancelled() (gas: 114898)\n[PASS] test_parityWithBrowser() (gas: 63317)\n[PASS] test_pendingKeyDoesNotBlockPurchases() (gas: 405469)\n[PASS] test_priceFloor() (gas: 100721)\n[PASS] test_purchasesResumeOnlyAfterKeyActivation() (gas: 877747)\n[PASS] test_qualityAndVeloBounded() (gas: 322014)\n[PASS] test_revealAtWindowEdgeStillCounts() (gas: 759879)\n[PASS] test_revokedKeyRejectsPurchasesWithoutMovingFunds() (gas: 281157)\n[PASS] test_sessionBuysForThePlayer() (gas: 489658)\n[PASS] test_sessionCannotBeClaimedTwice() (gas: 180232)\n[PASS] test_sessionCannotBuyWhileKeyRevoked() (gas: 381591)\n[PASS] test_sessionChainsRejected() (gas: 379161)\n[PASS] test_sessionConsentIsSingleUse() (gas: 315948)\n[PASS] test_sessionNeedsTheKeysConsent() (gas: 163195)\n[PASS] test_sessionRevokeAndRotate() (gas: 302978)\n[PASS] test_sessionSwingsForPlayer() (gas: 722762)\n[PASS] test_settleAgentLeague() (gas: 609646)\n[PASS] test_settlePaysOnlyThatDaysPot() (gas: 1140885)\n[PASS] test_settlePaysTheDaysTopThree() (gas: 1207816)\n[PASS] test_settleWaitsForTheDayToEnd() (gas: 937011)\n[PASS] test_settleWaitsForTheLastReveal() (gas: 732379)\n[PASS] test_singleTurnPrice() (gas: 291032)\n[PASS] test_slamPaysTenPercentOfItsLeagueVault() (gas: 9953183)\n[PASS] test_swingStoresVelo() (gas: 537297)\n[PASS] test_tokenWithoutCodeRefusesPurchases() (gas: 4480497)\n[PASS] test_underPowerLineNoBombOrSlam() (gas: 29184953)\n[PASS] test_unpayableSlamKeepsPrizeAndHomer() (gas: 9731629)\n[PASS] test_unpayableWinnerRollsOver() (gas: 977119)\n[PASS] test_whiffCostsTurnNoRoll() (gas: 414432)\n[PASS] test_wrongSaltRejected() (gas: 555744)\n[PASS] test_zeroCountPurchaseReverts() (gas: 77857)\nSuite result: ok. 59 passed; 0 failed; 0 skipped; finished in 349.99ms (507.61ms CPU time)\n\nRan 16 tests for test/SwarmDerbyDraw.t.sol:SwarmDerbyDrawTest\n[PASS] test_badKeysRejected() (gas: 865144)\n[PASS] test_blockDataCannotSteerTheRoll() (gas: 1712055)\n[PASS] test_copiedCommitDoesNotBlockItsOwner() (gas: 2289808)\n[PASS] test_drawForAnotherSwingRejected() (gas: 1237525)\n[PASS] test_drawFromAnotherDeploymentRejected() (gas: 5684347)\n[PASS] test_drawOnlyOnceAndNotForAWhiff() (gas: 1888488)\n[PASS] test_drawWindowCloses() (gas: 967946)\n[PASS] test_drawnButUnrevealedIsAFoulNotARefund() (gas: 1104268)\n[PASS] test_houseKeyChangeWaitsForTheDelay() (gas: 2496243)\n[PASS] test_houseKeyProposalCanBeCancelledAndLapses() (gas: 804095)\n[PASS] test_noDrawRefundsAgentTurn() (gas: 246217)\n[PASS] test_noDrawRefundsTurnAndCapOnce() (gas: 404043)\n[PASS] test_realDrawFullSwing() (gas: 1134066)\n[PASS] test_reusedCommitRejected() (gas: 269915)\n[PASS] test_revokeStopsDrawsAtOnceAndSwingsRefund() (gas: 1564364)\n[PASS] test_tamperedDrawRejected() (gas: 1050090)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 350.04ms (136.39ms CPU time)\n\nRan 18 tests for test/SwarmDerbyFailures.t.sol:SwarmDerbyFailuresTest\n[PASS] testFuzz_allLeagueValidatedEntrypointsRejectInvalidLeague(uint8) (runs: 1000, μ: 402836, ~: 402821)\n[PASS] testFuzz_purchaseSplitConservesEveryWei(uint256,uint256,bool,bool) (runs: 1000, μ: 424579, ~: 424462)\n[PASS] test_allAdminFunctionsRejectPlayer() (gas: 1039613)\n[PASS] test_drawAtExactDeadlineSucceedsAndCannotThenRefund() (gas: 1427790)\n[PASS] test_failedSettlerTipRollsBackQueueThenDifferentCallerCanSettle() (gas: 2023411)\n[PASS] test_falseOrRevertingPullRollsBackAllPurchaseEffects() (gas: 1061623)\n[PASS] test_houseDrawSignatureCannotReplayAcrossChains() (gas: 1332959)\n[PASS] test_malformedPullCannotCreditUnbackedTurns() (gas: 1171996)\n[PASS] test_malformedSessionSignaturesCannotBind() (gas: 256027)\n[PASS] test_malformedWinnerPaymentsRollOverAndOtherWinnerIsPaid() (gas: 3542799)\n[PASS] test_maximumPurchaseCountsRevertWithoutEffects() (gas: 346107)\n[PASS] test_previousDayRefundDoesNotFreeTodaysCapSlot() (gas: 760535)\n[PASS] test_purchaseWithoutAllowanceCannotChangeQueueOrMoney() (gas: 526226)\n[PASS] test_refundedCommitCannotBeReusedInEitherLeague() (gas: 1148368)\n[PASS] test_rejectedBurnRollsBackSuccessfulPullAndAllowance() (gas: 1805473)\n[PASS] test_rejectedOpsWithdrawalRestoresBalance() (gas: 749775)\n[PASS] test_replacingKeyProposalRestartsDelayAndRevokeCancelsIt() (gas: 503580)\n[PASS] test_sessionSignatureDomainAndFailedRotationPreserveOldSession() (gas: 326535)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 350.12ms (475.58ms CPU time)\n\nRan 40 tests for test/DerbyAuction.t.sol:DerbyAuctionTest\n[PASS] testFuzz_conservationAcrossAuctionSequences(uint256) (runs: 256, μ: 13576939, ~: 13799187)\n[PASS] test_adminPermissionsFeeCapAndTwoStepOwnership() (gas: 537169)\n[PASS] test_agentScoresAndOtherDaysNeverAffectArcadeBonus() (gas: 3326203)\n[PASS] test_answerBoundaryValuesStoredAndBidEmitted() (gas: 660323)\n[PASS] test_answerLengthsAndEnums() (gas: 533362)\n[PASS] test_antiSnipeExtendsRepeatedlyAndKeepsOtherDaysIndependent() (gas: 1985950)\n[PASS] test_antiSnipeStopsAtOneHourSoVetoStaysOpen() (gas: 3782751)\n[PASS] test_bidMinimumAndIncrementRoundUp() (gas: 768959)\n[PASS] test_blockedReclaimIsCreditedAndCarryIsReusable() (gas: 1940239)\n[PASS] test_constructorRejectsZeroAddressesAndExcessFee() (gas: 11242)\n[PASS] test_constructorStoresArgumentsWithoutAnyDependencyCalls() (gas: 394597)\n[PASS] test_emptyArcadeWithAgentPlayersCarriesEverythingWithoutTip() (gas: 1857602)\n[PASS] test_emptyAuctionSettlesWithoutTakingCarry() (gas: 824063)\n[PASS] test_everyForbiddenByteRejectedInEveryString() (gas: 30597411)\n[PASS] test_failedOrShortTokenPullRollsBackBidAndAnswers() (gas: 1642645)\n[PASS] test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers() (gas: 2624649)\n[PASS] test_failedRefundAccumulatesAndWithdrawsOnlyOnce() (gas: 1324007)\n[PASS] test_failedStudioPaymentIsCreditedAndSettlementGoesOn() (gas: 846918)\n[PASS] test_failedTipRevertsAndAnotherCallerCanPay() (gas: 1589001)\n[PASS] test_falseAndMalformedRefundsDoNotBlockBids() (gas: 1139380)\n[PASS] test_fullNewBidMustBeFundedBeforeSelfRefund() (gas: 559374)\n[PASS] test_lateSettleKeepsTheFullReclaimGraceForTheBoard() (gas: 2767420)\n[PASS] test_maximumBidSettlesAndPaysWithoutIntermediateOverflow() (gas: 2615998)\n[PASS] test_noReturnTokenBidsRefundsFeesWithdrawalsAndBonus() (gas: 2123010)\n[PASS] test_onePlayerCarriesUnfilledSharesIntoNextAuction() (gas: 1888408)\n[PASS] test_openDayAndBidTimeBoundaries() (gas: 664919)\n[PASS] test_openDayNamesTheExtendedDayUntilItCloses() (gas: 725536)\n[PASS] test_outbidAndSelfRaiseRefundPreviousBid() (gas: 819741)\n[PASS] test_realSwingsPayOnlyAfterArcadeDayClosedAndOnlyTopThree() (gas: 3404861)\n[PASS] test_reclaimGraceBoundaryReturnsOwnNetBidNotCarryToWinner() (gas: 1552630)\n[PASS] test_reclaimRejectsUnsettledEmptyAndAlreadyPaidAuctions() (gas: 799007)\n[PASS] test_reentrantBonusAndReclaimCannotPayTwice() (gas: 2243929)\n[PASS] test_reentrantTokenCannotBidOrWithdrawDuringTransfers() (gas: 1346649)\n[PASS] test_settleOnOrAfterThemeDayKeepsCarryForLaterBoards() (gas: 1516271)\n[PASS] test_settleOneIMDFeeAndSettingsApplyOnlyAtSettlement() (gas: 689653)\n[PASS] test_settleZeroFeeExactlyAndOnlyOnce() (gas: 669534)\n[PASS] test_twoPlayersCarryUnfilledShareIntoNextAuction() (gas: 2463366)\n[PASS] test_vetoOwnerOnlyBeforeThemeDayReturnsOwnNetBidNotCarry() (gas: 1508086)\n[PASS] test_vetoRejectsUnsettledEmptyAndThemeDayBoundary() (gas: 727152)\n[PASS] test_zeroFeeVetoRefundsFullBidAndBlockedWinnerGetsCredit() (gas: 738849)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 383.82ms (418.69ms CPU time)\n\nRan 2 tests for test/SwarmDerbyInvariant.t.sol:SwarmDerbyInvariantTest\n[PASS]\nSwarmDerbyInvariantTest invariants:\n[PASS] invariant_potsEqualOpenDaysAndRollover\n[PASS] invariant_scoresBoardsAndSessions\n[PASS] invariant_tokenBackingAndConservation\n[PASS] invariant_turnsCapsAndTerminalStates\n SwarmDerbyInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭----------------------+----------+-------+---------+----------╮\n| Contract             | Selector | Calls | Reverts | Discards |\n+==============================================================+\n| DerbySequenceHandler | advance  | 1345  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | buy      | 1322  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | donate   | 1370  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | draw     | 1353  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | expire   | 1345  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | finalize | 1412  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | play     | 2719  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | prices   | 1393  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | session  | 1342  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | settle   | 1373  | 0       | 0        |\n|----------------------+----------+-------+---------+----------|\n| DerbySequenceHandler | withdraw | 1410  | 0       | 0        |\n╰----------------------+----------+-------+---------+----------╯\n\n[PASS] test_handlerSequenceReachesPayoutRefundAndRejectedWithdrawal() (gas: 4783074)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 32.14s (32.15s CPU time)\n\nRan 7 test suites in 32.15s (34.28s CPU time): 145 tests passed, 0 failed, 0 skipped (145 total tests)\n","passed":true},{"durationMs":49,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"DerbyAuction.acceptOwnership()\",\"DerbyAuction.bid(uint256,uint256,(string,uint8,uint8,uint8,string,string))\",\"DerbyAuction.payBonus(uint256)\",\"DerbyAuction.reclaim(uint256)\",\"DerbyAuction.setBuildFee(uint256)\",\"DerbyAuction.setStudio(address)\",\"DerbyAuction.settle(uint256)\",\"DerbyAuction.transferOwnership(address)\",\"DerbyAuction.veto(uint256)\",\"DerbyAuction.withdrawRefund()\",\"SwarmDerby.acceptOwnership()\",\"SwarmDerby.activateHouseKey()\",\"SwarmDerby.buyPacks(uint8,uint256)\",\"SwarmDerby.buyTurns(uint8,uint256)\",\"SwarmDerby.cancelHouseKey()\",\"SwarmDerby.draw(uint256,bytes)\",\"SwarmDerby.expire(uint256)\",\"SwarmDerby.finalize(uint256,bytes32)\",\"SwarmDerby.leaveSession()\",\"SwarmDerby.proposeHouseKey(bytes)\",\"SwarmDerby.revokeHouseKey()\",\"SwarmDerby.setPrices(uint256,uint256)\",\"SwarmDerby.setSession(address,bytes)\",\"SwarmDerby.settleNextDay(uint8)\",\"SwarmDerby.swing(uint8,uint8,uint8,bytes32)\",\"SwarmDerby.transferOwnership(address)\",\"SwarmDerby.withdrawOps(address,uint256)\"],\"files\":{\".gitignore\":5,\"ADAPTATION.md\":136,\"DEPLOY.md\":311,\"HANDOFF.md\":148,\"LICENSE\":21,\"README.md\":15,\"e2e/Mocks.sol\":27,\"e2e/README.md\":35,\"e2e/board.py\":50,\"e2e/leagues.py\":48,\"e2e/play.py\":63,\"e2e/recover.py\":26,\"e2e/recover_unmined.py\":28,\"e2e/refund.py\":26,\"e2e/settle.py\":59,\"e2e/setup.py\":33,\"foundry.toml\":9,\"house/README.md\":64,\"house/house.mjs\":217,\"house/keygen.mjs\":15,\"house/package-lock.json\":122,\"house/package.json\":9,\"imd-check.mjs\":40,\"specs/README.md\":70,\"specs/WP1-theme-packs.md\":142,\"specs/WP2-daily-conditions.md\":17,\"specs/WP3-auction-contract.md\":134,\"specs/WP4-auction-ui.md\":89,\"specs/WP5-theme-build-job.md\":110,\"specs/WP6-operator-runbook.md\":56,\"src/DerbyAuction.sol\":378,\"src/DerbyOdds.sol\":69,\"src/HouseDraw.sol\":45,\"src/SwarmDerby.sol\":711,\"test/DerbyAuction.t.sol\":1096,\"test/HouseDraw.t.sol\":71,\"test/HouseKey.sol\":84,\"test/SwarmDerby.t.sol\":1015,\"test/SwarmDerbyCoverage.md\":44,\"test/SwarmDerbyDraw.t.sol\":296,\"test/SwarmDerbyFailures.t.sol\":414,\"test/SwarmDerbyInvariant.t.sol\":479,\"test/SwarmDerbyLaunch.t.sol\":116,\"test/fixtures/house-test-key.mjs\":65,\"web/derby-odds.js\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"322f3d908dafaaa1972f9da5c6e5dd5d9ac79fb8c076774452fb5690b3727fe1","verifiedTreeHash":"957ef76687f1a671ea19dcf983472b187f5c80a6","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":41680,"exitCode":0,"name":"build","output":"Compiling 29 files with Solc 0.8.26\nSolc 0.8.26 finished in 41.51s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:21:5:\n   |\n21 |     function test_validSignatures() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:27:5:\n   |\n27 |     function test_signatureIsDeterministic() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:31:5:\n   |\n31 |     function test_wrongMessage() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:35:5:\n   |\n35 |     function test_flippedBit() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:42:5:\n   |\n42 |     function test_signaturePlusModulusRejected() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:54:5:\n   |\n54 |     function test_wrongLengths() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/SwarmDerbyDraw.t.sol:35:5:\n   |\n35 |     function _sign(uint256 id) internal returns (bytes memory) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:535:48\n    │\n535 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/HouseDraw.sol:21:13\n   │\n21 │             abi.encodePacked(KEY_BYTES, uint256(3), KEY_BYTES, sig, hex\"010001\", modulus)\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:535:55\n    │\n535 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/DerbyOdds.sol:67:16\n   │\n67 │         feet = uint16(lo + (d % span));\n   │                ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-arithmetic]: `singlePrice` is changed without an event but is used in arithmetic\n    ╭▸ src/SwarmDerby.sol:608:9\n    │\n608 │         singlePrice = single;\n    │         ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-arithmetic]: `packPrice` is changed without an event but is used in arithmetic\n    ╭▸ src/SwarmDerby.sol:609:9\n    │\n609 │         packPrice = pack;\n    │         ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/DerbyAuction.sol:301:9\n    │\n301 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `pendingOwner` is changed without an event but is used for access control\n    ╭▸ src/DerbyAuction.sol:302:9\n    │\n302 │         pendingOwner = address(0);\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/SwarmDerby.sol:671:9\n    │\n671 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `pendingOwner` is changed without an event but is used for access control\n    ╭▸ src/SwarmDerby.sol:672:9\n    │\n672 │         pendingOwner = address(0);\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:137:13\n    │\n137 │         if (block.timestamp < CLOSE_OFFSET) return 1;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:139:13\n    │\n139 │         if (day > 2 && block.timestamp < _end(day - 1)) return day - 1;\n    │             ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:139:24\n    │\n139 │         if (day > 2 && block.timestamp < _end(day - 1)) return day - 1;\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_entered` is updated\n    ╭▸ src/DerbyAuction.sol:353:13\n    │\n353 │             address(imd).call(abi.encodeCall(IERC20.transferFrom, (from, address(this), amount)));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_entered` is updated\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:168:29\n    │\n168 │         if (sale.settled || block.timestamp < (day - 2) * 1 days + CLOSE_OFFSET || block.timestamp >= end) {\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:168:84\n    │\n168 │         if (sale.settled || block.timestamp < (day - 2) * 1 days + CLOSE_OFFSET || block.timestamp >= end) {\n    │                                                                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:175:13\n    │\n175 │         if (end - block.timestamp < ANTI_SNIPE) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:178:17\n    │\n178 │             if (end > latest) end = latest;\n    │                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:345:13\n    │\n345 │             emit RefundCredited(bidder, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:187:9\n    │\n187 │         emit Bid(day, msg.sender, amount, end, a.creature, a.vibe, a.stadium, a.weather, a.title, a.shoutout);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:209:47\n    │\n209 │         emit Settled(day, a.leader, a.amount, fee, a.bonus);\n    │                                               ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:193:13\n    │\n193 │         if (block.timestamp < _end(day)) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:201:17\n    │\n201 │             if (block.timestamp < day * 1 days) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:209:9\n    │\n209 │         emit Settled(day, a.leader, a.amount, fee, a.bonus);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/DerbyAuction.sol:212:51\n    │\n212 │     function veto(uint256 day) external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:215:13\n    │\n215 │         if (block.timestamp >= day * 1 days) revert BidClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:219:9\n    │\n219 │         emit Vetoed(day, a.leader, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `carry` is updated\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:247:27\n    │\n247 │         _send(msg.sender, tip);\n    │                           ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:245:35\n    │\n245 │         uint256 carried = bonus - paid;\n    │                                   ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:255:9\n    │\n255 │         emit BonusPaid(day, winners, amounts, msg.sender, tip, carried);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/DerbyAuction.sol:229:37\n    │\n229 │         (address[] memory board,) = derby.board(0, day);\n    │                                     ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:265:13\n    │\n265 │         if (block.timestamp <= from + RECLAIM_AFTER) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:269:9\n    │\n269 │         emit Reclaimed(day, a.leader, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:277:9\n    │\n277 │         emit RefundWithdrawn(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:271:9\n    │\n271 │         emit TurnsBought(player, league, count, cost, burned);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:355:91\n    │\n355 │             swings[swingId] = Swing(player, league, 0, velo, Status.Final, 0, bytes32(0), uint32(day), bytes32(0));\n    │                                                                                           ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:364:24\n    │\n364 │         uint64 nowTs = uint64(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:367:97\n    │\n367 │         swings[swingId] = Swing(player, league, quality, velo, Status.Committed, nowTs, commit, uint32(day), bytes32(0));\n    │                                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:382:13\n    │\n382 │         if (block.timestamp > uint256(s.committedAt) + DRAW_WINDOW) revert DrawClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:387:9\n    │\n387 │         emit SwingDrawn(swingId, h);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `vault` is updated\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:402:13\n    │\n402 │         if (block.timestamp > uint256(s.committedAt) + DRAW_WINDOW + REVEAL_WINDOW) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:418:13\n    │\n418 │             emit GrandSlam(swingId, s.player, s.league, feet, payout);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:420:9\n    │\n420 │         emit SwingResolved(swingId, s.player, tier, feet);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:429:17\n    │\n429 │             if (block.timestamp <= committedAt + DRAW_WINDOW) revert NotExpired();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:435:17\n    │\n435 │             if (block.timestamp <= committedAt + DRAW_WINDOW + REVEAL_WINDOW) revert NotExpired();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:519:38\n    │\n519 │         return day < currentDay() && block.timestamp > uint256(dayLastCommit[league][day]) + DRAW_WINDOW + REVEAL_WINDOW;\n    │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:540:51\n    │\n540 │         if (_board[league][day].length > 0) tip = (amount * PAYOUT_BPS / 10_000) * SETTLE_TIP_BPS / 10_000;\n    │                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[reentrancy-no-eth]: external call can be reentered before `rollover` is updated\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:564:19\n    │\n564 │             tip = (distributable * SETTLE_TIP_BPS) / 10_000;\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmDerby.sol:576:27\n    │\n576 │         _send(msg.sender, tip);\n    │                           ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmDerby.sol:574:37\n    │\n574 │         rollover[league] = amount - paid;\n    │                                     ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:584:9\n    │\n584 │         emit DaySettled(league, day, winners, amounts, msg.sender, tip, rollover[league]);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/DerbyAuction.sol:293:32\n    │\n293 │     function transferOwnership(address to) external onlyOwner {\n    │                                ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/DerbyAuction.sol:333:91\n    │\n333 │             if (c < 0x20 || c > 0x7e || c == 0x3c || c == 0x3e || c == 0x22 || c == 0x5c) revert BadAnswers();\n    │                                                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/DerbyAuction.sol:339:16\n    │\n339 │         return amount / 10_000 * bps + (amount % 10_000) * bps / 10_000;\n    │                ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:630:39\n    │\n630 │         if (pendingHouseKeyAt == 0 || block.timestamp < pendingHouseKeyAt) revert KeyNotReady();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:631:13\n    │\n631 │         if (block.timestamp > pendingHouseKeyAt + KEY_WINDOW) revert KeyExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmDerby.sol:662:32\n    │\n662 │     function transferOwnership(address to) external onlyOwner {\n    │                                ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/SwarmDerby.t.sol:145:18\n    │\n145 │         vm.warp((block.timestamp / 1 days + 1) * 1 days + derby.DRAW_WINDOW() + derby.REVEAL_WINDOW() + 1);\n    │         ─────────━━━━━━━━━━━━━━━────────────────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n    ╭▸ test/SwarmDerbyDraw.t.sol:155:21\n    │\n155 │             vm.roll(block.number + i * 7);\n    │             ────────━━━━━━━━━━━━───────── `vm.roll` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockNumber()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/SwarmDerbyDraw.t.sol:158:21\n    │\n158 │             vm.warp(block.timestamp + i);\n    │             ────────━━━━━━━━━━━━━━━───── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":531,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/HouseDraw.t.sol:HouseDrawTest\n[PASS] test_flippedBit() (gas: 735666)\n[PASS] test_signatureIsDeterministic() (gas: 1402158)\n[PASS] test_signaturePlusModulusRejected() (gas: 2585886)\n[PASS] test_validSignatures() (gas: 1469431)\n[PASS] test_wrongLengths() (gas: 778356)\n[PASS] test_wrongMessage() (gas: 735624)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 17.98ms (73.90ms CPU time)\n\nRan 59 tests for test/SwarmDerby.t.sol:SwarmDerbyTest\n[PASS] testFuzz_boardsAreTopTen(uint256) (runs: 256, μ: 5083088, ~: 5086430)\n[PASS] testFuzz_settlementConserves(uint256) (runs: 256, μ: 5427915, ~: 5477138)\n[PASS] test_agentLeagueHasNoCap() (gas: 2762548)\n[PASS] test_arcadeCapIsTwentyPerDay() (gas: 2580839)\n[PASS] test_arcadeKeepsLongestAgentKeepsTotal() (gas: 299154)\n[PASS] test_badLeagueRejected() (gas: 32969)\n[PASS] test_boardResetsEachDay() (gas: 216895)\n[PASS] test_buyPackSplitsPerLeague() (gas: 530237)\n[PASS] test_capCountsSessionSwingsForThePlayer() (gas: 2324997)\n[PASS] test_commitBoundToPlayer() (gas: 645220)\n[PASS] test_constructorRejectsZeroAddressesAndFreeTurns() (gas: 1523754)\n[PASS] test_contactNeedsCommit() (gas: 339271)\n[PASS] test_eachDaySettlesOnceInOrder() (gas: 1399451)\n[PASS] test_emptyDayRollsOverWithoutTip() (gas: 1040549)\n[PASS] test_expireUnrevealed() (gas: 675309)\n[PASS] test_finalizeNeedsTheDraw() (gas: 493821)\n[PASS] test_finalizeUpdatesArcadeBoard() (gas: 771376)\n[PASS] test_fullSwingMatchesOdds() (gas: 574094)\n[PASS] test_lateFinalizeScoresOnCommitDay() (gas: 771591)\n[PASS] test_lateRevealIsFoul() (gas: 585987)\n[PASS] test_leagueTurnsAreSeparate() (gas: 300675)\n[PASS] test_leaveSessionFreesTheKey() (gas: 207085)\n[PASS] test_nextSettlementBeforeAnything() (gas: 12117)\n[PASS] test_oddTransferAnswerKeepsSlamPrize() (gas: 9699835)\n[PASS] test_oddsMonotoneInQuality() (gas: 317019)\n[PASS] test_ownerIsConstructorArg() (gas: 4110418)\n[PASS] test_ownerOnlyReachesOps() (gas: 425949)\n[PASS] test_ownershipIsTwoStep() (gas: 171361)\n[PASS] test_ownershipMoveCanBeCancelled() (gas: 114898)\n[PASS] test_parityWithBrowser() (gas: 63317)\n[PASS] test_pendingKeyDoesNotBlockPurchases() (gas: 405469)\n[PASS] test_priceFloor() (gas: 100721)\n[PASS] test_purchasesResumeOnlyAfterKeyActivation() (gas: 877747)\n[PASS] test_qualityAndVeloBounded() (gas: 322014)\n[PASS] test_revealAtWindowEdgeStillCounts() (gas: 759879)\n[PASS] test_revokedKeyRejectsPurchasesWithoutMovingFunds() (gas: 281157)\n[PASS] test_sessionBuysForThePlayer() (gas: 489658)\n[PASS] test_sessionCannotBeClaimedTwice() (gas: 180232)\n[PASS] test_sessionCannotBuyWhileKeyRevoked() (gas: 381591)\n[PASS] test_sessionChainsRejected() (gas: 379161)\n[PASS] test_sessionConsentIsSingleUse() (gas: 315948)\n[PASS] test_sessionNeedsTheKeysConsent() (gas: 163195)\n[PASS] test_sessionRevokeAndRotate() (gas: 302978)\n[PASS] test_sessionSwingsForPlayer() (gas: 722762)\n[PASS] test_settleAgentLeague() (gas: 609646)\n[PASS] test_settlePaysOnlyThatDaysPot() (gas: 1140885)\n[PASS] test_settlePaysTheDaysTopThree() (gas: 1207816)\n[PASS] test_settleWaitsForTheDayToEnd() (gas: 937011)\n[PASS] test_settleWaitsForTheLastReveal() (gas: 732379)\n[PASS] test_singleTurnPrice() (gas: 291032)\n[PASS] test_slamPaysTenPercentOfItsLeagueVault() (gas: 9953183)\n[PASS] test_swingStoresVelo() (gas: 537297)\n[PASS] test_tokenWithoutCodeRefusesPurchases() (gas: 4480497)\n[PASS] test_underPowerLineNoBombOrSlam() (gas: 29184953)\n[PASS] test_unpayableSlamKeepsPrizeAndHomer() (gas: 9731629)\n[PASS] test_unpayableWinnerRollsOver() (gas: 977119)\n[PASS] test_whiffCostsTurnNoRoll() (gas: 414432)\n[PASS] test_wrongSaltRejected() (gas: 555744)\n[PASS] test_zeroCountPurchaseReverts() (gas: 77857)\nSuite result: ok. 59 passed; 0 failed; 0 skipped; finished in 219.72ms (520.58ms CPU time)\n\nRan 4 tests for test/SwarmDerbyLaunch.t.sol:SwarmDerbyLaunchTest\n[PASS] test_constructorDoesNotCallToken() (gas: 4405006)\n[PASS] test_constructorIsNonpayable() (gas: 399086)\n[PASS] test_constructorRejectsMissingKeyWord() (gas: 562840)\n[PASS] test_factoryDeploysExactLaunchConfigurationWithoutToken() (gas: 7180274)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 412.86ms (9.27ms CPU time)\n\nRan 16 tests for test/SwarmDerbyDraw.t.sol:SwarmDerbyDrawTest\n[PASS] test_badKeysRejected() (gas: 865144)\n[PASS] test_blockDataCannotSteerTheRoll() (gas: 1712055)\n[PASS] test_copiedCommitDoesNotBlockItsOwner() (gas: 2289808)\n[PASS] test_drawForAnotherSwingRejected() (gas: 1237525)\n[PASS] test_drawFromAnotherDeploymentRejected() (gas: 5684347)\n[PASS] test_drawOnlyOnceAndNotForAWhiff() (gas: 1888488)\n[PASS] test_drawWindowCloses() (gas: 967946)\n[PASS] test_drawnButUnrevealedIsAFoulNotARefund() (gas: 1104268)\n[PASS] test_houseKeyChangeWaitsForTheDelay() (gas: 2496243)\n[PASS] test_houseKeyProposalCanBeCancelledAndLapses() (gas: 804095)\n[PASS] test_noDrawRefundsAgentTurn() (gas: 246217)\n[PASS] test_noDrawRefundsTurnAndCapOnce() (gas: 404043)\n[PASS] test_realDrawFullSwing() (gas: 1134066)\n[PASS] test_reusedCommitRejected() (gas: 269915)\n[PASS] test_revokeStopsDrawsAtOnceAndSwingsRefund() (gas: 1564364)\n[PASS] test_tamperedDrawRejected() (gas: 1050090)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 412.88ms (99.66ms CPU time)\n\nRan 40 tests for test/DerbyAuction.t.sol:DerbyAuctionTest\n[PASS] testFuzz_conservationAcrossAuctionSequences(uint256) (runs: 256, μ: 13651095, ~: 13359954)\n[PASS] test_adminPermissionsFeeCapAndTwoStepOwnership() (gas: 537169)\n[PASS] test_agentScoresAndOtherDaysNeverAffectArcadeBonus() (gas: 3326203)\n[PASS] test_answerBoundaryValuesStoredAndBidEmitted() (gas: 660323)\n[PASS] test_answerLengthsAndEnums() (gas: 533362)\n[PASS] test_antiSnipeExtendsRepeatedlyAndKeepsOtherDaysIndependent() (gas: 1985950)\n[PASS] test_antiSnipeStopsAtOneHourSoVetoStaysOpen() (gas: 3782751)\n[PASS] test_bidMinimumAndIncrementRoundUp() (gas: 768959)\n[PASS] test_blockedReclaimIsCreditedAndCarryIsReusable() (gas: 1940239)\n[PASS] test_constructorRejectsZeroAddressesAndExcessFee() (gas: 11242)\n[PASS] test_constructorStoresArgumentsWithoutAnyDependencyCalls() (gas: 394597)\n[PASS] test_emptyArcadeWithAgentPlayersCarriesEverythingWithoutTip() (gas: 1857602)\n[PASS] test_emptyAuctionSettlesWithoutTakingCarry() (gas: 824063)\n[PASS] test_everyForbiddenByteRejectedInEveryString() (gas: 30597411)\n[PASS] test_failedOrShortTokenPullRollsBackBidAndAnswers() (gas: 1642645)\n[PASS] test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers() (gas: 2624649)\n[PASS] test_failedRefundAccumulatesAndWithdrawsOnlyOnce() (gas: 1324007)\n[PASS] test_failedStudioPaymentIsCreditedAndSettlementGoesOn() (gas: 846918)\n[PASS] test_failedTipRevertsAndAnotherCallerCanPay() (gas: 1589001)\n[PASS] test_falseAndMalformedRefundsDoNotBlockBids() (gas: 1139380)\n[PASS] test_fullNewBidMustBeFundedBeforeSelfRefund() (gas: 559374)\n[PASS] test_lateSettleKeepsTheFullReclaimGraceForTheBoard() (gas: 2767420)\n[PASS] test_maximumBidSettlesAndPaysWithoutIntermediateOverflow() (gas: 2615998)\n[PASS] test_noReturnTokenBidsRefundsFeesWithdrawalsAndBonus() (gas: 2123010)\n[PASS] test_onePlayerCarriesUnfilledSharesIntoNextAuction() (gas: 1888408)\n[PASS] test_openDayAndBidTimeBoundaries() (gas: 664919)\n[PASS] test_openDayNamesTheExtendedDayUntilItCloses() (gas: 725536)\n[PASS] test_outbidAndSelfRaiseRefundPreviousBid() (gas: 819741)\n[PASS] test_realSwingsPayOnlyAfterArcadeDayClosedAndOnlyTopThree() (gas: 3404861)\n[PASS] test_reclaimGraceBoundaryReturnsOwnNetBidNotCarryToWinner() (gas: 1552630)\n[PASS] test_reclaimRejectsUnsettledEmptyAndAlreadyPaidAuctions() (gas: 799007)\n[PASS] test_reentrantBonusAndReclaimCannotPayTwice() (gas: 2243929)\n[PASS] test_reentrantTokenCannotBidOrWithdrawDuringTransfers() (gas: 1346649)\n[PASS] test_settleOnOrAfterThemeDayKeepsCarryForLaterBoards() (gas: 1516271)\n[PASS] test_settleOneIMDFeeAndSettingsApplyOnlyAtSettlement() (gas: 689653)\n[PASS] test_settleZeroFeeExactlyAndOnlyOnce() (gas: 669534)\n[PASS] test_twoPlayersCarryUnfilledShareIntoNextAuction() (gas: 2463366)\n[PASS] test_vetoOwnerOnlyBeforeThemeDayReturnsOwnNetBidNotCarry() (gas: 1508086)\n[PASS] test_vetoRejectsUnsettledEmptyAndThemeDayBoundary() (gas: 727152)\n[PASS] test_zeroFeeVetoRefundsFullBidAndBlockedWinnerGetsCredit() (gas: 738849)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 426.86ms (476.66ms CPU time)\n\nRan 5 test suites in 427.52ms (1.49s CPU time): 125 tests passed, 0 failed, 0 skipped (125 total tests)\n","passed":true},{"durationMs":65,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"DerbyAuction.acceptOwnership()\",\"DerbyAuction.bid(uint256,uint256,(string,uint8,uint8,uint8,string,string))\",\"DerbyAuction.payBonus(uint256)\",\"DerbyAuction.reclaim(uint256)\",\"DerbyAuction.setBuildFee(uint256)\",\"DerbyAuction.setStudio(address)\",\"DerbyAuction.settle(uint256)\",\"DerbyAuction.transferOwnership(address)\",\"DerbyAuction.veto(uint256)\",\"DerbyAuction.withdrawRefund()\",\"SwarmDerby.acceptOwnership()\",\"SwarmDerby.activateHouseKey()\",\"SwarmDerby.buyPacks(uint8,uint256)\",\"SwarmDerby.buyTurns(uint8,uint256)\",\"SwarmDerby.cancelHouseKey()\",\"SwarmDerby.draw(uint256,bytes)\",\"SwarmDerby.expire(uint256)\",\"SwarmDerby.finalize(uint256,bytes32)\",\"SwarmDerby.leaveSession()\",\"SwarmDerby.proposeHouseKey(bytes)\",\"SwarmDerby.revokeHouseKey()\",\"SwarmDerby.setPrices(uint256,uint256)\",\"SwarmDerby.setSession(address,bytes)\",\"SwarmDerby.settleNextDay(uint8)\",\"SwarmDerby.swing(uint8,uint8,uint8,bytes32)\",\"SwarmDerby.transferOwnership(address)\",\"SwarmDerby.withdrawOps(address,uint256)\"],\"files\":{\".gitignore\":5,\"ADAPTATION.md\":136,\"DEPLOY.md\":311,\"HANDOFF.md\":148,\"LICENSE\":21,\"README.md\":15,\"e2e/Mocks.sol\":27,\"e2e/README.md\":35,\"e2e/board.py\":50,\"e2e/leagues.py\":48,\"e2e/play.py\":63,\"e2e/recover.py\":26,\"e2e/recover_unmined.py\":28,\"e2e/refund.py\":26,\"e2e/settle.py\":59,\"e2e/setup.py\":33,\"foundry.toml\":9,\"house/README.md\":64,\"house/house.mjs\":217,\"house/keygen.mjs\":15,\"house/package-lock.json\":122,\"house/package.json\":9,\"imd-check.mjs\":40,\"specs/README.md\":70,\"specs/WP1-theme-packs.md\":142,\"specs/WP2-daily-conditions.md\":17,\"specs/WP3-auction-contract.md\":134,\"specs/WP4-auction-ui.md\":89,\"specs/WP5-theme-build-job.md\":110,\"specs/WP6-operator-runbook.md\":56,\"src/DerbyAuction.sol\":378,\"src/DerbyOdds.sol\":69,\"src/HouseDraw.sol\":45,\"src/SwarmDerby.sol\":711,\"test/DerbyAuction.t.sol\":1096,\"test/HouseDraw.t.sol\":71,\"test/HouseKey.sol\":84,\"test/SwarmDerby.t.sol\":1015,\"test/SwarmDerbyDraw.t.sol\":296,\"test/SwarmDerbyLaunch.t.sol\":116,\"test/fixtures/house-test-key.mjs\":65,\"web/derby-odds.js\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":3514,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/DerbyAuction.sol:338: DerbyAuction._bps(uint256,uint256) (src/DerbyAuction.sol#338-340) uses a weak PRNG: \"amount / 10_000 * bps + (amount % 10_000) * bps / 10_000 (src/DerbyAuction.sol#339)\"\n[high/medium] reentrancy-balance at src/DerbyAuction.sol:349: Reentrancy in DerbyAuction._pull(address,uint256) (src/DerbyAuction.sol#349-357):\n[high/high] uninitialized-state at src/SwarmDerby.sol:460: SwarmDerby._board (src/SwarmDerby.sol#130) is never initialized. It is used in:\n[high/high] uninitialized-state at src/SwarmDerby.sol:528: SwarmDerby._days (src/SwarmDerby.sol#139) is never initialized. It is used in:\n[medium/medium] divide-before-multiply at src/SwarmDerby.sol:547: SwarmDerby.settleNextDay(uint8) (src/SwarmDerby.sol#547-585) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/SwarmDerby.sol:528: SwarmDerby.nextSettlement(uint8) (src/SwarmDerby.sol#528-541) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/DerbyAuction.sol:338: DerbyAuction._bps(uint256,uint256) (src/DerbyAuction.sol#338-340) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/SwarmDerby.sol:547: SwarmDerby.settleNextDay(uint8) (src/SwarmDerby.sol#547-585) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/DerbyAuction.sol:370: DerbyAuction._accepted(bytes) (src/DerbyAuction.sol#370-377) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/DerbyAuction.sol:370: DerbyAuction._accepted(bytes) (src/DerbyAuction.sol#370-377) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/DerbyAuction.sol:305: DerbyAuction._end(uint256) (src/DerbyAuction.sol#305-309) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/DerbyAuction.sol:363: DerbyAuction._trySend(address,uint256) (src/DerbyAuction.sol#363-368) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/SwarmDerby.sol:629: SwarmDerby.activateHouseKey() (src/SwarmDerby.sol#629-636) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/DerbyAuction.sol:222: Reentrancy in DerbyAuction.payBonus(uint256) (src/DerbyAuction.sol#222-256):\n[medium/medium] reentrancy-no-eth at src/SwarmDerby.sol:547: Reentrancy in SwarmDerby.settleNextDay(uint8) (src/SwarmDerby.sol#547-585):\n[medium/medium] uninitialized-local at src/SwarmDerby.sol:561: SwarmDerby.settleNextDay(uint8).paid (src/SwarmDerby.sol#561) is a local variable never initialized\n[medium/medium] uninitialized-local at src/DerbyAuction.sol:195: DerbyAuction.settle(uint256).fee (src/DerbyAuction.sol#195) is a local variable never initialized\n[medium/medium] uninitialized-local at src/DerbyAuction.sol:234: DerbyAuction.payBonus(uint256).paid (src/DerbyAuction.sol#234) is a local variable never initialized\n[medium/medium] uninitialized-local at src/DerbyAuction.sol:233: DerbyAuction.payBonus(uint256).tip (src/DerbyAuction.sol#233) is a local variable never initialized\n[medium/medium] uninitialized-local at src/SwarmDerby.sol:560: SwarmDerby.settleNextDay(uint8).tip (src/SwarmDerby.sol#560) is a local variable never initialized\n[medium/medium] unused-return at src/DerbyAuction.sol:222: DerbyAuction.payBonus(uint256) (src/DerbyAuction.sol#222-256) ignores return value by (board,None) = derby.board(0,day) (src/DerbyAuction.sol#229)\n[low/medium] missing-zero-check at src/SwarmDerby.sol:662: SwarmDerby.transferOwnership(address).to (src/SwarmDerby.sol#662) lacks a zero-check on :\n[low/medium] missing-zero-check at src/DerbyAuction.sol:293: DerbyAuction.transferOwnership(address).to (src/DerbyAuction.sol#293) lacks a zero-check on :\n[low/medium] reentrancy-events at src/SwarmDerby.sol:547: Reentrancy in SwarmDerby.settleNextDay(uint8) (src/SwarmDerby.sol#547-585):\n[low/medium] reentrancy-events at src/SwarmDerby.sol:253: Reentrancy in SwarmDerby._buy(uint8,uint256,uint256) (src/SwarmDerby.sol#253-272):\n[low/medium] reentrancy-events at src/SwarmDerby.sol:396: Reentrancy in SwarmDerby.finalize(uint256,bytes32) (src/SwarmDerby.sol#396-421):\n[low/medium] timestamp at src/DerbyAuction.sol:305: DerbyAuction._end(uint256) (src/DerbyAuction.sol#305-309) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmDerby.sol:379: SwarmDerby.draw(uint256,bytes) (src/SwarmDerby.sol#379-388) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmDerby.sol:518: SwarmDerby.dayClosed(uint8,uint256) (src/SwarmDerby.sol#518-520) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:260: DerbyAuction.reclaim(uint256) (src/DerbyAuction.sol#260-270) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:363: DerbyAuction._trySend(address,uint256) (src/DerbyAuction.sol#363-368) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmDerby.sol:622: SwarmDerby.cancelHouseKey() (src/SwarmDerby.sol#622-627) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:157: DerbyAuction.minNextBid(uint256) (src/DerbyAuction.sol#157-163) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:190: DerbyAuction.settle(uint256) (src/DerbyAuction.sol#190-210) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:370: DerbyAuction._accepted(bytes) (src/DerbyAuction.sol#370-377) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:165: DerbyAuction.bid(uint256,uint256,DerbyAuction.Answers) (src/DerbyAuction.sol#165-188) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:212: DerbyAuction.veto(uint256) (src/DerbyAuction.sol#212-220) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmDerby.sol:597: SwarmDerby._markDay(uint8,uint256) (src/SwarmDerby.sol#597-600) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmDerby.sol:629: SwarmDerby.activateHouseKey() (src/SwarmDerby.sol#629-636) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:135: DerbyAuction.openDay() (src/DerbyAuction.sol#135-141) uses timestamp for comparisons\n[low/medium] timestamp at src/DerbyAuction.sol:349: DerbyAuction._pull(address,uint256) (src/DerbyAuction.sol#349-357) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmDerby.sol:396: SwarmDerby.finalize(uint256,bytes32) (src/SwarmDerby.sol#396-421) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmDerby.sol:425: SwarmDerby.expire(uint256) (src/SwarmDerby.sol#425-441) uses timestamp for comparisons","passed":true},{"durationMs":406,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/HouseDraw.sol:21: `abi.encodePacked()` Hash Collision\n[high] reentrancy-state-change at src/DerbyAuction.sol:225: Reentrancy: State change after external call (2 places)\n[low] centralization-risk at src/DerbyAuction.sol:212: Centralization Risk (10 places)\n[low] costly-loop at src/DerbyAuction.sol:248: Costly operations inside loop (3 places)\n[low] division-before-multiplication at src/DerbyAuction.sol:339: Incorrect Order of Division and Multiplication\n[low] ecrecover at src/SwarmDerby.sol:689: `ecrecover` Signature Malleability\n[low] internal-function-used-once at src/DerbyOdds.sol:32: Internal Function Used Only Once (2 places)\n[low] large-numeric-literal at src/DerbyAuction.sol:160: Large Numeric Literal (15 places)\n[low] literal-instead-of-constant at src/DerbyAuction.sol:160: Literal Instead of Constant (48 places)\n[low] missing-inheritance at src/SwarmDerby.sol:43: Missing Inheritance\n[low] non-reentrant-not-first at src/DerbyAuction.sol:212: `nonReentrant` is Not the First Modifier\n[low] require-revert-in-loop at src/DerbyAuction.sol:331: Loop Contains `require`/`revert`\n[low] state-change-without-event at src/SwarmDerby.sol:606: State Change Without Event (2 places)\n[low] state-no-address-check at src/DerbyAuction.sol:294: Address State Variable Set Without Checks (2 places)\n[low] uninitialized-local-variable at src/DerbyAuction.sol:331: Uninitialized Local Variable (2 places)\n[low] unsafe-erc20-operation at src/DerbyAuction.sol:353: Unsafe ERC20 Operation (4 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"630ea36bd9340b886431026d63f48d7932423f6bcb9161b8c26facb29f5ed00f","verifiedTreeHash":"72d676d78e8819af02e87668ec649e0f51011b4e","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":34965,"exitCode":0,"name":"build","output":"Compiling 29 files with Solc 0.8.26\nSolc 0.8.26 finished in 34.82s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:21:5:\n   |\n21 |     function test_validSignatures() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:27:5:\n   |\n27 |     function test_signatureIsDeterministic() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:31:5:\n   |\n31 |     function test_wrongMessage() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:35:5:\n   |\n35 |     function test_flippedBit() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:42:5:\n   |\n42 |     function test_signaturePlusModulusRejected() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/HouseDraw.t.sol:54:5:\n   |\n54 |     function test_wrongLengths() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/SwarmDerbyDraw.t.sol:35:5:\n   |\n35 |     function _sign(uint256 id) internal returns (bytes memory) {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:535:48\n    │\n535 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/HouseDraw.sol:21:13\n   │\n21 │             abi.encodePacked(KEY_BYTES, uint256(3), KEY_BYTES, sig, hex\"010001\", modulus)\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:535:55\n    │\n535 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/DerbyOdds.sol:67:16\n   │\n67 │         feet = uint16(lo + (d % span));\n   │                ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/DerbyAuction.sol:301:9\n    │\n301 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `pendingOwner` is changed without an event but is used for access control\n    ╭▸ src/DerbyAuction.sol:302:9\n    │\n302 │         pendingOwner = address(0);\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-arithmetic]: `singlePrice` is changed without an event but is used in arithmetic\n    ╭▸ src/SwarmDerby.sol:608:9\n    │\n608 │         singlePrice = single;\n    │         ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-arithmetic]: `packPrice` is changed without an event but is used in arithmetic\n    ╭▸ src/SwarmDerby.sol:609:9\n    │\n609 │         packPrice = pack;\n    │         ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/SwarmDerby.sol:671:9\n    │\n671 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `pendingOwner` is changed without an event but is used for access control\n    ╭▸ src/SwarmDerby.sol:672:9\n    │\n672 │         pendingOwner = address(0);\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:137:13\n    │\n137 │         if (block.timestamp < CLOSE_OFFSET) return 1;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:139:13\n    │\n139 │         if (day > 2 && block.timestamp < _end(day - 1)) return day - 1;\n    │             ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:139:24\n    │\n139 │         if (day > 2 && block.timestamp < _end(day - 1)) return day - 1;\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_entered` is updated\n    ╭▸ src/DerbyAuction.sol:353:13\n    │\n353 │             address(imd).call(abi.encodeCall(IERC20.transferFrom, (from, address(this), amount)));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_entered` is updated\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:168:29\n    │\n168 │         if (sale.settled || block.timestamp < (day - 2) * 1 days + CLOSE_OFFSET || block.timestamp >= end) {\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:168:84\n    │\n168 │         if (sale.settled || block.timestamp < (day - 2) * 1 days + CLOSE_OFFSET || block.timestamp >= end) {\n    │                                                                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:175:13\n    │\n175 │         if (end - block.timestamp < ANTI_SNIPE) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:178:17\n    │\n178 │             if (end > latest) end = latest;\n    │                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:345:13\n    │\n345 │             emit RefundCredited(bidder, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:187:9\n    │\n187 │         emit Bid(day, msg.sender, amount, end, a.creature, a.vibe, a.stadium, a.weather, a.title, a.shoutout);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:209:47\n    │\n209 │         emit Settled(day, a.leader, a.amount, fee, a.bonus);\n    │                                               ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:193:13\n    │\n193 │         if (block.timestamp < _end(day)) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:201:17\n    │\n201 │             if (block.timestamp < day * 1 days) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:209:9\n    │\n209 │         emit Settled(day, a.leader, a.amount, fee, a.bonus);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/DerbyAuction.sol:212:51\n    │\n212 │     function veto(uint256 day) external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:215:13\n    │\n215 │         if (block.timestamp >= day * 1 days) revert BidClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:219:9\n    │\n219 │         emit Vetoed(day, a.leader, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `carry` is updated\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:245:35\n    │\n245 │         uint256 carried = bonus - paid;\n    │                                   ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/DerbyAuction.sol:247:27\n    │\n247 │         _send(msg.sender, tip);\n    │                           ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/DerbyAuction.sol:366:40\n    │\n366 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:255:9\n    │\n255 │         emit BonusPaid(day, winners, amounts, msg.sender, tip, carried);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/DerbyAuction.sol:229:37\n    │\n229 │         (address[] memory board,) = derby.board(0, day);\n    │                                     ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/DerbyAuction.sol:265:13\n    │\n265 │         if (block.timestamp <= from + RECLAIM_AFTER) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:269:9\n    │\n269 │         emit Reclaimed(day, a.leader, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/DerbyAuction.sol:277:9\n    │\n277 │         emit RefundWithdrawn(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:271:9\n    │\n271 │         emit TurnsBought(player, league, count, cost, burned);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/DerbyAuction.sol:293:32\n    │\n293 │     function transferOwnership(address to) external onlyOwner {\n    │                                ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:355:91\n    │\n355 │             swings[swingId] = Swing(player, league, 0, velo, Status.Final, 0, bytes32(0), uint32(day), bytes32(0));\n    │                                                                                           ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:364:24\n    │\n364 │         uint64 nowTs = uint64(block.timestamp);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmDerby.sol:367:97\n    │\n367 │         swings[swingId] = Swing(player, league, quality, velo, Status.Committed, nowTs, commit, uint32(day), bytes32(0));\n    │                                                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:382:13\n    │\n382 │         if (block.timestamp > uint256(s.committedAt) + DRAW_WINDOW) revert DrawClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:387:9\n    │\n387 │         emit SwingDrawn(swingId, h);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `vault` is updated\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:402:13\n    │\n402 │         if (block.timestamp > uint256(s.committedAt) + DRAW_WINDOW + REVEAL_WINDOW) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:418:13\n    │\n418 │             emit GrandSlam(swingId, s.player, s.league, feet, payout);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:420:9\n    │\n420 │         emit SwingResolved(swingId, s.player, tier, feet);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:429:17\n    │\n429 │             if (block.timestamp <= committedAt + DRAW_WINDOW) revert NotExpired();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:435:17\n    │\n435 │             if (block.timestamp <= committedAt + DRAW_WINDOW + REVEAL_WINDOW) revert NotExpired();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:519:38\n    │\n519 │         return day < currentDay() && block.timestamp > uint256(dayLastCommit[league][day]) + DRAW_WINDOW + REVEAL_WINDOW;\n    │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:540:51\n    │\n540 │         if (_board[league][day].length > 0) tip = (amount * PAYOUT_BPS / 10_000) * SETTLE_TIP_BPS / 10_000;\n    │                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[reentrancy-no-eth]: external call can be reentered before `rollover` is updated\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:564:19\n    │\n564 │             tip = (distributable * SETTLE_TIP_BPS) / 10_000;\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmDerby.sol:574:37\n    │\n574 │         rollover[league] = amount - paid;\n    │                                     ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmDerby.sol:576:27\n    │\n576 │         _send(msg.sender, tip);\n    │                           ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/SwarmDerby.sol:708:40\n    │\n708 │         (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:584:9\n    │\n584 │         emit DaySettled(league, day, winners, amounts, msg.sender, tip, rollover[league]);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/DerbyAuction.sol:333:91\n    │\n333 │             if (c < 0x20 || c > 0x7e || c == 0x3c || c == 0x3e || c == 0x22 || c == 0x5c) revert BadAnswers();\n    │                                                                                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/DerbyAuction.sol:339:16\n    │\n339 │         return amount / 10_000 * bps + (amount % 10_000) * bps / 10_000;\n    │                ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:630:39\n    │\n630 │         if (pendingHouseKeyAt == 0 || block.timestamp < pendingHouseKeyAt) revert KeyNotReady();\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmDerby.sol:631:13\n    │\n631 │         if (block.timestamp > pendingHouseKeyAt + KEY_WINDOW) revert KeyExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmDerby.sol:662:32\n    │\n662 │     function transferOwnership(address to) external onlyOwner {\n    │                                ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/SwarmDerby.t.sol:145:18\n    │\n145 │         vm.warp((block.timestamp / 1 days + 1) * 1 days + derby.DRAW_WINDOW() + derby.REVEAL_WINDOW() + 1);\n    │         ─────────━━━━━━━━━━━━━━━────────────────────────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n    ╭▸ test/SwarmDerbyDraw.t.sol:155:21\n    │\n155 │             vm.roll(block.number + i * 7);\n    │             ────────━━━━━━━━━━━━───────── `vm.roll` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockNumber()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/SwarmDerbyDraw.t.sol:158:21\n    │\n158 │             vm.warp(block.timestamp + i);\n    │             ────────━━━━━━━━━━━━━━━───── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":436,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/SwarmDerbyLaunch.t.sol:SwarmDerbyLaunchTest\n[PASS] test_constructorDoesNotCallToken() (gas: 4405006)\n[PASS] test_constructorIsNonpayable() (gas: 399086)\n[PASS] test_constructorRejectsMissingKeyWord() (gas: 562840)\n[PASS] test_factoryDeploysExactLaunchConfigurationWithoutToken() (gas: 7180274)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 166.97ms (7.36ms CPU time)\n\nRan 16 tests for test/SwarmDerbyDraw.t.sol:SwarmDerbyDrawTest\n[PASS] test_badKeysRejected() (gas: 865144)\n[PASS] test_blockDataCannotSteerTheRoll() (gas: 1712055)\n[PASS] test_copiedCommitDoesNotBlockItsOwner() (gas: 2289808)\n[PASS] test_drawForAnotherSwingRejected() (gas: 1237525)\n[PASS] test_drawFromAnotherDeploymentRejected() (gas: 5684347)\n[PASS] test_drawOnlyOnceAndNotForAWhiff() (gas: 1888488)\n[PASS] test_drawWindowCloses() (gas: 967946)\n[PASS] test_drawnButUnrevealedIsAFoulNotARefund() (gas: 1104268)\n[PASS] test_houseKeyChangeWaitsForTheDelay() (gas: 2496243)\n[PASS] test_houseKeyProposalCanBeCancelledAndLapses() (gas: 804095)\n[PASS] test_noDrawRefundsAgentTurn() (gas: 246217)\n[PASS] test_noDrawRefundsTurnAndCapOnce() (gas: 404043)\n[PASS] test_realDrawFullSwing() (gas: 1134066)\n[PASS] test_reusedCommitRejected() (gas: 269915)\n[PASS] test_revokeStopsDrawsAtOnceAndSwingsRefund() (gas: 1564364)\n[PASS] test_tamperedDrawRejected() (gas: 1050090)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 170.89ms (108.43ms CPU time)\n\nRan 59 tests for test/SwarmDerby.t.sol:SwarmDerbyTest\n[PASS] testFuzz_boardsAreTopTen(uint256) (runs: 256, μ: 5062542, ~: 5065586)\n[PASS] testFuzz_settlementConserves(uint256) (runs: 256, μ: 5456109, ~: 5478162)\n[PASS] test_agentLeagueHasNoCap() (gas: 2762548)\n[PASS] test_arcadeCapIsTwentyPerDay() (gas: 2580839)\n[PASS] test_arcadeKeepsLongestAgentKeepsTotal() (gas: 299154)\n[PASS] test_badLeagueRejected() (gas: 32969)\n[PASS] test_boardResetsEachDay() (gas: 216895)\n[PASS] test_buyPackSplitsPerLeague() (gas: 530237)\n[PASS] test_capCountsSessionSwingsForThePlayer() (gas: 2324997)\n[PASS] test_commitBoundToPlayer() (gas: 645220)\n[PASS] test_constructorRejectsZeroAddressesAndFreeTurns() (gas: 1523754)\n[PASS] test_contactNeedsCommit() (gas: 339271)\n[PASS] test_eachDaySettlesOnceInOrder() (gas: 1399451)\n[PASS] test_emptyDayRollsOverWithoutTip() (gas: 1040549)\n[PASS] test_expireUnrevealed() (gas: 675309)\n[PASS] test_finalizeNeedsTheDraw() (gas: 493821)\n[PASS] test_finalizeUpdatesArcadeBoard() (gas: 771376)\n[PASS] test_fullSwingMatchesOdds() (gas: 574094)\n[PASS] test_lateFinalizeScoresOnCommitDay() (gas: 771591)\n[PASS] test_lateRevealIsFoul() (gas: 585987)\n[PASS] test_leagueTurnsAreSeparate() (gas: 300675)\n[PASS] test_leaveSessionFreesTheKey() (gas: 207085)\n[PASS] test_nextSettlementBeforeAnything() (gas: 12117)\n[PASS] test_oddTransferAnswerKeepsSlamPrize() (gas: 9699835)\n[PASS] test_oddsMonotoneInQuality() (gas: 317019)\n[PASS] test_ownerIsConstructorArg() (gas: 4110418)\n[PASS] test_ownerOnlyReachesOps() (gas: 425949)\n[PASS] test_ownershipIsTwoStep() (gas: 171361)\n[PASS] test_ownershipMoveCanBeCancelled() (gas: 114898)\n[PASS] test_parityWithBrowser() (gas: 63317)\n[PASS] test_pendingKeyDoesNotBlockPurchases() (gas: 405469)\n[PASS] test_priceFloor() (gas: 100721)\n[PASS] test_purchasesResumeOnlyAfterKeyActivation() (gas: 877747)\n[PASS] test_qualityAndVeloBounded() (gas: 322014)\n[PASS] test_revealAtWindowEdgeStillCounts() (gas: 759879)\n[PASS] test_revokedKeyRejectsPurchasesWithoutMovingFunds() (gas: 281157)\n[PASS] test_sessionBuysForThePlayer() (gas: 489658)\n[PASS] test_sessionCannotBeClaimedTwice() (gas: 180232)\n[PASS] test_sessionCannotBuyWhileKeyRevoked() (gas: 381591)\n[PASS] test_sessionChainsRejected() (gas: 379161)\n[PASS] test_sessionConsentIsSingleUse() (gas: 315948)\n[PASS] test_sessionNeedsTheKeysConsent() (gas: 163195)\n[PASS] test_sessionRevokeAndRotate() (gas: 302978)\n[PASS] test_sessionSwingsForPlayer() (gas: 722762)\n[PASS] test_settleAgentLeague() (gas: 609646)\n[PASS] test_settlePaysOnlyThatDaysPot() (gas: 1140885)\n[PASS] test_settlePaysTheDaysTopThree() (gas: 1207816)\n[PASS] test_settleWaitsForTheDayToEnd() (gas: 937011)\n[PASS] test_settleWaitsForTheLastReveal() (gas: 732379)\n[PASS] test_singleTurnPrice() (gas: 291032)\n[PASS] test_slamPaysTenPercentOfItsLeagueVault() (gas: 9953183)\n[PASS] test_swingStoresVelo() (gas: 537297)\n[PASS] test_tokenWithoutCodeRefusesPurchases() (gas: 4480497)\n[PASS] test_underPowerLineNoBombOrSlam() (gas: 29184953)\n[PASS] test_unpayableSlamKeepsPrizeAndHomer() (gas: 9731629)\n[PASS] test_unpayableWinnerRollsOver() (gas: 977119)\n[PASS] test_whiffCostsTurnNoRoll() (gas: 414432)\n[PASS] test_wrongSaltRejected() (gas: 555744)\n[PASS] test_zeroCountPurchaseReverts() (gas: 77857)\nSuite result: ok. 59 passed; 0 failed; 0 skipped; finished in 198.13ms (464.55ms CPU time)\n\nRan 6 tests for test/HouseDraw.t.sol:HouseDrawTest\n[PASS] test_flippedBit() (gas: 735666)\n[PASS] test_signatureIsDeterministic() (gas: 1402158)\n[PASS] test_signaturePlusModulusRejected() (gas: 2585886)\n[PASS] test_validSignatures() (gas: 1469431)\n[PASS] test_wrongLengths() (gas: 778356)\n[PASS] test_wrongMessage() (gas: 735624)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 347.01ms (54.84ms CPU time)\n\nRan 40 tests for test/DerbyAuction.t.sol:DerbyAuctionTest\n[PASS] testFuzz_conservationAcrossAuctionSequences(uint256) (runs: 256, μ: 13470788, ~: 13471753)\n[PASS] test_adminPermissionsFeeCapAndTwoStepOwnership() (gas: 537169)\n[PASS] test_agentScoresAndOtherDaysNeverAffectArcadeBonus() (gas: 3326203)\n[PASS] test_answerBoundaryValuesStoredAndBidEmitted() (gas: 660323)\n[PASS] test_answerLengthsAndEnums() (gas: 533362)\n[PASS] test_antiSnipeExtendsRepeatedlyAndKeepsOtherDaysIndependent() (gas: 1985950)\n[PASS] test_antiSnipeStopsAtOneHourSoVetoStaysOpen() (gas: 3782751)\n[PASS] test_bidMinimumAndIncrementRoundUp() (gas: 768959)\n[PASS] test_blockedReclaimIsCreditedAndCarryIsReusable() (gas: 1940239)\n[PASS] test_constructorRejectsZeroAddressesAndExcessFee() (gas: 11242)\n[PASS] test_constructorStoresArgumentsWithoutAnyDependencyCalls() (gas: 394597)\n[PASS] test_emptyArcadeWithAgentPlayersCarriesEverythingWithoutTip() (gas: 1857602)\n[PASS] test_emptyAuctionSettlesWithoutTakingCarry() (gas: 824063)\n[PASS] test_everyForbiddenByteRejectedInEveryString() (gas: 30597411)\n[PASS] test_failedOrShortTokenPullRollsBackBidAndAnswers() (gas: 1642645)\n[PASS] test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers() (gas: 2624649)\n[PASS] test_failedRefundAccumulatesAndWithdrawsOnlyOnce() (gas: 1324007)\n[PASS] test_failedStudioPaymentIsCreditedAndSettlementGoesOn() (gas: 846918)\n[PASS] test_failedTipRevertsAndAnotherCallerCanPay() (gas: 1589001)\n[PASS] test_falseAndMalformedRefundsDoNotBlockBids() (gas: 1139380)\n[PASS] test_fullNewBidMustBeFundedBeforeSelfRefund() (gas: 559374)\n[PASS] test_lateSettleKeepsTheFullReclaimGraceForTheBoard() (gas: 2767420)\n[PASS] test_maximumBidSettlesAndPaysWithoutIntermediateOverflow() (gas: 2615998)\n[PASS] test_noReturnTokenBidsRefundsFeesWithdrawalsAndBonus() (gas: 2123010)\n[PASS] test_onePlayerCarriesUnfilledSharesIntoNextAuction() (gas: 1888408)\n[PASS] test_openDayAndBidTimeBoundaries() (gas: 664919)\n[PASS] test_openDayNamesTheExtendedDayUntilItCloses() (gas: 725536)\n[PASS] test_outbidAndSelfRaiseRefundPreviousBid() (gas: 819741)\n[PASS] test_realSwingsPayOnlyAfterArcadeDayClosedAndOnlyTopThree() (gas: 3404861)\n[PASS] test_reclaimGraceBoundaryReturnsOwnNetBidNotCarryToWinner() (gas: 1552630)\n[PASS] test_reclaimRejectsUnsettledEmptyAndAlreadyPaidAuctions() (gas: 799007)\n[PASS] test_reentrantBonusAndReclaimCannotPayTwice() (gas: 2243929)\n[PASS] test_reentrantTokenCannotBidOrWithdrawDuringTransfers() (gas: 1346649)\n[PASS] test_settleOnOrAfterThemeDayKeepsCarryForLaterBoards() (gas: 1516271)\n[PASS] test_settleOneIMDFeeAndSettingsApplyOnlyAtSettlement() (gas: 689653)\n[PASS] test_settleZeroFeeExactlyAndOnlyOnce() (gas: 669534)\n[PASS] test_twoPlayersCarryUnfilledShareIntoNextAuction() (gas: 2463366)\n[PASS] test_vetoOwnerOnlyBeforeThemeDayReturnsOwnNetBidNotCarry() (gas: 1508086)\n[PASS] test_vetoRejectsUnsettledEmptyAndThemeDayBoundary() (gas: 727152)\n[PASS] test_zeroFeeVetoRefundsFullBidAndBlockedWinnerGetsCredit() (gas: 738849)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 347.12ms (381.78ms CPU time)\n\nRan 5 test suites in 347.96ms (1.23s CPU time): 125 tests passed, 0 failed, 0 skipped (125 total tests)\n","passed":true},{"durationMs":62,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"DerbyAuction.acceptOwnership()\",\"DerbyAuction.bid(uint256,uint256,(string,uint8,uint8,uint8,string,string))\",\"DerbyAuction.payBonus(uint256)\",\"DerbyAuction.reclaim(uint256)\",\"DerbyAuction.setBuildFee(uint256)\",\"DerbyAuction.setStudio(address)\",\"DerbyAuction.settle(uint256)\",\"DerbyAuction.transferOwnership(address)\",\"DerbyAuction.veto(uint256)\",\"DerbyAuction.withdrawRefund()\",\"SwarmDerby.acceptOwnership()\",\"SwarmDerby.activateHouseKey()\",\"SwarmDerby.buyPacks(uint8,uint256)\",\"SwarmDerby.buyTurns(uint8,uint256)\",\"SwarmDerby.cancelHouseKey()\",\"SwarmDerby.draw(uint256,bytes)\",\"SwarmDerby.expire(uint256)\",\"SwarmDerby.finalize(uint256,bytes32)\",\"SwarmDerby.leaveSession()\",\"SwarmDerby.proposeHouseKey(bytes)\",\"SwarmDerby.revokeHouseKey()\",\"SwarmDerby.setPrices(uint256,uint256)\",\"SwarmDerby.setSession(address,bytes)\",\"SwarmDerby.settleNextDay(uint8)\",\"SwarmDerby.swing(uint8,uint8,uint8,bytes32)\",\"SwarmDerby.transferOwnership(address)\",\"SwarmDerby.withdrawOps(address,uint256)\"],\"files\":{\".gitignore\":5,\"ADAPTATION.md\":136,\"DEPLOY.md\":311,\"HANDOFF.md\":148,\"LICENSE\":21,\"README.md\":15,\"e2e/Mocks.sol\":27,\"e2e/README.md\":35,\"e2e/board.py\":50,\"e2e/leagues.py\":48,\"e2e/play.py\":63,\"e2e/recover.py\":26,\"e2e/recover_unmined.py\":28,\"e2e/refund.py\":26,\"e2e/settle.py\":59,\"e2e/setup.py\":33,\"foundry.toml\":9,\"house/README.md\":64,\"house/house.mjs\":217,\"house/keygen.mjs\":15,\"house/package-lock.json\":122,\"house/package.json\":9,\"imd-check.mjs\":40,\"launch.json\":23,\"specs/README.md\":70,\"specs/WP1-theme-packs.md\":142,\"specs/WP2-daily-conditions.md\":17,\"specs/WP3-auction-contract.md\":134,\"specs/WP4-auction-ui.md\":89,\"specs/WP5-theme-build-job.md\":110,\"specs/WP6-operator-runbook.md\":56,\"src/DerbyAuction.sol\":378,\"src/DerbyOdds.sol\":69,\"src/HouseDraw.sol\":45,\"src/SwarmDerby.sol\":711,\"test/DerbyAuction.t.sol\":1096,\"test/HouseDraw.t.sol\":71,\"test/HouseKey.sol\":84,\"test/SwarmDerby.t.sol\":1015,\"test/SwarmDerbyDraw.t.sol\":296,\"test/SwarmDerbyLaunch.t.sol\":116,\"test/fixtures/house-test-key.mjs\":65,\"web/derby-odds.js\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8488fec0d048399d7ebea60af5cf4bd8b800825b9bd0db6fb2cbcae1b78d5845","verifiedTreeHash":"fce13987b9076d4a09efd3695576f9583ef2c70f","verifierVersion":"0.1.0+ad90ce4c"}]}