{"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":"3bfde4f8-74f7-4afd-b9c0-a0bdba9bac42","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"50c6de42d0c8b6f6f0831c327c01f9f3f74cec4ba59796ae4dc65b253c5df809","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":"7f0656c41b54ef80425768d01eaa5c2f04807b8720455f598a944468a4f9d69e","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":"9516a678caa2864788929a168bce8fd28c28e29fec279661091e9bf5ee481756","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":"72c04967c3ba45bc5f423664ab1c6df57440b1a6ac16c4663fe2ce69314facf3","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":"a22f8937157766b5f9bdc45b437861136a12a89dfe52a69ff9c83dd1babd36de","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":"5b2c3532c08e1f4ee3da79b876d878b9d9aaeea37ae5528a9fd487d8e3d02b76","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":"09fb38863fcf6149d4127fffe9e5be32a5447734be8e0678e60b0e690d92f416","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":"de73315a1acd3d2179d2bcb09a26c851955b0e274b58424f086d15fc065e0f8e","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"ae71e6d38bcdb7de2c18221c15702ccc37dc3cb7a2fa94df1775c461ab78d7b3","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 only DerbyAuction (src/DerbyAuction.sol) to Robinhood Chain. Do not deploy or change SwarmDerby or DerbyOdds, and do not create a token, distributor or pool. Constructor arguments in order: owner_ = $owner; imd_ = 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127; derby_ = 0xBa58BC6b5aCf8043DAEa2Bf1BF6C1c09cF84b03C; studio_ = $owner; buildFee_ = 0. DerbyAuction passed IMD audit job 928b670b-477f-4132-875c-7c0b872ddfcd on commit f797a19 (0 critical, 0 high, 1 medium, 3 low); this commit fixes the medium and the three lows, with a test for each. Keep the code as it is unless the audit finds a critical or high issue. A site will call this exact ABI, so do not change function signatures, events, errors, constants or the payout math. 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. src/SwarmDerby.sol, src/DerbyOdds.sol and test/SwarmDerby.t.sol stay unchanged. Both test files select chain id 31337 because Foundry 1.8.5 and later intercept ArbSys on chain 4663 and bypass the etched MockArbSys. forge test must pass (94 tests). Accepted by the owner, do not change: anti-snipe extensions stop at 19:00 UTC (MAX_EXTENSION); settle reads the build fee and studio at settlement; after the grace period payBonus and reclaim can race.","parentJobId":null,"planHash":"8e710c91b43a8750803646d766ff6a5d1151715a69cbcaef06d4e8c5053b4f5d","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"3bfde4f8-74f7-4afd-b9c0-a0bdba9bac42","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1053-src-derbyauction-sol"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52276","feedbackHash":"cddda8965be23ab0a4f487bd4370aa97a0cc3540b1877f9e94ec1c463fb9e711","nodeKey":"adapt_contract_project","submissionHash":"50c6de42d0c8b6f6f0831c327c01f9f3f74cec4ba59796ae4dc65b253c5df809","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51481","feedbackHash":"e4836fba35e28e7801717f3f941a47b6d47f4a481397c65935ae8284708c7485","nodeKey":"audit_economics","submissionHash":"7f0656c41b54ef80425768d01eaa5c2f04807b8720455f598a944468a4f9d69e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51343","feedbackHash":"0d7adb89ac3c37b6825f7264ccccd6ffbf4f23206ad846eb757a9bee8dfd8af0","nodeKey":"audit_flow","submissionHash":"9516a678caa2864788929a168bce8fd28c28e29fec279661091e9bf5ee481756","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51025","feedbackHash":"ad952c3ac824a106d4d823bca37ac244528d399d3ceb084109a84d7c0fd2bf79","nodeKey":"audit_imported_code","submissionHash":"72c04967c3ba45bc5f423664ab1c6df57440b1a6ac16c4663fe2ce69314facf3","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51032","feedbackHash":"6128a230782b28f7712634c65351cdd299336bd661e8e83e115bd54ba0364ed5","nodeKey":"audit_judge","submissionHash":"a22f8937157766b5f9bdc45b437861136a12a89dfe52a69ff9c83dd1babd36de","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51022","feedbackHash":"9110183c8d4b4fe644e1fb14917b76e824dffba4d7d663ea1e19cf9a51753d86","nodeKey":"audit_math","submissionHash":"5b2c3532c08e1f4ee3da79b876d878b9d9aaeea37ae5528a9fd487d8e3d02b76","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51024","feedbackHash":"0ede11b08df34b3364bd717f5a48470271b7674cc8062c91a0f71e34092b1a8c","nodeKey":"audit_permissions","submissionHash":"09fb38863fcf6149d4127fffe9e5be32a5447734be8e0678e60b0e690d92f416","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51238","feedbackHash":"2af39768fb22e455494022a347c7c13cd0a8da3398ddbdd1f9016c1e147849c2","nodeKey":"manifest","submissionHash":"de73315a1acd3d2179d2bcb09a26c851955b0e274b58424f086d15fc065e0f8e","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52274","feedbackHash":"05eb24916d823f5265846bc229776307608fbd186199b713fd379f668fa0826c","nodeKey":"write_foundry_tests","submissionHash":"ae71e6d38bcdb7de2c18221c15702ccc37dc3cb7a2fa94df1775c461ab78d7b3","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"1b85cef6e5bcc4dd9890f5fbfa8328e0121731e7e2bc6ba36ba15fa2dd743408","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e6de8d4c6cf97551","findings":[{"citation":"resolved","description":"Trust-gap seam access x asymmetry, reported as a documented privileged-power risk, not as a permission bypass. settle() reads buildFee and studio at settlement time (line 197, 207) and veto() returns only bonus - carryIn[day] (line 217, 315-320), so the winner's refund after a veto is amount - fee. At launch studio_ = $owner and buildFee_ = 0, so the owner can, after bids were placed under fee 0, call setBuildFee(1e18), let settle run, then veto: the bidder recovers 1 IMD of a 2 IMD bid and the owner keeps 1 IMD although no theme is built. The amount is capped at MAX_BUILD_FEE (1 IMD per auction) and the task statement accepts 'settle reads the build fee and studio at settlement'; DEPLOY.md documents this as 'Owner trust'. No unprivileged amplifier exists: only the owner can set the fee or veto, and no outside party can widen the loss. Nothing to change in the code under the agreed design; the operational guard is to keep buildFee at 0 (the launch value) or to change it only between auction windows.","line":197,"path":"src/DerbyAuction.sol","reproduction":"Deploy DerbyAuction(owner, imd, derby, studio = owner, buildFee = 0). At start(DAY) alice bids 2e18 on DAY. owner calls setBuildFee(1e18). At end(DAY) anyone calls settle(DAY): imd.balanceOf(owner) == 1e18, bonus == 1e18. Before DAY*86400 owner calls veto(DAY): imd.balanceOf(alice) == 1e18, imd.balanceOf(owner) == 1e18, imd.balanceOf(sale) == 0. Expected under the agreed design: exactly this (documented). Verified with a scratch Foundry test (test_ownerFeeThenVetoKeepsFeeFromWinner) against the current tree.","severity":"info","snippet":"            fee = buildFee < a.amount ? buildFee : a.amount;","title":"Owner trust: a fee raised after bidding is kept by the studio (the owner at launch) even when the owner then vetoes the theme"}],"hash":"09fb38863fcf6149d4127fffe9e5be32a5447734be8e0678e60b0e690d92f416","nodeId":"4e312444-38ca-4e7d-b32b-62bc008b398d","outcome":"completed","summary":"The review is complete and written to `.imd-findings.json`. No file under `src/`, `test/` or configuration was changed, and the scratch directory is removed.\n\n**Outcome:** no critical, high, medium or low defect in the Access Control, Trust Gap or Asymmetry areas of DerbyAuction. One informational trust item is recorded.\n\n**What I checked**\n\n- **Permission map.** Owner holds veto, setStudio, setBuildFee and transferOwnership. Only the pending owner can accept. Everything else is permissionless by design. No storage variable has a weaker writer than its guarded sibling. Ownership comes from the explicit `owner_` argument, not the factory's `msg.sender`, and cannot be renounced.\n- **Asymmetry pairs.** Veto and reclaim mirror each other: both zero the bonus, return `bonus - carryIn` to the leader and restore the carried part to `carry`. Settle's winner and empty branches, and its before-midnight and after-midnight carry branches, were diffed. Every storage variable has matching writers and readers, and the conservation invariant holds through all of them.\n- **Trust seams.** The payBonus tip is bounded and only paid on a non-empty board. Permissionless settle timing cannot be blocked by an outsider, so the carry decision cannot be forced against the honest party. The owner's only in-flight lever is the fee and studio read at settlement, which the task accepts.\n- **Constructor and dependencies, verified live on chain 4663.** The token address holds code, reports symbol IMD with 18 decimals. The derby address holds code, its `imd()` returns that token, and `currentDay`, `dayClosed` and `board` answer with the shapes DerbyAuction calls.\n\n**The one recorded item (info).** With studio set to the owner and the fee cap at 1 IMD, the owner can raise the fee after bids were placed, let settlement run, then veto. The winner gets back their bid less 1 IMD while no theme is built. Reproduced with a scratch test against the current tree. It is owner-only with no unprivileged amplifier and is already documented as an owner trust assumption, so it needs no code change under the agreed design.\n\n**Coverage.** All 22 listed entry points have a row, plus rows for the constructor arguments and the balance-conservation invariant. All DerbyAuction rows are `holds` except setBuildFee, which points at the info item. The SwarmDerby rows are marked `holds` as out of the assigned area and unchanged, since DerbyAuction only reads its views.","treeHash":null,"usage":{"cachedInputTokens":1293126,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":29737,"runtime":"claude","turns":28,"wallClockMs":578075}},{"artifacts":[],"attempt":1,"bundleHash":"d04ac1104314f513a8b4b95dc05a02eb0f13f83114a259b99e826503a5c800fd","device":"41822d343cdb63ba","findings":[],"hash":"50c6de42d0c8b6f6f0831c327c01f9f3f74cec4ba59796ae4dc65b253c5df809","nodeId":"a2fcaa0f-849c-409e-8bf4-e68abeeb470f","outcome":"completed","summary":"Added [ADAPTATION.md](/home/imd4/.identitymd/work/3bfde4f8-74f7-4afd-b9c0-a0bdba9bac42/a2fcaa0f-849c-409e-8bf4-e68abeeb470f/ADAPTATION.md) with exact launch arguments, audit dispositions, and verification evidence. Contract code and ABI remain unchanged.\n\n- `forge build` passed.\n- All 94 project tests passed.\n- Five scratch checks passed, including empty-chain CREATE2 deployment.\n\nLive RPC checks returned HTTP 403; that limitation is documented. No live deployment was performed.","treeHash":"2a51a0cd20be74df0c0a45f04e0ab522f91082cc","usage":{"cachedInputTokens":1045753,"inputTokens":112732,"model":"gpt-6.1-sol","outputTokens":6197,"runtime":"codex","turns":4,"wallClockMs":159539}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c35be49d2f8f8def","findings":[{"citation":"resolved","description":"Boundary guide, sentinel return value. For block.timestamp < 64800 the view returns day 1, but _end() reverts BadDay() for any day < 2, so auction(1) and bid(1, ...) both revert and the 'open day' the view names cannot be read or bid on. Every other return value of openDay() names a day whose [start, end) window contains now (fuzz-checked over all timestamps from 64800 to 2^62). Unreachable on Robinhood Chain, whose timestamps are ~1.76e9; it only matters for a fresh local chain or a test that warps below 18:00 UTC of day 0. No funds are affected. Reported for completeness of the boundary pass; no change is recommended given the frozen ABI.","line":137,"path":"src/DerbyAuction.sol","reproduction":"Deploy DerbyAuction with any valid arguments. vm.warp(1000). openDay() == 1. auction(1) reverts BadDay(). bid(1, 2e18, validAnswers) reverts BadDay(). Expected: openDay() names a day that auction()/bid() accept (day 2, whose window opens at 64800), or the view reverts the same way. Actual: a day number no entry point accepts. Verified with test/scratch/MathProps.t.sol::test_openDayBeforeFirstCloseIsUnbiddable (passes on current code, i.e. documents the behaviour).","severity":"info","snippet":"        if (block.timestamp < CLOSE_OFFSET) return 1;","title":"openDay() returns day 1 before the chain's first 18:00 UTC, a day no function accepts"}],"hash":"5b2c3532c08e1f4ee3da79b876d878b9d9aaeea37ae5528a9fd487d8e3d02b76","nodeId":"5a789dc7-d263-4156-ae4e-17970fb5e9d1","outcome":"completed","summary":"The review is complete. The findings file is in place and the only other new files are under test/scratch, which the harness excludes and deletes.\n\n**Outcome: no critical, high, medium or low defects in the math of DerbyAuction.** One info-level boundary note is recorded. The code should ship as it is.\n\n**What I checked in the assigned area**\n\n- **Fixed-point math.** The basis-point helper is exactly floor(amount × bps / 10000) with no overflowing intermediate. The minimum next bid equals max(2 IMD, ceil(lead × 1.05)) for every lead whose product fits in 256 bits, fuzz-verified over 3000 runs including 0, 1, 9999, 10000 and 10001.\n- **Bonus split.** Tip plus the three shares plus the carried remainder always equals the bonus, for bonuses from 1 wei to the uint256 maximum, boards of 0 to 5 players and any pattern of failed sends. Dust is at most 3 wei and goes to carry. The bonus is always at least 1 IMD because the fee cap is below the minimum bid, so no share can round to zero.\n- **Subtractions.** Every subtraction (end minus now, amount minus fee, bonus minus tip, bonus minus carryIn) has its bound enforced on the path before it. Veto and reclaim return exactly the winner's own net bid and send carryIn back to carry, fuzz-verified.\n- **Time boundaries.** The bid window, the carry cutoff in settle, the veto cutoff and the reclaim grace all sit on the same day arithmetic. The anti-snipe end never moves backwards and never passes 19:00 UTC. For every timestamp from 64800 to 2^62, with and without an extension of the previous day, openDay names a day whose window contains now.\n- **External boundaries.** Token calls handle no-code, false-return, void-return, malformed-return and zero-amount cases without blocking other recipients. The derby's reveal window and its dayClosed use the same inequality, so the board payBonus reads is final.\n- **Target chain.** Reads against the public Robinhood Chain RPC confirm chain id 4663, the derby address has code and reports the IMD token address, and the token has symbol IMD with 18 decimals, matching the contract's constants.\n\n**The one note.** Before the chain's first 18:00 UTC, openDay returns day 1, which auction and bid reject with BadDay. This is unreachable on the live chain and affects no funds. It is recorded as info with a reproduction, and no change is recommended given the frozen ABI.\n\n**Coverage record.** All 22 listed entry points have a row, plus rows for openDay, minNextBid, the bps helper, the balance conservation invariant and the constructor arguments. The project suite passes with 94 tests. Not reached: no fork test against the live derby, and the real token's transfer semantics were only checked by symbol and decimals reads.","treeHash":null,"usage":{"cachedInputTokens":1700550,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":35424,"runtime":"claude","turns":31,"wallClockMs":705298}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b273d407784470b4","findings":[{"citation":"resolved","description":"Contracts read in full: src/DerbyAuction.sol (every external and public state-changing function: bid, settle, veto, payBonus, reclaim, withdrawRefund, setStudio, setBuildFee, transferOwnership, acceptOwnership, plus the views and internals), src/SwarmDerby.sol (the ISwarmDerby surface the auction trusts: currentDay, dayClosed, board, _bump, _recordDinger) and src/DerbyOdds.sol only as far as the tests use it. test/DerbyAuction.t.sol (40 tests, including the conservation fuzz) and test/SwarmDerby.t.sol were read; forge test passes 94/94 on Forge 1.8.3. Checks run: (1) the protected harness opcode scan replayed on the compiled DerbyAuction runtime: 9520 bytes, no DELEGATECALL, CALLCODE or SELFDESTRUCT; the constructor makes no external call. (2) Robinhood Chain RPC (chain id 4663): 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 is a contract (symbol IMD, 18 decimals, has an owner); 0xBa58BC6b5aCf8043DAEa2Bf1BF6C1c09cF84b03C is a contract whose imd() returns 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 and whose runtime bytecode is byte-identical to a local build of src/SwarmDerby.sol once the imd immutable is masked; dayClosed(0, day) and board(0, day) decode as the ISwarmDerby interface expects. (3) A fork test with the exact launch constructor arguments (owner, IMD, derby, studio = owner, fee 0) ran bid, outbid refund, settle and veto against the real IMD token: transferFrom and transfer return a 32-byte true and move the exact amount, so _pull and _accepted work with this token. Not reached: the IMD token source (the Blockscout API returned HTML to this host), so its owner powers (block list, pause) are known only from DEPLOY.md; payBonus could not be run on the fork because Forge 1.8.3 has no ArbSys at address 100 on a forked chain (it is covered by the unit tests with the etched mock). Checklist passes applied from the Pashov guide: math precision (_bps is an exact floor, minNextBid rounds up, a max-uint bid has no overflowing product), access control (owner-only veto and setters, two-step ownership; settle, payBonus and reclaim deliberately permissionless), execution trace and reentrancy (effects before interactions on every path, nonReentrant on every token-moving function, token callbacks cannot re-enter), invariants (IMD balance = unsettled leads + unpaid bonuses + carry + credited refunds holds on every path including failed sends), boundary and periphery (zero-amount sends, tokens with no return data or a malformed boolean, fee-on-transfer rejected by the balance diff, derby or token without code), flow gaps (bid after settle, veto after payBonus, payBonus after reclaim and reclaim after veto are blocked by settled or _checkRefundable; veto needs now < day*86400 and payBonus needs day < currentDay, so they can never both run), and the launch-forbids list (no mint, pause, freeze, blacklist, seize, proxy or initializer; the constructor fully configures the contract). The items the owner accepted (extensions stop at 19:00 UTC, settle reads buildFee and studio, payBonus and reclaim race after the grace) were confirmed to behave as the brief states and are not reported.","line":17,"path":"src/DerbyAuction.sol","reproduction":"Not a defect. Evidence: forge test (94 passed); a scratch opcode-scan test over address(new DerbyAuction(...)).code; cast calls to https://rpc.mainnet.chain.robinhood.com (chain-id 4663; code at both constructor addresses; derby imd() == 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127; derby bytecode equals forge inspect SwarmDerby deployedBytecode after masking the 20-byte immutable, 0 differing bytes); a fork test calling bid(openDay(), 2e18), then bid 3e18 from a second wallet (first wallet refunded in full, refunds == 0), settle at end (bonus == 3e18), owner veto (winner refunded 3e18, contract balance 0).","severity":"info","snippet":"contract DerbyAuction {","title":"Audit coverage: DerbyAuction read in full and checked against the live dependencies; no critical, high or medium defect found"},{"citation":"resolved","description":"settle pays min(buildFee, amount) to studio before the owner decides whether to veto. veto and reclaim then refund a.bonus - carryIn[day], which excludes the fee, so a bidder whose theme is never built still pays for the build. The owner controls buildFee (up to MAX_BUILD_FEE = 1 IMD), studio and veto, so a malicious owner could set studio to itself, set the fee to 1 IMD and veto every day, collecting 1 IMD per settled auction while bidders get nothing built. This is documented in DEPLOY.md (Owner trust) and in WP3, the launch fee is 0, the fee is capped, and the brief accepts that settle reads the fee at settlement, so it is reported as a trust assumption for the panel, not as a defect to change. No unprivileged actor can trigger it.","line":197,"path":"src/DerbyAuction.sol","reproduction":"State: buildFee = 1e18 (owner calls setBuildFee(1e18)), studio = owner. Alice bids 2e18 on day D. At end(D) anyone calls settle(D): studio receives 1e18 and bonus(D) = 1e18. The owner calls veto(D) before D*86400: Alice receives 1e18 back. Expected by a bidder: the full 2e18 back when no theme is built. Actual: 1e18 stays with the studio. At the launch value buildFee_ = 0 the fee is 0 and nothing is lost.","severity":"info","snippet":"            fee = buildFee < a.amount ? buildFee : a.amount;","title":"Trust assumption: a vetoed or reclaimed winner gets the bid less the build fee, and the owner sets both the fee and the veto"},{"citation":"resolved","description":"carry accumulates from empty or short boards, rounding dust and prizes the token refused to deliver. The only outflow is lines 201-205: a day with a winner settled strictly before its theme day starts folds the whole carry into its bonus. There is no owner sweep (by design; DEPLOY.md: no owner sweep of player funds). If auctions stop, or every later winning auction is settled late (after day*86400), the carry is unrecoverable. This mirrors the SwarmDerby rollover and is a design choice, so it is info; it is recorded so the operator knows that settling each winning auction before midnight UTC is what keeps carry flowing.","line":201,"path":"src/DerbyAuction.sol","reproduction":"State: day D settled with bid 2e18, board(0, D) empty, payBonus(D) called after dayClosed: carry = 2e18. From then on no bid is placed on any day (or every later winning day is settled only after its theme day started). Expected by a user: the 2e18 eventually reaches some board or the operator. Actual: carry stays 2e18 indefinitely; no function can move it except settle of a future winning day before that day begins.","severity":"info","snippet":"            if (block.timestamp < day * 1 days) {","title":"Carry has no exit: if no later auction with a winner is settled before its theme day, carried IMD stays in the contract forever"},{"citation":"resolved","description":"payBonus moves a failed prize transfer into carry (lines 249-253) with no per-winner credit, whereas bid, settle, veto and reclaim credit refunds[to] when a transfer fails. A winner blocked by the IMD token at payout time therefore never gets that prize, even after being unblocked; it goes to a later board. This matches SwarmDerby settleNextDay and is documented in DEPLOY.md (failed prize transfers become carry), and the brief forbids ABI changes, so it is a note for the panel, not a change request. The trigger needs the IMD token owner to block a winner (privileged, outside the auction).","line":250,"path":"src/DerbyAuction.sol","reproduction":"State: day D settled with bonus 2e18+7, board(0, D) has three players, and the IMD token refuses transfers to players[1] (test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers in test/DerbyAuction.t.sol models this with failure mode 4). payBonus(D): players[0] and players[2] are paid, players[1] gets 0, carry grows by the 25% share of players[1], refunds[players[1]] stays 0. Unblocking players[1] later gives them no way to claim it.","severity":"info","snippet":"                carry += amounts[i];","title":"A top-3 winner the token refuses to pay loses the prize to carry, while bidders and the studio get a refunds credit"},{"citation":"resolved","description":"Every movement of value is an IMD transfer or transferFrom. The token at 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 has an owner (owner() = 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7 at review time) and DEPLOY.md states that owner can block addresses or stop transfers. If the auction contract itself is blocked: bid reverts TransferFailed, withdrawRefund reverts TransferFailed, payBonus reverts on the caller tip, while settle, veto and reclaim still complete and credit refunds instead of paying. Funds are not lost: credited refunds and unpaid bonuses remain claimable once transfers resume. Documented for SwarmDerby under DEPLOY.md Known limits; the auction section inherits it. The token source could not be read from here (the Blockscout API returned HTML), so the exact admin powers come from the repo's notes.","line":366,"path":"src/DerbyAuction.sol","reproduction":"State: the IMD owner blocks address(sale) (or pauses the token). Alice calls bid(D, 2e18, answers): transferFrom reverts or returns false and bid reverts TransferFailed; nobody can bid. A leader whose refund is due gets refunds[leader] credited (RefundCredited) and withdrawRefund reverts TransferFailed until the block is lifted. Expected: no permanent loss. Actual: the same; only liveness is affected for the duration.","severity":"info","snippet":"        (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));","title":"External dependency: the Robinhood IMD token has an owner that can block addresses or stop transfers, which halts the auction while it lasts"}],"hash":"72c04967c3ba45bc5f423664ab1c6df57440b1a6ac16c4663fe2ce69314facf3","nodeId":"077b3ed7-f49b-4c22-a67d-3cc7d87c453e","outcome":"completed","summary":"The findings file is in place and the working tree holds nothing else of mine. The build output directories are gitignored and the scratch directory is deleted.\n\n**Result: no critical, high or medium defect in DerbyAuction.** The review is written to `.imd-findings.json` as five info entries: one coverage statement and four trust notes, each with a concrete state and the expected versus actual outcome.\n\n**What I read and checked**\n\n- Read in full: `src/DerbyAuction.sol`, the `ISwarmDerby` surface of `src/SwarmDerby.sol`, both test files, the WP3 spec and DEPLOY.md. `forge test` passes 94 of 94 on Forge 1.8.3.\n- Walked every state-changing function against the Pashov checklist: math, access control, reentrancy, flow ordering, boundaries, invariants and the launch-forbids list. Effects precede interactions everywhere, every token-moving path is reentrancy guarded, the balance invariant holds through failed sends, and veto and payBonus are provably mutually exclusive in time.\n- Replayed the protected harness opcode scan on the compiled runtime. It is 9,520 bytes with no DELEGATECALL, CALLCODE or SELFDESTRUCT, and the constructor makes no external call.\n- Verified the constructor inputs on Robinhood Chain over RPC. Both addresses hold code, the deployed SwarmDerby's `imd()` returns the IMD address the brief names, and its runtime bytecode is byte-identical to a local build of the repo's source once the IMD immutable is masked.\n- Ran a fork test with the exact launch arguments against the real IMD token. Bid, outbid refund, settle and veto all moved the exact amounts, so the strict transfer and return-data handling works with this token.\n\n**What could not be reached**\n\n- The IMD token's source. The Blockscout API returned HTML to this host, so its owner powers are taken from DEPLOY.md.\n- `payBonus` on the fork, because Forge 1.8.3 has no ArbSys precompile on a forked chain. The unit tests cover it with the etched mock.\n\n**Trust notes recorded (all info)**\n\n- A vetoed or reclaimed winner gets the bid less the build fee, and the owner controls fee, studio and veto. Zero impact at the launch fee of 0, and documented.\n- Carry has no exit if auctions stop or every later winning day settles late. Design choice mirroring SwarmDerby's rollover.\n- A top-3 winner the token refuses to pay loses the prize to carry with no credit, unlike bidders and the studio. Documented and ABI-bound.\n- The IMD token owner can block or pause transfers, which halts the auction for the duration without losing funds.\n\nThe accepted items in the brief (extensions stop at 19:00 UTC, settle reads the fee and studio at settlement, the payBonus and reclaim race) behave as stated and are not reported as findings.","treeHash":null,"usage":{"cachedInputTokens":1429887,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":37453,"runtime":"claude","turns":27,"wallClockMs":685760}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3f91b58cf7cd2d45","findings":[{"citation":"resolved","description":"Carry (unfilled board places, empty boards, dust, failed prize sends) is folded whole into the first winning auction settled before its theme day. The bid itself is a sponsorship with no monetary return, so the only party with an incentive to bid on a quiet day is one who also expects to hold the arcade top 3. The arcade cap is per wallet and bots may play, which DEPLOY.md lists as a known limit for the daily pot; carry concentrates many days of unfilled prize money onto a single day the bidder chooses, so the sybil incentive scales with carry rather than with one day's pot. No guard in DerbyAuction or SwarmDerby interrupts the path; this is an economic property of the accepted design, not a code defect, and any mitigation (cap per fold-in, spreading carry over several days) would change the payout math the brief forbids changing. Reported for the judge's record only.","line":202,"path":"src/DerbyAuction.sol","reproduction":"State: three sponsored days each with an empty arcade board leave carry = 150 IMD (3 x 50 IMD bids, settled, closed, payBonus with empty board, tip 0). Attacker bids MIN_BID = 2 IMD on day D with no competing bidder; settle(D) before D*86400 sets bonus = 152 IMD, carryIn[D] = 150. On day D the attacker's three wallets each buy one turn (0.15 IMD) and hit one homer each; no other arcade homer. After dayClosed(0,D), attacker calls payBonus(D): tip 0.76 IMD to attacker, 90.744 / 37.81 / 22.686 IMD to the three wallets. Attacker side receives 152 IMD for an outlay of 2.45 IMD; carry = 0. Expected by design: the carry goes to that day's board. Actual: identical, the board is the attacker's. Reproduced in test/scratch/EconReview.t.sol test_minimumBidCapturesAccumulatedCarry (logs 152000000000000000000 received vs 2450000000000000000 outlay).","severity":"info","snippet":"                carryIn[day] = carry;\n                a.bonus += carry;\n                carry = 0;","title":"Accumulated carry is captured by one minimum bid on a quiet day whose board the bidder fills (documented known limit, amplified by carry)"},{"citation":"resolved","description":"Earlier reviews could not reach the Robinhood RPC and retained the token's admin powers as unverified. This review read the live token 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 on chain 4663: name 'Identity.md', symbol IMD, 18 decimals, owner 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7, selectors blocked(address), transferOwnership, renounceOwnership present; no pause, fee, proxy implementation slot or ERC1820 hook found; blocked() is currently false for IMD, SwarmDerby, address(0) and 0xdEaD. DerbyAuction already treats a reverting or false-returning transfer as a failed send (refund credit, prize to carry) and a failed pull as a reverted bid, so a blocked bidder or winner is handled. The one state it cannot handle is the auction contract itself being blocked: every outbound send fails, refunds accumulate as credits, withdrawRefund reverts, and payBonus reverts on the tip until the token owner unblocks it. No code change is appropriate; this records the dependency with live evidence.","line":366,"path":"src/DerbyAuction.sol","reproduction":"State: IMD owner sets blocked(address(DerbyAuction)) = true (assumed to make transfers from that address fail, as the auction's own failure model expects). Then: bid(D, 3 IMD) by Bob after Alice led with 2 IMD -> Alice's refund is credited to refunds[Alice] (RefundCredited) instead of sent; Alice's withdrawRefund() reverts TransferFailed; payBonus(D) reverts TransferFailed on the tip send; veto/reclaim credit the winner instead of paying. Expected: funds move; actual: all IMD held by the auction is frozen until the token owner unblocks the address. Local equivalent is covered by the existing tests test_failedRefundAccumulatesAndWithdrawsOnlyOnce and test_failedTipRevertsAndAnotherCallerCanPay using the mock token's failure modes.","severity":"info","snippet":"        (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));\n        return ok && _accepted(data);","title":"Live IMD token has an owner-controlled blocklist; a blocked DerbyAuction address freezes bids, payouts and refund withdrawals until unblocked (external trust assumption, verified on chain)"}],"hash":"7f0656c41b54ef80425768d01eaa5c2f04807b8720455f598a944468a4f9d69e","nodeId":"f7b89659-f11c-41f8-bdab-8607ac806907","outcome":"completed","summary":"Review complete. The findings file is at `.imd-findings.json` with two informational entries and a 27-row coverage record. No source files were changed; the only other file I created is the scratch test under `test/scratch/`, which is not kept.\n\n**Result: no critical, high, medium or low defect in the Economic Security, Invariant or Flow Gap areas.** Every DerbyAuction entry point traced clean, and the full suite passes (94 tests, 0 failed).\n\nWhat I verified:\n- **Conservation** holds across bid, settle, veto, payBonus, reclaim and withdrawRefund, matching the project fuzz invariant. Veto and reclaim return only the bid less fee, never inherited carry.\n- **Carry ordering is deterministic.** The settle-before-theme-day windows of consecutive days never overlap, so carry cannot be raced between two auctions. A scratch test confirms day D+1 cannot be settled while day D can still take carry.\n- **Payout finality.** Once SwarmDerby reports the day closed, any late reveal is a foul, so the board payBonus reads cannot change. A winner has no way to make their own bonus unpayable to force a reclaim.\n- **Live periphery.** The derby at the brief's address has runtime bytecode identical to this repo's build except for the immutable IMD address, its token matches the auction's `imd_`, and `dayClosed` works on chain through ArbSys. Earlier reviews could not reach the RPC, so this is new evidence.\n\nThe two informational entries:\n1. **Carry capture by a minimum bid.** Once carry has accumulated from empty or short boards, a 2 IMD bid on a quiet day plus three self-owned arcade wallets collects the whole pool. The reproduction shows 152 IMD received for a 2.45 IMD outlay. This is the documented known limit about bots playing the arcade, amplified by carry concentration. Any mitigation would change the payout math the brief forbids changing, so it is recorded, not proposed as a fix.\n2. **IMD blocklist dependency.** The live token has an owner-controlled `blocked(address)` and no pause, fee or proxy. The auction already handles a blocked bidder or winner. If the auction contract itself were blocked, all its IMD would freeze until unblocked. External trust assumption, now with on-chain evidence.\n\nAccepted items (19:00 extension cap, settlement-time fee and studio, post-grace race) were traced and left out of the findings as instructed.","treeHash":null,"usage":{"cachedInputTokens":1308896,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":40284,"runtime":"claude","turns":28,"wallClockMs":654468}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"feba2a869621cab2","findings":[{"citation":"resolved","description":"Periphery check of the constructor's imd_ argument against the live chain (RPC https://rpc.mainnet.chain.robinhood.com, chain id 4663, read on 2026-10-08). The token at 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 has code (not an EIP-1967 proxy), symbol IMD, 18 decimals, OpenZeppelin v5 errors (ERC20InvalidSender), transfer() returns exactly 32 bytes `true` and emits Transfer for the full amount (no fee), so _pull's balance-delta check and _accepted's 32-byte rule match it. Its selector set also includes setBlocked(address,bool), blocked(address), enableTransfers(), transfersEnabled() and the OFT bridge entry points (lzReceive, send, setPeer); owner() = 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7, currently transfersEnabled() = true, blocked(derby) = false. The derby at 0xBa58BC6b5aCf8043DAEa2Bf1BF6C1c09cF84b03C has code, imd() equals the same token, BOARD_SIZE = 10, dayClosed(0, 20733) = true and board(0, 20733) returned one player, so the ISwarmDerby reads the auction makes decode as expected. Consequence traced through the auction (execution x periphery): a winner the token owner has blocked, or a globally disabled token, makes _trySend return false, so that winner's share is moved to carry with no refund credit (line 249-253); a blocked auction contract makes _pull revert every bid with TransferFailed (line 354) and makes the tip _send revert every payBonus (line 247) until unblocked, after which reclaim credits the bidder (line 268). Nothing in DerbyAuction can override this; it is the documented 'failed winner prize becomes carry' rule plus the token owner's powers. Reported as information for the launch review, not as a code change: the code's failure handling is the accepted design.","line":249,"path":"src/DerbyAuction.sol","reproduction":"Local model of the live token's block list using the existing AuctionToken failure modes (test/DerbyAuction.t.sol): (1) _settled(2 ether); warp to the theme day; _board(3); _close(DAY); imd.setFailure(players[1], 1) (revert, as a blocked recipient would); _pay(DAY). Expected if the token were plain: players[1] receives 2.4875e17. Actual: players[1] receives 0, sale.refunds(players[1]) == 0, sale.carry() == 2.4875e17 (test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers shows the same for mode 4). (2) imd.setFailure(payer, 1) then payBonus from payer: reverts TransferFailed and the day stays unpaid (test_failedTipRevertsAndAnotherCallerCanPay). On the live chain the equivalent trigger is the token owner calling setBlocked(address,true) on a winner, the payer, or the auction address, or leaving transfersEnabled() false. No unprivileged actor can trigger it.","severity":"info","snippet":"            if (!_trySend(winners[i], amounts[i])) {\n                carry += amounts[i];\n                carried += amounts[i];\n                amounts[i] = 0;\n            }","title":"Live IMD token (0x5F7B...B127) is a LayerZero OFT with owner-controlled setBlocked and transfersEnabled; a blocked or disabled token turns prizes into carry and stalls bids and tips (external trust as"}],"hash":"9516a678caa2864788929a168bce8fd28c28e29fec279661091e9bf5ee481756","nodeId":"40e84e7d-f63c-41d0-a040-94c2f82e1b98","outcome":"completed","summary":"The findings file is in place and the harness excludes it from git by design. No tracked file changed.\n\n**Review complete: no defects found in `DerbyAuction`; one informational trust note recorded.**\n\n**What I covered**\n\n- Traced every `DerbyAuction` entry point for the Execution Trace, Periphery and First Principles failure modes: wrong-state execution, partial state updates, stale reads, sentinel paths, external return handling, and each implicit assumption in the day arithmetic, carry accounting, refund credits and reentrancy guards. All hold.\n- Confirmed the four audit fixes behave as the spec says: reclaim grace from the later of theme-day end and settlement, no carry on late settlement, credited studio fee, and `openDay` naming an extended day.\n- Ran five scratch probes under `test/scratch/` for cases the suite does not state directly: two auctions open at once during an extension, the carry boundary at midnight with veto returning carry, an absent derby, self-raise net flow, and studio equal to leader. All passed as the code intends.\n- Verified the live periphery on Robinhood Chain, since the RPC answered this time. The token at the pinned address is an OpenZeppelin v5 ERC20 and not a proxy. Its `transfer` returns exactly 32-byte `true` with no fee, so the strict 32-byte acceptance rule and balance-delta check match it. The derby at the pinned address has code, points at the same token, and its `board` and `dayClosed` reads decode as the auction expects.\n\n**The one note** is informational. The live IMD token is a LayerZero OFT whose owner can block addresses and disable transfers. Today transfers are enabled and nothing relevant is blocked. If that changes, the auction's documented failure handling applies: a blocked winner's prize becomes carry with no credit, and a blocked auction address stalls bids and tips until unblocked. That is an external trust assumption, not a code defect, and no unprivileged actor can trigger it.\n\n**Coverage record** has 25 rows: all 22 listed entry points, the constructor arguments, and two invariants. Every `DerbyAuction` row is `holds` except `payBonus`, which references the informational note. The `SwarmDerby` rows are `holds`, with `swing`, `finalize` and `settleNextDay` traced for the auction's dependency on a board that is final once `dayClosed` is true.\n\nThe full suite still passes at 94 tests. No critical or high finding exists, so no proof test is attached and the code should ship unchanged.","treeHash":null,"usage":{"cachedInputTokens":1737081,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":28480,"runtime":"claude","turns":35,"wallClockMs":532049}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2a9662a76cb5f51d","findings":[{"citation":"resolved","description":"Merged from audit_flow and audit_economics (second finding): one root cause, the token at 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 has owner-controlled transfer restrictions that DerbyAuction cannot override. Verified live on chain 4663 on 2026-10-08: the token has code (30,899 bytes), symbol IMD, 18 decimals, owner 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7, selectors blocked(address), transfersEnabled() and enableTransfers() present, transfersEnabled() == true and blocked(derby) == false today. Consequences traced through the code: _trySend (line 363-368) treats a reverting transfer as a failed send, so payBonus moves a blocked winner's share to carry with no refund credit (line 249-253); _pull (line 354) reverts every bid when the auction address is blocked or transfers are disabled; the tip _send (line 247) reverts payBonus; veto/reclaim credit the winner (line 342-347) and withdrawRefund reverts (line 276) until the token owner unblocks. This is the documented 'failed prize becomes carry' rule and the same dependency SwarmDerby already lives with (DEPLOY.md Known limits). No unprivileged actor can trigger it; no code change under the agreed design.","line":366,"path":"src/DerbyAuction.sol","reproduction":"Local model of the live token (test/scratch/Review.t.sol, RToken with blocked[] and transfersEnabled). (a) test_blockedWinnerPrizeBecomesCarry: alice bids 2 IMD on DAY, settle at end, three real arcade homers on DAY, close the day, token blocks board[1], payBonus. Expected if the token were plain: board[1] receives 0.4975 IMD. Actual: board[1] receives 0, refunds(board[1]) == 0, carry == 0.4975 IMD, board[0] and board[2] still receive 1.194 and 0.2985 IMD. (b) test_blockedAuctionFreezesBidsRefundsAndPayout: with the auction address blocked, a 3 IMD counter-bid reverts TransferFailed, payBonus reverts TransferFailed on the tip, reclaim after the grace credits refunds(alice) == 2 IMD, withdrawRefund reverts TransferFailed, and succeeds once unblocked. (c) test_disabledTokenTurnsPrizeIntoCarryAndBlocksTip: transfersEnabled == false makes payBonus revert; re-enabling lets it pay. All three pass on the current tree, i.e. they document the behaviour.","severity":"info","snippet":"        (bool ok, bytes memory data) = address(imd).call(abi.encodeCall(IERC20.transfer, (to, amount)));","title":"External trust: the live IMD token's owner blocklist and global transfer switch turn a blocked winner's prize into carry, and a blocked auction address freezes bids, refunds, tips and reclaims until u"},{"citation":"resolved","description":"From audit_permissions; reproduced. settle reads buildFee and studio at settlement (line 197, 207), and veto returns only bonus - carryIn[day] (line 217, 315-320), so a winner vetoed after the owner raised the fee recovers amount - fee while the studio keeps the fee although nothing was built. At launch studio = $owner and buildFee = 0, the fee is capped at MAX_BUILD_FEE (1 IMD per auction), only the owner can set the fee or veto, and the task statement accepts that settle reads the fee and studio at settlement. Documented in DEPLOY.md as 'Owner trust'. Not a permission bypass; recorded as a privileged-power risk. Operational guard: keep the fee at 0 or change it only between auction windows.","line":197,"path":"src/DerbyAuction.sol","reproduction":"test/scratch/Review.t.sol::test_ownerFeeThenVetoKeepsFeeFromWinner (passes, documents). Deploy DerbyAuction(owner, imd, derby, studio = owner, fee = 0). At start(DAY) alice bids 2e18. owner calls setBuildFee(1e18). At end(DAY) settle(DAY): imd.balanceOf(owner) == 1e18, bonus == 1e18. At DAY*86400 - 1 owner calls veto(DAY). Expected under the agreed design and actual: imd.balanceOf(alice) == 1e18, imd.balanceOf(owner) == 1e18, imd.balanceOf(sale) == 0.","severity":"info","snippet":"            fee = buildFee < a.amount ? buildFee : a.amount;","title":"Owner trust: a build fee raised after bids were placed is paid to the studio at settlement and is not returned by a later veto"},{"citation":"resolved","description":"From audit_economics (first finding); reproduced with real SwarmDerby swings. Carry (empty boards, unfilled places, failed sends, dust) is added entirely to the bonus of the first auction with a winner settled before its theme day (line 201-205). The bid is a sponsorship with no monetary return, so the party with the strongest incentive to bid on a quiet day is one who expects to hold the arcade top 3. The arcade cap is per wallet and bots may play, which DEPLOY.md lists as a known limit; carry makes the sybil incentive scale with accumulated carry rather than one day's pot. No guard in DerbyAuction or SwarmDerby interrupts the path. This is an economic property of the accepted payout math, which the brief forbids changing; recorded for the record, not as a code defect.","line":202,"path":"src/DerbyAuction.sol","reproduction":"test/scratch/Review.t.sol::test_minimumBidCapturesAccumulatedCarry (passes, documents; logs received 152e18 vs outlay 2.45e18). Three sponsored days DAY..DAY+2 each with a 50 IMD bid, settled at their end, closed with an empty arcade board, payBonus with tip 0: carry == 150 IMD. attacker bids MIN_BID (2 IMD) on D = DAY+5 with no competitor; settle(D) at end(D): bonus == 152 IMD, carryIn(D) == 150 IMD. On day D three attacker wallets each buy one 0.15 IMD turn and hit one homer; nobody else plays. After dayClosed(0, D) the attacker calls payBonus(D). Expected by design and actual: attacker side receives 152 IMD (tip 0.76 plus 90.744 / 37.81 / 22.686), carry == 0.","severity":"info","snippet":"                carryIn[day] = carry;","title":"Accumulated carry is folded whole into the next on-time winning auction, so one minimum bid on a quiet day whose board the bidder fills captures every prior day's unfilled prize money"},{"citation":"resolved","description":"From audit_math; reproduced. For block.timestamp < 64800 the view returns 1, but _end() (line 306) reverts BadDay() for any day < 2, so auction(1) and bid(1, ...) revert. From 64800 onward every value openDay() returns names a day whose bid window contains now. Unreachable on Robinhood Chain (timestamps ~1.79e9); it only shows on a fresh local chain or a test that warps below 18:00 UTC of day 0, and the existing test_openDayAndBidTimeBoundaries already asserts this value. No funds affected; nothing to change under the frozen ABI.","line":137,"path":"src/DerbyAuction.sol","reproduction":"test/scratch/Review.t.sol::test_openDayBeforeFirstCloseNamesUnbiddableDay (passes, documents). vm.warp(1000): openDay() == 1; auction(1) reverts BadDay(); bid(1, 2e18, validAnswers) reverts BadDay(). vm.warp(64800): openDay() == 2 and bid(2, 2e18, validAnswers) succeeds. Expected: the named day is biddable or the view reverts the same way; actual below 64800: a day number no entry point accepts.","severity":"info","snippet":"        if (block.timestamp < CLOSE_OFFSET) return 1;","title":"openDay() returns day 1 before the chain's first 18:00 UTC, a day no entry point accepts"},{"citation":"resolved","description":"Own check, not raised by the specialists. setStudio only rejects address(0) (line 281). If the owner sets the studio to the auction contract itself, settle's _refund(studio, fee) (line 207) performs imd.transfer(address(this), fee), which a standard ERC20 accepts, so the call returns true and nothing is credited to refunds; the fee is then neither bonus, carry nor a refund credit and no function can ever move it. Only the owner can cause it, the fee is capped at 1 IMD per auction and the launch fee is 0, so this is an operational note under the owner trust assumption rather than a defect to fix under the frozen ABI.","line":282,"path":"src/DerbyAuction.sol","reproduction":"test/scratch/Review.t.sol::test_studioSetToSelfStrandsFee (passes, documents). owner calls setStudio(address(sale)) and setBuildFee(1e18); alice bids 2e18 on DAY; settle(DAY) at end(DAY). Actual: imd.balanceOf(sale) == 2e18, bonus == 1e18, refunds(sale) == 0, carry == 0, so 1e18 is held by the contract and owed to nobody. Expected with any other studio address: the fee leaves the contract or is credited to refunds[studio].","severity":"info","snippet":"        studio = studio_;","title":"Owner foot-gun: setStudio(address(this)) makes the build fee a self-transfer that is owed to nobody and has no sweep"}],"hash":"a22f8937157766b5f9bdc45b437861136a12a89dfe52a69ff9c83dd1babd36de","nodeId":"3f6875bf-2369-444b-a31b-9eafdf0f673d","outcome":"completed","summary":"Review complete. No tracked file changed; `.imd-findings.json` holds five informational findings and a 25-row coverage record.\n\n**Outcome: no critical, high, medium or low defect in DerbyAuction.** The fix commit for the earlier medium and three lows is correct, and every specialist finding reproduced only as documented, accepted behaviour.\n\nWhat I verified:\n\n- **Fix commit.** Reclaim grace from the later of theme-day end and settlement, late settle takes no carry, unsendable studio fee is credited, and openDay names the extended day. Each traced in source and covered by the existing regression tests.\n- **Test suite.** The full suite passes with 101 tests: 40 auction, 54 SwarmDerby, and 7 from the independent tester's invariant and boundary file. The invariant run completed 256 runs and 16,384 handler calls.\n- **Live dependencies.** On chain 4663 the IMD token reports symbol IMD, 18 decimals and transfers enabled. The derby at the brief's address returns the same token, a board size of 10, and working board and dayClosed reads. Its runtime bytecode is byte-identical to a local build of this repo's SwarmDerby source with immutables masked.\n- **Deployability.** DerbyAuction's runtime uses PUSH0 and MCOPY. An eth_call probe on the live RPC executed MCOPY, TSTORE and PUSH0 successfully, while an INVALID probe errored, so the chain supports the Cancun bytecode. The runtime has none of the forbidden opcodes.\n- **Manifest.** launch.json lists the five constructor arguments in order with the brief's exact addresses, $owner for owner and studio, and fee zero.\n\nFindings kept, all informational and each reproduced in `test/scratch/Review.t.sol`:\n\n1. **Live IMD token owner powers** (merged from audit_flow and audit_economics). A blocked winner's prize goes to carry, a blocked auction address freezes bids, tips and withdrawals until unblocked. Verified live that the token exposes blocked and transfersEnabled.\n2. **Fee raised after bids then veto** (audit_permissions). Studio keeps the fee, winner gets bid less fee. Accepted owner trust, launch fee is zero.\n3. **Carry captured by one minimum bid on a quiet day** (audit_economics). Reproduced with real swings: 152 IMD received for a 2.45 IMD outlay. Property of the accepted payout math.\n4. **openDay returns day 1 before the first 18:00 UTC** (audit_math). Unreachable on mainnet.\n5. **My own note:** setStudio to the auction's own address strands the fee as a self-transfer owed to nobody. Owner-only, capped at 1 IMD per auction.\n\nCoverage: all 22 entry points marked holds with reasons, plus rows for the conservation invariant, the manifest, and Cancun deployability. No proofs attached since nothing reached critical or high.","treeHash":null,"usage":{"cachedInputTokens":1327344,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":39068,"runtime":"claude","turns":30,"wallClockMs":636038}},{"artifacts":[],"attempt":1,"bundleHash":"6f8f2fadf1708699905db0dd8d38fcef658dbcd0b27659738cfe42d94687be4b","device":"7d2db8d9021f8063","findings":[],"hash":"ae71e6d38bcdb7de2c18221c15702ccc37dc3cb7a2fa94df1775c461ab78d7b3","nodeId":"9f32ed76-b1d6-49da-ac74-83864ede340e","outcome":"completed","summary":"Added failure-path tests, 1,000-run fuzz properties, and random-sequence invariants in [DerbyAuction.invariant.t.sol](/home/imd3/.identitymd/work/3bfde4f8-74f7-4afd-b9c0-a0bdba9bac42/9f32ed76-b1d6-49da-ac74-83864ede340e/test/DerbyAuction.invariant.t.sol).\n\n`forge build` succeeds; `forge test` passes all 101 tests. Only the new test file was added. Live Robinhood Chain integration remains unverified.","treeHash":"5432726be7fb701bd3ce2b2ce6b527686999bc36","usage":{"cachedInputTokens":1331673,"inputTokens":99008,"model":"gpt-6.1-sol","outputTokens":12873,"runtime":"codex","turns":5,"wallClockMs":297367}},{"artifacts":[],"attempt":1,"bundleHash":"4eb8e1bb51ff229f4fba0bdf7df899f040aa7f1561f289094d28e00c9eabeeb7","device":"97c4e9eb9244090f","findings":[],"hash":"de73315a1acd3d2179d2bcb09a26c851955b0e274b58424f086d15fc065e0f8e","nodeId":"50570f87-e003-40af-a43d-61f721e542ac","outcome":"completed","summary":"Created [launch.json](/home/imd8/.identitymd/work/3bfde4f8-74f7-4afd-b9c0-a0bdba9bac42/50570f87-e003-40af-a43d-61f721e542ac/launch.json) for DerbyAuction only, using the exact approved constructor arguments.\n\nValidated the manifest structure and compiled constructor ABI. `forge build` succeeded; all 94 tests passed. No other files changed.","treeHash":"30c7326feb218cabca8b01dddb03ddc30f9be5df","usage":{"cachedInputTokens":155216,"inputTokens":26102,"model":"gpt-6.1-sol","outputTokens":1563,"runtime":"codex","turns":2,"wallClockMs":57919}}],"verification":[{"checks":[{"durationMs":26036,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 25.90s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:436:48\n    │\n436 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:436:55\n    │\n436 │         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:507:9\n    │\n507 │         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:508:9\n    │\n508 │         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:528:9\n    │\n528 │         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:529:9\n    │\n529 │         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:212:9\n    │\n212 │         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:296:91\n    │\n296 │             swings[swingId] = Swing(player, league, 0, velo, Status.Final, 0, bytes32(0), uint32(day));\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:302:25\n    │\n302 │         uint64 target = uint64(ARB_SYS.arbBlockNumber() + REVEAL_DELAY);\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:305:98\n    │\n305 │         swings[swingId] = Swing(player, league, quality, velo, Status.Committed, target, commit, uint32(day));\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[reentrancy-no-eth]: external call can be reentered before `vault` is updated\n    ╭▸ src/SwarmDerby.sol:564:40\n    │\n564 │         (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/SwarmDerby.sol:323:13\n    │\n323 │         if (bh == bytes32(0)) {\n    │             ━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:339:13\n    │\n339 │             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:341:9\n    │\n341 │         emit SwingResolved(swingId, s.player, tier, feet);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:441:51\n    │\n441 │         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:564:40\n    │\n564 │         (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:465:19\n    │\n465 │             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:477:27\n    │\n477 │         _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:475:37\n    │\n475 │         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:564:40\n    │\n564 │         (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:485:9\n    │\n485 │         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[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmDerby.sol:519:32\n    │\n519 │     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:105:18\n    │\n105 │         vm.warp((block.timestamp / 1 days + 1) * 1 days + 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\n","passed":true},{"durationMs":448,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 54 tests for test/SwarmDerby.t.sol:SwarmDerbyTest\n[PASS] testFuzz_boardsAreTopTen(uint256) (runs: 256, μ: 5057733, ~: 5052555)\n[PASS] testFuzz_settlementConserves(uint256) (runs: 256, μ: 5567291, ~: 5575777)\n[PASS] test_agentLeagueHasNoCap() (gas: 2695596)\n[PASS] test_arcadeCapIsTwentyPerDay() (gas: 2523316)\n[PASS] test_arcadeKeepsLongestAgentKeepsTotal() (gas: 298076)\n[PASS] test_badLeagueRejected() (gas: 32903)\n[PASS] test_boardResetsEachDay() (gas: 216345)\n[PASS] test_buyPackSplitsPerLeague() (gas: 518853)\n[PASS] test_capCountsSessionSwingsForThePlayer() (gas: 2274997)\n[PASS] test_commitBoundToPlayer() (gas: 588030)\n[PASS] test_constructorRejectsZeroAddressesAndFreeTurns() (gas: 1145480)\n[PASS] test_contactNeedsCommit() (gas: 334529)\n[PASS] test_eachDaySettlesOnceInOrder() (gas: 1443282)\n[PASS] test_emptyDayRollsOverWithoutTip() (gas: 1103450)\n[PASS] test_expireUnrevealed() (gas: 613957)\n[PASS] test_finalizeTooEarly() (gas: 503290)\n[PASS] test_finalizeUpdatesArcadeBoard() (gas: 629256)\n[PASS] test_fullSwingMatchesOdds() (gas: 522204)\n[PASS] test_lateFinalizeScoresOnCommitDay() (gas: 664435)\n[PASS] test_lateRevealIsFoul() (gas: 516676)\n[PASS] test_leagueTurnsAreSeparate() (gas: 295691)\n[PASS] test_leaveSessionFreesTheKey() (gas: 205604)\n[PASS] test_nextSettlementBeforeAnything() (gas: 11875)\n[PASS] test_oddsMonotoneInQuality() (gas: 316953)\n[PASS] test_ownerIsConstructorArg() (gas: 2913055)\n[PASS] test_ownerOnlyReachesOps() (gas: 418230)\n[PASS] test_ownershipIsTwoStep() (gas: 169425)\n[PASS] test_ownershipMoveCanBeCancelled() (gas: 113732)\n[PASS] test_parityWithBrowser() (gas: 63207)\n[PASS] test_priceFloor() (gas: 100369)\n[PASS] test_qualityAndVeloBounded() (gas: 317033)\n[PASS] test_revealAtWindowEdgeStillCounts() (gas: 615287)\n[PASS] test_sessionBuysForThePlayer() (gas: 483847)\n[PASS] test_sessionCannotBeClaimedTwice() (gas: 179047)\n[PASS] test_sessionChainsRejected() (gas: 376382)\n[PASS] test_sessionConsentIsSingleUse() (gas: 313925)\n[PASS] test_sessionNeedsTheKeysConsent() (gas: 161365)\n[PASS] test_sessionRevokeAndRotate() (gas: 300545)\n[PASS] test_sessionSwingsForPlayer() (gas: 671328)\n[PASS] test_settleAgentLeague() (gas: 633371)\n[PASS] test_settlePaysOnlyThatDaysPot() (gas: 1162741)\n[PASS] test_settlePaysTheDaysTopThree() (gas: 1224382)\n[PASS] test_settleWaitsForTheDayToEnd() (gas: 927961)\n[PASS] test_settleWaitsForTheLastReveal() (gas: 687692)\n[PASS] test_singleTurnPrice() (gas: 285720)\n[PASS] test_slamPaysTenPercentOfItsLeagueVault() (gas: 4962665)\n[PASS] test_swingStoresVelo() (gas: 449101)\n[PASS] test_tokenWithoutCodeRefusesPurchases() (gas: 3276413)\n[PASS] test_underPowerLineNoBombOrSlam() (gas: 29184887)\n[PASS] test_unpayableSlamKeepsPrizeAndHomer() (gas: 4747467)\n[PASS] test_unpayableWinnerRollsOver() (gas: 997516)\n[PASS] test_whiffCostsTurnNoRoll() (gas: 404595)\n[PASS] test_wrongSaltRejected() (gas: 498546)\n[PASS] test_zeroCountPurchaseReverts() (gas: 77131)\nSuite result: ok. 54 passed; 0 failed; 0 skipped; finished in 359.98ms (470.56ms CPU time)\n\nRan 40 tests for test/DerbyAuction.t.sol:DerbyAuctionTest\n[PASS] testFuzz_conservationAcrossAuctionSequences(uint256) (runs: 256, μ: 13312347, ~: 13407534)\n[PASS] test_adminPermissionsFeeCapAndTwoStepOwnership() (gas: 537169)\n[PASS] test_agentScoresAndOtherDaysNeverAffectArcadeBonus() (gas: 3439055)\n[PASS] test_answerBoundaryValuesStoredAndBidEmitted() (gas: 660479)\n[PASS] test_answerLengthsAndEnums() (gas: 533362)\n[PASS] test_antiSnipeExtendsRepeatedlyAndKeepsOtherDaysIndependent() (gas: 1985845)\n[PASS] test_antiSnipeStopsAtOneHourSoVetoStaysOpen() (gas: 3782541)\n[PASS] test_bidMinimumAndIncrementRoundUp() (gas: 768929)\n[PASS] test_blockedReclaimIsCreditedAndCarryIsReusable() (gas: 1967897)\n[PASS] test_constructorRejectsZeroAddressesAndExcessFee() (gas: 11236)\n[PASS] test_constructorStoresArgumentsWithoutAnyDependencyCalls() (gas: 394597)\n[PASS] test_emptyArcadeWithAgentPlayersCarriesEverythingWithoutTip() (gas: 1964774)\n[PASS] test_emptyAuctionSettlesWithoutTakingCarry() (gas: 851775)\n[PASS] test_everyForbiddenByteRejectedInEveryString() (gas: 30597411)\n[PASS] test_failedOrShortTokenPullRollsBackBidAndAnswers() (gas: 1642681)\n[PASS] test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers() (gas: 2698359)\n[PASS] test_failedRefundAccumulatesAndWithdrawsOnlyOnce() (gas: 1323926)\n[PASS] test_failedStudioPaymentIsCreditedAndSettlementGoesOn() (gas: 846879)\n[PASS] test_failedTipRevertsAndAnotherCallerCanPay() (gas: 1637508)\n[PASS] test_falseAndMalformedRefundsDoNotBlockBids() (gas: 1139296)\n[PASS] test_fullNewBidMustBeFundedBeforeSelfRefund() (gas: 559341)\n[PASS] test_lateSettleKeepsTheFullReclaimGraceForTheBoard() (gas: 2814187)\n[PASS] test_maximumBidSettlesAndPaysWithoutIntermediateOverflow() (gas: 2689714)\n[PASS] test_noReturnTokenBidsRefundsFeesWithdrawalsAndBonus() (gas: 2166408)\n[PASS] test_onePlayerCarriesUnfilledSharesIntoNextAuction() (gas: 1931905)\n[PASS] test_openDayAndBidTimeBoundaries() (gas: 664904)\n[PASS] test_openDayNamesTheExtendedDayUntilItCloses() (gas: 725506)\n[PASS] test_outbidAndSelfRaiseRefundPreviousBid() (gas: 819684)\n[PASS] test_realSwingsPayOnlyAfterArcadeDayClosedAndOnlyTopThree() (gas: 3547081)\n[PASS] test_reclaimGraceBoundaryReturnsOwnNetBidNotCarryToWinner() (gas: 1580309)\n[PASS] test_reclaimRejectsUnsettledEmptyAndAlreadyPaidAuctions() (gas: 826720)\n[PASS] test_reentrantBonusAndReclaimCannotPayTwice() (gas: 2287466)\n[PASS] test_reentrantTokenCannotBidOrWithdrawDuringTransfers() (gas: 1346649)\n[PASS] test_settleOnOrAfterThemeDayKeepsCarryForLaterBoards() (gas: 1543954)\n[PASS] test_settleOneIMDFeeAndSettingsApplyOnlyAtSettlement() (gas: 689632)\n[PASS] test_settleZeroFeeExactlyAndOnlyOnce() (gas: 669513)\n[PASS] test_twoPlayersCarryUnfilledShareIntoNextAuction() (gas: 2523243)\n[PASS] test_vetoOwnerOnlyBeforeThemeDayReturnsOwnNetBidNotCarry() (gas: 1535771)\n[PASS] test_vetoRejectsUnsettledEmptyAndThemeDayBoundary() (gas: 727137)\n[PASS] test_zeroFeeVetoRefundsFullBidAndBlockedWinnerGetsCredit() (gas: 738816)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 371.80ms (432.02ms CPU time)\n\nRan 2 test suites in 372.61ms (731.78ms CPU time): 94 tests passed, 0 failed, 0 skipped (94 total tests)\n","passed":true},{"durationMs":45,"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.buyPacks(uint8,uint256)\",\"SwarmDerby.buyTurns(uint8,uint256)\",\"SwarmDerby.expire(uint256)\",\"SwarmDerby.finalize(uint256,bytes32)\",\"SwarmDerby.leaveSession()\",\"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\":92,\"DEPLOY.md\":259,\"HANDOFF.md\":144,\"LICENSE\":21,\"README.md\":15,\"e2e/Mocks.sol\":27,\"e2e/README.md\":23,\"e2e/board.py\":47,\"e2e/leagues.py\":45,\"e2e/play.py\":63,\"e2e/recover.py\":23,\"e2e/recover_unmined.py\":28,\"e2e/settle.py\":55,\"e2e/setup.py\":30,\"foundry.toml\":9,\"imd-check.mjs\":40,\"specs/README.md\":69,\"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/SwarmDerby.sol\":567,\"test/DerbyAuction.t.sol\":1120,\"test/SwarmDerby.t.sol\":864,\"web/derby-odds.js\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"50c6de42d0c8b6f6f0831c327c01f9f3f74cec4ba59796ae4dc65b253c5df809","verifiedTreeHash":"2a51a0cd20be74df0c0a45f04e0ab522f91082cc","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":31482,"exitCode":0,"name":"build","output":"Compiling 25 files with Solc 0.8.26\nSolc 0.8.26 finished in 31.33s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:436:48\n    │\n436 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:436:55\n    │\n436 │         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:507:9\n    │\n507 │         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:508:9\n    │\n508 │         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:528:9\n    │\n528 │         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:529:9\n    │\n529 │         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:212:9\n    │\n212 │         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:296:91\n    │\n296 │             swings[swingId] = Swing(player, league, 0, velo, Status.Final, 0, bytes32(0), uint32(day));\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:302:25\n    │\n302 │         uint64 target = uint64(ARB_SYS.arbBlockNumber() + REVEAL_DELAY);\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:305:98\n    │\n305 │         swings[swingId] = Swing(player, league, quality, velo, Status.Committed, target, commit, uint32(day));\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[reentrancy-no-eth]: external call can be reentered before `vault` is updated\n    ╭▸ src/SwarmDerby.sol:564:40\n    │\n564 │         (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/SwarmDerby.sol:323:13\n    │\n323 │         if (bh == bytes32(0)) {\n    │             ━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:339:13\n    │\n339 │             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:341:9\n    │\n341 │         emit SwingResolved(swingId, s.player, tier, feet);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:441:51\n    │\n441 │         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:564:40\n    │\n564 │         (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:465:19\n    │\n465 │             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:475:37\n    │\n475 │         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:477:27\n    │\n477 │         _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:564:40\n    │\n564 │         (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:485:9\n    │\n485 │         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[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmDerby.sol:519:32\n    │\n519 │     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:105:18\n    │\n105 │         vm.warp((block.timestamp / 1 days + 1) * 1 days + 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\n","passed":true},{"durationMs":3260,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 54 tests for test/SwarmDerby.t.sol:SwarmDerbyTest\n[PASS] testFuzz_boardsAreTopTen(uint256) (runs: 256, μ: 5071527, ~: 5081487)\n[PASS] testFuzz_settlementConserves(uint256) (runs: 256, μ: 5536621, ~: 5551289)\n[PASS] test_agentLeagueHasNoCap() (gas: 2695596)\n[PASS] test_arcadeCapIsTwentyPerDay() (gas: 2523316)\n[PASS] test_arcadeKeepsLongestAgentKeepsTotal() (gas: 298076)\n[PASS] test_badLeagueRejected() (gas: 32903)\n[PASS] test_boardResetsEachDay() (gas: 216345)\n[PASS] test_buyPackSplitsPerLeague() (gas: 518853)\n[PASS] test_capCountsSessionSwingsForThePlayer() (gas: 2274997)\n[PASS] test_commitBoundToPlayer() (gas: 588030)\n[PASS] test_constructorRejectsZeroAddressesAndFreeTurns() (gas: 1145480)\n[PASS] test_contactNeedsCommit() (gas: 334529)\n[PASS] test_eachDaySettlesOnceInOrder() (gas: 1443282)\n[PASS] test_emptyDayRollsOverWithoutTip() (gas: 1103450)\n[PASS] test_expireUnrevealed() (gas: 613957)\n[PASS] test_finalizeTooEarly() (gas: 503290)\n[PASS] test_finalizeUpdatesArcadeBoard() (gas: 629256)\n[PASS] test_fullSwingMatchesOdds() (gas: 522204)\n[PASS] test_lateFinalizeScoresOnCommitDay() (gas: 664435)\n[PASS] test_lateRevealIsFoul() (gas: 516676)\n[PASS] test_leagueTurnsAreSeparate() (gas: 295691)\n[PASS] test_leaveSessionFreesTheKey() (gas: 205604)\n[PASS] test_nextSettlementBeforeAnything() (gas: 11875)\n[PASS] test_oddsMonotoneInQuality() (gas: 316953)\n[PASS] test_ownerIsConstructorArg() (gas: 2913055)\n[PASS] test_ownerOnlyReachesOps() (gas: 418230)\n[PASS] test_ownershipIsTwoStep() (gas: 169425)\n[PASS] test_ownershipMoveCanBeCancelled() (gas: 113732)\n[PASS] test_parityWithBrowser() (gas: 63207)\n[PASS] test_priceFloor() (gas: 100369)\n[PASS] test_qualityAndVeloBounded() (gas: 317033)\n[PASS] test_revealAtWindowEdgeStillCounts() (gas: 615287)\n[PASS] test_sessionBuysForThePlayer() (gas: 483847)\n[PASS] test_sessionCannotBeClaimedTwice() (gas: 179047)\n[PASS] test_sessionChainsRejected() (gas: 376382)\n[PASS] test_sessionConsentIsSingleUse() (gas: 313925)\n[PASS] test_sessionNeedsTheKeysConsent() (gas: 161365)\n[PASS] test_sessionRevokeAndRotate() (gas: 300545)\n[PASS] test_sessionSwingsForPlayer() (gas: 671328)\n[PASS] test_settleAgentLeague() (gas: 633371)\n[PASS] test_settlePaysOnlyThatDaysPot() (gas: 1162741)\n[PASS] test_settlePaysTheDaysTopThree() (gas: 1224382)\n[PASS] test_settleWaitsForTheDayToEnd() (gas: 927961)\n[PASS] test_settleWaitsForTheLastReveal() (gas: 687692)\n[PASS] test_singleTurnPrice() (gas: 285720)\n[PASS] test_slamPaysTenPercentOfItsLeagueVault() (gas: 4962665)\n[PASS] test_swingStoresVelo() (gas: 449101)\n[PASS] test_tokenWithoutCodeRefusesPurchases() (gas: 3276413)\n[PASS] test_underPowerLineNoBombOrSlam() (gas: 29184887)\n[PASS] test_unpayableSlamKeepsPrizeAndHomer() (gas: 4747467)\n[PASS] test_unpayableWinnerRollsOver() (gas: 997516)\n[PASS] test_whiffCostsTurnNoRoll() (gas: 404595)\n[PASS] test_wrongSaltRejected() (gas: 498546)\n[PASS] test_zeroCountPurchaseReverts() (gas: 77131)\nSuite result: ok. 54 passed; 0 failed; 0 skipped; finished in 213.59ms (496.95ms CPU time)\n\nRan 40 tests for test/DerbyAuction.t.sol:DerbyAuctionTest\n[PASS] testFuzz_conservationAcrossAuctionSequences(uint256) (runs: 256, μ: 13068426, ~: 12806213)\n[PASS] test_adminPermissionsFeeCapAndTwoStepOwnership() (gas: 537169)\n[PASS] test_agentScoresAndOtherDaysNeverAffectArcadeBonus() (gas: 3439055)\n[PASS] test_answerBoundaryValuesStoredAndBidEmitted() (gas: 660479)\n[PASS] test_answerLengthsAndEnums() (gas: 533362)\n[PASS] test_antiSnipeExtendsRepeatedlyAndKeepsOtherDaysIndependent() (gas: 1985845)\n[PASS] test_antiSnipeStopsAtOneHourSoVetoStaysOpen() (gas: 3782541)\n[PASS] test_bidMinimumAndIncrementRoundUp() (gas: 768929)\n[PASS] test_blockedReclaimIsCreditedAndCarryIsReusable() (gas: 1967897)\n[PASS] test_constructorRejectsZeroAddressesAndExcessFee() (gas: 11236)\n[PASS] test_constructorStoresArgumentsWithoutAnyDependencyCalls() (gas: 394597)\n[PASS] test_emptyArcadeWithAgentPlayersCarriesEverythingWithoutTip() (gas: 1964774)\n[PASS] test_emptyAuctionSettlesWithoutTakingCarry() (gas: 851775)\n[PASS] test_everyForbiddenByteRejectedInEveryString() (gas: 30597411)\n[PASS] test_failedOrShortTokenPullRollsBackBidAndAnswers() (gas: 1642681)\n[PASS] test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers() (gas: 2698359)\n[PASS] test_failedRefundAccumulatesAndWithdrawsOnlyOnce() (gas: 1323926)\n[PASS] test_failedStudioPaymentIsCreditedAndSettlementGoesOn() (gas: 846879)\n[PASS] test_failedTipRevertsAndAnotherCallerCanPay() (gas: 1637508)\n[PASS] test_falseAndMalformedRefundsDoNotBlockBids() (gas: 1139296)\n[PASS] test_fullNewBidMustBeFundedBeforeSelfRefund() (gas: 559341)\n[PASS] test_lateSettleKeepsTheFullReclaimGraceForTheBoard() (gas: 2814187)\n[PASS] test_maximumBidSettlesAndPaysWithoutIntermediateOverflow() (gas: 2689714)\n[PASS] test_noReturnTokenBidsRefundsFeesWithdrawalsAndBonus() (gas: 2166408)\n[PASS] test_onePlayerCarriesUnfilledSharesIntoNextAuction() (gas: 1931905)\n[PASS] test_openDayAndBidTimeBoundaries() (gas: 664904)\n[PASS] test_openDayNamesTheExtendedDayUntilItCloses() (gas: 725506)\n[PASS] test_outbidAndSelfRaiseRefundPreviousBid() (gas: 819684)\n[PASS] test_realSwingsPayOnlyAfterArcadeDayClosedAndOnlyTopThree() (gas: 3547081)\n[PASS] test_reclaimGraceBoundaryReturnsOwnNetBidNotCarryToWinner() (gas: 1580309)\n[PASS] test_reclaimRejectsUnsettledEmptyAndAlreadyPaidAuctions() (gas: 826720)\n[PASS] test_reentrantBonusAndReclaimCannotPayTwice() (gas: 2287466)\n[PASS] test_reentrantTokenCannotBidOrWithdrawDuringTransfers() (gas: 1346649)\n[PASS] test_settleOnOrAfterThemeDayKeepsCarryForLaterBoards() (gas: 1543954)\n[PASS] test_settleOneIMDFeeAndSettingsApplyOnlyAtSettlement() (gas: 689632)\n[PASS] test_settleZeroFeeExactlyAndOnlyOnce() (gas: 669513)\n[PASS] test_twoPlayersCarryUnfilledShareIntoNextAuction() (gas: 2523243)\n[PASS] test_vetoOwnerOnlyBeforeThemeDayReturnsOwnNetBidNotCarry() (gas: 1535771)\n[PASS] test_vetoRejectsUnsettledEmptyAndThemeDayBoundary() (gas: 727137)\n[PASS] test_zeroFeeVetoRefundsFullBidAndBlockedWinnerGetsCredit() (gas: 738816)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 400.30ms (469.44ms CPU time)\n\nRan 5 tests for test/DerbyAuction.invariant.t.sol:DerbyAuctionBoundaryTest\n[PASS] testFuzz_failedReplacementPreservesLeaderAnswersDeadlineAndBalances(uint256,uint8) (runs: 1000, μ: 855001, ~: 855099)\n[PASS] testFuzz_minimumIncrementIsSmallestWholeWeiAtLeastFivePercent(uint256) (runs: 1000, μ: 585638, ~: 585788)\n[PASS] test_boardReadRevertRollsBackPaidFlagAndAllowsRetry() (gas: 636065)\n[PASS] test_deploymentUsesExactLaunchArgumentsOnEmptyChain() (gas: 208569)\n[PASS] test_lateSettlementCannotTakeCarryReservedForFutureThemeDay() (gas: 1016140)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 400.37ms (793.14ms CPU time)\n\nRan 2 tests for test/DerbyAuction.invariant.t.sol:DerbyAuctionInvariantTest\n[PASS]\nDerbyAuctionInvariantTest invariants:\n[PASS] invariant_allObligationsRemainFullyBacked\n[PASS] invariant_noValueIsCreatedOrLost\n[PASS] invariant_terminalStatesAndExtensionCapHold\n DerbyAuctionInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭------------------------+-----------------+-------+---------+----------╮\n| Contract               | Selector        | Calls | Reverts | Discards |\n+=======================================================================+\n| AuctionSequenceHandler | advance         | 2076  | 0       | 0        |\n|------------------------+-----------------+-------+---------+----------|\n| AuctionSequenceHandler | bidNow          | 2038  | 0       | 0        |\n|------------------------+-----------------+-------+---------+----------|\n| AuctionSequenceHandler | configure       | 2006  | 0       | 0        |\n|------------------------+-----------------+-------+---------+----------|\n| AuctionSequenceHandler | donate          | 2069  | 0       | 0        |\n|------------------------+-----------------+-------+---------+----------|\n| AuctionSequenceHandler | settle          | 1990  | 0       | 0        |\n|------------------------+-----------------+-------+---------+----------|\n| AuctionSequenceHandler | terminate       | 2113  | 0       | 0        |\n|------------------------+-----------------+-------+---------+----------|\n| AuctionSequenceHandler | transferFailure | 2022  | 0       | 0        |\n|------------------------+-----------------+-------+---------+----------|\n| AuctionSequenceHandler | withdraw        | 2070  | 0       | 0        |\n╰------------------------+-----------------+-------+---------+----------╯\n\n[PASS] test_handlerExercisesCarryCreditsVetoReclaimAndWithdraw() (gas: 3206603)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.16s (3.16s CPU time)\n\nRan 4 test suites in 3.16s (4.18s CPU time): 101 tests passed, 0 failed, 0 skipped (101 total tests)\n","passed":true},{"durationMs":56,"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.buyPacks(uint8,uint256)\",\"SwarmDerby.buyTurns(uint8,uint256)\",\"SwarmDerby.expire(uint256)\",\"SwarmDerby.finalize(uint256,bytes32)\",\"SwarmDerby.leaveSession()\",\"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\":92,\"DEPLOY.md\":259,\"HANDOFF.md\":144,\"LICENSE\":21,\"README.md\":15,\"e2e/Mocks.sol\":27,\"e2e/README.md\":23,\"e2e/board.py\":47,\"e2e/leagues.py\":45,\"e2e/play.py\":63,\"e2e/recover.py\":23,\"e2e/recover_unmined.py\":28,\"e2e/settle.py\":55,\"e2e/setup.py\":30,\"foundry.toml\":9,\"imd-check.mjs\":40,\"specs/README.md\":69,\"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/SwarmDerby.sol\":567,\"test/DerbyAuction.invariant.t.sol\":442,\"test/DerbyAuction.t.sol\":1120,\"test/SwarmDerby.t.sol\":864,\"web/derby-odds.js\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ae71e6d38bcdb7de2c18221c15702ccc37dc3cb7a2fa94df1775c461ab78d7b3","verifiedTreeHash":"5432726be7fb701bd3ce2b2ce6b527686999bc36","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":27986,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 27.79s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:436:48\n    │\n436 │         if (i >= _days[league].length) return (false, false, 0, 0, 0);\n    │                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/SwarmDerby.sol:436:55\n    │\n436 │         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:507:9\n    │\n507 │         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:508:9\n    │\n508 │         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:528:9\n    │\n528 │         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:529:9\n    │\n529 │         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:212:9\n    │\n212 │         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:296:91\n    │\n296 │             swings[swingId] = Swing(player, league, 0, velo, Status.Final, 0, bytes32(0), uint32(day));\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:302:25\n    │\n302 │         uint64 target = uint64(ARB_SYS.arbBlockNumber() + REVEAL_DELAY);\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:305:98\n    │\n305 │         swings[swingId] = Swing(player, league, quality, velo, Status.Committed, target, commit, uint32(day));\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[reentrancy-no-eth]: external call can be reentered before `vault` is updated\n    ╭▸ src/SwarmDerby.sol:564:40\n    │\n564 │         (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/SwarmDerby.sol:323:13\n    │\n323 │         if (bh == bytes32(0)) {\n    │             ━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmDerby.sol:339:13\n    │\n339 │             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:341:9\n    │\n341 │         emit SwingResolved(swingId, s.player, tier, feet);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/SwarmDerby.sol:441:51\n    │\n441 │         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[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[reentrancy-no-eth]: external call can be reentered before `rollover` is updated\n    ╭▸ src/SwarmDerby.sol:564:40\n    │\n564 │         (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:465:19\n    │\n465 │             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:477:27\n    │\n477 │         _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:475:37\n    │\n475 │         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:564:40\n    │\n564 │         (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:485:9\n    │\n485 │         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[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmDerby.sol:519:32\n    │\n519 │     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:105:18\n    │\n105 │         vm.warp((block.timestamp / 1 days + 1) * 1 days + 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\n","passed":true},{"durationMs":488,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 40 tests for test/DerbyAuction.t.sol:DerbyAuctionTest\n[PASS] testFuzz_conservationAcrossAuctionSequences(uint256) (runs: 256, μ: 13358108, ~: 13474504)\n[PASS] test_adminPermissionsFeeCapAndTwoStepOwnership() (gas: 537169)\n[PASS] test_agentScoresAndOtherDaysNeverAffectArcadeBonus() (gas: 3439055)\n[PASS] test_answerBoundaryValuesStoredAndBidEmitted() (gas: 660479)\n[PASS] test_answerLengthsAndEnums() (gas: 533362)\n[PASS] test_antiSnipeExtendsRepeatedlyAndKeepsOtherDaysIndependent() (gas: 1985845)\n[PASS] test_antiSnipeStopsAtOneHourSoVetoStaysOpen() (gas: 3782541)\n[PASS] test_bidMinimumAndIncrementRoundUp() (gas: 768929)\n[PASS] test_blockedReclaimIsCreditedAndCarryIsReusable() (gas: 1967897)\n[PASS] test_constructorRejectsZeroAddressesAndExcessFee() (gas: 11236)\n[PASS] test_constructorStoresArgumentsWithoutAnyDependencyCalls() (gas: 394597)\n[PASS] test_emptyArcadeWithAgentPlayersCarriesEverythingWithoutTip() (gas: 1964774)\n[PASS] test_emptyAuctionSettlesWithoutTakingCarry() (gas: 851775)\n[PASS] test_everyForbiddenByteRejectedInEveryString() (gas: 30597411)\n[PASS] test_failedOrShortTokenPullRollsBackBidAndAnswers() (gas: 1642681)\n[PASS] test_failedPrizeAndRoundingDustCarryWithoutBlockingOthers() (gas: 2698359)\n[PASS] test_failedRefundAccumulatesAndWithdrawsOnlyOnce() (gas: 1323926)\n[PASS] test_failedStudioPaymentIsCreditedAndSettlementGoesOn() (gas: 846879)\n[PASS] test_failedTipRevertsAndAnotherCallerCanPay() (gas: 1637508)\n[PASS] test_falseAndMalformedRefundsDoNotBlockBids() (gas: 1139296)\n[PASS] test_fullNewBidMustBeFundedBeforeSelfRefund() (gas: 559341)\n[PASS] test_lateSettleKeepsTheFullReclaimGraceForTheBoard() (gas: 2814187)\n[PASS] test_maximumBidSettlesAndPaysWithoutIntermediateOverflow() (gas: 2689714)\n[PASS] test_noReturnTokenBidsRefundsFeesWithdrawalsAndBonus() (gas: 2166408)\n[PASS] test_onePlayerCarriesUnfilledSharesIntoNextAuction() (gas: 1931905)\n[PASS] test_openDayAndBidTimeBoundaries() (gas: 664904)\n[PASS] test_openDayNamesTheExtendedDayUntilItCloses() (gas: 725506)\n[PASS] test_outbidAndSelfRaiseRefundPreviousBid() (gas: 819684)\n[PASS] test_realSwingsPayOnlyAfterArcadeDayClosedAndOnlyTopThree() (gas: 3547081)\n[PASS] test_reclaimGraceBoundaryReturnsOwnNetBidNotCarryToWinner() (gas: 1580309)\n[PASS] test_reclaimRejectsUnsettledEmptyAndAlreadyPaidAuctions() (gas: 826720)\n[PASS] test_reentrantBonusAndReclaimCannotPayTwice() (gas: 2287466)\n[PASS] test_reentrantTokenCannotBidOrWithdrawDuringTransfers() (gas: 1346649)\n[PASS] test_settleOnOrAfterThemeDayKeepsCarryForLaterBoards() (gas: 1543954)\n[PASS] test_settleOneIMDFeeAndSettingsApplyOnlyAtSettlement() (gas: 689632)\n[PASS] test_settleZeroFeeExactlyAndOnlyOnce() (gas: 669513)\n[PASS] test_twoPlayersCarryUnfilledShareIntoNextAuction() (gas: 2523243)\n[PASS] test_vetoOwnerOnlyBeforeThemeDayReturnsOwnNetBidNotCarry() (gas: 1535771)\n[PASS] test_vetoRejectsUnsettledEmptyAndThemeDayBoundary() (gas: 727137)\n[PASS] test_zeroFeeVetoRefundsFullBidAndBlockedWinnerGetsCredit() (gas: 738816)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 388.62ms (448.16ms CPU time)\n\nRan 54 tests for test/SwarmDerby.t.sol:SwarmDerbyTest\n[PASS] testFuzz_boardsAreTopTen(uint256) (runs: 256, μ: 5062919, ~: 5079331)\n[PASS] testFuzz_settlementConserves(uint256) (runs: 256, μ: 5528624, ~: 5483768)\n[PASS] test_agentLeagueHasNoCap() (gas: 2695596)\n[PASS] test_arcadeCapIsTwentyPerDay() (gas: 2523316)\n[PASS] test_arcadeKeepsLongestAgentKeepsTotal() (gas: 298076)\n[PASS] test_badLeagueRejected() (gas: 32903)\n[PASS] test_boardResetsEachDay() (gas: 216345)\n[PASS] test_buyPackSplitsPerLeague() (gas: 518853)\n[PASS] test_capCountsSessionSwingsForThePlayer() (gas: 2274997)\n[PASS] test_commitBoundToPlayer() (gas: 588030)\n[PASS] test_constructorRejectsZeroAddressesAndFreeTurns() (gas: 1145480)\n[PASS] test_contactNeedsCommit() (gas: 334529)\n[PASS] test_eachDaySettlesOnceInOrder() (gas: 1443282)\n[PASS] test_emptyDayRollsOverWithoutTip() (gas: 1103450)\n[PASS] test_expireUnrevealed() (gas: 613957)\n[PASS] test_finalizeTooEarly() (gas: 503290)\n[PASS] test_finalizeUpdatesArcadeBoard() (gas: 629256)\n[PASS] test_fullSwingMatchesOdds() (gas: 522204)\n[PASS] test_lateFinalizeScoresOnCommitDay() (gas: 664435)\n[PASS] test_lateRevealIsFoul() (gas: 516676)\n[PASS] test_leagueTurnsAreSeparate() (gas: 295691)\n[PASS] test_leaveSessionFreesTheKey() (gas: 205604)\n[PASS] test_nextSettlementBeforeAnything() (gas: 11875)\n[PASS] test_oddsMonotoneInQuality() (gas: 316953)\n[PASS] test_ownerIsConstructorArg() (gas: 2913055)\n[PASS] test_ownerOnlyReachesOps() (gas: 418230)\n[PASS] test_ownershipIsTwoStep() (gas: 169425)\n[PASS] test_ownershipMoveCanBeCancelled() (gas: 113732)\n[PASS] test_parityWithBrowser() (gas: 63207)\n[PASS] test_priceFloor() (gas: 100369)\n[PASS] test_qualityAndVeloBounded() (gas: 317033)\n[PASS] test_revealAtWindowEdgeStillCounts() (gas: 615287)\n[PASS] test_sessionBuysForThePlayer() (gas: 483847)\n[PASS] test_sessionCannotBeClaimedTwice() (gas: 179047)\n[PASS] test_sessionChainsRejected() (gas: 376382)\n[PASS] test_sessionConsentIsSingleUse() (gas: 313925)\n[PASS] test_sessionNeedsTheKeysConsent() (gas: 161365)\n[PASS] test_sessionRevokeAndRotate() (gas: 300545)\n[PASS] test_sessionSwingsForPlayer() (gas: 671328)\n[PASS] test_settleAgentLeague() (gas: 633371)\n[PASS] test_settlePaysOnlyThatDaysPot() (gas: 1162741)\n[PASS] test_settlePaysTheDaysTopThree() (gas: 1224382)\n[PASS] test_settleWaitsForTheDayToEnd() (gas: 927961)\n[PASS] test_settleWaitsForTheLastReveal() (gas: 687692)\n[PASS] test_singleTurnPrice() (gas: 285720)\n[PASS] test_slamPaysTenPercentOfItsLeagueVault() (gas: 4962665)\n[PASS] test_swingStoresVelo() (gas: 449101)\n[PASS] test_tokenWithoutCodeRefusesPurchases() (gas: 3276413)\n[PASS] test_underPowerLineNoBombOrSlam() (gas: 29184887)\n[PASS] test_unpayableSlamKeepsPrizeAndHomer() (gas: 4747467)\n[PASS] test_unpayableWinnerRollsOver() (gas: 997516)\n[PASS] test_whiffCostsTurnNoRoll() (gas: 404595)\n[PASS] test_wrongSaltRejected() (gas: 498546)\n[PASS] test_zeroCountPurchaseReverts() (gas: 77131)\nSuite result: ok. 54 passed; 0 failed; 0 skipped; finished in 388.63ms (470.11ms CPU time)\n\nRan 2 test suites in 389.55ms (777.25ms CPU time): 94 tests passed, 0 failed, 0 skipped (94 total tests)\n","passed":true},{"durationMs":41,"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.buyPacks(uint8,uint256)\",\"SwarmDerby.buyTurns(uint8,uint256)\",\"SwarmDerby.expire(uint256)\",\"SwarmDerby.finalize(uint256,bytes32)\",\"SwarmDerby.leaveSession()\",\"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\":92,\"DEPLOY.md\":259,\"HANDOFF.md\":144,\"LICENSE\":21,\"README.md\":15,\"e2e/Mocks.sol\":27,\"e2e/README.md\":23,\"e2e/board.py\":47,\"e2e/leagues.py\":45,\"e2e/play.py\":63,\"e2e/recover.py\":23,\"e2e/recover_unmined.py\":28,\"e2e/settle.py\":55,\"e2e/setup.py\":30,\"foundry.toml\":9,\"imd-check.mjs\":40,\"launch.json\":16,\"specs/README.md\":69,\"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/SwarmDerby.sol\":567,\"test/DerbyAuction.t.sol\":1120,\"test/SwarmDerby.t.sol\":864,\"web/derby-odds.js\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"de73315a1acd3d2179d2bcb09a26c851955b0e274b58424f086d15fc065e0f8e","verifiedTreeHash":"30c7326feb218cabca8b01dddb03ddc30f9be5df","verifierVersion":"0.1.0+ad90ce4c"}]}