{"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":"a3f22a32-7027-4391-a4d0-8f779a60ada0","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"57378880e0fe1e0808e5cc879e0eeed4601440b52082ec2682ce5cd034b34002","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"ea5db8ea23a93d7611f9ab749d6255ad6596ee76a985c1261d43e63612dfc3cf","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"ea5db8ea23a93d7611f9ab749d6255ad6596ee76a985c1261d43e63612dfc3cf","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"98a8fea19637cdb4822793b9968b88d98560ad575d19ed68d7ad48e957098192","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"7959af521c127069931ed2a7fec081d32282f8b0d1cb5b9469cb6ae12abf9a23","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"062323a626e1c6969a503688599bb3c999d9be5adeb08016c87fd7c340b94cbb","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b72293c3366fff3f0b93151bca72cc6cbd189dad31d1ccd1d34dd483f2165a36","skillId":"audit-imported-code","subagents":4,"tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"b72293c3366fff3f0b93151bca72cc6cbd189dad31d1ccd1d34dd483f2165a36","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"de9bc8d729b0f82f0b093ba87d757c8efeb0fa3a408b101beb275ea2da9c25d7","dependsOn":["adapt_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","subagents":4,"tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"d2325796819882585e5dc6c706b167b7eb38a16d743c3e0e2a423c1721931693","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"02dfb9715f4854734e1af7ac463e89e9e7028c4d58217177a15aa80c1661f53a","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"4835220326d51fbc3a01a2a6ff1cb6a10af66dc41e35d491d43a1bc013ed6ea5","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"7e47cbf0667b1d2a18e1b7d15af3493f44e580cd2fa8eac4ee68db20d3be264c","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","subagents":4,"tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Launch IMDuel (IMDUEL) from launch.json exactly as committed: the IMDuelHook Uniswap v4 hook with the six constructor arguments listed there (the engine is the ChessEngineV5 already deployed at 0xc21788f704a8b9456f7391a01d8a3d95be215a27; the constructor does not check its code, so the hook builds where the engine has none), the standard launch token src/IMDuelToken.sol (named IMDuel, symbol IMDUEL, 1,000,000,000 fixed, minted to the factory; launch.json's token.contract), and its pool paired with IMD at fee 12500 and tick spacing 60. The hook takes 0.5% of every swap of its pools (0.4% to that pool's reward pools, 0.1% converted into IMDUEL in the main duel in capped batches, half kept for rewards and half burned), in the main duel's first 300 seconds the reward-pool share starts at 25.4% of the swap (0.4% plus 25 points) and falls linearly to 0.4%, all of it to its reward pools (duels opened later don't have it). It has no owner, admin, pause or upgrade path and no backend signer; getHookPermissions() returns exactly the permissions in launch.json. Every swap bids for its team's next chess move, which a later swap plays through the engine. Three design decisions are deliberate and must stay: (1) a move's reward is recorded as owed to its owner and claimed with withdraw / withdrawTo; nothing is ever sent inside a trade, so no recipient runs code while a trader's PoolManager is unlocked; (2) a bid's owner is the address in hookData (20 bytes packed or 32 bytes ABI-encoded; a zero address counts as none), else tx.origin, the wallet that signed the transaction, so a trade through any router or aggregator earns; the known case of a trade relayed for a smart-contract wallet without hookData crediting the relayer is accepted and documented; (3) there is no native ETH route: every duel pairs IMD or IMDUEL, so every protocol slice is in one of them and converts in the main duel. Do not change any contract source, constructor argument or compiler setting: the project builds with forge build and its tests pass with forge test, including launches shaped like the factory's in both token orders and the blank-chain admission test. Token logo: draw IMDuel's existing mark exactly, nothing else. A 3 x 3 chessboard turned 45 degrees so it stands on one corner, a diamond of nine equal squares; the four corner squares and the centre square are dark, the other four light (so the bottom corner is dark, like a1). Around it a thin hollow diamond frame, the chessboard inside it with even clear space on all four sides. One colour: bone #ebe4d5 for the light squares and the frame line, ink #1b1715 for the dark squares and the whole background. Flat and geometric: no letters, no pieces, no gradients, no shading, no texture, no second colour. The mark sits centred and fills about 60% of the width so it survives a circular crop.","parentJobId":null,"planHash":"159bdd78ec8d3edbe7f5b08a5986e98e87e1f9fc4a79794571f64267e96785f3","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"a3f22a32-7027-4391-a4d0-8f779a60ada0","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2671-launch-imduel-imduel-launch-json"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51032","feedbackHash":"26b821334976d82720559ec18fd635d1fd0c17e84841218aa782edabac4a4f5f","nodeKey":"adapt_contract_project","submissionHash":"82001ba14867d3ad649a6d83f9db57e74ac3d1fcf2de9a9351a9fccebf72f1f7","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"56008","feedbackHash":"430ed7368af03f65d750bfefa72c3ab1fa4a7ff1d2cb03c0c2e5209b38c97ec8","nodeKey":"adapt_contract_project","submissionHash":"0aa68897c3bcb0f201dae13343c2ab38f8e2a8374764815c0243bb386624401d","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52254","feedbackHash":"86f4ae3bec173776ddd4b6c88df278a998751639445df11cbb3932c73d25a993","nodeKey":"adapt_contract_project","submissionHash":"57378880e0fe1e0808e5cc879e0eeed4601440b52082ec2682ce5cd034b34002","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52180","feedbackHash":"f2275e4eee409289cc94383a260e386398c46edd51f3a547c03fee5ec21dcce6","nodeKey":"audit_economics","submissionHash":"98a8fea19637cdb4822793b9968b88d98560ad575d19ed68d7ad48e957098192","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51473","feedbackHash":"407548ef6e736c849fdb0dc11918436269e425f9d78a4cbddd6d698ac2ff8d49","nodeKey":"audit_flow","submissionHash":"7959af521c127069931ed2a7fec081d32282f8b0d1cb5b9469cb6ae12abf9a23","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52615","feedbackHash":"418a0e4343e0495ed40bdd33913d1c45dca5f2f943989b5e9271bea9b090721b","nodeKey":"audit_imported_code","submissionHash":"062323a626e1c6969a503688599bb3c999d9be5adeb08016c87fd7c340b94cbb","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"54333","feedbackHash":"1bdaee19ac5aca67488d5289d73dae3ce4f3373fa6972a15fce14523a7d9d20c","nodeKey":"audit_judge","submissionHash":"23b6709cdde228110d4859eb1deb22ba2161e37c00b1c9ea118c798dc20e8177","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51040","feedbackHash":"ecedb3e83734aa3b0d7c0fcec27922efab6ce881f0888ec59dff407411513574","nodeKey":"audit_judge","submissionHash":"b5d6e1ec3dd848d004a0fb9ccb189d59d61936b1f6cc6b29ab6302633515dfe4","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52600","feedbackHash":"ad517393ce433902e4ec02633fe523f5aa11fc75cd6b3d481f19c70cc8e08e61","nodeKey":"audit_judge","submissionHash":"de9bc8d729b0f82f0b093ba87d757c8efeb0fa3a408b101beb275ea2da9c25d7","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52138","feedbackHash":"e66d103dfebe4468261dcd717a6a19f560380b7513190a2ad1d4152a551ab1ab","nodeKey":"audit_math","submissionHash":"d2325796819882585e5dc6c706b167b7eb38a16d743c3e0e2a423c1721931693","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52419","feedbackHash":"1c90c543727644f77f4e69fbba1052b0ad19902eea6409f01d546c60655339ec","nodeKey":"audit_permissions","submissionHash":"02dfb9715f4854734e1af7ac463e89e9e7028c4d58217177a15aa80c1661f53a","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"54149","feedbackHash":"7da8a1124ba159c9d8579f4586ab94eb169e517e1c71f707f3fc3f1bff46ea53","nodeKey":"manifest","submissionHash":"63563b8be837a40384608cf30952375fedf451b9b2199b43975e80e2aca4386b","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52681","feedbackHash":"12cf7b2bacf6d2ed9fe5be2e4c433862406e01107d360321d9da5fee7d322b33","nodeKey":"manifest","submissionHash":"4835220326d51fbc3a01a2a6ff1cb6a10af66dc41e35d491d43a1bc013ed6ea5","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51313","feedbackHash":"537cdb793a329355227b7429dd81eeb1447980f475196602e32e10e8b59c0d06","nodeKey":"manifest","submissionHash":"b41053948ae65398ef44d51c036f87ace5517f29af9a52188c36c23058bc7b0e","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51203","feedbackHash":"96946f2f9cb80c6625ef66f34b27066850ffa926a2ebeedf519d9aa67d1c40bc","nodeKey":"write_foundry_tests","submissionHash":"50c6fc57d604d7b6e80007c3639d625a765d2e4a4028e34d942e0662295baa59","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52396","feedbackHash":"cdade147f06261132d43d216916e444f60051e281d03c2af8ea8e049786c8de0","nodeKey":"write_foundry_tests","submissionHash":"7e47cbf0667b1d2a18e1b7d15af3493f44e580cd2fa8eac4ee68db20d3be264c","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51367","feedbackHash":"16925679fcc9daaf91452ccb59b72a177d86a1cefda593e74f40ec2ea4310ffc","nodeKey":"write_foundry_tests","submissionHash":"3b3268d29bc97cf76fef270239b03d6a60f44a7971dd066b287bd2ab6e3a181c","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"bf6a7b1379f6c7264c513165a68ae793c55fe717fd0c4e8ed2a7f01ebdc02e75","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7e50667f872c7f5e","findings":[{"citation":"resolved","description":"Asymmetry between the two delivery paths of a reward. withdrawTo(c, to) forwards `to` unchecked to _send -> manager.take(c, to, amount). For an ERC-20 reward (IMD, IMDUEL) a zero `to` reverts inside the token's transfer (IMDuelToken._transfer rejects to == address(0)), so the owed balance survives. For a native-ETH reward (any ETH/IMD or ETH/IMDUEL duel, which anyone may open on this hook: afterInitialize only requires one side to be IMD or IMDUEL) the PoolManager's native transfer to address(0) succeeds, `owed` is already zeroed at line 373, and the reward is gone. The token contract and `approve` both refuse the zero address; the hook's only user-named destination does not. Only the owed party can trigger it (withdraw(who, c) always pays `who`), so this is a footgun for integrators passing an uninitialised recipient, not an attack: severity info. Minimal fix: `if (to == address(0)) revert BadValue();` in withdrawTo (or in _withdraw), which changes no intended behaviour.","line":366,"path":"src/IMDuelHook.sol","reproduction":"State: an ETH/IMD duel opened on the hook (PoolKey(ADDRESS_ZERO, IMD, 3000, 60, hook)), its ETH chest funded with fundChest{value: 5 ether}(key, false, 5 ether), and owed[A][0] == 1 ether for some owner A (a reward from a move of ETH's team; in the scratch test the mapping entry is written with vm.store after locating the slot). Call, as A: hook.withdrawTo(Currency.wrap(address(0)), address(0)). Expected: revert (as the ERC-20 path and the token's own zero-address checks do) and owed[A][0] still 1 ether. Actual: the call succeeds, owed[A][0] == 0, address(0).balance grows by exactly 1 ether and the hook's ETH claims fall by 1 ether. Verified with test/scratch/Perm.t.sol::test_withdrawToZeroBurnsEth on this tree (passes, i.e. the burn happens).","severity":"info","snippet":"    function withdrawTo(Currency c, address to) external {\n        _withdraw(msg.sender, c, to);\n    }","title":"withdrawTo accepts the zero address as destination: a native-ETH reward sent there is burned, while the ERC-20 path reverts"}],"hash":"02dfb9715f4854734e1af7ac463e89e9e7028c4d58217177a15aa80c1661f53a","nodeId":"45be7fc2-833c-41ff-a9c8-288085accb27","outcome":"completed","summary":"Both scratch checks pass: the hookData owner parsing behaves exactly as documented, and the zero-destination ETH burn in withdrawTo is confirmed. The findings file is written and its snippet matches the tree.\n\n**Outcome.** The permission model of IMDuelHook and IMDuelToken holds. I found no access-control bypass, trust gap or asymmetry that loses funds or breaks a guarantee. One info-level finding is recorded in `.imd-findings.json`, with a coverage row for all 12 entry points plus four invariant and trust-assumption rows.\n\n**What I checked, by guide**\n\n- **Access Control.** Every callback refuses callers other than the PoolManager. The main-duel binding in afterInitialize is one-shot and cannot be front-run, since a pool naming the hook before it has code fails the manager's return-data check and the factory deploys and initializes in one transaction. unlockCallback is only ever reached by the hook's own unlock, convertBatch only by the hook itself, and fundChest pulls only from msg.sender. No setter, owner, delegatecall or selfdestruct exists, and launch.json's constructor arguments and permissions match the source and the deployed engine record.\n- **Trust Gap.** Permissionless convert cannot make the hook buy outside its 0.1% band or more than one batch per block. Permissionless withdraw only delivers to the owed party. A hostile recipient or token acting inside the hook's own unlock either hits AlreadyUnlocked or leaves a nonzero delta that reverts the whole claim. Rewards are never sent inside a trade, so no code runs while a trader's manager is unlocked.\n- **Asymmetry.** Exact-input and exact-output fee paths, the ETH and ERC-20 branches of fundChest, withdraw versus withdrawTo, and the before/after fee split were diffed. The one asymmetry with an effect is the finding below.\n\n**Finding (info).** withdrawTo passes its destination unchecked. For a native-ETH reward in an ETH-paired duel, which anyone may open on this hook, a zero destination burns the reward, while the same call on an ERC-20 reward reverts. Only the owed party can trigger it. The reproduction is in the finding and verified by a scratch test.\n\n**Verification.** The full suite passes with the project's fuzz seed, 152 of 152. Nothing in src, launch.json or configuration was changed. The scratch tests live under test/scratch/ and are not part of the submission.\n\n**Not reached.** Economics of the batch price band, engine gas pathologies and chess-rule correctness are outside this area and were not audited beyond what the permission paths touch.","treeHash":null,"usage":{"cachedInputTokens":1824794,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":58161,"runtime":"claude","turns":37,"wallClockMs":1058493}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b8fd8054ea57c5d8","findings":[{"citation":"resolved","description":"The brief requires that the project's tests pass with forge test, but this one fails on the tree as committed. forge test (forge 1.8.3, foundry.toml as committed) runs 152 tests: 151 pass and 1 fails, LaunchTest.test_launchPairedWithEth with 'assertion failed: 8 <= 20'. The hook is not at fault. In this deterministic run, game 0 of the ETH-paired main duel ends with White checkmating on its 23rd half-move: GameOver(pool, gameNo 0, result 1, plies 23) is emitted, then GameStarted(gameNo 1). The hook starts game 1 and resets g.ply to 0 (_newGame), so after the 30-block loop the pool stands at gameNo 1, ply 8. The test checks the half-move counter of the current game (st().ply > 20) when it means 'a move every block'. Any finished game breaks that check, whatever the moves were. The two IMD-paired launch tests (test_launchTokenBelowImd / AboveImd, line 101) use the same check and pass only because their seeds do not finish a game within 31 moves. Fix it in the test, not the contracts: count moves across games, for example by counting Moved events, or by asserting st().gameNo > 0 || st().ply > 20.","line":137,"path":"test/Launch.t.sol","reproduction":"From the repository root on the committed tree: `forge test --match-path test/Launch.t.sol`. Expected: 3 passed, because the brief says the tests pass. Actual: 'Suite result: FAILED. 2 passed; 1 failed', with '[FAIL: assertion failed: 8 <= 20] test_launchPairedWithEth()'. Running it with -vvvv shows `emit GameOver(..., gameNo: 0, result: 1, plies: 23)` and then `emit GameStarted(..., gameNo: 1)`. At the assertion, game(id) gives gameNo = 1 and ply = 8. A full `forge test` reports '151 tests passed, 1 failed'.","severity":"medium","snippet":"        assertGt(st().ply, 20);","title":"forge test fails: test_launchPairedWithEth assumes game 0 never ends, but White mates at ply 23"}],"hash":"062323a626e1c6969a503688599bb3c999d9be5adeb08016c87fd7c340b94cbb","nodeId":"22a61f7f-18cf-41db-98c8-e8adf633cbdf","outcome":"completed","summary":"The audit turned up no defect in the contracts. There is one finding, and it is in the tests: `forge test` does not fully pass. It's recorded in `.imd-findings.json`. I changed no repository files.\n\n**Finding (medium): one test fails.**\n- **Where:** `test/Launch.t.sol:137`, `assertGt(st().ply, 20);` in `test_launchPairedWithEth`.\n- **Result:** a full `forge test` (forge 1.8.3) gives 151 passed and 1 failed, with `assertion failed: 8 <= 20`.\n- **Cause:** in this run, White checkmates at ply 23 (`GameOver(gameNo 0, result 1, plies 23)`). The hook then starts game 1 and resets `ply` to 0, so by the assertion the pool is at game 1, ply 8. The test reads the current game's move counter as if it counted moves across all games.\n- **Fix:** change the test, not the contracts — count `Moved` events, or assert `gameNo > 0 || ply > 20`. The two IMD-paired launch tests use the same check and pass only because their games don't end that early.\n\n**What I checked and found sound:**\n- **Engine:** the code at `0xc21788f7…5a27` on mainnet is byte-for-byte the local `ChessEngineV5` runtime (23,339 bytes), fetched from a public RPC.\n- **Accounting:** the hook's claims always equal chests plus the conversion pile plus rewards owed, on every path that changes them. The fees taken before and after the swap net to zero against the pool, and the partial-fill check matches how v4 adjusts the swap amount.\n- **Callbacks and calls:** every hook callback accepts only the PoolManager. `unlockCallback` only runs from the hook's own `unlock`. `convertBatch` can only be called by the hook itself.\n- **Reentrancy:** `withdraw`, `fundChest` and `convert` can't run while another trade has the PoolManager unlocked. Nothing is sent to a reward owner during a trade; the only transfer inside a trade is the burn to `0x…dEaD`, which runs no code.\n- **Conversion:** batches are capped, run at most once per block, and buy only near the best of three block-start prices. That price can't be moved without passing through the hook, so a price pushed within one block can't overcharge the hook.\n- **Gas:** a trade sent with too little gas for the engine reverts rather than playing a weaker move. A trade sent at the wallet's gas estimate still converts a due batch (the repo's own tests cover both).\n- **Launch rules:** no owner, admin, pause, upgrade path or signer, and no minting after launch. Scanning reachable bytecode found no DELEGATECALL, CALLCODE or SELFDESTRUCT in the hook (17,403 bytes), the token or the engine.\n- **Manifest:** `getHookPermissions()` matches launch.json exactly. The six constructor arguments are in declaration order, fee 12500 is accepted, and notes are 3,382 characters (under 4,000).\n- **Token:** a plain fixed-supply ERC-20 (1,000,000,000 IMDUEL, 18 decimals) minted entirely to its deployer.\n- **Tests:** the launch tests in both token orders and the blank-chain admission tests pass.\n\n**Coverage:**\n- **Read in full:** `IMDuelHook.sol`, `IMDuelToken.sol`, `Strength.sol`, `IChessEngine.sol`, `Rules.sol`, `Chess.sol`, launch.json and the other launch files, the four protected tests, and the relevant repo tests.\n- **Not read line by line:** `ChessEngineV5.sol` and `Bitboard.sol`, the chess logic. I checked only that the engine doesn't depend on gas, sender or block values and that it matches what's deployed. Whether every move it plays is legal is left to the repo's chess tests.\n- **Not run:** Slither, which I couldn't install here. The protected floor tests, which need verifier files that aren't in this repo; I ran their bytecode and permission checks myself instead.\n- **No helpers:** I made the twelve specialty passes from the Pashov guide myself.\n\nTwo small manifest points, not filed as findings:\n- The notes still say the engine address \"is replaced… before this launch is opened\", but the real address is already in the arguments.\n- `token.constructorArgs` and `token.totalSupply` aren't schema keys, so they're dropped.","treeHash":null,"usage":{"cachedInputTokens":2578501,"inputTokens":54,"model":"claude-opus-5-5","outputTokens":52903,"runtime":"claude","turns":28,"wallClockMs":686417}},{"artifacts":[],"attempt":1,"bundleHash":"cb8a4bf42f337d8ab5d1bcea7ce86dbc905277199f3721678f7fffde3e92a1d7","device":"354bd4842bcfd989","findings":[],"hash":"0aa68897c3bcb0f201dae13343c2ab38f8e2a8374764815c0243bb386624401d","nodeId":"bf5b7810-0017-4ccd-a50a-78b19aefe981","outcome":"completed","summary":"Fixed the reproduced test failure by counting moves across game resets. Added the exact SVG logo and documented all changes in ADAPTATION.md.\n\nContracts, `launch.json`, compiler settings, and dependencies remain unchanged.\n\nValidation: `forge build` succeeded; all **152 tests passed** with the supplied fuzz seed, including both token orders and blank-chain admission.","treeHash":"d58e37d925fc85d9f66e206682cef9845389b22f","usage":{"cachedInputTokens":2467072,"inputTokens":155766,"model":"gpt-6-astra","outputTokens":13056,"runtime":"codex","turns":8,"wallClockMs":502360}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4b046083653bdcb3","findings":[{"citation":"resolved","description":"Settles the prior medium 9537d3ff. The author's fix (_sampleDepth, lines 516-526) does stop the bracket I reported: the attached proof Proof_9537d3ff1425.t.sol now passes (Bob near 9,000 like Alice), and test/JitStrength.t.sol covers it. But the fix rests on the claim at lines 509-514 that the first observation of a block 'comes before any swap of it has changed it' and that liquidity 'has to be in the pool at the start of three traded blocks ... held through two public ones'. The hook has no liquidity callbacks, so a modifyLiquidity before the block's first swap is invisible, and the first swap's sample (line 519, manager.getLiquidity read at line 289) already includes it. An attacker that opens three traded blocks with [add L, 100 wei swap, remove L] in one transaction each makes all three samples L while the pool holds L at no public moment and at no block boundary. The min-of-three at lines 522-525 is then L. In the third block, after its bracket, the victim's trade is measured by _trade (lines 634-637) against L and Strength.fromShare returns the floor, exactly as before the fix, while the attacker's own trade, made as the first swap of the next block with no bracket, samples the honest 1e24, which becomes the minimum of the three, and plays at the cap. Cost: gas plus the LP and hook fee on 300 wei; the liquidity is returned in the same transaction, so no capital is held and the attacker's own bids are not weakened. Compared with the original bracket the attacker must be the first swapper of the victim's block and of two earlier traded blocks (on a quiet pool, any two), so the bar is somewhat higher but the economic effect is identical: the victim keeps paying the 0.5% hook fee and owns the move, but the engine plays it at ~0%, so the victim captures less and blunders more and the other team's bidders collect the chests. Same impact as 9537d3ff, so medium. Reported this round by write_foundry_tests (b1b6bbcd); reproduced here by running its proof on this tree. Root cause: without afterAddLiquidity the hook has no observation of liquidity that is only ever present inside a transaction, so no sampling rule driven by swaps alone can exclude it (any rule that averages or takes the min over N swap-sampled blocks is defeated by N self-contained brackets). Fix that keeps the design: enable afterAddLiquidity (a LOW-risk permission; the matching address bit and launch.json's permissions list change in step) and, when a pool's block has not been sampled yet, record the block's start liquidity there as getLiquidity(id) minus the add's liquidityDelta (the liquidity before the add), so a same-block add can never raise the block's sample; a remove before the first swap only lowers the sample, which is the self-harming direction already documented. The factory's zero-liquidity fee collection is a remove and is untouched. Alternatively, time-lock removes with beforeRemoveLiquidity (let liquidityDelta == 0 through for the factory). If neither is acceptable, the limitation must be documented instead of the guarantee at lines 509-514 and Strength.sol line 4.","line":518,"path":"src/IMDuelHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolSwapTest} from \"v4-core/src/test/PoolSwapTest.sol\";\nimport {PoolModifyLiquidityTest} from \"v4-core/src/test/PoolModifyLiquidityTest.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {SwapParams, ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\nimport {StateLibrary} from \"v4-core/src/libraries/StateLibrary.sol\";\nimport {MockERC20} from \"solmate/src/test/utils/mocks/MockERC20.sol\";\nimport {IMDuelHook, IMDUEL_HOOK_FLAGS} from \"src/IMDuelHook.sol\";\n\n/// _sampleDepth takes each block's sample at the block's first swap and assumes nothing changed the liquidity before\n/// it. The hook has no liquidity callbacks, so a bracket [add liquidity, dust swap, remove liquidity] that is the\n/// first swap of a block records the inflated liquidity as \"the start of the block\", although the pool held it for\n/// no public moment at all. Three such brackets (the victim's own block being the third, ahead of the victim's\n/// trade) make the minimum of the three samples the inflated depth, and a victim trading later in that block, when\n/// the pool holds only its honest liquidity, bids at the strength curve's floor.\ncontract DepthFirstSwapTest is Test {\n    using PoolIdLibrary for PoolKey;\n    using StateLibrary for IPoolManager;\n\n    uint160 constant SQRT_PRICE_1_1 = 79228162514264337593543950336;\n    IPoolManager manager;\n    PoolSwapTest swapRouter;\n    PoolModifyLiquidityTest lpRouter;\n    IMDuelHook hook;\n    PoolKey key;\n    PoolId id;\n\n    function setUp() public {\n        manager = IPoolManager(vm.deployCode(\"PoolManager.sol:PoolManager\", abi.encode(address(this))));\n        swapRouter = PoolSwapTest(vm.deployCode(\"PoolSwapTest.sol:PoolSwapTest\", abi.encode(manager)));\n        lpRouter = PoolModifyLiquidityTest(vm.deployCode(\"PoolModifyLiquidityTest.sol:PoolModifyLiquidityTest\", abi.encode(manager)));\n        MockERC20 a = new MockERC20(\"A\", \"A\", 18);\n        MockERC20 b = new MockERC20(\"B\", \"B\", 18);\n        (Currency c0, Currency c1) = address(a) < address(b)\n            ? (Currency.wrap(address(a)), Currency.wrap(address(b)))\n            : (Currency.wrap(address(b)), Currency.wrap(address(a)));\n        for (uint256 i; i < 2; i++) {\n            MockERC20 t = i == 0 ? a : b;\n            t.mint(address(this), 2 ** 200);\n            t.approve(address(swapRouter), type(uint256).max);\n            t.approve(address(lpRouter), type(uint256).max);\n        }\n        address engine = vm.deployCode(\"ChessEngineV5.sol:ChessEngineV5\");\n        address at = address(IMDUEL_HOOK_FLAGS | (uint160(0x1D0E1) << 40));\n        // the launch's shape: IMD (here c0), minimums, three-block turns\n        deployCodeTo(\"IMDuelHook.sol:IMDuelHook\", abi.encode(manager, engine, c0, 10e18, 1_000_000e18, 3), at);\n        hook = IMDuelHook(at);\n        key = PoolKey(c0, c1, 12500, 60, IHooks(at));\n        id = key.toId();\n        manager.initialize(key, SQRT_PRICE_1_1);\n        lp(1e24); // the pool's honest, standing liquidity\n        vm.warp(block.timestamp + 400); // past the opening surcharge, within the turn timeout\n        vm.roll(block.number + 1);\n    }\n\n    function lp(int256 liquidity) internal {\n        lpRouter.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, liquidity, 0), \"\");\n    }\n\n    function swap(bool zeroForOne, uint256 amountIn, address owner) internal {\n        swapRouter.swap(\n            key,\n            SwapParams(zeroForOne, -int256(amountIn), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),\n            PoolSwapTest.TestSettings(false, false),\n            abi.encodePacked(owner)\n        );\n    }\n\n    /// The side to move's top bid.\n    function topBid() internal view returns (IMDuelHook.TopBid memory) {\n        IMDuelHook.Game memory g = hook.game(id);\n        return g.bids[(g.gameNo & 1) ^ (g.slice ^ 1) ^ (g.ply & 1)];\n    }\n\n    /// White (the team buying currency1) is to move. A 1e22 trade is a 1% share of the pool's 1e24.\n    function test_victimShareMeasuredAgainstHonestDepth() public {\n        // control: with no attacker, the 1% share plays near the 90% cap\n        uint256 snap = vm.snapshotState();\n        swap(true, 1e22, address(0xA11CE));\n        uint16 honest = topBid().strength;\n        assertGe(honest, 8_000, \"control: a 1% share\");\n        vm.revertToState(snap);\n\n        // three blocks, each opened by an atomic bracket around a dust swap; the liquidity is gone by its end\n        for (uint256 i; i < 3; i++) {\n            if (i > 0) {\n                vm.warp(block.timestamp + 12);\n                vm.roll(block.number + 1);\n            }\n            lp(1e27);\n            swap(false, 100, address(0xBAD)); // the block's first swap: samples 1e27 + 1e24\n            lp(-1e27);\n        }\n        assertEq(manager.getLiquidity(id), 1e24, \"the pool holds only its honest liquidity again\");\n\n        // the victim's trade, later in the third block, against a pool that held 1e24 at the start of every block\n        swap(true, 1e22, address(0xA11CE));\n        IMDuelHook.TopBid memory v = topBid();\n        assertEq(v.owner, address(0xA11CE));\n        // expected: about `honest` (>= 8,000, the pool never held more than 1e24 at any public moment)\n        // actual: the curve's floor, measured against 1e27 that was in the pool only inside the attacker's brackets\n        assertGe(v.strength, 8_000, \"victim's share measured against liquidity never held at a block's start\");\n    }\n}","reproduction":"Main duel IMD/X, fee 12500, spacing 60, real IMDuelHook with the launch's shape (minImd 10e18, minImduel 1e24, turnBlocks 3), price 1:1, 1e24 full-range liquidity, 400 s after opening. Control: White buys with 1e22 (a 1% share) -> top bid strength >= 8,000 (8,987). Attack: in each of three consecutive blocks, in one transaction: modifyLiquidity(+1e27 full range), swap 100 wei oneForZero (the block's first swap), modifyLiquidity(-1e27); getLiquidity is 1e24 again after each. Then, in the third block, the victim buys with 1e22, hookData = victim. Expected: strength about the control's (>= 8,000), since the pool never held more than 1e24 at any block boundary or public moment. Actual: the victim owns the move at strength 0. Run: copy the attached proof to test/scratch/DepthFirstSwap.t.sol and `forge test --match-path test/scratch/DepthFirstSwap.t.sol` -> FAIL \"victim's share measured against liquidity never held at a block's start: 0 < 8000\" on this tree.","severity":"medium","snippet":"        if ((s >> 168) & 0xffffffffff != block.number) {\n            s = (block.number << 168) | ((s << SAMPLE_BITS) & ((1 << 168) - 1)) | _pack(uint160(liquidity));\n            depths[id] = s;","title":"Sampled bid depth is still inflatable at no cost: a block's first swap records liquidity added in the same transaction as that block's start liquidity, so three self-contained brackets play a victim's"}],"hash":"23b6709cdde228110d4859eb1deb22ba2161e37c00b1c9ea118c798dc20e8177","nodeId":"1ded2cd8-f75c-475f-8994-4ebef921000c","outcome":"completed","summary":"The review is written to `.imd-findings.json`. One medium finding is kept, carried from last round's JIT issue; the other four prior findings are confirmed fixed.\n\n**Settled from last round**\n\n- **9537d3ff (JIT bracket, medium): partially fixed.** Both attached proofs now pass, and the author's new test file covers the reported same-block bracket. But the root cause survives in a different shape, below.\n- **c1752b40 (withdrawTo zero address): fixed.** Line 392 reverts before the owed balance is touched. The author's test passes.\n- **8c23f3ef (batch bound off by 9 wei): fixed.** The bound is now exactly ten minimums, with the overflow-safe check kept first.\n- **68825ec7 (zero minimum accepted): fixed.** The constructor rejects either zero minimum. The launch's arguments are unaffected.\n- **64cb1176 (burn inside a trade, docs): fixed.** The contract notes now name the burn as the one transfer a trade makes.\n\n**Kept this round (medium, with proof)**\n\nThe sampled depth in `_sampleDepth` is written by a block's first swap, but the hook has no liquidity callbacks, so an add in the same transaction before that swap is already inside the sample. Three one-transaction brackets of add, dust swap, remove across three traded blocks make all three samples inflated while the pool holds that liquidity at no block boundary. A victim trading later in the third block is measured against it and plays at strength 0; the attacker's next-block trade samples honest liquidity and plays at the cap. Cost is gas plus fees on 300 wei. The tester's proof fails on this tree with the stated message and is attached. The suggested fix is to enable afterAddLiquidity and record a block's start liquidity as the pre-add liquidity, with launch.json's permissions updated in step, or to document the limitation instead of the guarantee.\n\n**Other checks**\n\n- Full suite: 172 passed, 0 failed.\n- All 12 entry points answered in the coverage record, plus two invariant rows. Only beforeSwap and afterSwap reference the finding.\n- Static analysis leads (XOR in teamOf, strict equalities, reentrancy, uninitialized locals) were read and are not defects.\n- The scratch copies of the proofs were removed, so no tracked file changed.","treeHash":null,"usage":{"cachedInputTokens":586242,"inputTokens":194,"model":"claude-fable-5-1","outputTokens":13423,"runtime":"claude","turns":12,"wallClockMs":382929}},{"artifacts":[],"attempt":1,"bundleHash":"f36c411454b6c777c23d48a7eed1fe5f5516334972aff6554e1aa1c520b13414","device":"ddfb1efa72fe9a94","findings":[{"description":"_batch returns the whole pile unless amount / BATCH_MINS > min. Integer division means a pile in [10*min, 10*min + 9] passes as 'not over the cap' and the batch spends all of it, so it spends up to BATCH_MINS - 1 wei more than the documented 'at most 10 minimums'. The economic effect is negligible (9 wei against a 100 IMD cap at the launch's minImd = 10e18). It is reported because the code does not match its documented bound. A fix such as `amount > BATCH_MINS * min ? BATCH_MINS * min : amount` makes the bound exact.","line":451,"path":"src/IMDuelHook.sol","reproduction":"Harness hook with minImd = minImduel = 1e15 and main duel currency0 = IMD. Run trade(1, (10e15 + 9) * 1000) so that pile(IMD) = 10e15 + 9, then sampleBlocks(pool). Expected: spent <= 10e15. Actual: spent = 10000000000000009 (the whole pile). test/Edges.t.sol:test_aPileJustOverTheCapSpendsTenMinimums covers the cap where it does hold (a pile of 10.01e15 spends exactly 10e15).","severity":"info","title":"A conversion batch can spend up to 9 wei more than its ten-minimum cap"},{"description":"The constructor accepts minImd_ = 0 and minImduel_ = 0. With min = 0, _batch returns BATCH_MINS * 0 = 0 for any pile of 10 wei or more, and _swapClaims returns (0, 0) on amountIn == 0. The IMD slice is then never converted, by trades or by convert(), and never feeds the $IMDUEL chest or the burn. This launch is not affected: launch.json passes 10e18 and 1e24. It matters only if the hook is reused with a zero minimum. Rejecting 0 in the constructor (BadConfig), or treating 0 as 'no cap', would close it.","line":451,"path":"src/IMDuelHook.sol","reproduction":"Harness hook with minImd = minImduel = 0. Run trade(1, 1000e18) (pile = 1e18 IMD), sampleBlocks(pool), next(12), then hook.convert(IMD). Expected: some of the pile converts. Actual: pile stays exactly 1e18.","severity":"info","title":"minImd or minImduel of 0 stops conversion for good"}],"hash":"3b3268d29bc97cf76fef270239b03d6a60f44a7971dd066b287bd2ab6e3a181c","nodeId":"d4d33cc8-e851-4432-8ff7-69e38f9d0ee9","outcome":"completed","summary":"I added 8 tests in `test/Edges.t.sol`. The full suite passes with the verifier's seed: 160 tests in 24 suites, none failing or skipped. I found no serious defect, and I reported two minor ones in `.imd-findings.json` instead of writing tests that pass on them. I changed no contract source, configuration or launch file.\n\n**New tests (they cover gaps in the existing suite):**\n- **Who earns a bid** (`OwnerShapesTest`):\n  - A 20-byte address or a 32-byte encoded address in hookData gets the bid.\n  - Otherwise the wallet that signed the transaction gets it, not the router. That covers empty hookData, a zero address in either form, a 32-byte value too wide to be an address, and lengths of 19, 21 and 64 bytes.\n  - A fuzz test checks the rule exactly as the brief states it, over random addresses, values and byte strings.\n  - A bid that is only 5% higher doesn't take the move from the current top bidder.\n- **Conversion batches** (`BatchCapTest`):\n  - A pile just over the cap converts exactly 10 minimums in one batch and leaves the rest waiting.\n  - A pile under one minimum isn't converted by trades, but anyone can still convert it by calling `convert()`.\n  - Nothing converts before three blocks have been sampled.\n  - The hook's IMD holdings still equal what it owes afterwards.\n- **`previewMove`** (`PreviewEdgesTest`, three-block windows): it reports nothing before the window's last block, or when nobody has bid, and is ready only in that last block.\n\n**Reported in `.imd-findings.json`** (both minor, each reproduced with a test I ran and saw fail):\n1. **A batch can spend up to 9 wei more than its cap** (`src/IMDuelHook.sol:451`). Because of integer division, a pile between 10 minimums and 10 minimums + 9 wei is converted whole. With a pile of 10e15 + 9 the batch spent 10000000000000009 against a 10e15 cap. The amount is negligible, but the code doesn't hold its stated limit. The finding includes a one-line fix.\n2. **A minimum of 0 stops conversion for good.** The constructor accepts 0, and then every batch spends nothing: a 1e18 pile stayed exactly 1e18 after `convert()`. This launch isn't affected because launch.json sets 10 IMD and 1,000,000 IMDUEL. It would matter only if the hook were reused with a zero minimum.\n\nThe existing suite already had invariant tests over random call sequences for the hook's holdings and the token's fixed supply, so I didn't add more. I haven't committed anything; the new file and the findings file are in the working tree.","treeHash":"a99ca68abaf9825314cf28e923d2b08598b7aff2","usage":{"cachedInputTokens":1505802,"inputTokens":32,"model":"claude-opus-5-5","outputTokens":33851,"runtime":"claude","turns":18,"wallClockMs":707129}},{"artifacts":[],"attempt":1,"bundleHash":"8d72219c5ed444b77fb48cfa8abc353f658765625a8fcfedafbe20c622620fda","device":"1a7606be97f168d4","findings":[],"hash":"4835220326d51fbc3a01a2a6ff1cb6a10af66dc41e35d491d43a1bc013ed6ea5","nodeId":"5a8d0013-bc3e-41b1-bd04-0c7d852e38f1","outcome":"completed","summary":"Done. The root launch.json is written and is the only file changed. The build succeeds and the full suite passes with the verifier's fuzz seed, 163 tests across 22 suites.\n\n**What launch.json describes**\n\n- **Hook** IMDuelHook with six constructor arguments in declaration order: `$poolManager`, the deployed ChessEngineV5 address, IMD as the pair currency, minImd of 10 IMD, minImduel of 1,000,000 IMDUEL, and turnBlocks 3. These match the constructor signature in the hook source and the values in the repository's launch/hook.json, with the engine placeholder there replaced by the real address the brief gives.\n- **Permissions** afterInitialize, beforeAddLiquidity, beforeSwap, afterSwap, beforeSwapReturnDelta and afterSwapReturnDelta. I checked these against getHookPermissions in src/IMDuelHook.sol, and the repository's LaunchFiles test asserts the same set against the hook's flag constant.\n- **Token** IMDuelToken, name IMDuel, symbol IMDUEL, 18 decimals. I dropped the non-schema keys the previous file carried for token constructor arguments and total supply, since supply is not a manifest field.\n- **Pool** paired with IMD at 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7, fee 12500, tick spacing 60, initial price \"79228162514264337593543950336\", exactly as the launch facts give them.\n- **Notes** at 3728 characters, under the 4000 cap. They cover the no-owner design, the 0.5% hook fee split and the 300-second opening schedule, the IMD-or-IMDUEL-only routing, the three deliberate design decisions, and that the hook has no `$owner` argument because it has no owner. I removed the previous attempt's stale sentence saying the engine address would be replaced before launch, since the engine is already deployed.\n\nNo placeholder gap exists: the hook needs no owner, factory or launch-number argument, so no stand-in address was written. The token logo is not part of this task's writable paths and was left untouched.","treeHash":"54a8d2553ff990e6efc4a6303e431525e46d0197","usage":{"cachedInputTokens":363438,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":5639,"runtime":"claude","turns":10,"wallClockMs":172277}},{"artifacts":[],"attempt":1,"bundleHash":"6928692a8b038abd9faf8c628aa5ec1deda83d5090d19ac1fb4702a0e75969d1","device":"896d1238054266ca","findings":[{"description":"The fix for 9537d3ff (_sampleDepth) records a pool's liquidity at the first swap of each block and measures every bid against the smallest of the three latest samples. The code notes say the sample is the liquidity 'at the start of this block' and that liquidity 'has to be in the pool at the start of three traded blocks to count, held through two public ones where anyone can trade against it'. That isn't true. The hook has no liquidity callbacks, so a modifyLiquidity before the block's first swap goes unseen, and the first swap's sample already includes it. An attacker who opens three traded blocks with [add L, dust swap, remove L] (one unlock or one bundle, no capital held, only gas and the LP fee on 100 wei) makes all three samples L. In the third block (the victim's), any later trade is measured against L although the pool holds only its honest liquidity again. It doesn't need to be sandwiched. The victim's move plays at the strength curve's floor. Compared with the original JIT bracket, the attacker now has to front-run the victim in the victim's block and be the first swapper of two earlier traded blocks of the pool (on a quiet pool, any two blocks), so the bar is higher but the attack is still free. Without liquidity permissions, the hook can't see when liquidity changes inside a block, so a fix needs a different sampling rule (for example, samples the attacker can't produce with a self-contained bracket), or the limitation should be documented instead of the property claimed.","line":516,"path":"src/IMDuelHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolSwapTest} from \"v4-core/src/test/PoolSwapTest.sol\";\nimport {PoolModifyLiquidityTest} from \"v4-core/src/test/PoolModifyLiquidityTest.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {SwapParams, ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\nimport {StateLibrary} from \"v4-core/src/libraries/StateLibrary.sol\";\nimport {MockERC20} from \"solmate/src/test/utils/mocks/MockERC20.sol\";\nimport {IMDuelHook, IMDUEL_HOOK_FLAGS} from \"src/IMDuelHook.sol\";\n\n/// _sampleDepth takes each block's sample at the block's first swap and assumes nothing changed the liquidity before\n/// it. The hook has no liquidity callbacks, so a bracket [add liquidity, dust swap, remove liquidity] that is the\n/// first swap of a block records the inflated liquidity as \"the start of the block\", although the pool held it for\n/// no public moment at all. Three such brackets (the victim's own block being the third, ahead of the victim's\n/// trade) make the minimum of the three samples the inflated depth, and a victim trading later in that block, when\n/// the pool holds only its honest liquidity, bids at the strength curve's floor.\ncontract DepthFirstSwapTest is Test {\n    using PoolIdLibrary for PoolKey;\n    using StateLibrary for IPoolManager;\n\n    uint160 constant SQRT_PRICE_1_1 = 79228162514264337593543950336;\n    IPoolManager manager;\n    PoolSwapTest swapRouter;\n    PoolModifyLiquidityTest lpRouter;\n    IMDuelHook hook;\n    PoolKey key;\n    PoolId id;\n\n    function setUp() public {\n        manager = IPoolManager(vm.deployCode(\"PoolManager.sol:PoolManager\", abi.encode(address(this))));\n        swapRouter = PoolSwapTest(vm.deployCode(\"PoolSwapTest.sol:PoolSwapTest\", abi.encode(manager)));\n        lpRouter = PoolModifyLiquidityTest(vm.deployCode(\"PoolModifyLiquidityTest.sol:PoolModifyLiquidityTest\", abi.encode(manager)));\n        MockERC20 a = new MockERC20(\"A\", \"A\", 18);\n        MockERC20 b = new MockERC20(\"B\", \"B\", 18);\n        (Currency c0, Currency c1) = address(a) < address(b)\n            ? (Currency.wrap(address(a)), Currency.wrap(address(b)))\n            : (Currency.wrap(address(b)), Currency.wrap(address(a)));\n        for (uint256 i; i < 2; i++) {\n            MockERC20 t = i == 0 ? a : b;\n            t.mint(address(this), 2 ** 200);\n            t.approve(address(swapRouter), type(uint256).max);\n            t.approve(address(lpRouter), type(uint256).max);\n        }\n        address engine = vm.deployCode(\"ChessEngineV5.sol:ChessEngineV5\");\n        address at = address(IMDUEL_HOOK_FLAGS | (uint160(0x1D0E1) << 40));\n        // the launch's shape: IMD (here c0), minimums, three-block turns\n        deployCodeTo(\"IMDuelHook.sol:IMDuelHook\", abi.encode(manager, engine, c0, 10e18, 1_000_000e18, 3), at);\n        hook = IMDuelHook(at);\n        key = PoolKey(c0, c1, 12500, 60, IHooks(at));\n        id = key.toId();\n        manager.initialize(key, SQRT_PRICE_1_1);\n        lp(1e24); // the pool's honest, standing liquidity\n        vm.warp(block.timestamp + 400); // past the opening surcharge, within the turn timeout\n        vm.roll(block.number + 1);\n    }\n\n    function lp(int256 liquidity) internal {\n        lpRouter.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, liquidity, 0), \"\");\n    }\n\n    function swap(bool zeroForOne, uint256 amountIn, address owner) internal {\n        swapRouter.swap(\n            key,\n            SwapParams(zeroForOne, -int256(amountIn), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),\n            PoolSwapTest.TestSettings(false, false),\n            abi.encodePacked(owner)\n        );\n    }\n\n    /// The side to move's top bid.\n    function topBid() internal view returns (IMDuelHook.TopBid memory) {\n        IMDuelHook.Game memory g = hook.game(id);\n        return g.bids[(g.gameNo & 1) ^ (g.slice ^ 1) ^ (g.ply & 1)];\n    }\n\n    /// White (the team buying currency1) is to move. A 1e22 trade is a 1% share of the pool's 1e24.\n    function test_victimShareMeasuredAgainstHonestDepth() public {\n        // control: with no attacker, the 1% share plays near the 90% cap\n        uint256 snap = vm.snapshotState();\n        swap(true, 1e22, address(0xA11CE));\n        uint16 honest = topBid().strength;\n        assertGe(honest, 8_000, \"control: a 1% share\");\n        vm.revertToState(snap);\n\n        // three blocks, each opened by an atomic bracket around a dust swap; the liquidity is gone by its end\n        for (uint256 i; i < 3; i++) {\n            if (i > 0) {\n                vm.warp(block.timestamp + 12);\n                vm.roll(block.number + 1);\n            }\n            lp(1e27);\n            swap(false, 100, address(0xBAD)); // the block's first swap: samples 1e27 + 1e24\n            lp(-1e27);\n        }\n        assertEq(manager.getLiquidity(id), 1e24, \"the pool holds only its honest liquidity again\");\n\n        // the victim's trade, later in the third block, against a pool that held 1e24 at the start of every block\n        swap(true, 1e22, address(0xA11CE));\n        IMDuelHook.TopBid memory v = topBid();\n        assertEq(v.owner, address(0xA11CE));\n        // expected: about `honest` (>= 8,000, the pool never held more than 1e24 at any public moment)\n        // actual: the curve's floor, measured against 1e27 that was in the pool only inside the attacker's brackets\n        assertGe(v.strength, 8_000, \"victim's share measured against liquidity never held at a block's start\");\n    }\n}","reproduction":"Main duel IMD/X, fee 12500, spacing 60, real IMDuelHook (launch shape: minImd 10e18, minImduel 1e24, turnBlocks 3), 1:1 price, 1e24 full-range liquidity, 400 s after opening. Control: White buys with 1e22 (a 1% share) -> top bid strength >= 8,000. Attack: in each of three consecutive blocks, add 1e27 full-range liquidity, swap 100 wei (oneForZero), remove 1e27 (the pool is back at 1e24 after each). Then in the third block the victim buys with 1e22. Expected: strength about the control's (>= 8,000), because the pool never held more than 1e24 at any public moment or at the start of any block. Actual: strength 0. The proof (test/scratch/DepthFirstSwap.t.sol) fails with 'victim's share measured against liquidity never held at a block's start: 0 < 8000'.","severity":"medium","title":"Sampled bid depth can still be inflated at no cost: a bracket that is a block's first swap is recorded as that block's start liquidity"}],"hash":"50c6fc57d604d7b6e80007c3639d625a765d2e4a4028e34d942e0662295baa59","nodeId":"d4d33cc8-e851-4432-8ff7-69e38f9d0ee9","outcome":"completed","summary":"I found a new medium-severity defect in the hook's revised bid-depth sampling and reported it in `.imd-findings.json`. I also added 8 tests to `test/Edges.t.sol`. With the verifier's seed, the full suite passes: 172 passed, 0 failed (the scratch proof is excluded, as it is on the verifier).\n\n**Finding (medium): the fix for the earlier liquidity-bracket finding can still be beaten at no cost** (`src/IMDuelHook.sol:516`, `_sampleDepth`)\n- **What's wrong:** the hook records a pool's liquidity once per block, at that block's first swap, and treats that as the block's starting liquidity. The hook has no liquidity callbacks, so it never sees liquidity added earlier in the same block.\n- **The attack:** an attacker opens three blocks with \"add 1e27 liquidity, swap 100 wei, remove it\". All three samples then read 1e27, though the pool never held it at any public moment. A victim trading later in the third block is scored against that inflated depth, without being sandwiched. The attacker only has to trade first in those blocks, which is easy on a quiet pool, and pays gas plus a fee on 100 wei.\n- **Effect:** the code comment says liquidity must be held through two public blocks to count. That is false here.\n- **Proof:** a self-contained test using the real hook in its launch shape. A control trade with a 1% share gets strength ≥ 8,000. After the attack, the same trade gets **0**, and the test fails with \"0 < 8000\". Its source is in the finding's `proof` field. Since the hook can't see liquidity changes without new permissions, a fix needs a different sampling rule, or the comment should describe the limitation instead of claiming the property.\n\n**New tests, all passing:**\n- **Batch size:** a fuzz test (1,000 runs) of the batch limit over every pile and minimum. A batch never spends more than the pile or more than ten minimums, spends exactly ten minimums once the pile holds them, and never overflows. Plus exact checks at the largest values.\n- **Depth sampling:**\n  - Liquidity removed after a block's first swap doesn't strengthen later bids in that block.\n  - Liquidity removed before a block's first swap counts at once.\n  - Blocks with no trade take no sample.\n\nThe rest of the earlier `Edges.t.sol` is unchanged and still passes against the revised hook. I modified only `test/Edges.t.sol` and wrote `.imd-findings.json`. I committed nothing.","treeHash":"055b4f5b011d28da0992fba8a0e4f1fa6b1cda9e","usage":{"cachedInputTokens":1212017,"inputTokens":36,"model":"claude-opus-5-5","outputTokens":22476,"runtime":"claude","turns":21,"wallClockMs":623874}},{"artifacts":[],"attempt":1,"bundleHash":"d09834da5ff4d60a9d08557f6b8608ab55778c15f8c8ef520884d94bbedf7fd8","device":"584bd638e7e022f0","findings":[],"hash":"57378880e0fe1e0808e5cc879e0eeed4601440b52082ec2682ce5cd034b34002","nodeId":"bf5b7810-0017-4ccd-a50a-78b19aefe981","outcome":"completed","summary":"The responses file is excluded by the harness's own `.git/info/exclude`, so it is expected there in the working tree. The work is complete.\n\n**Finding 87c3e492 reproduced and is fixed.** The reviewer's proof failed on the starting tree exactly as reported, with the victim's move at strength 0, and passes now.\n\n**Cause.** The hook observed liquidity only at swaps, so one transaction of add, dust swap, remove at the start of three blocks made every sample the added liquidity. No swap-driven sampling rule can exclude liquidity that exists only inside a transaction.\n\n**Fix in `src/IMDuelHook.sol`.** The hook now enables `beforeAddLiquidity`. The callback requires the PoolManager as caller, reads the pool's liquidity before the add and, if nothing has sampled the block yet, records it as the block's start liquidity. It never refuses an add and returns only its selector. A same-block add can therefore never raise a block's sample. I chose `beforeAddLiquidity` over the suggested `afterAddLiquidity` because it gives the pre-add liquidity exactly, with no in-range arithmetic. There is still no remove callback, so the factory's zero-liquidity fee collection is untouched, and an empty pool's add is not sampled, so the factory's seed-and-trade block still works from its first trade. The stale comment claiming the first swap sees the block's start liquidity was rewritten.\n\n**Manifest.** The permission set grew by one, so `launch.json` and the two files under `launch/` list `beforeAddLiquidity` and the notes sentence that said liquidity callbacks were unused was replaced. The launch cannot run without this: the address is mined from the manifest's permissions and the constructor rejects a mismatch. Nothing else in the manifest changed.\n\n**Tests.** New in `test/JitStrength.t.sol`: the three-bracket attack with the victim and the attacker's own next-block trade both at the control's strength, a block opened by an add recording the pre-add liquidity, a remove before the first sample only lowering it, and the callback refusing an outsider. The admission, Game and LaunchFiles suites were extended for the new callback. A standalone copy of the bracket test fails without the source fix and passes with it.\n\n| Check | Result |\n| --- | --- |\n| `forge build` | passes |\n| `forge test` with the verifier's fuzz seed | 163 project tests pass, plus the proof copy |\n| Hook runtime size | 17,884 bytes, budget 23,500 |\n\n**Imported audit finding 57614ed6** no longer reproduces: it was fixed last round and the launch tests pass on both trees. Both findings are answered in `.imd-responses.json`, and `ADAPTATION.md` records every change and the rule or finding behind it.","treeHash":"63949b48b0022647ac107b5103498c28d4796011","usage":{"cachedInputTokens":2344682,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":44708,"runtime":"claude","turns":55,"wallClockMs":939831}},{"artifacts":[],"attempt":1,"bundleHash":"a87f36406846b06c5f91ccaa068108ee9c0d2892dc420420b11988b44ff26f3d","device":"06d00e98fbdd1ee9","findings":[],"hash":"63563b8be837a40384608cf30952375fedf451b9b2199b43975e80e2aca4386b","nodeId":"5a8d0013-bc3e-41b1-bd04-0c7d852e38f1","outcome":"completed","summary":"The protected suites from the reads do not compile standalone here. They import verifier-side scaffolding such as src/HookFlags.sol, mocks/ and floor/ that this repository does not carry, so the verifier supplies those when it runs them. That matches earlier rounds and is unrelated to the manifest. The scratch folder is removed and the working tree shows only launch.json modified.\n\n**Outcome:** launch.json is updated and verified. Only its notes changed. The build passes and the full suite passes with the verifier's fuzz seed.\n\n| Check | Result |\n| --- | --- |\n| forge build | passed |\n| forge test with the verifier seed | 159 passed, 0 failed, 22 suites |\n| notes length | 3971 of 4000 characters |\n| files changed | launch.json only |\n\n**What was already correct and left alone.** The committed manifest's first field is the univ4_hook discriminator. The hook contract is IMDuelHook with six constructor arguments in declaration order: the pool manager placeholder, the deployed ChessEngineV5, IMD, 10 IMD, 1,000,000 IMDUEL and 3 turn blocks. The permissions list matches what getHookPermissions returns: afterInitialize, beforeSwap, afterSwap, beforeSwapReturnDelta and afterSwapReturnDelta. The token is IMDuelToken, IMDuel / IMDUEL, 18 decimals. The pool pairs IMD at fee 12500, tick spacing 60, with the one-to-one initial price from the launch facts.\n\n**What the notes now say that they did not before.** The later revision of the hook, accepted after my previous manifest commit, left the notes stale in four places, and its change record asked the manifest step to fix the first:\n\n- The claim that nothing is ever sent inside a trade is corrected to no reward is ever sent inside a trade. The one transfer a trade can make is the slice batch's burn of IMDUEL to the dead address, a plain token with no callbacks, inside a try/catch that cannot revert the trade.\n- Bid strength is measured against the smallest in-range liquidity at the start of the pool's three latest traded blocks, so a just-in-time liquidity bracket cannot collapse an opponent's bid.\n- withdrawTo refuses the zero address.\n- The constructor rejects a zero engine, a zero minimum, or turn blocks outside 1 to 1000.\n\nThe change is uncommitted in the working tree, as in earlier rounds where the worker pipeline made the commit.","treeHash":"c591e3de35a80cc4bc764ebb92d0ca91075a31b6","usage":{"cachedInputTokens":363325,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":5589,"runtime":"claude","turns":9,"wallClockMs":171080}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f768e94767a9dde3","findings":[],"hash":"76a539e98bb69108108fd2e4d70da323efde24517a3df2d4bd586f870c5782c5","nodeId":"5a8d0013-bc3e-41b1-bd04-0c7d852e38f1","outcome":"failed","summary":"could not restore accepted work: accepted work conflicts with a dependency that changed the same files after it was accepted: Command failed: git -c user.name=IdentityMD Worker -c user.email=worker@identitymd.invalid merge --no-edit -m imd: reapply this node's accepted work af90ce1fb907f60ec91539e933e5e6d115cd6d0c\n","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"claude","turns":0,"wallClockMs":2043}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dc34db8e17664ebd","findings":[{"citation":"resolved","description":"The contract notes (lines 36-38) and launch.json say nothing is ever sent inside a trade so that no recipient runs code while the trader's PoolManager is unlocked. Rewards honour this: _payBounty only records owed[]. But the protocol-slice batch does not: afterSwap -> _play -> this.convertBatch (line 566) -> _convert -> _send(imduel, DEAD, burned) (line 445) calls manager.burn + manager.take (lines 355-356), which moves real $IMDUEL from the PoolManager to 0x...dEaD during the trader's unlock. The safety goal still holds because $IMDUEL is the plain launch token (src/IMDuelToken.sol has no transfer callbacks) and 0x...dEaD has no code, and the call sits inside try/catch so a failed take cannot revert the trade. This is a documentation accuracy note, not a loss path; no fix to the code is needed. If the author wants the statement to be literally true, the burn could be deferred to the external convert() path only.","line":445,"path":"src/IMDuelHook.sol","reproduction":"State: a hook whose main duel pairs IMD/$IMDUEL, and a second duel X/$IMDUEL (slice taken in $IMDUEL). Call: one exact-input swap selling 10e18 $IMDUEL into the X/$IMDUEL duel with minImduel <= 0.01e18 (test/Slice.t.sol test_imduelDuelsNeedNoSwap uses MIN = 1e15). Expected per the notes: no token leaves the PoolManager inside the trade. Actual: within that same swap transaction $IMDUEL.balanceOf(0x...dEaD) rises by 0.005e18 (the Converted event is emitted inside the swap), i.e. manager.take ran while the trader's unlock was open. Harmless with the fixed $IMDUEL token; recorded so the invariant is stated precisely.","severity":"info","snippet":"        if (burned != 0) _send(imduel, DEAD, burned);","title":"A real IMDUEL transfer (the burn to 0x...dEaD) does happen inside a trader's unlock; the 'nothing is ever sent inside a trade' statement is only exact for rewards"}],"hash":"7959af521c127069931ed2a7fec081d32282f8b0d1cb5b9469cb6ae12abf9a23","nodeId":"d7be8a99-9343-4ef5-910b-12e9adf885ce","outcome":"completed","summary":"The review is complete and the findings file is written. The working tree holds only the ignored findings file, so nothing in the repository changed.\n\n**Outcome.** No reproducible defect in the control-flow area. The file `.imd-findings.json` holds one informational note and 17 coverage rows, one for each of the 12 listed entry points plus five rows for invariants, periphery helpers, the manifest and the unreached engine code.\n\n**What I checked, by guide.**\n\n- **Execution Trace.** The fee is minted as ERC-6909 claims on the specified side in beforeSwap and on the unspecified side in afterSwap, and each mint nets to zero against the hook delta the PoolManager accounts. The PartialFill check holds for both exact-input and exact-output orders. The transient stash cannot be clobbered between the two callbacks because the hook's own conversion swap runs without callbacks and the engine is called by staticcall. The unlock callback can only ever receive the hook's own encoding, since the PoolManager calls back only the unlock caller.\n- **Periphery.** The sqrt-price packer keeps the mantissa under 48 bits and the exponent under 256 for any uint160. The samples word's five fields do not overlap. The assembly masks are 160 and 128 bits wide. The hookData owner parser accepts only 20 or 32 bytes. Block-hash lookups fall back to zero and become timeout moves. Engine replies are length-checked before decoding.\n- **First Principles.** Chest, pile and owed balances move in lockstep with claim mints and burns, so held always equals owed. Stale bids carrying into the next game, timeout moves, late bids and the no-hash path all resolve to consistent state. A hostile token can only act inside the hook's own unlock, where a nested unlock reverts and a direct swap must settle itself.\n\n**The one note.** The notes say nothing is ever sent inside a trade. That is exact for rewards, but the slice batch burns $IMDUEL to the dead address with a real transfer inside the trader's unlock. The goal still holds because the launch token has no callbacks and the call is wrapped in try/catch, so I filed it as informational with a concrete trigger.\n\n**Verification.** The project builds with forge build. All 131 tests across 22 suites pass, including both launch token orders and the blank-chain admission tests. The manifest's six constructor arguments, permissions, fee tier, tick spacing and notes length match the implementation.\n\n**Not reached.** The engine and bitboard move generation were outside my area and are marked unreached; only the hook's handling of their return values was traced.","treeHash":null,"usage":{"cachedInputTokens":1128066,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":57784,"runtime":"claude","turns":32,"wallClockMs":1145803}},{"artifacts":[],"attempt":1,"bundleHash":"70754f9045d38ae93eca3311a1450cba62fdcb154cff9c09c1ae6abbaabfc6b2","device":"a11137177fc72d8b","findings":[{"description":"The 87c3e492 fix makes beforeAddLiquidity record the pre-add in-range liquidity as the block's sample, but only `if (liquidity != 0)` (line 297). When the pool's price sits outside every position's range at a block's start (in-range liquidity 0, common with concentrated liquidity and reachable by anyone who pushes the price through a concentrated range at the end of a block), the add records nothing, so the block's first swap in the same transaction records the bracketed liquidity: one transaction [add 1e27, dust swap, remove 1e27] at the start of three such blocks makes the depth 1e27 although the pool held it at no block boundary, the exact attack 87c3e492 was fixed for. Separately, a swap that opens a block with zero in-range liquidity records a 0 sample (_recordDepth), the min loop in _sampleDepth skips zeros, and when all three latest samples are 0 the depth is 0 and Strength.fromShare returns 0: parking the price outside the honest range at three block starts (no bracket at all) plays every bid of the block the price returns in at 0%. ADAPTATION.md and the contract notes state that liquidity only counts once it has been in the pool at the start of three sampled blocks; both cases break that. Exposure: the factory seeds the launch pool full range, so the main duel needs the price pushed past the full-range position to reach it; any duel or main-duel liquidity that is concentrated is directly exposed. A candidate fix that passes both proof tests and every test in test/JitStrength.t.sol: in _recordDepth, when liquidity == 0 and the pool already has a nonzero sample, stamp the block as sampled without shifting the samples (keep the last honest depths), and call _recordDepth from beforeAddLiquidity unconditionally (an empty pool with no samples yet still returns without stamping, so the launch's first block keeps measuring against its first trade).","line":297,"path":"src/IMDuelHook.sol","reproduction":"Main duel IMD/IMDUEL, fee 3000, spacing 60, the honest LP 1e24 in [-600, 600] only, three honest dust-traded blocks (samples 1e24). Control: a White trade of 1e22 (1% share) bids at strength 8987. Attack A: at a block's end the attacker adds a pocket 1e22 in [600, 6000] (or mirrored), swaps 3.2e22 buying Black's token through the honest range into the pocket, and removes the pocket (in-range liquidity 0). Then in each of three blocks the first transaction is [add 1e27 in [-12000, 12000], swap 100 wei, remove 1e27]; in the third block a 1e15 White trade walks the price back into the honest range (getLiquidity = 1e24) and the victim's 1e22 White trade bids. Expected: about 8987, like the control (the pool held 1e27 at no block boundary). Actual: 42. Attack B (no bracket): the price parked out of range at the start of three blocks, each opened by a 100-wei swap toward the honest range (sample 0) and re-parked; the victim's 1e22 trade in the third block: expected about 8987, actual 0. Both in the proof file: forge test --match-path test/scratch/EmptyRangeBracket.t.sol.","severity":"medium","title":"Depth sampling still inflatable (or zeroed) when a block starts with no in-range liquidity: empty-range adds record nothing and zero samples are skipped"}],"hash":"7e47cbf0667b1d2a18e1b7d15af3493f44e580cd2fa8eac4ee68db20d3be264c","nodeId":"d4d33cc8-e851-4432-8ff7-69e38f9d0ee9","outcome":"completed","summary":"I found a remaining defect in the hook's new depth sampling and reported it in `.imd-findings.json`. I also added three tests for the new `beforeAddLiquidity` callback. `forge build` passes, and `forge test` with the verifier's seed passes all 179 tests in 28 suites.\n\n**Context.** Since my last round, the hook gained a `beforeAddLiquidity` callback. It records the pool's in-range liquidity before an add, so liquidity added inside a block can't set that block's \"depth\" (the liquidity a bid's strength is measured against). The existing 176 tests already passed against this change.\n\n**Finding (medium): `src/IMDuelHook.sol:297`.** The callback records nothing when in-range liquidity is zero (`if (liquidity != 0)`), and zero samples are skipped when the depth is taken. If the price sits outside every liquidity position's range at the start of a block, two attacks work:\n- **Bracket still works.** One transaction of [add 1e27, 100-wei swap, remove 1e27] at the start of three such blocks makes the depth 1e27, even though the pool never held that at a block boundary. A victim's 1% trade then plays at strength **42 instead of 8987**. This is the same attack the last fix was meant to stop.\n- **No bracket needed.** Parking the price out of range at the start of three blocks makes all three samples zero, so the depth is zero. The victim plays at strength **0 instead of 8987**.\n\nThe launch pool is seeded across the full price range, so the main duel is only exposed if someone pushes the price past that position. Any duel with liquidity in a narrower range is exposed directly.\n\nThe proof is the file `test/scratch/EmptyRangeBracket.t.sol`; its source is embedded in the finding. Both of its tests fail on the current code. To check it can be fixed, I tried a fix on a temporary copy of the source and then restored it (`git status` shows only my test file changed). With that fix, both proof tests pass, and so does every test in `test/JitStrength.t.sol`. The fix:\n- When in-range liquidity is zero and the pool already has a sample, mark the block as sampled but keep the earlier depths.\n- Call `_recordDepth` from `beforeAddLiquidity` every time. An empty pool with no samples is left alone, so the launch's first block works as before.\n\n**New tests, in `test/Edges.t.sol` as `AddCallbackEdgesTest`:**\n- **Fee collection:** the launch factory collects fees with a zero-liquidity change, which v4 treats as a removal. The test checks it pays the LP fees, moves no liquidity, and doesn't change the depth.\n- **Adds are never refused (fuzzed, 256 runs):** any tick range, in range or not, sizes up to 1e30, before or after the block's first swap.\n- **Adds into empty ranges:** adds into an empty or out-of-range pool, and twice in one block, are accepted.\n\nThe fuzz test only adds liquidity and doesn't remove it again. When removing a tiny position returns zero tokens, an `assert` in v4's test router fails. That is a quirk of the router, not the hook.","treeHash":"350b0ef63dc516eeb36d5d4b7b3f8cd9e323f767","usage":{"cachedInputTokens":1725954,"inputTokens":43,"model":"claude-opus-5-5","outputTokens":32621,"runtime":"claude","turns":26,"wallClockMs":668095}},{"artifacts":[],"attempt":1,"bundleHash":"d90e3c76d5f36a5219d9286f973ab5a3578d2aad48adad5ab1acc6094c932fbb","device":"2a9662a76cb5f51d","findings":[],"hash":"82001ba14867d3ad649a6d83f9db57e74ac3d1fcf2de9a9351a9fccebf72f1f7","nodeId":"bf5b7810-0017-4ccd-a50a-78b19aefe981","outcome":"completed","summary":"All findings were reproduced and answered. The revision is complete and verified.\n\n**Main finding (medium, fixed).** The reviewer's proof failed on the starting tree with Bob's bid at 271 bps. The hook read the pool's live liquidity at the moment of each trade, so a same-block add-and-remove bracket shrank an opponent's share for free. The hook now samples each pool's in-range liquidity at the start of every traded block and measures a bid against the smallest of the three latest samples. A bracket has to be held through the start of three traded blocks to count, and then it weakens every bid including the bracketer's own. Permissions in launch.json stay exactly as committed, so no liquidity callbacks were added. The proof now passes with Bob near the cap like Alice and the attacker.\n\n**Advisory findings, all judged real and fixed.**\n- `withdrawTo` refuses the zero address, so a native-ETH reward can no longer be burned.\n- A conversion batch now spends exactly ten minimums at most, with the never-minimum still safe from overflow.\n- The constructor rejects a zero minimum. The launch's own arguments are nonzero and unaffected.\n- The \"nothing is ever sent inside a trade\" note now says no reward is sent, and names the burn as the one transfer. Code unchanged there.\n\n**Tests.** New suite `test/JitStrength.t.sol` covers the bracket, a one-block hold, a three-block hold that does count, a pool's first block, and per-pool samples. Money, Game and Size tests gained the other cases. The size test had encoded a stale argument shape with zero minimums and now uses the launch's six arguments.\n\nResults with the verifier's fuzz seed:\n\n| Check | Result |\n| --- | --- |\n| forge build | passes |\n| forge test | 160 passed, 0 failed |\n| Reviewer's proof (copied to test/scratch) | passes |\n| Hook runtime size | 17,628 bytes, under the 23,500 budget |\n\nlaunch.json, foundry.toml, the token, and every dependency are byte-for-byte unchanged. ADAPTATION.md records each change and the finding it answers, and `.imd-responses.json` answers all six finding ids, including the first-round Launch test fix, which was re-verified.","treeHash":"2bccfcbffba173ad77ba9d1b4b62095517aee807","usage":{"cachedInputTokens":2572310,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":41854,"runtime":"claude","turns":66,"wallClockMs":949247}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c722c2e9ac9aa084","findings":[{"citation":"resolved","description":"beforeSwap reads the pool's current in-range liquidity and _trade() turns the trade's share of it into the move's strength (Strength.fromShare: 0% at a 0.001% share, 90% cap from 1%). The hook enables no liquidity callbacks (getHookPermissions), so anyone can add liquidity in the transaction before an opponent's trade and remove it in the transaction after, in the same block. Adding and removing liquidity costs nothing but gas, and the bracketing LP even collects the opponent's 1.25% LP fee for that one swap. The opponent's bid keeps its size (it still owns the move and pays the 0.5% hook fee) but its recorded strength collapses, so the engine plays a near-random move for it; the attacker's own trade of the same size, made once the liquidity is gone, plays at the cap. Strength.sol documents the opposite guarantee (\"from its share of the pool, never from other traders' sizes\"). Economic effect: moves are the only way a team's chest pays out (captures 0.3%-2.7% plus 0.3% check, mate 25.3%, capped at 2x the trade). A bidder whose moves are forced to ~0% captures far less and blunders far more, so the opposing team's bidders collect the captures and mates. It is a zero-cost, same-block grief available to any LP-capable account (a flash loan of IMD plus bought IMDUEL suffices for in-range liquidity), and in the main duel the factory's single-sided seed is the only liquidity the attacker cannot remove, so the ratio can be pushed arbitrarily high. No funds are taken directly: the loss is the opponent's expected reward and the fairness of the game the hook sells. Fix options that keep the design: read the liquidity at the start of the block or of the move's window (sample it like the price samples) instead of spot, or compute the share against a liquidity snapshot taken when the turn opened; alternatively enable before/afterAddLiquidity to time-lock JIT adds, which the factory's fee collection (a zero-liquidity-change remove) would still pass.","line":269,"path":"src/IMDuelHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolSwapTest} from \"v4-core/src/test/PoolSwapTest.sol\";\nimport {PoolModifyLiquidityTest} from \"v4-core/src/test/PoolModifyLiquidityTest.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {ModifyLiquidityParams, SwapParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\nimport {IChessEngine} from \"src/IChessEngine.sol\";\nimport {IMDuelHook, IMDUEL_HOOK_FLAGS} from \"src/IMDuelHook.sol\";\nimport {IMDuelToken} from \"src/IMDuelToken.sol\";\n\ncontract Plain {\n    string public constant name = \"IMD\";\n    string public constant symbol = \"IMD\";\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function mint(address to, uint256 v) external { balanceOf[to] += v; }\n    function approve(address s, uint256 v) external returns (bool) { allowance[msg.sender][s] = v; return true; }\n    function transfer(address to, uint256 v) external returns (bool) { balanceOf[msg.sender] -= v; balanceOf[to] += v; return true; }\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        if (allowance[f][msg.sender] != type(uint256).max) allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v; balanceOf[to] += v; return true;\n    }\n}\n\n/// JIT liquidity against a bidder's strength: the strength of a bid is its share of the pool's in-range liquidity read\n/// in beforeSwap, and the hook has no liquidity callbacks, so anyone can add liquidity just before an opponent's trade\n/// and remove it just after, in the same block, at no cost. The opponent's identical trade then bids at 0% instead\n/// of 90%, while the attacker's own trade of the same size, with the liquidity gone again, bids at 90%.\ncontract JitStrengthTest is Test {\n    using PoolIdLibrary for PoolKey;\n\n    IPoolManager manager;\n    PoolSwapTest router;\n    PoolModifyLiquidityTest lp;\n    IMDuelHook hook;\n    PoolKey key;\n    Plain imd;\n    IMDuelToken duel;\n    uint160 constant SQRT_1_1 = 79228162514264337593543950336;\n\n    function setUp() public {\n        manager = IPoolManager(address(new PoolManager(address(this))));\n        router = new PoolSwapTest(manager);\n        lp = new PoolModifyLiquidityTest(manager);\n        imd = new Plain();\n        duel = new IMDuelToken();\n        imd.mint(address(this), 1e30);\n        imd.approve(address(router), type(uint256).max);\n        imd.approve(address(lp), type(uint256).max);\n        duel.approve(address(router), type(uint256).max);\n        duel.approve(address(lp), type(uint256).max);\n        address at = address(IMDUEL_HOOK_FLAGS | (uint160(0x4444) << 40));\n        deployCodeTo(\"IMDuelHook.sol:IMDuelHook\", abi.encode(manager, IChessEngine(address(0xE)), Currency.wrap(address(imd)), uint256(10e18), uint256(1e24), uint256(3)), at);\n        hook = IMDuelHook(at);\n        (Currency c0, Currency c1) = address(imd) < address(duel)\n            ? (Currency.wrap(address(imd)), Currency.wrap(address(duel)))\n            : (Currency.wrap(address(duel)), Currency.wrap(address(imd)));\n        key = PoolKey(c0, c1, 12500, 60, IHooks(at));\n        manager.initialize(key, SQRT_1_1);\n        // 1e24 of full-range liquidity: about 1e24 of each token in range at 1:1\n        lp.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, 1e24, 0), \"\");\n        vm.warp(block.timestamp + 400); // past the main duel's opening surcharge\n        vm.roll(block.number + 1);\n    }\n\n    function buyDuel(uint256 imdIn, address owner) internal {\n        bool zeroForOne = Currency.unwrap(key.currency0) == address(imd);\n        router.swap(key, SwapParams(zeroForOne, -int256(imdIn), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),\n            PoolSwapTest.TestSettings(false, false), abi.encodePacked(owner));\n    }\n\n    function whiteBid() internal view returns (IMDuelHook.TopBid memory) {\n        IMDuelHook.Game memory g = hook.game(key.toId());\n        return g.bids[(g.gameNo & 1) ^ (g.slice ^ 1) ^ (g.ply & 1)];\n    }\n\n    /// What the hook documents (\"strength from its share of the pool, never from other traders' sizes\"): a trade's\n    /// strength must not depend on liquidity another party adds just before it and removes just after it. Fails on the\n    /// current code: Bob's 1.2% trade plays at 275 bps while Alice's 1% and the attacker's 1.5% play at ~8600.\n    function test_aBidsStrengthDoesNotDependOnLiquidityAddedAndRemovedAroundIt() public {\n        // Alice: 1% of the in-range depth, near the 90% cap\n        buyDuel(1e22, address(0xA11CE));\n        uint16 alice = whiteBid().strength;\n        assertGe(alice, 8000, \"a 1% trade plays near the 90% cap\");\n        // the attacker brackets Bob's trade with 1000x liquidity, in the same block\n        uint256 imdBefore = imd.balanceOf(address(this));\n        uint256 duelBefore = duel.balanceOf(address(this));\n        lp.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, 1e27, 0), \"\");\n        buyDuel(1.2e22, address(0xB0B)); // beats Alice's bid by 20%\n        lp.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, -1e27, 0), \"\");\n        assertEq(whiteBid().owner, address(0xB0B), \"Bob's bigger trade owns the move\");\n        uint16 bob = whiteBid().strength;\n        // the attacker got all its liquidity back plus Bob's LP fee: the bracket cost it nothing\n        assertGe(imd.balanceOf(address(this)) + duel.balanceOf(address(this)), imdBefore + duelBefore - 1.2e22 - 2, \"the attacker is not out of pocket\");\n        // the attacker's own trade afterwards, at the depth Alice saw\n        buyDuel(1.5e22, address(0xBAD));\n        assertEq(whiteBid().owner, address(0xBAD));\n        uint16 attacker = whiteBid().strength;\n        emit log_named_uint(\"alice strength (bps)\", alice);\n        emit log_named_uint(\"bob strength (bps), bracketed by JIT liquidity\", bob);\n        emit log_named_uint(\"attacker strength (bps)\", attacker);\n        assertGe(bob, 8000, \"Bob's 1.2% trade must play near the cap like Alice's and the attacker's\");\n    }\n}","reproduction":"Main duel IMD/IMDUEL at 1:1 with 1e24 full-range liquidity (1% of depth = 1e22), past the 300 s opening, launch constructor arguments (10e18, 1e24, 3). (1) Alice buys IMDUEL with 1e22 IMD, hookData=Alice: her bid is recorded at 8987 bps. (2) Attacker in the same block: modifyLiquidity(+1e27 full range); Bob buys with 1.2e22 IMD (beats Alice by 20%); attacker modifyLiquidity(-1e27). Expected: Bob's strength near the cap like Alice's (a larger trade against the same durable pool). Actual: Bob owns the move at 271 bps; the attacker's token balances are back to their start minus Bob's swap input (it kept Bob's LP fee). (3) Attacker buys with 1.5e22: strength 9000 bps. Run: forge test --match-path test/scratch/JitStrength.t.sol (fails on current code with \"271 < 8000\").","severity":"medium","snippet":"        uint256 depth = manager.getLiquidity(id); // sets a bid's strength: every buy bids","title":"Bid strength reads spot in-range liquidity with no liquidity callbacks: JIT liquidity brackets an opponent's trade and plays its move at ~3% instead of ~90%, at zero cost"}],"hash":"98a8fea19637cdb4822793b9968b88d98560ad575d19ed68d7ad48e957098192","nodeId":"7cc710ce-2e69-45ec-ad55-45389dabdc4e","outcome":"completed","summary":"The economics review is complete and `.imd-findings.json` is written with one substantiated finding and 18 coverage rows.\n\n**Finding (medium, with a failing Foundry proof):** a bid's strength is computed from the pool's spot in-range liquidity read in `beforeSwap`, and the hook has no liquidity callbacks. Anyone can add liquidity in the transaction before an opponent's trade and remove it in the next transaction of the same block, at zero cost (the bracketer even keeps that swap's LP fee). In the reproduction, Alice's 1% trade bids at 8987 bps, Bob's larger trade bracketed by 1000x liquidity bids at 271 bps, and the attacker's own trade afterwards bids at 9000 bps. Strength.sol documents the opposite guarantee. No funds are taken directly; the effect is on which team's bidders capture pieces and mates from the chests. The proof in `test/scratch/JitStrength.t.sol` fails on the current code with \"271 < 8000\".\n\n**What held after tracing:**\n- Fee and claim accounting sums to zero on every path, and the hook's claims always equal chests plus pile plus owed rewards. Full project suite with the documented seed: 152 passed, 0 failed.\n- The `PartialFill` check matches v4's delta semantics in both swap directions. The only token ever sent inside a trade is IMDUEL to the dead address, backed by pool reserves.\n- The ChessEngineV5 dependency has code on Ethereum mainnet identical to the local build.\n- The conversion band resisted a multi-block push: holding a pushed price through three sampled blocks and converting for 12 blocks lost the attacker 4.8 to 20.9 IMD and drained under 18 IMD of a 101 IMD pile, so that stays coverage rather than a finding.\n- The manifest's six constructor arguments, permissions, fee tier and notes length agree with the implementation.\n\nEverything in the assigned area was reached. The scratch tests and generator script live under `test/scratch/`, which is not kept.","treeHash":null,"usage":{"cachedInputTokens":5383501,"inputTokens":834,"model":"claude-fable-5-1","outputTokens":95925,"runtime":"claude","turns":60,"wallClockMs":1936496}},{"artifacts":[],"attempt":1,"bundleHash":"fae180e3bbbd78ba39acd381e20f74c86343b4eb135d4751ee07a1f4cae8f542","device":"c4e8f98d7a2a37dc","findings":[],"hash":"b41053948ae65398ef44d51c036f87ace5517f29af9a52188c36c23058bc7b0e","nodeId":"5a8d0013-bc3e-41b1-bd04-0c7d852e38f1","outcome":"completed","summary":"Updated `launch.json` only: removed unsupported token fields, corrected the engine notes, and preserved all constructor arguments, permissions, and pool values. Notes are within the 4,000-character limit.\n\n`forge build` passed. All 152 tests passed with the required fuzz seed, including both token orders and blank-chain admission.","treeHash":"74fdfdd14f9cef9abb467891d02e52bafd60a0e9","usage":{"cachedInputTokens":1027456,"inputTokens":65123,"model":"gpt-6-astra","outputTokens":8303,"runtime":"codex","turns":5,"wallClockMs":329920}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"df74f6c887684f20","findings":[{"citation":"resolved","description":"beforeSwap reads the pool's current in-range liquidity (line 269), stashes it, and afterSwap's _play -> _trade (lines 572-579) turns the trade's share of it into the move's strength with Strength.fromShare (0 bps at a 1/100,000 share, the 9,000 bps cap from a 1% share). getHookPermissions enables no liquidity callbacks, so any account can add liquidity in the transaction before an opponent's trade and remove it in the transaction after, in the same block. The opponent's bid keeps its size (it still owns the move and still pays the 0.5% hook fee) but its recorded strength collapses, so the engine plays a near-random move for it, while the attacker's own trade of the same size, made once the liquidity is gone, plays at the cap. The bracket costs only gas: the attacker gets its liquidity back and even collects the opponent's 1.25% LP fee on that one swap. Strength.sol line 4 documents the opposite guarantee ('from its share of the pool, never from other traders' sizes'). Moves are the only way a team's chest pays out (captures 0.3%-2.7%, check 0.3%, mate 25.3%, capped at 2x the trade), so a bidder whose moves are forced to ~0% captures far less and blunders far more, and the other team's bidders collect the chests. No funds are taken directly: the loss is the victim's expected reward and the fairness the hook sells, hence medium. Reported by audit_economics; reproduced here with its proof, which fails on this tree (Bob at 271 bps against Alice at 8,987 and the attacker at 9,000). Fixes that keep the design: compute the share against the liquidity at the start of the block or of the move's window (sample it as the prices are sampled in _sample), or enable before/afterAddLiquidity to time-lock JIT adds (the factory's zero-liquidity fee collection is a remove and would still pass).","line":269,"path":"src/IMDuelHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolSwapTest} from \"v4-core/src/test/PoolSwapTest.sol\";\nimport {PoolModifyLiquidityTest} from \"v4-core/src/test/PoolModifyLiquidityTest.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {ModifyLiquidityParams, SwapParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\nimport {IChessEngine} from \"src/IChessEngine.sol\";\nimport {IMDuelHook, IMDUEL_HOOK_FLAGS} from \"src/IMDuelHook.sol\";\nimport {IMDuelToken} from \"src/IMDuelToken.sol\";\n\ncontract Plain {\n    string public constant name = \"IMD\";\n    string public constant symbol = \"IMD\";\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function mint(address to, uint256 v) external { balanceOf[to] += v; }\n    function approve(address s, uint256 v) external returns (bool) { allowance[msg.sender][s] = v; return true; }\n    function transfer(address to, uint256 v) external returns (bool) { balanceOf[msg.sender] -= v; balanceOf[to] += v; return true; }\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        if (allowance[f][msg.sender] != type(uint256).max) allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v; balanceOf[to] += v; return true;\n    }\n}\n\n/// JIT liquidity against a bidder's strength: the strength of a bid is its share of the pool's in-range liquidity read\n/// in beforeSwap, and the hook has no liquidity callbacks, so anyone can add liquidity just before an opponent's trade\n/// and remove it just after, in the same block, at no cost. The opponent's identical trade then bids at 0% instead\n/// of 90%, while the attacker's own trade of the same size, with the liquidity gone again, bids at 90%.\ncontract JitStrengthTest is Test {\n    using PoolIdLibrary for PoolKey;\n\n    IPoolManager manager;\n    PoolSwapTest router;\n    PoolModifyLiquidityTest lp;\n    IMDuelHook hook;\n    PoolKey key;\n    Plain imd;\n    IMDuelToken duel;\n    uint160 constant SQRT_1_1 = 79228162514264337593543950336;\n\n    function setUp() public {\n        manager = IPoolManager(address(new PoolManager(address(this))));\n        router = new PoolSwapTest(manager);\n        lp = new PoolModifyLiquidityTest(manager);\n        imd = new Plain();\n        duel = new IMDuelToken();\n        imd.mint(address(this), 1e30);\n        imd.approve(address(router), type(uint256).max);\n        imd.approve(address(lp), type(uint256).max);\n        duel.approve(address(router), type(uint256).max);\n        duel.approve(address(lp), type(uint256).max);\n        address at = address(IMDUEL_HOOK_FLAGS | (uint160(0x4444) << 40));\n        deployCodeTo(\"IMDuelHook.sol:IMDuelHook\", abi.encode(manager, IChessEngine(address(0xE)), Currency.wrap(address(imd)), uint256(10e18), uint256(1e24), uint256(3)), at);\n        hook = IMDuelHook(at);\n        (Currency c0, Currency c1) = address(imd) < address(duel)\n            ? (Currency.wrap(address(imd)), Currency.wrap(address(duel)))\n            : (Currency.wrap(address(duel)), Currency.wrap(address(imd)));\n        key = PoolKey(c0, c1, 12500, 60, IHooks(at));\n        manager.initialize(key, SQRT_1_1);\n        // 1e24 of full-range liquidity: about 1e24 of each token in range at 1:1\n        lp.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, 1e24, 0), \"\");\n        vm.warp(block.timestamp + 400); // past the main duel's opening surcharge\n        vm.roll(block.number + 1);\n    }\n\n    function buyDuel(uint256 imdIn, address owner) internal {\n        bool zeroForOne = Currency.unwrap(key.currency0) == address(imd);\n        router.swap(key, SwapParams(zeroForOne, -int256(imdIn), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),\n            PoolSwapTest.TestSettings(false, false), abi.encodePacked(owner));\n    }\n\n    function whiteBid() internal view returns (IMDuelHook.TopBid memory) {\n        IMDuelHook.Game memory g = hook.game(key.toId());\n        return g.bids[(g.gameNo & 1) ^ (g.slice ^ 1) ^ (g.ply & 1)];\n    }\n\n    /// What the hook documents (\"strength from its share of the pool, never from other traders' sizes\"): a trade's\n    /// strength must not depend on liquidity another party adds just before it and removes just after it. Fails on the\n    /// current code: Bob's 1.2% trade plays at 275 bps while Alice's 1% and the attacker's 1.5% play at ~8600.\n    function test_aBidsStrengthDoesNotDependOnLiquidityAddedAndRemovedAroundIt() public {\n        // Alice: 1% of the in-range depth, near the 90% cap\n        buyDuel(1e22, address(0xA11CE));\n        uint16 alice = whiteBid().strength;\n        assertGe(alice, 8000, \"a 1% trade plays near the 90% cap\");\n        // the attacker brackets Bob's trade with 1000x liquidity, in the same block\n        uint256 imdBefore = imd.balanceOf(address(this));\n        uint256 duelBefore = duel.balanceOf(address(this));\n        lp.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, 1e27, 0), \"\");\n        buyDuel(1.2e22, address(0xB0B)); // beats Alice's bid by 20%\n        lp.modifyLiquidity(key, ModifyLiquidityParams(-887220, 887220, -1e27, 0), \"\");\n        assertEq(whiteBid().owner, address(0xB0B), \"Bob's bigger trade owns the move\");\n        uint16 bob = whiteBid().strength;\n        // the attacker got all its liquidity back plus Bob's LP fee: the bracket cost it nothing\n        assertGe(imd.balanceOf(address(this)) + duel.balanceOf(address(this)), imdBefore + duelBefore - 1.2e22 - 2, \"the attacker is not out of pocket\");\n        // the attacker's own trade afterwards, at the depth Alice saw\n        buyDuel(1.5e22, address(0xBAD));\n        assertEq(whiteBid().owner, address(0xBAD));\n        uint16 attacker = whiteBid().strength;\n        emit log_named_uint(\"alice strength (bps)\", alice);\n        emit log_named_uint(\"bob strength (bps), bracketed by JIT liquidity\", bob);\n        emit log_named_uint(\"attacker strength (bps)\", attacker);\n        assertGe(bob, 8000, \"Bob's 1.2% trade must play near the cap like Alice's and the attacker's\");\n    }\n}","reproduction":"Main duel IMD/IMDUEL at 1:1 with 1e24 full-range liquidity (a 1% share is 1e22), warped past the 300 s opening, launch constructor arguments (minImd 10e18, minImduel 1e24, turnBlocks 3). (1) Alice buys IMDUEL with 1e22 IMD, hookData = Alice: her bid is recorded at 8,987 bps. (2) In the same block the attacker calls modifyLiquidity(+1e27 full range); Bob buys IMDUEL with 1.2e22 IMD (beats Alice's bid by 20%); the attacker calls modifyLiquidity(-1e27). Expected: Bob owns the move at a strength near the cap, like Alice's, since his trade is larger against the same durable pool. Actual: Bob owns the move at 271 bps; the attacker's IMD+IMDUEL balances are back to their start minus only Bob's swap input (it kept Bob's LP fee). (3) The attacker then buys with 1.5e22: strength 9,000 bps. Run: forge test --match-path test/scratch/JitStrength.t.sol -> FAIL 'Bob's 1.2% trade must play near the cap like Alice's and the attacker's: 271 < 8000'.","severity":"medium","snippet":"        uint256 depth = manager.getLiquidity(id); // sets a bid's strength: every buy bids","title":"Bid strength is read from spot in-range liquidity with no liquidity callbacks: JIT liquidity bracketing an opponent's trade plays its move at ~3% instead of ~90% at no cost"},{"citation":"resolved","description":"withdrawTo forwards `to` unchecked through _withdraw (line 370) into the unlock, where action 0 calls _send(c, to, amount) -> manager.burn + manager.take(c, to, amount) (lines 355-356). owed[who][c] is zeroed at line 373 before the unlock. For an ERC-20 reward (IMD, IMDUEL) a zero `to` reverts inside the token's transfer (IMDuelToken._transfer line 53 rejects to == address(0)), so the whole call reverts and the owed balance survives. For a native-ETH reward the PoolManager's CurrencyLibrary.transfer is a plain CALL with value to address(0), which succeeds, so the reward is gone. ETH duels are reachable on this hook: afterInitialize (line 251) admits any pool whose other side is IMD or IMDUEL, so an ETH/IMD pool is a valid duel whose ETH team's chest pays rewards in native ETH. Only the owed party can trigger it (withdraw(who, c) always pays `who`), so this is a footgun for an integrator passing an uninitialised recipient, not an attack. The token contract and approve both refuse the zero address; the hook's only user-named destination does not. Minimal fix: `if (to == address(0)) revert BadValue();` in withdrawTo, which changes no intended behaviour. Reported by audit_permissions; confirmed by trace.","line":366,"path":"src/IMDuelHook.sol","reproduction":"State: an ETH/IMD duel opened on the hook (PoolKey(ADDRESS_ZERO, IMD, 3000, 60, hook)), its ETH chest funded with fundChest{value: 5 ether}(key, false, 5 ether), and owed[A][0] == 1 ether for some owner A (a reward from a move of ETH's team, or the mapping entry written with vm.store in a test). As A call hook.withdrawTo(Currency.wrap(address(0)), address(0)). Expected: revert, as the ERC-20 path and the token's own zero-address checks do, with owed[A][0] still 1 ether. Actual: the call succeeds, owed[A][0] == 0, address(0).balance grows by exactly 1 ether and the hook's native claims (manager.balanceOf(hook, 0)) fall by 1 ether. The same call with c = IMD reverts with IMDuelToken.InvalidAddress.","severity":"low","snippet":"    function withdrawTo(Currency c, address to) external {\n        _withdraw(msg.sender, c, to);\n    }","title":"withdrawTo accepts address(0) as destination: a native-ETH reward sent there is burned, while the ERC-20 path reverts"},{"citation":"resolved","description":"_batch is documented (line 449 and launch.json notes) as spending at most BATCH_MINS minimums. Integer division makes the test `amount / BATCH_MINS > min` false for any pile in [BATCH_MINS * min, BATCH_MINS * min + BATCH_MINS - 1], so such a pile is returned whole and the batch spends up to 9 wei more than the bound. With the launch's minImd = 10e18 that is 9 wei against a 100 IMD cap: economically nil, kept because the code does not match its stated bound. `amount > BATCH_MINS * min ? BATCH_MINS * min : amount` makes it exact. Reported by write_foundry_tests; confirmed by arithmetic.","line":451,"path":"src/IMDuelHook.sol","reproduction":"Pure arithmetic on line 451 with min = 10e18: amount = 100e18 + 9 gives amount / 10 = 10e18 + 0 (the 9 wei truncate), which is not > min, so the function returns 100e18 + 9. Expected (documented): at most 100e18. Actual: 100e18 + 9. amount = 100e18 + 10 gives 10e18 + 1 > min and returns 100e18, so the bound only slips inside that 9-wei window. Harness check: a hook with minImd = 1e15 and an IMD pile of exactly 10e15 + 9, three sampled blocks, then convert(IMD): Converted.spent == 10000000000000009.","severity":"info","snippet":"        return amount / BATCH_MINS > min ? BATCH_MINS * min : amount;","title":"A conversion batch can spend up to BATCH_MINS - 1 wei more than its documented cap of ten minimums"},{"citation":"resolved","description":"The constructor validates the engine and turnBlocks but not the two minimums. With minImd = 0, _batch(amount, 0) (line 451) returns BATCH_MINS * 0 = 0 for every pile of 10 wei or more, and _swapClaims returns (0, 0) on amountIn == 0 (line 467), so the IMD slice is never converted, by trades or by convert(), and never feeds the IMDUEL chest or the burn; meanwhile `pile >= _minBatch(s)` (line 565) is always true, so every trade of an IMD-slice duel spends up to CONVERT_GAS on a batch that does nothing. launch.json passes 10e18 and 1e24, so the committed launch is unaffected; it matters only if the hook is redeployed with a zero minimum. Rejecting 0 in the constructor (BadConfig) or treating 0 as 'no cap' closes it. Reported by write_foundry_tests; confirmed by trace.","line":196,"path":"src/IMDuelHook.sol","reproduction":"Deploy the hook with minImd = minImduel = 0 (the constructor accepts it), open the main duel IMD/IMDUEL with liquidity, trade so that pile[IMD] = 1e18, sample three blocks, then call convert(IMD). Expected: some of the pile converts (a Converted event with spent > 0). Actual: _batch(1e18, 0) = 0, _swapClaims returns (0, 0), pile[IMD] stays exactly 1e18 and Converted is emitted with spent = bought = burned = 0.","severity":"info","snippet":"        if (address(engine_) == address(0) || turnBlocks_ == 0 || turnBlocks_ > 1_000) revert BadConfig();","title":"The constructor accepts minImd = 0, which silently stops IMD conversion for good (not this launch's configuration)"},{"citation":"resolved","description":"The contract notes (lines 36-38, 345-347) and launch.json state that nothing is ever sent inside a trade so that no recipient runs code while the trader's PoolManager is unlocked. Rewards honour this: _payBounty only records owed[]. The protocol-slice batch does not: afterSwap -> _play -> this.convertBatch (line 566) -> _convert -> _send(imduel, DEAD, burned) -> manager.burn + manager.take (lines 355-356) moves real IMDUEL from the PoolManager to 0x...dEaD during the trader's unlock. The safety goal still holds: IMDUEL is the plain launch token with no transfer callbacks, 0x...dEaD has no code, and the batch runs inside try/catch so a failed take cannot revert the trade. Documentation accuracy only; no code change needed unless the author wants the statement literally true (defer the burn to the external convert path). Reported by audit_flow; confirmed by trace.","line":445,"path":"src/IMDuelHook.sol","reproduction":"State: a hook whose main duel pairs IMD/IMDUEL with liquidity, and a second duel X/IMDUEL (slice taken in IMDUEL), minImduel <= 0.01e18. Call: one exact-input swap selling 10e18 IMDUEL into the X/IMDUEL duel. Expected per the notes: no token leaves the PoolManager inside the trade. Actual: within that swap transaction IMDUEL.balanceOf(0x...dEaD) rises by 0.005e18 (half of the 0.1% slice) and Converted is emitted before the swap returns, i.e. manager.take ran while the trader's unlock was open. test/Slice.t.sol test_imduelDuelsNeedNoSwap exercises the same path.","severity":"info","snippet":"        if (burned != 0) _send(imduel, DEAD, burned);","title":"The IMDUEL burn transfer does happen inside a trader's unlock; 'nothing is ever sent inside a trade' is exact only for rewards"}],"hash":"b5d6e1ec3dd848d004a0fb9ccb189d59d61936b1f6cc6b29ab6302633515dfe4","nodeId":"1ded2cd8-f75c-475f-8994-4ebef921000c","outcome":"completed","summary":"Review complete. The findings file is written at `.imd-findings.json` and no tracked file was changed.\n\n**Outcome.** All five specialist findings reproduce against the code. None were duplicates of each other, so none were merged. My own pass with the auditor references found nothing further: the delta accounting, fee paths, PartialFill guard, bid and resolve logic, gas-starvation guard, withdrawal ordering, manifest, sizes and logo all hold, and the full suite passes with 160 of 160 tests.\n\n**Findings kept, in severity order:**\n\n- **Medium, JIT liquidity collapses an opponent's bid strength** (src/IMDuelHook.sol:269). Strength comes from spot in-range liquidity and the hook has no liquidity callbacks, so a bracketing add and remove in the same block forces a rival's move to about 3% while costing only gas. The economics specialist's proof fails on this tree exactly as stated, Bob at 271 bps against Alice at 8,987, and is attached to the finding.\n- **Low, withdrawTo accepts the zero address** (src/IMDuelHook.sol:366). A native-ETH reward sent there is burned while the ERC-20 path reverts. Only the owed party can trigger it, so it is a footgun rather than an attack. Raised from the specialist's info to low because funds are lost.\n- **Info, batch cap slips by up to 9 wei** (line 451), **info, zero minimums disable IMD conversion** (line 196, not this launch's arguments), and **info, the burn transfer does run inside a trade** (line 445), so the \"nothing is ever sent inside a trade\" statement is exact only for rewards.\n\n**Coverage.** All twelve entry points are answered: eight hold, four carry findings. Extra rows record the solvency invariant, the manifest, size limits and the logo as holding. The one unreached row is the verifier's Slither pass, which I could not run because this machine has no pip. That is the one check left for the verifier's own run.","treeHash":null,"usage":{"cachedInputTokens":829057,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":38751,"runtime":"claude","turns":24,"wallClockMs":746624}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"62491201fe455e89","findings":[],"hash":"d2325796819882585e5dc6c706b167b7eb38a16d743c3e0e2a423c1721931693","nodeId":"6a4379da-777b-44b7-9fa2-2adc9fca63ef","outcome":"completed","summary":"The review is complete. The findings file is written with an empty findings list and a full coverage record, and the working tree is clean apart from it.\n\n**Outcome: no reproducible math defect in the assigned area.** I checked `src/IMDuelHook.sol`, `src/Strength.sol` and `src/IMDuelToken.sol` against the Math Precision, Boundary and Numerical Gap checklists, confirmed the build and all 152 existing tests pass, and ran my own scratch probes against the live contracts before deleting them.\n\nWhat I verified, with concrete inputs:\n\n- **Fee arithmetic.** The chest share is `amount * bps / 10000` with bps falling from 2540 to 40 over 300 seconds. It rounds down, so swaps under 25 wei pay no chest share and under 1000 wei no slice, which is a gas-bounded dust case, not a leak. An exact-output buy of 100 tokens at age 1 second delivered exactly 100 and credited 25.31 to the chest.\n- **PartialFill guard.** v4 passes the raw pool delta into afterSwap before subtracting the hook delta, so the equality against `amountSpecified + taken` is exact in both swap directions and both order types.\n- **Conversion batches.** Sample packing round-trips every sqrt price from MIN to MAX within a relative error of 2^-47 and fits 56 bits. The batch cap spends at most 10 minimums plus 9 wei at one boundary. Spent never exceeds the pile, so the subtraction cannot underflow.\n- **Strength curve.** Fuzzed monotone in the payment and capped at 9000. Measured points are 0 at a 1e-5 share, 3065 at 1e-4, 6010 at 1e-3, 8998 at 1e-2, within the documented tolerance of the linear log fraction.\n- **Casts and packing.** The `int128` fee cast is guarded by the manager's SafeCast on mint. Bid size and cap fit `uint128` because pool deltas are `int128`. The transient stash fields do not overlap.\n- **Token.** Unchecked balance addition is bounded by the fixed supply, and self-transfers resolve correctly.\n\nOne boundary I traced but did not report as a defect: the `uint160` cast of the batch price limit truncates only when the main duel's sqrt price sits in the top 0.1% of the range, and the truncated limit then simply skips the batch with nothing lost. It is recorded as a note in the coverage record.\n\nCoverage has one row for each of the 12 listed entry points, all `holds`, plus three invariant rows. Nothing in my area was left unreached.","treeHash":null,"usage":{"cachedInputTokens":1170473,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":51006,"runtime":"claude","turns":28,"wallClockMs":944745}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fa4b91aed45c94fa","findings":[{"citation":"resolved","description":"Settles the residual of my earlier medium 87c3e492 (fixed for pools with liquidity in range at the block's start: its proof passes on this tree) and merges write_foundry_tests' finding 7bbfb875, which I reproduced. The fix makes beforeAddLiquidity record the pre-add in-range liquidity as the block's sample, but only `if (liquidity != 0)` (line 297), and _sampleDepth's minimum skips zero samples (line 548: `if (l != 0 && (depth == 0 || l < depth)) depth = l;`). When the pool's price sits outside every position at a block's start (in-range liquidity 0), two things follow. (A) An add records nothing, so the one-transaction bracket [add 1e27, dust swap, remove 1e27] at the start of three blocks is again each block's sample: the depth is 1e27 although the pool held it at no block boundary, exactly what 87c3e492 was fixed for. (B) A swap that opens such a block records a 0 sample; three such blocks make all three samples 0, the loop skips them all, depth is 0 and Strength.fromShare(paid, 0) returns 0 for every bid of the block the price returns in, with no bracket at all. Who can reach the zero-liquidity state: any duel whose liquidity is all concentrated (anyone may open a duel on this hook), by pushing the price through the range into a pocket it adds and removes; and the factory's own main duel, because script/LaunchPolicy.sol seeds it single-sided with the opening tick as one boundary of the position, so there is no liquidity past the opening tick: selling IMDUEL for the IMD the pool holds (plus a pocket beyond the opening tick to absorb the remainder) leaves in-range liquidity 0 at a price just past the opening tick, and the attacker's position is a trade at the pool's price it can unwind later, not a loss. Cost of (B) in a quiet pool: the 1.75% LP+hook fees on the parking trade and on dust re-parks; the victim keeps paying the 0.5% hook fee and owns the move but the engine plays it at 0%, so the victim captures less and blunders more and the other team's bidders collect the chests, the impact that made 9537d3ff and 87c3e492 medium. The contract notes (lines 539-543, 'to count, liquidity has to be in the pool at the start of three sampled blocks') and Strength.sol line 4 ('never from other traders' sizes') do not hold in this state. A fix that keeps the design: treat a zero observation as 'no information' rather than a sample or a non-event: in _recordDepth, when liquidity == 0 and a nonzero sample exists, stamp the block as sampled without shifting the samples (so neither a following bracket nor a zero enters), and call _recordDepth from beforeAddLiquidity unconditionally; see finding 2 for the one case (no sample exists yet) this leaves.","line":297,"path":"src/IMDuelHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolSwapTest} from \"v4-core/src/test/PoolSwapTest.sol\";\nimport {PoolModifyLiquidityTest} from \"v4-core/src/test/PoolModifyLiquidityTest.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {SwapParams, ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\nimport {StateLibrary} from \"v4-core/src/libraries/StateLibrary.sol\";\nimport {MockERC20} from \"solmate/src/test/utils/mocks/MockERC20.sol\";\nimport {IMDuelHook, IMDUEL_HOOK_FLAGS} from \"src/IMDuelHook.sol\";\n\n/// A pool whose price sits outside every position at a block's start has in-range liquidity 0 there. Then\n/// beforeAddLiquidity records nothing (`if (liquidity != 0)`), so a same-transaction [add, dust swap, remove]\n/// bracket is again the block's sample; and a block opened by a swap records a 0 sample, which _sampleDepth skips,\n/// so three such blocks give a depth of 0 and every bid of the block the price returns in plays at 0%.\n/// Duel: IMD (c0) / token (c1), fee 12500, spacing 60, the honest 1e24 of liquidity in [-600, 600] only, the\n/// launch's hook arguments (10e18, 1e24, 3). White buys c1 (zeroForOne); Black buys c0 (oneForZero, price up).\ncontract EmptyRangeDepthTest is Test {\n    using PoolIdLibrary for PoolKey;\n    using StateLibrary for IPoolManager;\n\n    uint160 constant SQRT_PRICE_1_1 = 79228162514264337593543950336;\n    address constant ALICE = address(0xA11CE);\n    address constant BAD = address(0xBAD);\n    IPoolManager manager;\n    PoolSwapTest swapRouter;\n    PoolModifyLiquidityTest lpRouter;\n    IMDuelHook hook;\n    PoolKey key;\n    PoolId id;\n\n    function setUp() public {\n        manager = IPoolManager(vm.deployCode(\"PoolManager.sol:PoolManager\", abi.encode(address(this))));\n        swapRouter = PoolSwapTest(vm.deployCode(\"PoolSwapTest.sol:PoolSwapTest\", abi.encode(manager)));\n        lpRouter = PoolModifyLiquidityTest(vm.deployCode(\"PoolModifyLiquidityTest.sol:PoolModifyLiquidityTest\", abi.encode(manager)));\n        MockERC20 a = new MockERC20(\"A\", \"A\", 18);\n        MockERC20 b = new MockERC20(\"B\", \"B\", 18);\n        (Currency c0, Currency c1) = address(a) < address(b)\n            ? (Currency.wrap(address(a)), Currency.wrap(address(b)))\n            : (Currency.wrap(address(b)), Currency.wrap(address(a)));\n        for (uint256 i; i < 2; i++) {\n            MockERC20 t = i == 0 ? a : b;\n            t.mint(address(this), 2 ** 200);\n            t.approve(address(swapRouter), type(uint256).max);\n            t.approve(address(lpRouter), type(uint256).max);\n        }\n        address engine = vm.deployCode(\"ChessEngineV5.sol:ChessEngineV5\");\n        address at = address(IMDUEL_HOOK_FLAGS | (uint160(0x1D0E1) << 40));\n        deployCodeTo(\"IMDuelHook.sol:IMDuelHook\", abi.encode(manager, engine, c0, 10e18, 1_000_000e18, 3), at);\n        hook = IMDuelHook(at);\n        key = PoolKey(c0, c1, 12500, 60, IHooks(at));\n        id = key.toId();\n        manager.initialize(key, SQRT_PRICE_1_1);\n        lp(-600, 600, 1e24); // the pool's honest, standing liquidity: concentrated\n        vm.warp(block.timestamp + 400); // past the opening surcharge, within the turn timeout\n        // three honest blocks: every sample is the honest 1e24\n        for (uint256 i; i < 3; i++) {\n            next();\n            swap(false, 100, BAD);\n        }\n    }\n\n    function next() internal {\n        vm.roll(vm.getBlockNumber() + 1);\n        vm.warp(vm.getBlockTimestamp() + 12);\n    }\n\n    function lp(int24 lower, int24 upper, int256 liquidity) internal {\n        lpRouter.modifyLiquidity(key, ModifyLiquidityParams(lower, upper, liquidity, 0), \"\");\n    }\n\n    function swap(bool zeroForOne, uint256 amountIn, address owner) internal {\n        swapRouter.swap(\n            key,\n            SwapParams(zeroForOne, -int256(amountIn), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),\n            PoolSwapTest.TestSettings(false, false),\n            abi.encodePacked(owner)\n        );\n    }\n\n    /// White's (currency1's team's) top bid.\n    function whiteBid() internal view returns (IMDuelHook.TopBid memory) {\n        return hook.game(id).bids[1];\n    }\n\n    function control() internal returns (uint16 strength) {\n        uint256 snap = vm.snapshotState();\n        next();\n        swap(true, 1e22, ALICE);\n        assertEq(whiteBid().owner, ALICE);\n        strength = whiteBid().strength;\n        assertGe(strength, 8_000, \"control: a 1% share of the honest depth plays near the cap\");\n        vm.revertToState(snap);\n    }\n\n    /// Parks the price above the honest range with no liquidity in range: a pocket above it absorbs what crosses it.\n    function park(uint256 amountIn) internal {\n        lp(600, 6000, 2e22);\n        swap(false, amountIn, BAD); // Black buys c0 through the honest range (or just across its edge) into the pocket\n        lp(600, 6000, -2e22);\n        assertEq(manager.getLiquidity(id), 0, \"no liquidity at the parked price\");\n    }\n\n    /// Attack B: at the start of three blocks the price is parked outside the honest range. Each block's first swap\n    /// records 0, which the depth skips, so the victim trading in the third block (after its first swap walked the\n    /// price back into the honest 1e24) bids at 0%.\n    function test_parkedPriceZeroesTheDepth() public {\n        uint16 expected = control();\n        park(3.2e22);\n        for (uint256 i; i < 3; i++) {\n            next();\n            swap(true, 100, BAD); // the block's first swap: walks the price down into the honest range, samples 0\n            if (i < 2) park(300); // back out across the edge for the next block boundary\n        }\n        assertEq(manager.getLiquidity(id), 1e24, \"the pool holds its honest liquidity again\");\n        swap(true, 1e22, ALICE);\n        assertEq(whiteBid().owner, ALICE, \"the victim owns the move\");\n        assertApproxEqAbs(whiteBid().strength, expected, 100, \"the victim's share of the honest depth\");\n    }\n\n    /// Attack A: with the price parked outside every position, beforeAddLiquidity records nothing, so a bracket\n    /// [add 1e27, dust swap, remove 1e27] at the start of three blocks is each block's sample, as before 87c3e492.\n    function test_bracketOnAnEmptyRangeInflatesTheDepth() public {\n        uint16 expected = control();\n        park(3.2e22);\n        for (uint256 i; i < 3; i++) {\n            next();\n            lp(-12000, 12000, 1e27); // beforeAddLiquidity sees 0 in range and records nothing\n            swap(true, 100, BAD); // samples 1e27\n            lp(-12000, 12000, -1e27);\n        }\n        assertEq(manager.getLiquidity(id), 0, \"the pool is back to its parked state\");\n        swap(true, 1e22, ALICE); // walks the price into the honest 1e24 and trades against it\n        assertEq(manager.getLiquidity(id), 1e24);\n        assertEq(whiteBid().owner, ALICE, \"the victim owns the move\");\n        assertApproxEqAbs(whiteBid().strength, expected, 100, \"measured against liquidity the pool never held at a block's start\");\n    }\n}","reproduction":"Duel IMD (c0) / token (c1), fee 12500, spacing 60, hook built with the launch's arguments (10e18, 1e24, 3), price 1:1, the honest 1e24 of liquidity in [-600, 600] only, 400 s after opening, three honest dust-traded blocks (samples 1e24). Control: White buys c1 with 1e22 (a 1% share) -> top bid strength 8987. Park: add a pocket of 2e22 in [600, 6000], Black buys c0 with 3.2e22 (crosses the honest range into the pocket), remove the pocket -> getLiquidity(id) == 0. Attack B: in each of three blocks the first swap is a 100-wei White trade (walks the price back into the honest 1e24; beforeSwap sampled 0), then for the first two blocks re-park with [add pocket, 300-wei Black trade, remove pocket]. In the third block, after its first swap (getLiquidity == 1e24), the victim buys c1 with 1e22, hookData = victim. Expected: strength about 8987 like the control. Actual: the victim owns the move at strength 0. Attack A: after parking, in each of three blocks one transaction [add 1e27 in [-12000, 12000], 100-wei White trade, remove 1e27] (beforeAddLiquidity sees 0 and records nothing; the swap records 1e27); in the third block the victim's 1e22 White trade walks into the honest 1e24 and bids. Expected about 8987; actual 116. Run: copy the proof to test/scratch/EmptyRangeDepth.t.sol and `forge test --match-path test/scratch/EmptyRangeDepth.t.sol` -> both tests FAIL on this tree ('the victim's share of the honest depth: 0 !~= 8987' and 'measured against liquidity the pool never held at a block's start: 116 !~= 8987').","severity":"medium","snippet":"        if (liquidity != 0) _recordDepth(id, liquidity);","title":"Depth sampling is defeated when a block starts with zero in-range liquidity: beforeAddLiquidity records nothing and zero swap samples are skipped, so a bracket inflates the depth or parking the price "},{"citation":"resolved","description":"Same mechanism as finding 1 (a zero in-range liquidity observation becomes the block's sample and a depth of 0), but deterministic and with no attacker, in the launch's own first block, and not covered by finding 1's suggested fix because no earlier sample exists yet. script/LaunchPolicy.sol opening(false) (the token is currency1, one of the two CREATE2 address orders the task says must both work) initializes the pool at tick 128940 and seeds 80% of the supply in [-887220, 128940]. v4 counts a position in range only while tickLower <= tick < tickUpper, so at the opening tick the pool's liquidity is 0 (the proof asserts manager.getLiquidity(id) == 0 after the seed; test/Launch.t.sol's launches pass because they never assert the first bid's strength). The first buy's beforeSwap therefore records 0 as that block's start liquidity (line 315 -> _sampleDepth -> _recordDepth), _sampleDepth skips the zero and returns depth 0, and _trade gives every bid of that block strength 0: the opening block, where buyers pay the 25.4% opening surcharge, has its moves played at 0%. The next block samples the liquidity the first buy found and the same share plays at the cap. In the other order (token is currency0, position [open, EDGE]) the seed is in range at the opening tick and the first block measures correctly, so the behaviour of the launch depends on the mined token address. Impact is one block of moves (the chests are nearly empty then, so the reward lost is small), hence low. Fix together with finding 1: when a block's first observation finds no liquidity in range and no sample exists yet, take the sample from the liquidity in range after the block's first swap (its end price) instead of 0, or let the next nonzero observation of the block supply it.","line":315,"path":"src/IMDuelHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolSwapTest} from \"v4-core/src/test/PoolSwapTest.sol\";\nimport {PoolModifyLiquidityTest} from \"v4-core/src/test/PoolModifyLiquidityTest.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {PoolId, PoolIdLibrary} from \"v4-core/src/types/PoolId.sol\";\nimport {SwapParams, ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {TickMath} from \"v4-core/src/libraries/TickMath.sol\";\nimport {FullMath} from \"v4-core/src/libraries/FullMath.sol\";\nimport {StateLibrary} from \"v4-core/src/libraries/StateLibrary.sol\";\nimport {MockERC20} from \"solmate/src/test/utils/mocks/MockERC20.sol\";\nimport {IMDuelHook, IMDUEL_HOOK_FLAGS} from \"src/IMDuelHook.sol\";\n\n/// The factory's shape when $IMDUEL sorts above IMD (script/LaunchPolicy.sol): the pool opens at tick 128940 and\n/// 80% of the supply is seeded single-sided in [-887220, 128940]. At the opening tick that position is out of range\n/// (tick < tickUpper fails), so in-range liquidity is 0 until the first buy moves the price. The block of the first\n/// buy therefore samples 0 and every bid in it plays at 0%, however large its share.\ncontract OpeningBlockDepthTest is Test {\n    using PoolIdLibrary for PoolKey;\n    using StateLibrary for IPoolManager;\n\n    int24 constant OPEN_TICK = 128_940;\n    int24 constant EDGE = 887_220;\n    address constant ALICE = address(0xA11CE);\n    address constant BOB = address(0xB0B);\n    IPoolManager manager;\n    PoolSwapTest swapRouter;\n    PoolModifyLiquidityTest lpRouter;\n    IMDuelHook hook;\n    PoolKey key;\n    PoolId id;\n\n    function setUp() public {\n        manager = IPoolManager(vm.deployCode(\"PoolManager.sol:PoolManager\", abi.encode(address(this))));\n        swapRouter = PoolSwapTest(vm.deployCode(\"PoolSwapTest.sol:PoolSwapTest\", abi.encode(manager)));\n        lpRouter = PoolModifyLiquidityTest(vm.deployCode(\"PoolModifyLiquidityTest.sol:PoolModifyLiquidityTest\", abi.encode(manager)));\n        MockERC20 a = new MockERC20(\"A\", \"A\", 18);\n        MockERC20 b = new MockERC20(\"B\", \"B\", 18);\n        // IMD is the lower address, the token the higher: the token is currency1\n        (Currency imd, Currency token) = address(a) < address(b)\n            ? (Currency.wrap(address(a)), Currency.wrap(address(b)))\n            : (Currency.wrap(address(b)), Currency.wrap(address(a)));\n        for (uint256 i; i < 2; i++) {\n            MockERC20 t = i == 0 ? a : b;\n            t.mint(address(this), 2 ** 200);\n            t.approve(address(swapRouter), type(uint256).max);\n            t.approve(address(lpRouter), type(uint256).max);\n        }\n        address engine = vm.deployCode(\"ChessEngineV5.sol:ChessEngineV5\");\n        address at = address(IMDUEL_HOOK_FLAGS | (uint160(0x1D0E1) << 40));\n        deployCodeTo(\"IMDuelHook.sol:IMDuelHook\", abi.encode(manager, engine, imd, 10e18, 1_000_000e18, 3), at);\n        hook = IMDuelHook(at);\n        key = PoolKey(imd, token, 12500, 60, IHooks(at));\n        id = key.toId();\n        // LaunchPolicy.opening(false): price at OPEN_TICK, the token alone in [-EDGE, OPEN_TICK]\n        manager.initialize(key, TickMath.getSqrtPriceAtTick(OPEN_TICK));\n        uint160 lo = TickMath.getSqrtPriceAtTick(-EDGE);\n        uint160 hi = TickMath.getSqrtPriceAtTick(OPEN_TICK);\n        uint256 liquidity = FullMath.mulDiv(8e26, 1 << 96, hi - lo) * 999 / 1000;\n        lpRouter.modifyLiquidity(key, ModifyLiquidityParams(-EDGE, OPEN_TICK, int256(liquidity), 0), \"\");\n    }\n\n    function buy(uint256 imdIn, address owner) internal {\n        swapRouter.swap(\n            key,\n            SwapParams(true, -int256(imdIn), TickMath.MIN_SQRT_PRICE + 1),\n            PoolSwapTest.TestSettings(false, false),\n            abi.encodePacked(owner)\n        );\n    }\n\n    /// White's ($IMDUEL's team's, currency1) top bid.\n    function whiteBid() internal view returns (IMDuelHook.TopBid memory) {\n        return hook.game(id).bids[1];\n    }\n\n    function test_firstBuysBlockMeasuresAgainstNothing() public {\n        assertEq(manager.getLiquidity(id), 0, \"the seed is out of range at the opening tick\");\n        buy(50e18, ALICE); // 50 IMD: about 2.5% of the seed's IMD-side depth (2,000 IMD at 2,500 per supply)\n        assertGt(manager.getLiquidity(id), 0, \"the first buy moved the price into the seed\");\n        assertEq(whiteBid().owner, ALICE);\n        uint16 opening = whiteBid().strength;\n        // the same share one block later: the next block samples the liquidity the first buy found\n        vm.roll(vm.getBlockNumber() + 1);\n        vm.warp(vm.getBlockTimestamp() + 12);\n        buy(60e18, BOB);\n        assertEq(whiteBid().owner, BOB);\n        assertGe(whiteBid().strength, 8_000, \"the next block: a 3% share plays at the cap\");\n        assertGe(opening, 8_000, \"the opening block: a 2.5% share should play near the cap too\");\n    }\n}","reproduction":"IMD at the lower address, the token at the higher (currency1); hook built with the launch's arguments; pool IMD/token at fee 12500, spacing 60, initialized at TickMath.getSqrtPriceAtTick(128940); the token seeded alone in [-887220, 128940] with liquidity 8e26 * 2^96 / (sqrtP(128940) - sqrtP(-887220)) * 999 / 1000, as LaunchPolicy.opening(false) gives it. State: manager.getLiquidity(id) == 0. Call: Alice buys the token with 50 IMD (zeroForOne exact input, hookData = Alice), about 2.5% of the seed's IMD-side depth. Expected: White's top bid (bids[1]) owned by Alice at strength >= 8000 (the same share one block later, Bob's 60 IMD buy, bids at 9000). Actual: Alice's bid has strength 0. Run: copy the proof to test/scratch/OpeningBlockDepth.t.sol and `forge test --match-path test/scratch/OpeningBlockDepth.t.sol` -> FAIL 'the opening block: a 2.5% share should play near the cap too: 0 < 8000'.","severity":"low","snippet":"        uint256 depth = _sampleDepth(id, manager.getLiquidity(id)); // sets a bid's strength: every buy bids","title":"In the factory's launch with IMDUEL sorting above IMD, the seed is out of range at the opening tick, so the block of the first buy samples depth 0 and every bid in it plays at 0% whatever its share"},{"citation":"resolved","description":"Merges audit_flow's 07b091e3, reproduced. Design decision (1) holds for rewards: _payBounty -> _pay only records owed[] (src/IMDuelHook.sol lines 399-403) and withdraw / withdrawTo move the tokens later. But afterSwap -> _play -> this.convertBatch (line 653) -> _convert -> _send(imduel, DEAD, burned) (line 498) calls manager.burn and manager.take (lines 406-407), so real IMDUEL leaves the PoolManager for 0x...dEaD during the trader's unlock. It is harmless: IMDUEL is the plain src/IMDuelToken.sol with no transfer callbacks, 0x...dEaD has no code, and the call sits in try/catch so a failed take cannot revert the trade; the contract notes at lines 39-41 now state exactly this. The manifest's notes (launch.json line 34, last sentence) still make the unqualified claim. Documentation accuracy only; no code change needed, the sentence in the notes should match the contract's.","line":34,"path":"launch.json","reproduction":"State: a hook whose main duel pairs IMD/IMDUEL and a second duel X/IMDUEL (slice taken in IMDUEL), minImduel small (test/Slice.t.sol test_imduelDuelsNeedNoSwap uses 1e15). Call: one exact-input swap selling 10e18 IMDUEL into the X/IMDUEL duel. Expected per the manifest's notes: no token leaves the PoolManager inside the trade. Actual: within that swap IMDUEL.balanceOf(0x...dEaD) rises by 0.005e18 and the Converted event is emitted inside the swap, i.e. manager.take ran while the trader's unlock was open. `forge test --match-path test/Slice.t.sol --match-test test_imduelDuelsNeedNoSwap -vvvv` shows the Transfer to 0x...dEaD nested inside the swap.","severity":"info","snippet":"nothing is ever sent inside a trade, so no recipient runs code while a trader's PoolManager is unlocked.","title":"launch.json's notes still say nothing is ever sent inside a trade; the slice batch's burn of IMDUEL to 0x...dEaD does run inside a trader's unlock (the contract notes now say so, the manifest does not"}],"hash":"de9bc8d729b0f82f0b093ba87d757c8efeb0fa3a408b101beb275ea2da9c25d7","nodeId":"1ded2cd8-f75c-475f-8994-4ebef921000c","outcome":"completed","summary":"The findings file is written and verified against the tree. Recap of this round:\n\n**My earlier finding 87c3e492 is fixed.** Both attached proofs pass on the revised code, the new beforeAddLiquidity callback records the pre-add liquidity as claimed, and the whole project suite passes (179 tests).\n\n**What I kept, in `.imd-findings.json`:**\n\n1. **Medium.** The fix covers only blocks that start with liquidity in range. When in-range liquidity is zero at a block's start, the add callback skips the record (the `if (liquidity != 0)` guard at src/IMDuelHook.sol:297) and the depth minimum skips zero samples. I reproduced both consequences in a self-contained proof: the one-transaction bracket again inflates the depth (victim at strength 116 against a control of 8,987), and simply parking the price outside the range at three block starts zeroes it (victim at 0). This is reachable in any concentrated-only duel, and in the factory's main duel too, since the single-sided seed has the opening tick as its boundary. This merges the tester's finding 7bbfb875.\n\n2. **Low.** In the token-above-IMD address order, the factory's seed is out of range at the opening tick, so the block of the very first buy samples depth 0 and every bid in it plays at 0%. A 2.5% share bids at 0 in that block and at the cap one block later. Deterministic, one block, no attacker, so low. A proof is attached.\n\n3. **Info.** The launch.json notes still claim nothing is ever sent inside a trade, while the contract notes now correctly qualify the in-trade burn to 0x…dEaD. Documentation only.\n\n**Dropped:** audit_permissions' zero-address withdrawTo note is already fixed at line 418 of the hook. audit_economics' JIT finding is the original defect, now fixed, and its proof passes. Slither and aderyn leads did not reproduce as defects: the caret in teamOf is an intentional XOR, the strict equalities are block-number stamps, and the reentrancy sites are gated by the transient lock and try/catch.\n\n**Coverage:** all 13 entry points answered, 11 holding and 2 carrying finding 1, plus two invariant rows. Scratch files under test/scratch/ are mine and are not part of the submission.","treeHash":null,"usage":{"cachedInputTokens":1891935,"inputTokens":674,"model":"claude-fable-5-1","outputTokens":39941,"runtime":"claude","turns":31,"wallClockMs":725831}}],"verification":[{"checks":[{"durationMs":74471,"exitCode":0,"name":"build","output":"Compiling 111 files with Solc 0.8.26\nSolc 0.8.26 finished in 74.35s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:70:5:\n   |\n70 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3821,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 73186)\nLogs:\n  hook: 17403\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.57ms (1.86ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.94ms (1.37ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1739826)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1153483)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2248837)\n[PASS] test_sliceSide() (gas: 645447)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 417313)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 15.78ms (7.66ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 239931)\n[PASS] test_moveCap() (gas: 239972)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 179920)\n[PASS] test_quietMoveLimit() (gas: 246190)\n[PASS] test_stalemate() (gas: 237744)\n[PASS] test_thirdRepetition() (gas: 963450)\n[PASS] test_tooFewPiecesToMate() (gas: 231569)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 17.06ms (6.14ms CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 158255)\n[PASS] test_sepoliaLaunchFile() (gas: 153655)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 23.06ms (15.43ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1426784)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1952577)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1222460)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1062878)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1040461)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 974158)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1466876)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1283692)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1511150)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1621408)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1077584)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1811511)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1222876)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 23.60ms (30.22ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22193400)\n[PASS] test_launchTokenAboveImd() (gas: 23442523)\nLogs:\n  first buy (opens game 0, bids for White): 366430\n\n[PASS] test_launchTokenBelowImd() (gas: 23389720)\nLogs:\n  first buy (opens game 0, bids for White): 361713\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 43.80ms (124.34ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4841127)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2823010)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1886986)\n[PASS] test_anyoneCanConvert() (gas: 461614)\n[PASS] test_booksBalanceAcrossPools() (gas: 8515045)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 763804)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 498890)\n[PASS] test_noRouteNoDuel() (gas: 1250179)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1186640)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 52.88ms (31.36ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 31426026)\n[PASS] test_blankChainTokenBelowImd() (gas: 31353650)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 72.85ms (97.24ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4841322)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2823009)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1886985)\n[PASS] test_anyoneCanConvert() (gas: 461614)\n[PASS] test_booksBalanceAcrossPools() (gas: 8515043)\n[PASS] test_crossBlockViaConvert() (gas: 4383013)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4545174)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 763803)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 498902)\n[PASS] test_noRouteNoDuel() (gas: 1250177)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1186639)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 121.96ms (59.40ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2485776)\nLogs:\n  plain trade: 207571\n  trade that converts a batch: 271382\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27682885)\nLogs:\n  hook share of a moving trade: average: 276326\n  hook share of a moving trade: max: 307180\n\n[PASS] test_middlegameGas() (gas: 8148240)\nLogs:\n  first bid in a new pool: 270547\n  bidding trade: 191911\n  outbidding trade: 208007\n  plain trade: 182442\n  next block: play the turn and bid: 531060\n\n[PASS] test_openingGas() (gas: 3364403)\nLogs:\n  first bid in a new pool: 270547\n  bidding trade: 192524\n  outbidding trade: 208007\n  plain trade: 182583\n  next block: play the turn and bid: 507698\n\n[PASS] test_runningGameGas() (gas: 52971319)\nLogs:\n  running game, moving trades measured: 50\n  running game, moving trade average: 446235\n  running game, moving trade max: 532353\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 125.53ms (163.84ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 980144, ~: 980840)\nLogs:\n  Bound result 500000000000000000\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 464530, ~: 464653)\nLogs:\n  Bound result 653\n  Bound result 995884975030811798149\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1079207, ~: 1079259)\nLogs:\n  Bound result 39\n  Bound result 268\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2575179)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123553)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 215686)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121368)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98261)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344594)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111113)\n[PASS] test_lastSurchargeSecond() (gas: 470038)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 2998664)\n[PASS] test_openingEdges() (gas: 469660)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1149576)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 469551)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 89931)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 136.65ms (286.42ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9157, ~: 9118)\nLogs:\n  Bound result 140408634885699395999353210173794253356013074822392266714587117801872617862\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 12013, ~: 12425)\nLogs:\n  Bound result 3905690605402760688486569470973352707\n  Bound result 2175930215851458032844206630585034303747446649436\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14662, ~: 15266)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13856, ~: 13724)\nLogs:\n  Bound result 300000000000000000000\n  Bound result 297000000000005662\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14027, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050508654\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913128200095\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 136.59ms (326.96ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4208794)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2382749)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8555477)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1011842)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3314594)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3078768)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2367325)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 2990838)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 3976592)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1557734)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3705920)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23932899)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 136.37ms (121.45ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3837983)\nLogs:\n  smallest gas limit that converts: 310375\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 4170322)\nLogs:\n  smallest gas limit that plays and records the bounty: 390416\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15567947)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 151.60ms (174.40ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9594048, ~: 9552725)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 74128344)\nLogs:\n  moves played: 110\n  bids (incl. outbid ones): 141\n  most gas for a swap: 614832\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 686212)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1304091)\n[PASS] test_aTradeBidsForTheTurn() (gas: 483422)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 965022)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1413164)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1754655)\n[PASS] test_anyTradeSizeBids() (gas: 450023)\n[PASS] test_lateTradeStillBidsNormally() (gas: 429657)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 145185)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 415770)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 915258)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1047939)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6373797)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 926666)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 782279)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179407)\n[PASS] test_theMainDuelMustPairImd() (gas: 292053)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1038350)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 412203)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1533973)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 740.65ms (884.83ms CPU time)\n\nRan 21 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10670805, ~: 10756018)\n[PASS] test_aFullChestTakesNoMore() (gas: 1070662)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 582835)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 826940)\n[PASS] test_bountyTable() (gas: 44573)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 806848)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 650063)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5518374)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 384955)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 808490)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 461737)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 363792)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48714)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41852)\n[PASS] test_fundChestWithEth() (gas: 252795)\n[PASS] test_fundChestWithTokens() (gas: 205591)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3485358)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 881351)\n[PASS] test_quietMovePaysNothing() (gas: 613837)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1245166)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 948054)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 826.48ms (843.02ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 575514472)\nLogs:\n  bot moves: 0\n  other moves: 149\n  captures among other moves: 25\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 967.12ms (966.48ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 19999999000000000031\n  Bound result 19999999000000017348\n  Bound result 38332894068056391680\n  Bound result 98\n  Bound result 19999999000000007001\n  Bound result 63\n  Bound result 80\n  Bound result 19999999000000001568\n  Bound result 19999999495924113525\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 19243497235015328446\n  Bound result 19999999000177362150\n  Bound result 230000\n  Bound result 17380275022719779\n  Bound result 13147\n  Bound result 1437185599\n  Bound result 90\n  Bound result 19999999000000200001\n  Bound result 19999999000000184201\n  Bound result 15600679758904\n  Bound result 1374389534720\n  Bound result 14999999999985\n  Bound result 19999999000000002324\n  Bound result 7527\n  Bound result 19999999000081008943\n  Bound result 19999999000000000021\n  Bound result 499999999999500\n  Bound result 19999999000000010056\n  Bound result 19999999000000011831\n  Bound result 16732\n  Bound result 19999999000000006049\n  Bound result 19999999000000000012\n  Bound result 80\n  Bound result 112\n  Bound result 19999999000000010056\n  Bound result 11087287370205750110\n  Bound result 19999999000000001198\n  Bound result 49425749022699434082\n  Bound result 19999999000000005176\n  Bound result 19999999000000003400\n  Bound result 19999999000000001930\n  Bound result 19999999000000007565\n  Bound result 19908107207707819244\n  Bound result 15\n  Bound result 19999999000000000061\n  Bound result 19999999000000000091\n  Bound result 21989\n  Bound result 24\n  Bound result 112108561573182545\n  Bound result 19999999000000013080\n  Bound result 19999999386547056641\n  Bound result 19999999063368430181\n  Bound result 19999999000000050001\n  Bound result 64\n  Bound result 17256293755346024653\n  Bound result 56\n  Bound result 11\n  Bound result 17462041093041794489\n  Bound result 69\n  Bound result 9241421688590303745\n  Bound result 9384671937848548256\n  Bound result 10000000000000000\n  Bound result 19999999000000009370\n  Bound result 281474976710656\n  Bound result 15915\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.18s (1.18s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4294902015\n  Bound result 4597\n  Bound result 0\n  Bound result 7038\n  Bound result 120396004288981\n  Bound result 10\n  Bound result 8874\n  Bound result 191\n  Bound result 0\n  Bound result 2\n  Bound result 2738504042791640380511251\n  Bound result 48879\n  Bound result 2\n  Bound result 0\n  Bound result 3950\n  Bound result 1290\n  Bound result 1809217764\n  Bound result 1741\n  Bound result 560000\n  Bound result 100\n  Bound result 150\n  Bound result 929\n  Bound result 120\n  Bound result 1896903457\n  Bound result 2655\n  Bound result 926\n  Bound result 71\n  Bound result 6412\n  Bound result 3600\n  Bound result 32\n  Bound result 167\n  Bound result 229\n  Bound result 4294894986\n  Bound result 5493\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55898, ~: 55857)\nLogs:\n  Bound result 893409364866962332856807\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.58s (2.69s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1086394136\n  Bound result 9999999000000000004596\n  Bound result 4999999999000022060\n  Bound result 482656664672130512400\n  Bound result 2770973894068056359039\n  Bound result 47460125026787646792\n  Bound result 5104\n  Bound result 19999999999000011591\n  Bound result 12\n  Bound result 12\n  Bound result 499999999500\n  Bound result 19999999999000000019\n  Bound result 19999999999000009823\n  Bound result 19999999999000007803\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000097\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000000046\n  Bound result 9999999000000006000001\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 18225745714582542211\n  Bound result 50000000000000000000\n  Bound result 19999999999000018110\n  Bound result 12\n  Bound result 19999999999000010639\n  Bound result 2380\n  Bound result 180000000000000017069\n  Bound result 12\n  Bound result 39\n  Bound result 900000000000000000000\n  Bound result 12\n  Bound result 19999999999000013486\n  Bound result 189000000000000000001\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000000169\n  Bound result 576313801412550370823\n  Bound result 24\n  Bound result 9999999000000000007282\n  Bound result 9999999000000000004617\n  Bound result 4000000000000000000\n  Bound result 19999999999000016314\n  Bound result 19999999999000004505\n  Bound result 9302618518017444791\n  Bound result 21339\n  Bound result 180000000000000006799\n  Bound result 12\n  Bound result 482655664672130512657\n  Bound result 12\n  Bound result 19999999999000018456\n  Bound result 19999999999000014924\n  Bound result 84442493013196800\n  Bound result 12\n  Bound result 7885362738380271026\n  Bound result 94\n  Bound result 10899998000000000004614\n  Bound result 180000000000000002652\n  Bound result 12\n  Bound result 19999999999000008875\n  Bound result 71\n  Bound result 25\n  Bound result 40009298618518023456735\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 302723167751991649\n  Bound result 7542348211614510838368\n  Bound result 11406\n  Bound result 9999998000000000004023\n  Bound result 12\n  Bound result 20000000000000000000\n  Bound result 65\n  Bound result 8\n  Bound result 22948613226316474955\n  Bound result 95\n  Bound result 40\n  Bound result 8317639\n  Bound result 180000000000000002139\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000009282\n  Bound result 1000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 4999999999000010000\n  Bound result 12\n  Bound result 15\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000002531\n  Bound result 7036944328885724022\n  Bound result 12112318102210612724\n  Bound result 180000000000000000028\n  Bound result 12\n  Bound result 19999999999000011092\n  Bound result 9999999000000000000097\n  swaps: 38\n  moves: 24\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.64s (3.63s CPU time)\n\nRan 21 test suites in 3.64s (11.00s CPU time): 152 tests passed, 0 failed, 0 skipped (152 total tests)\n","passed":true},{"durationMs":68,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":58,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":36,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":36,\"launch/hook.sepolia.json\":36,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":860,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":336,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":80,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":157,\"test/LaunchFiles.t.sol\":75,\"test/Money.t.sol\":350,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":27,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0aa68897c3bcb0f201dae13343c2ab38f8e2a8374764815c0243bb386624401d","verifiedTreeHash":"d58e37d925fc85d9f66e206682cef9845389b22f","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":75510,"exitCode":0,"name":"build","output":"Compiling 112 files with Solc 0.8.26\nSolc 0.8.26 finished in 75.39s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:70:5:\n   |\n70 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":4016,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.55ms (864.12µs CPU time)\n\nRan 2 tests for test/Edges.t.sol:PreviewEdgesTest\n[PASS] test_aBidEarlyInTheWindowIsNotPreviewedUntilItsLastBlock() (gas: 609490)\n[PASS] test_noPreviewBeforeTheLastBlockOrWithoutABid() (gas: 609290)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.81ms (1.97ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1739826)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1153483)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2248837)\n[PASS] test_sliceSide() (gas: 645447)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 417313)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 7.07ms (6.31ms CPU time)\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 73186)\nLogs:\n  hook: 17403\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.85ms (8.69ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:BatchCapTest\n[PASS] test_aPileJustOverTheCapSpendsTenMinimums() (gas: 1614614)\n[PASS] test_aPileUnderOneMinimumOnlyConvertsOnRequest() (gas: 1374282)\n[PASS] test_nothingConvertsBeforeThreeSampledBlocks() (gas: 458422)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 12.49ms (11.67ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 239931)\n[PASS] test_moveCap() (gas: 239972)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 179920)\n[PASS] test_quietMoveLimit() (gas: 246190)\n[PASS] test_stalemate() (gas: 237744)\n[PASS] test_thirdRepetition() (gas: 963450)\n[PASS] test_tooFewPiecesToMate() (gas: 231569)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 14.54ms (9.78ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4841322)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2823009)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1886985)\n[PASS] test_anyoneCanConvert() (gas: 461614)\n[PASS] test_booksBalanceAcrossPools() (gas: 8515043)\n[PASS] test_crossBlockViaConvert() (gas: 4383013)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4545174)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 763803)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 498902)\n[PASS] test_noRouteNoDuel() (gas: 1250177)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1186639)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 42.91ms (77.14ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4841127)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2823010)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1886986)\n[PASS] test_anyoneCanConvert() (gas: 461614)\n[PASS] test_booksBalanceAcrossPools() (gas: 8515045)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 763804)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 498890)\n[PASS] test_noRouteNoDuel() (gas: 1250179)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1186640)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 57.43ms (61.64ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:OwnerShapesTest\n[PASS] testFuzz_ownerIsTheNamedAddressElseTheSigner(uint8,address,uint256,bytes) (runs: 256, μ: 416517, ~: 416433)\n[PASS] test_aBidThatDoesNotBeatTheTopKeepsItsOwner() (gas: 783490)\n[PASS] test_everyHookDataShape() (gas: 3067832)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 92.48ms (98.23ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9135, ~: 9118)\nLogs:\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 12002, ~: 12058)\nLogs:\n  Bound result 3905690605402760688486569470973352707\n  Bound result 2175930215851458032844206630585034303747446649436\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14623, ~: 15266)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13859, ~: 13724)\nLogs:\n  Bound result 340282366920938463463374607431767260830\n  Bound result 336879543251729078828740861357455249\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14040, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050514300\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007912563603600\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 121.63ms (51.23ms CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 158255)\n[PASS] test_sepoliaLaunchFile() (gas: 153655)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 121.70ms (7.53ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 31426026)\n[PASS] test_blankChainTokenBelowImd() (gas: 31353650)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 122.86ms (120.51ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22193400)\n[PASS] test_launchTokenAboveImd() (gas: 23442523)\nLogs:\n  first buy (opens game 0, bids for White): 366430\n\n[PASS] test_launchTokenBelowImd() (gas: 23389720)\nLogs:\n  first buy (opens game 0, bids for White): 361713\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 134.98ms (213.58ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4208794)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2382749)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8555477)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1011842)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3314594)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3078768)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2367325)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 2990838)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 3976592)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1557734)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3705920)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23932899)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 148.15ms (175.90ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1426784)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1952577)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1222460)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1062878)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1040461)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 974158)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1466876)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1283692)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1511150)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1621408)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1077584)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1811511)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1222876)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 169.58ms (40.73ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 980136, ~: 980840)\nLogs:\n  Bound result 284566226774981684014\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 464524, ~: 464653)\nLogs:\n  Bound result 599\n  Bound result 999999999999000000019\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1079221, ~: 1079259)\nLogs:\n  Bound result 292\n  Bound result 382\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2575179)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123553)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 215686)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121368)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98261)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344594)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111113)\n[PASS] test_lastSurchargeSecond() (gas: 470038)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 2998664)\n[PASS] test_openingEdges() (gas: 469660)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1149576)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 469551)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 89931)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 169.72ms (427.58ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3837983)\nLogs:\n  smallest gas limit that converts: 310375\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 4170322)\nLogs:\n  smallest gas limit that plays and records the bounty: 390416\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15567947)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 171.68ms (194.37ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2485776)\nLogs:\n  plain trade: 207571\n  trade that converts a batch: 271382\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27682885)\nLogs:\n  hook share of a moving trade: average: 276326\n  hook share of a moving trade: max: 307180\n\n[PASS] test_middlegameGas() (gas: 8148240)\nLogs:\n  first bid in a new pool: 270547\n  bidding trade: 191911\n  outbidding trade: 208007\n  plain trade: 182442\n  next block: play the turn and bid: 531060\n\n[PASS] test_openingGas() (gas: 3364403)\nLogs:\n  first bid in a new pool: 270547\n  bidding trade: 192524\n  outbidding trade: 208007\n  plain trade: 182583\n  next block: play the turn and bid: 507698\n\n[PASS] test_runningGameGas() (gas: 52971319)\nLogs:\n  running game, moving trades measured: 50\n  running game, moving trade average: 446235\n  running game, moving trade max: 532353\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 204.73ms (262.52ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9527210, ~: 9522603)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 74128344)\nLogs:\n  moves played: 110\n  bids (incl. outbid ones): 141\n  most gas for a swap: 614832\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 686212)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1304091)\n[PASS] test_aTradeBidsForTheTurn() (gas: 483422)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 965022)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1413164)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1754655)\n[PASS] test_anyTradeSizeBids() (gas: 450023)\n[PASS] test_lateTradeStillBidsNormally() (gas: 429657)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 145185)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 415770)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 915258)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1047939)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6373797)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 926666)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 782279)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179407)\n[PASS] test_theMainDuelMustPairImd() (gas: 292053)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1038350)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 412203)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1533973)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 788.34ms (1.03s CPU time)\n\nRan 21 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10682129, ~: 10787518)\n[PASS] test_aFullChestTakesNoMore() (gas: 1070662)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 582835)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 826940)\n[PASS] test_bountyTable() (gas: 44573)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 806848)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 650063)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5518374)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 384955)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 808490)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 461737)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 363792)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48714)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41852)\n[PASS] test_fundChestWithEth() (gas: 252795)\n[PASS] test_fundChestWithTokens() (gas: 205591)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3485358)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 881351)\n[PASS] test_quietMovePaysNothing() (gas: 613837)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1245166)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 948054)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 863.24ms (875.55ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 575514472)\nLogs:\n  bot moves: 0\n  other moves: 149\n  captures among other moves: 25\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.06s (1.06s CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 19999999000000000021\n  Bound result 19999999000000017348\n  Bound result 25333134452981760\n  Bound result 98\n  Bound result 19999999000000007001\n  Bound result 8\n  Bound result 80\n  Bound result 19999999000000001568\n  Bound result 19999999000000001040\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 13992672954971501637\n  Bound result 19999999000435658500\n  Bound result 20000\n  Bound result 17380275022719779\n  Bound result 31745\n  Bound result 1437185598\n  Bound result 24\n  Bound result 19999999000000020001\n  Bound result 24999499999975\n  Bound result 15600679758904\n  Bound result 84442493013196800\n  Bound result 19999999000000049375\n  Bound result 19999999000000008480\n  Bound result 7691\n  Bound result 17567030634919331765\n  Bound result 19999999000000000011\n  Bound result 19999999000000997001\n  Bound result 20000000000000000000\n  Bound result 19999999000000011265\n  Bound result 15205\n  Bound result 19999999000000006298\n  Bound result 19999999000000000014\n  Bound result 40\n  Bound result 16\n  Bound result 20000000000000000000\n  Bound result 103779459526178527\n  Bound result 19999999000000001533\n  Bound result 49425749022699434082\n  Bound result 19999999000000005305\n  Bound result 19999999000000013259\n  Bound result 19999999000000003169\n  Bound result 19999999000107477463\n  Bound result 19977026051926954812\n  Bound result 15\n  Bound result 19999999000000100001\n  Bound result 7011749056432742262\n  Bound result 20974\n  Bound result 15\n  Bound result 112108561573182545\n  Bound result 19999999000000015512\n  Bound result 25332747903959040\n  Bound result 19999999063368430181\n  Bound result 19999999000000000037\n  Bound result 64\n  Bound result 17256293755346024653\n  Bound result 16\n  Bound result 13\n  Bound result 17462041093041794489\n  Bound result 26\n  Bound result 9241421688590303745\n  Bound result 9384671937848548256\n  Bound result 49999999999950\n  Bound result 19999999000000008631\n  Bound result 17567031734430959541\n  Bound result 16548\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.15s (1.14s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4294902015\n  Bound result 4596\n  Bound result 52635820644892671\n  Bound result 7038\n  Bound result 120396004288981\n  Bound result 10\n  Bound result 8227\n  Bound result 193\n  Bound result 2\n  Bound result 2\n  Bound result 2738504042791640380511251\n  Bound result 99999\n  Bound result 4294909042\n  Bound result 4761\n  Bound result 3979\n  Bound result 2540\n  Bound result 11\n  Bound result 1742\n  Bound result 230000\n  Bound result 45\n  Bound result 14\n  Bound result 929\n  Bound result 500\n  Bound result 1357\n  Bound result 2604\n  Bound result 2473\n  Bound result 3869062606\n  Bound result 6858\n  Bound result 2109246264\n  Bound result 3114994816\n  Bound result 5542\n  Bound result 1672\n  Bound result 4294908923\n  Bound result 5238\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55899, ~: 55857)\nLogs:\n  Bound result 1300\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.82s (2.85s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1086394136\n  Bound result 9999999000000000004596\n  Bound result 4999999999000022060\n  Bound result 482656664672130512400\n  Bound result 2767036944190885724160\n  Bound result 47460125026787646792\n  Bound result 5104\n  Bound result 19999999999000011591\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999001000001\n  Bound result 19999999999000000041\n  Bound result 19999999999000009823\n  Bound result 19999999999000007418\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000097\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000196609\n  Bound result 9999999000000000900001\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 14211026072807217150\n  Bound result 997000\n  Bound result 19999999999000017973\n  Bound result 12\n  Bound result 19999999999000010690\n  Bound result 6370\n  Bound result 180000000000000017085\n  Bound result 12\n  Bound result 51\n  Bound result 9999999000000000057006\n  Bound result 12\n  Bound result 19999999999000015381\n  Bound result 180000000000000001801\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 1099511627775\n  Bound result 482655664672130534092\n  Bound result 15\n  Bound result 9999999000000000006597\n  Bound result 9999999000000000004362\n  Bound result 3000000000000000000\n  Bound result 19999999999000016333\n  Bound result 19999999999000015735\n  Bound result 9302618518017444791\n  Bound result 21211\n  Bound result 180000000000000006547\n  Bound result 12\n  Bound result 30009299618518018545763\n  Bound result 12\n  Bound result 19999999999000018500\n  Bound result 19999999999000013828\n  Bound result 3372037315775807539\n  Bound result 12\n  Bound result 19999999999000000113\n  Bound result 75\n  Bound result 999999999978308\n  Bound result 180000000000004594639\n  Bound result 12\n  Bound result 19999999999000017869\n  Bound result 8\n  Bound result 25\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 21153074588023261964\n  Bound result 9999998000000000014273\n  Bound result 10401\n  Bound result 999999999985734\n  Bound result 12\n  Bound result 134999999865\n  Bound result 104\n  Bound result 8\n  Bound result 49091255737883951121\n  Bound result 127\n  Bound result 120\n  Bound result 542\n  Bound result 180000000000000007253\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000011252\n  Bound result 6000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 12\n  Bound result 16\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 5300000000999999999\n  Bound result 386549022720\n  Bound result 1064470260\n  Bound result 190723151780598845932\n  Bound result 12\n  Bound result 19999999999000008496\n  Bound result 9999999000000000000097\n  swaps: 38\n  moves: 18\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.80s (3.79s CPU time)\n\nRan 24 test suites in 3.80s (12.08s CPU time): 160 tests passed, 0 failed, 0 skipped (160 total tests)\n","passed":true},{"durationMs":91,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":58,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":36,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":36,\"launch/hook.sepolia.json\":36,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":860,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/Edges.t.sol\":181,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":336,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":80,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":157,\"test/LaunchFiles.t.sol\":75,\"test/Money.t.sol\":350,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":27,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"3b3268d29bc97cf76fef270239b03d6a60f44a7971dd066b287bd2ab6e3a181c","verifiedTreeHash":"a99ca68abaf9825314cf28e923d2b08598b7aff2","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":77703,"exitCode":0,"name":"build","output":"Compiling 112 files with Solc 0.8.26\nSolc 0.8.26 finished in 77.58s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:74:5:\n   |\n74 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3767,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 74690)\nLogs:\n  hook: 17884\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.06ms (962.75µs CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.21ms (652.90µs CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 162073)\n[PASS] test_sepoliaLaunchFile() (gas: 156460)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.01ms (2.23ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1794857)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1185245)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2312963)\n[PASS] test_sliceSide() (gas: 647815)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 419601)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 5.04ms (10.18ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 240085)\n[PASS] test_moveCap() (gas: 240148)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 180030)\n[PASS] test_quietMoveLimit() (gas: 246366)\n[PASS] test_stalemate() (gas: 237898)\n[PASS] test_thirdRepetition() (gas: 964198)\n[PASS] test_tooFewPiecesToMate() (gas: 231723)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 6.27ms (3.87ms CPU time)\n\nRan 9 tests for test/JitStrength.t.sol:JitStrengthTest\n[PASS] test_aBlocksFirstAddRecordsTheLiquidityBeforeIt() (gas: 1686913)\n[PASS] test_bracketsAroundABlocksFirstSwapDoNotInflateTheSample() (gas: 3380544)\n[PASS] test_eachPoolSamplesItsOwnDepth() (gas: 1139381)\n[PASS] test_liquidityAddedAndRemovedAroundATradeDoesNotShrinkItsShare() (gas: 1447542)\n[PASS] test_liquidityHeldThroughOneBlockDoesNotShrinkTheShare() (gas: 1490670)\n[PASS] test_liquidityHeldThroughThreeTradedBlocksCounts() (gas: 1435144)\n[PASS] test_liquidityRemovedBeforeTheFirstSampleOnlyLowersIt() (gas: 2249607)\n[PASS] test_onlyThePoolManagerCallsBeforeAddLiquidity() (gas: 39697)\n[PASS] test_theFirstTradedBlockMeasuresAgainstTheLiquidityItStartsWith() (gas: 822315)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 20.99ms (25.13ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22687788)\n[PASS] test_launchTokenAboveImd() (gas: 23871208)\nLogs:\n  first buy (opens game 0, bids for White): 389763\n\n[PASS] test_launchTokenBelowImd() (gas: 24033367)\nLogs:\n  first buy (opens game 0, bids for White): 385201\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 61.85ms (160.98ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9149, ~: 9118)\nLogs:\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 11970, ~: 11970)\nLogs:\n  Bound result 3905690605402760688486569470973352707\n  Bound result 2175930215851458032844206630585034303747446649436\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14604, ~: 14270)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13863, ~: 13724)\nLogs:\n  Bound result 340282366920938463463374607431767211698\n  Bound result 336879543251729078828740863513321795\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14038, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050508702\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913123400244\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 63.20ms (41.90ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 68129144)\n[PASS] test_blankChainTokenBelowImd() (gas: 68055011)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 69.95ms (125.07ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2543571)\nLogs:\n  plain trade: 210590\n  trade that converts a batch: 274449\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27998922)\nLogs:\n  hook share of a moving trade: average: 283031\n  hook share of a moving trade: max: 313889\n\n[PASS] test_middlegameGas() (gas: 8203052)\nLogs:\n  first bid in a new pool: 273472\n  bidding trade: 194930\n  outbidding trade: 210932\n  plain trade: 185367\n  next block: play the turn and bid: 544398\n\n[PASS] test_openingGas() (gas: 3371499)\nLogs:\n  first bid in a new pool: 273472\n  bidding trade: 195550\n  outbidding trade: 210932\n  plain trade: 185367\n  next block: play the turn and bid: 442193\n\n[PASS] test_runningGameGas() (gas: 54197038)\nLogs:\n  running game, moving trades measured: 48\n  running game, moving trade average: 477875\n  running game, moving trade max: 700265\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 95.88ms (158.60ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4960497)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2910338)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1922133)\n[PASS] test_anyoneCanConvert() (gas: 464742)\n[PASS] test_booksBalanceAcrossPools() (gas: 8648684)\n[PASS] test_crossBlockViaConvert() (gas: 4473657)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4638746)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 793428)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 502184)\n[PASS] test_noRouteNoDuel() (gas: 1262161)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1219396)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 109.46ms (53.60ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4960302)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2910339)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1922134)\n[PASS] test_anyoneCanConvert() (gas: 464742)\n[PASS] test_booksBalanceAcrossPools() (gas: 8648686)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 793429)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 502172)\n[PASS] test_noRouteNoDuel() (gas: 1262163)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1219397)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 116.90ms (29.56ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 1006532, ~: 1007223)\nLogs:\n  Bound result 499999999999000020001\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 488304, ~: 488427)\nLogs:\n  Bound result 63\n  Bound result 999999999999000000245\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1102094, ~: 1102128)\nLogs:\n  Bound result 63\n  Bound result 244\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2619855)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123685)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 239394)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121434)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98327)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344748)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111179)\n[PASS] test_lastSurchargeSecond() (gas: 493834)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 3050462)\n[PASS] test_openingEdges() (gas: 493456)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1156075)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 493347)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 90078)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 117.62ms (291.61ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3537206)\nLogs:\n  smallest gas limit that converts: 313268\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 3824964)\nLogs:\n  smallest gas limit that plays and records the bounty: 397167\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15348541)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 181.76ms (154.79ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4212159)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2427962)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8594138)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1014196)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3333787)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3137388)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2406430)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 3025939)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 4015281)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1560088)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3745027)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23963154)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 181.75ms (105.90ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1457587)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1971256)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1232910)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1071568)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1049129)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 1003892)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1487683)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1320945)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1546122)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1614992)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1086318)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1852967)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1209879)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 181.82ms (26.41ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 168865847)\nLogs:\n  bot moves: 0\n  other moves: 42\n  captures among other moves: 11\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 294.40ms (294.24ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9781442, ~: 9671843)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 93045635)\nLogs:\n  moves played: 134\n  bids (incl. outbid ones): 169\n  most gas for a swap: 807516\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 712955)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1344781)\n[PASS] test_aTradeBidsForTheTurn() (gas: 507240)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 1006040)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1447893)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1812917)\n[PASS] test_anyTradeSizeBids() (gas: 473819)\n[PASS] test_lateTradeStillBidsNormally() (gas: 453453)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 171702)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 439544)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 956298)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1058301)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6591275)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 953519)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 809066)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179473)\n[PASS] test_theMainDuelMustPairImd() (gas: 294337)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1079368)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 435977)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1592213)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 758.32ms (946.89ms CPU time)\n\nRan 23 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10858942, ~: 10889314)\n[PASS] test_aBatchSpendsAtMostTenMinimumsExactly() (gas: 54123)\n[PASS] test_aFullChestTakesNoMore() (gas: 1094876)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 630295)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 850978)\n[PASS] test_bountyTable() (gas: 44705)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 830864)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 676894)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5627127)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 408707)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 834675)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 485621)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 387566)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48736)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41896)\n[PASS] test_fundChestWithEth() (gas: 252883)\n[PASS] test_fundChestWithTokens() (gas: 205789)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3614681)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 905418)\n[PASS] test_quietMovePaysNothing() (gas: 637765)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1274880)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 972242)\n[PASS] test_withdrawToRefusesTheZeroAddress() (gas: 610435)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 821.28ms (843.17ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 19999999000000000021\n  Bound result 19999999000000017192\n  Bound result 386549022720\n  Bound result 98\n  Bound result 19999999000000000301\n  Bound result 8\n  Bound result 39\n  Bound result 4629921925374754156\n  Bound result 19999999000000001096\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 19999999000000000209\n  Bound result 19999999000177362149\n  Bound result 900000\n  Bound result 17380275022719779\n  Bound result 13295\n  Bound result 1371698883\n  Bound result 106\n  Bound result 19999999000000000071\n  Bound result 19999999000000012501\n  Bound result 15600679758904\n  Bound result 3372497854775807539\n  Bound result 19999999000000020001\n  Bound result 19999999000000002320\n  Bound result 7932\n  Bound result 19999999000000006870\n  Bound result 6515626003710664071\n  Bound result 19999999000000995001\n  Bound result 749999999999250\n  Bound result 19999999000000011026\n  Bound result 15207\n  Bound result 19999999000000005716\n  Bound result 10000000000000000000\n  Bound result 80\n  Bound result 16\n  Bound result 749999999999250\n  Bound result 10439932692678225679\n  Bound result 19999999000000009527\n  Bound result 49425749022699434082\n  Bound result 19999999000000004909\n  Bound result 19999999000000003263\n  Bound result 19999999000000003533\n  Bound result 19999999000000007776\n  Bound result 19999999000000022484\n  Bound result 15\n  Bound result 19999999000000100001\n  Bound result 7616448877154347021\n  Bound result 21018\n  Bound result 15\n  Bound result 112108561573182545\n  Bound result 19999999000000015560\n  Bound result 7011749056432742262\n  Bound result 19999999063368430181\n  Bound result 19999999000000560001\n  Bound result 64\n  Bound result 17256293755346024653\n  Bound result 15\n  Bound result 80\n  Bound result 17462041093041794489\n  Bound result 63\n  Bound result 72624976668147840\n  Bound result 9384671937848548256\n  Bound result 19999999000000000126\n  Bound result 19999999000000009330\n  Bound result 19999999000000000225\n  Bound result 16871\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.13s (1.13s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8\n  Bound result 4649\n  Bound result 1\n  Bound result 7038\n  Bound result 120396004288981\n  Bound result 5\n  Bound result 8228\n  Bound result 6\n  Bound result 870060366358668890202810772\n  Bound result 4\n  Bound result 2738504042791640380511251\n  Bound result 9\n  Bound result 671217046808349282794304116\n  Bound result 2\n  Bound result 3949\n  Bound result 0\n  Bound result 100000000000000000\n  Bound result 2\n  Bound result 7\n  Bound result 196608\n  Bound result 18\n  Bound result 5\n  Bound result 500\n  Bound result 1357\n  Bound result 8\n  Bound result 999\n  Bound result 2\n  Bound result 6413\n  Bound result 6\n  Bound result 15\n  Bound result 7958\n  Bound result 229\n  Bound result 9\n  Bound result 4\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55899, ~: 55857)\nLogs:\n  Bound result 893409364866962332856807\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.56s (2.65s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4210605550\n  Bound result 9999999000000000012263\n  Bound result 4999999999000020765\n  Bound result 482656664672130512400\n  Bound result 25333134452981760\n  Bound result 47460125026787646792\n  Bound result 5275\n  Bound result 19999999999000011592\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000995001\n  Bound result 19999999999000000081\n  Bound result 19999999999000008611\n  Bound result 19999999999000007539\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000097\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000196609\n  Bound result 20000000000000000000\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 14211026072807217151\n  Bound result 9999\n  Bound result 19999999999000017973\n  Bound result 12\n  Bound result 19999999999000010929\n  Bound result 3111\n  Bound result 180000000000000017293\n  Bound result 12\n  Bound result 110\n  Bound result 9999999000000000001002\n  Bound result 12\n  Bound result 19999999999000015916\n  Bound result 100000000000000000000\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 7885362738380271025\n  Bound result 10019998000000000218805\n  Bound result 15\n  Bound result 9999999000000000008337\n  Bound result 1553747648601704612551\n  Bound result 1800\n  Bound result 19999999999000016459\n  Bound result 19999999999000004232\n  Bound result 9302618518017444791\n  Bound result 21714\n  Bound result 180000000000000009362\n  Bound result 12\n  Bound result 9303618518017422595\n  Bound result 12\n  Bound result 19999999999000018708\n  Bound result 19999999999000016733\n  Bound result 17707567918181156739\n  Bound result 12\n  Bound result 5819675075174645730\n  Bound result 107\n  Bound result 19999997000000003013266\n  Bound result 180000000000000002272\n  Bound result 12\n  Bound result 19999999999000008728\n  Bound result 51\n  Bound result 25\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 19763434960426817024\n  Bound result 1553746648601704617304\n  Bound result 10994\n  Bound result 9999998000000000004435\n  Bound result 12\n  Bound result 599999999400\n  Bound result 63\n  Bound result 8\n  Bound result 39806045361637064851\n  Bound result 244\n  Bound result 40\n  Bound result 1377\n  Bound result 180000000000000002538\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000012856\n  Bound result 6000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 4999999999000002001\n  Bound result 12\n  Bound result 88\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000004079\n  Bound result 19999999999001966081\n  Bound result 19999999999000001011\n  Bound result 180000000000000000032\n  Bound result 12\n  Bound result 19999999999000011292\n  Bound result 9999999000000000000017\n  swaps: 38\n  moves: 21\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.61s (3.60s CPU time)\n\nRan 22 test suites in 3.61s (10.40s CPU time): 163 tests passed, 0 failed, 0 skipped (163 total tests)\n","passed":true},{"durationMs":63,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":79,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":35,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":37,\"launch/hook.sepolia.json\":37,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":964,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":347,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":84,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/JitStrength.t.sol\":182,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":167,\"test/LaunchFiles.t.sol\":79,\"test/Money.t.sol\":400,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":38,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"4835220326d51fbc3a01a2a6ff1cb6a10af66dc41e35d491d43a1bc013ed6ea5","verifiedTreeHash":"54a8d2553ff990e6efc4a6303e431525e46d0197","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":83941,"exitCode":0,"name":"build","output":"Compiling 113 files with Solc 0.8.26\nSolc 0.8.26 finished in 83.80s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:70:5:\n   |\n70 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3909,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.19ms (513.79µs CPU time)\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 73829)\nLogs:\n  hook: 17628\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.58ms (1.47ms CPU time)\n\nRan 2 tests for test/Edges.t.sol:PreviewEdgesTest\n[PASS] test_aBidEarlyInTheWindowIsNotPreviewedUntilItsLastBlock() (gas: 633070)\n[PASS] test_noPreviewBeforeTheLastBlockOrWithoutABid() (gas: 632870)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.42ms (1.61ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:BatchCapTest\n[PASS] test_aPileJustOverTheCapSpendsTenMinimums() (gas: 1664608)\n[PASS] test_aPileUnderOneMinimumOnlyConvertsOnRequest() (gas: 1424132)\n[PASS] test_nothingConvertsBeforeThreeSampledBlocks() (gas: 482188)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 7.81ms (6.07ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 239953)\n[PASS] test_moveCap() (gas: 239994)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 179942)\n[PASS] test_quietMoveLimit() (gas: 246212)\n[PASS] test_stalemate() (gas: 237766)\n[PASS] test_thirdRepetition() (gas: 963626)\n[PASS] test_tooFewPiecesToMate() (gas: 231591)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 9.46ms (6.67ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:DepthSampleEdgesTest\n[PASS] test_liquidityRemovedAfterABlocksFirstSwapDoesNotCountInThatBlock() (gas: 1670688)\n[PASS] test_liquidityRemovedBeforeABlocksFirstSwapCountsAtOnce() (gas: 1555311)\n[PASS] test_quietBlocksTakeNoSample() (gas: 1682099)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 9.83ms (4.75ms CPU time)\n\nRan 5 tests for test/JitStrength.t.sol:JitStrengthTest\n[PASS] test_eachPoolSamplesItsOwnDepth() (gas: 1132886)\n[PASS] test_liquidityAddedAndRemovedAroundATradeDoesNotShrinkItsShare() (gas: 1438143)\n[PASS] test_liquidityHeldThroughOneBlockDoesNotShrinkTheShare() (gas: 1477821)\n[PASS] test_liquidityHeldThroughThreeTradedBlocksCounts() (gas: 1424428)\n[PASS] test_theFirstTradedBlockMeasuresAgainstTheLiquidityItStartsWith() (gas: 815952)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 10.28ms (7.38ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4923187)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2884338)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1914710)\n[PASS] test_anyoneCanConvert() (gas: 464503)\n[PASS] test_booksBalanceAcrossPools() (gas: 8663337)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 787342)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 501845)\n[PASS] test_noRouteNoDuel() (gas: 1250179)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1213060)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 25.26ms (26.17ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1456913)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1992032)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1252567)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1092985)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1070568)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 1003286)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1497005)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1316573)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1554405)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1658042)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1107691)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1851735)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1252983)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 31.30ms (21.90ms CPU time)\n\nRan 2 tests for test/Edges.t.sol:BatchBoundFuzzTest\n[PASS] testFuzz_batchBound(uint256,uint256) (runs: 1000, μ: 14559, ~: 14571)\nLogs:\n  Bound result 84442493013196800\n\n[PASS] test_batchAtTheEdges() (gas: 44999)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 54.53ms (51.11ms CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 159126)\n[PASS] test_sepoliaLaunchFile() (gas: 154500)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 54.46ms (1.88ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 25907580)\n[PASS] test_blankChainTokenBelowImd() (gas: 25835453)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 54.81ms (82.59ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22439603)\n[PASS] test_launchTokenAboveImd() (gas: 23691662)\nLogs:\n  first buy (opens game 0, bids for White): 389635\n\n[PASS] test_launchTokenBelowImd() (gas: 23639085)\nLogs:\n  first buy (opens game 0, bids for White): 385073\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 70.38ms (170.11ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2532287)\nLogs:\n  plain trade: 210439\n  trade that converts a batch: 274298\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27976648)\nLogs:\n  hook share of a moving trade: average: 282901\n  hook share of a moving trade: max: 313758\n\n[PASS] test_middlegameGas() (gas: 8202359)\nLogs:\n  first bid in a new pool: 273321\n  bidding trade: 194779\n  outbidding trade: 210781\n  plain trade: 185216\n  next block: play the turn and bid: 537587\n\n[PASS] test_openingGas() (gas: 3413416)\nLogs:\n  first bid in a new pool: 273321\n  bidding trade: 195396\n  outbidding trade: 210781\n  plain trade: 185216\n  next block: play the turn and bid: 514228\n\n[PASS] test_runningGameGas() (gas: 53462553)\nLogs:\n  running game, moving trades measured: 50\n  running game, moving trade average: 452812\n  running game, moving trade max: 538931\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 93.29ms (152.85ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9103, ~: 9118)\nLogs:\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 11977, ~: 11970)\nLogs:\n  Bound result 3905690605402760688486569470973352707\n  Bound result 2175930215851458032844206630585034303747446649436\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14611, ~: 14270)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13863, ~: 13724)\nLogs:\n  Bound result 340282366920938463463374607431767211492\n  Bound result 336879543251729078828740861357455200\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14036, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050514300\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007912563601001\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 119.47ms (37.41ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4252940)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2420483)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8586833)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1013025)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3358740)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3122908)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2398627)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 3018355)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 4007883)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1558917)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3737236)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23802213)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 119.54ms (158.71ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4923382)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2884337)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1914709)\n[PASS] test_anyoneCanConvert() (gas: 464503)\n[PASS] test_booksBalanceAcrossPools() (gas: 8663335)\n[PASS] test_crossBlockViaConvert() (gas: 4448978)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4613960)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 787341)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 501857)\n[PASS] test_noRouteNoDuel() (gas: 1250177)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1213059)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 128.07ms (40.26ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:OwnerShapesTest\n[PASS] testFuzz_ownerIsTheNamedAddressElseTheSigner(uint8,address,uint256,bytes) (runs: 256, μ: 440092, ~: 440013)\n[PASS] test_aBidThatDoesNotBeatTheTopKeepsItsOwner() (gas: 809844)\n[PASS] test_everyHookDataShape() (gas: 3116378)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 134.54ms (136.47ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 1010311, ~: 1010975)\nLogs:\n  Bound result 399476447386225879688\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 488103, ~: 488233)\nLogs:\n  Bound result 653\n  Bound result 995884975030811798149\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1115910, ~: 1115940)\nLogs:\n  Bound result 292\n  Bound result 382\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2619901)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123553)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 239266)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121368)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98261)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344594)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111113)\n[PASS] test_lastSurchargeSecond() (gas: 493618)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 3050248)\n[PASS] test_openingEdges() (gas: 493240)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1149731)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 493131)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 90012)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 134.59ms (306.80ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1771027)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1178034)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2303660)\n[PASS] test_sliceSide() (gas: 646625)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 418496)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 136.51ms (8.44ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3525746)\nLogs:\n  smallest gas limit that converts: 313268\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 3817204)\nLogs:\n  smallest gas limit that plays and records the bounty: 397167\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15340033)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 142.02ms (157.75ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9768890, ~: 9877560)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 74993302)\nLogs:\n  moves played: 110\n  bids (incl. outbid ones): 141\n  most gas for a swap: 621406\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 712566)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1336972)\n[PASS] test_aTradeBidsForTheTurn() (gas: 507002)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 995129)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1449845)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1791289)\n[PASS] test_anyTradeSizeBids() (gas: 473603)\n[PASS] test_lateTradeStillBidsNormally() (gas: 453237)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 145185)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 439350)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 945365)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1078046)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6469951)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 953042)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 808633)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179407)\n[PASS] test_theMainDuelMustPairImd() (gas: 293233)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1068457)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 435783)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1570607)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 720.42ms (866.45ms CPU time)\n\nRan 23 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10925912, ~: 10964389)\n[PASS] test_aBatchSpendsAtMostTenMinimumsExactly() (gas: 53969)\n[PASS] test_aFullChestTakesNoMore() (gas: 1094242)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 630039)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 850564)\n[PASS] test_bountyTable() (gas: 44573)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 830472)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 676417)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5622444)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 408535)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 838597)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 485339)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 387372)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48714)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41874)\n[PASS] test_fundChestWithEth() (gas: 252795)\n[PASS] test_fundChestWithTokens() (gas: 205591)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3592670)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 904960)\n[PASS] test_quietMovePaysNothing() (gas: 637439)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1268507)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 971630)\n[PASS] test_withdrawToRefusesTheZeroAddress() (gas: 610127)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 828.91ms (849.34ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 584493866)\nLogs:\n  bot moves: 0\n  other moves: 149\n  captures among other moves: 25\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.06s (1.06s CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 6515626003710664071\n  Bound result 19999999000000017509\n  Bound result 90\n  Bound result 98\n  Bound result 19999999000000008501\n  Bound result 8\n  Bound result 16\n  Bound result 2893925734761568124\n  Bound result 19999999000000001212\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 17160348014325642528\n  Bound result 19999999003350782303\n  Bound result 560000\n  Bound result 17380275022719779\n  Bound result 13378\n  Bound result 1437185598\n  Bound result 8\n  Bound result 19999999000000560001\n  Bound result 99999999999900000\n  Bound result 15600679758904\n  Bound result 19999999000000065536\n  Bound result 29999999999970\n  Bound result 19999999000000000324\n  Bound result 8749\n  Bound result 19999999000000006082\n  Bound result 18374403900871474942\n  Bound result 1000000000000\n  Bound result 24999499999975\n  Bound result 19999999000000011378\n  Bound result 2090626703\n  Bound result 19999999000000007373\n  Bound result 9000000000000000000\n  Bound result 39\n  Bound result 64\n  Bound result 24999499999975\n  Bound result 31766329989013006571\n  Bound result 19999999000000002442\n  Bound result 49425749022699434082\n  Bound result 19999999000000005293\n  Bound result 19999999000000003445\n  Bound result 19999999000000003987\n  Bound result 19999999000000008181\n  Bound result 35046394159071\n  Bound result 64\n  Bound result 19999999000000009001\n  Bound result 19999999000000000057\n  Bound result 21689\n  Bound result 15\n  Bound result 112108561573182545\n  Bound result 19999999000000013806\n  Bound result 19999999000000800001\n  Bound result 19999999063368430181\n  Bound result 19999999000000020001\n  Bound result 16\n  Bound result 17256293755346024653\n  Bound result 48\n  Bound result 120\n  Bound result 17462041093041794489\n  Bound result 103\n  Bound result 72624976668147840\n  Bound result 9384671937848548256\n  Bound result 19999999000000995001\n  Bound result 19999999000000009999\n  Bound result 19999999000000000098\n  Bound result 16877880372841293345\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.19s (1.19s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4\n  Bound result 4649\n  Bound result 6\n  Bound result 6\n  Bound result 120396004288981\n  Bound result 0\n  Bound result 522\n  Bound result 7\n  Bound result 5\n  Bound result 5419\n  Bound result 2738504042791640380511251\n  Bound result 200000000000000000000\n  Bound result 3000\n  Bound result 10000000000000000000\n  Bound result 3950\n  Bound result 3\n  Bound result 1199999999999999989\n  Bound result 3\n  Bound result 350000\n  Bound result 3\n  Bound result 80\n  Bound result 5\n  Bound result 900\n  Bound result 1357\n  Bound result 1953\n  Bound result 16\n  Bound result 2\n  Bound result 6413\n  Bound result 52\n  Bound result 3942270959919176369\n  Bound result 5705\n  Bound result 1701\n  Bound result 9\n  Bound result 5484\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55899, ~: 55857)\nLogs:\n  Bound result 893409364866962332856807\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.66s (2.68s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 157198259\n  Bound result 9999999000000000004694\n  Bound result 4999999999000022597\n  Bound result 482656664672130512400\n  Bound result 9999999000386547056641\n  Bound result 47460125026787646792\n  Bound result 5159\n  Bound result 19999999999000011602\n  Bound result 12\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 13787848793156543929\n  Bound result 19999999999000009867\n  Bound result 9999998000386547072061\n  Bound result 19999999999000007609\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000000019\n  Bound result 97000000000000000000\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 1099511627775\n  Bound result 16283019655932542976\n  Bound result 19999999999000018323\n  Bound result 12\n  Bound result 19999999999000011342\n  Bound result 6475\n  Bound result 180000000000000016827\n  Bound result 12\n  Bound result 51\n  Bound result 900000000000000000000\n  Bound result 12\n  Bound result 19999999999012568867\n  Bound result 180000000000000051967\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000009\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000000113\n  Bound result 15\n  Bound result 9999999000000000007115\n  Bound result 9999999000000000004261\n  Bound result 14264337593543950335\n  Bound result 4294967041\n  Bound result 19999999999000012337\n  Bound result 9302618518017444791\n  Bound result 25383\n  Bound result 180000000000000006729\n  Bound result 12\n  Bound result 10899998000000000004727\n  Bound result 12\n  Bound result 19999999999000018876\n  Bound result 19999999999000014729\n  Bound result 19999999999000000018\n  Bound result 12\n  Bound result 19999999999000000053\n  Bound result 26\n  Bound result 999999999999967\n  Bound result 180000000000000000509\n  Bound result 12\n  Bound result 19999999999000008941\n  Bound result 99\n  Bound result 25\n  Bound result 20106301618518017436503\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 36493006898100569396\n  Bound result 9999998000000000009160\n  Bound result 16499\n  Bound result 9999998000000000004335\n  Bound result 12\n  Bound result 19999999999000000111\n  Bound result 2\n  Bound result 120\n  Bound result 17286042803320986890\n  Bound result 95\n  Bound result 60\n  Bound result 1293\n  Bound result 180000000000000002476\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000012756\n  Bound result 7000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 3193615530130082513\n  Bound result 12\n  Bound result 15\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000002531\n  Bound result 25332747903959040\n  Bound result 19999999999000001242\n  Bound result 43456480722185093069\n  Bound result 12\n  Bound result 19999999999000011753\n  Bound result 9999999000000000000017\n  swaps: 38\n  moves: 23\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.75s (3.74s CPU time)\n\nRan 27 test suites in 3.75s (11.55s CPU time): 172 tests passed, 0 failed, 0 skipped (172 total tests)\n","passed":true},{"durationMs":66,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":70,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":36,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":36,\"launch/hook.sepolia.json\":36,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":931,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/Edges.t.sol\":269,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":345,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":84,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/JitStrength.t.sol\":103,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":157,\"test/LaunchFiles.t.sol\":75,\"test/Money.t.sol\":400,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":38,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"50c6fc57d604d7b6e80007c3639d625a765d2e4a4028e34d942e0662295baa59","verifiedTreeHash":"055b4f5b011d28da0992fba8a0e4f1fa6b1cda9e","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":77974,"exitCode":0,"name":"build","output":"Compiling 112 files with Solc 0.8.26\nSolc 0.8.26 finished in 77.85s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:74:5:\n   |\n74 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3867,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 74690)\nLogs:\n  hook: 17884\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 584.20µs (466.34µs CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.05ms (485.81µs CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 162073)\n[PASS] test_sepoliaLaunchFile() (gas: 156460)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.19ms (1.47ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 240085)\n[PASS] test_moveCap() (gas: 240148)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 180030)\n[PASS] test_quietMoveLimit() (gas: 246366)\n[PASS] test_stalemate() (gas: 237898)\n[PASS] test_thirdRepetition() (gas: 964198)\n[PASS] test_tooFewPiecesToMate() (gas: 231723)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 7.90ms (4.38ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1794857)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1185245)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2312963)\n[PASS] test_sliceSide() (gas: 647815)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 419601)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 10.40ms (11.02ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22687788)\n[PASS] test_launchTokenAboveImd() (gas: 23871208)\nLogs:\n  first buy (opens game 0, bids for White): 389763\n\n[PASS] test_launchTokenBelowImd() (gas: 24033367)\nLogs:\n  first buy (opens game 0, bids for White): 385201\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 67.19ms (188.36ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 68129144)\n[PASS] test_blankChainTokenBelowImd() (gas: 68055011)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 78.72ms (123.64ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2543571)\nLogs:\n  plain trade: 210590\n  trade that converts a batch: 274449\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27998922)\nLogs:\n  hook share of a moving trade: average: 283031\n  hook share of a moving trade: max: 313889\n\n[PASS] test_middlegameGas() (gas: 8203052)\nLogs:\n  first bid in a new pool: 273472\n  bidding trade: 194930\n  outbidding trade: 210932\n  plain trade: 185367\n  next block: play the turn and bid: 544398\n\n[PASS] test_openingGas() (gas: 3371499)\nLogs:\n  first bid in a new pool: 273472\n  bidding trade: 195550\n  outbidding trade: 210932\n  plain trade: 185367\n  next block: play the turn and bid: 442193\n\n[PASS] test_runningGameGas() (gas: 54197038)\nLogs:\n  running game, moving trades measured: 48\n  running game, moving trade average: 477875\n  running game, moving trade max: 700265\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 88.91ms (160.73ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4960497)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2910338)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1922133)\n[PASS] test_anyoneCanConvert() (gas: 464742)\n[PASS] test_booksBalanceAcrossPools() (gas: 8648684)\n[PASS] test_crossBlockViaConvert() (gas: 4473657)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4638746)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 793428)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 502184)\n[PASS] test_noRouteNoDuel() (gas: 1262161)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1219396)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 112.33ms (58.55ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9149, ~: 9118)\nLogs:\n  Bound result 140408634885699395999353210173794253356013074822392266714587117801872617862\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 11970, ~: 11970)\nLogs:\n  Bound result 3905690605402760688486569470973352707\n  Bound result 2175930215851458032844206630585034303747446649436\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14604, ~: 14270)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13863, ~: 13724)\nLogs:\n  Bound result 340282366920938463463374607431767231456\n  Bound result 336879543251729078828740861357455220\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14038, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050514300\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007912567600000\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 115.73ms (94.15ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4960302)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2910339)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1922134)\n[PASS] test_anyoneCanConvert() (gas: 464742)\n[PASS] test_booksBalanceAcrossPools() (gas: 8648686)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 793429)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 502172)\n[PASS] test_noRouteNoDuel() (gas: 1262163)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1219397)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 115.83ms (28.84ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4212159)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2427962)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8594138)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1014196)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3333787)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3137388)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2406430)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 3025939)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 4015281)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1560088)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3745027)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23963154)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 115.85ms (96.58ms CPU time)\n\nRan 9 tests for test/JitStrength.t.sol:JitStrengthTest\n[PASS] test_aBlocksFirstAddRecordsTheLiquidityBeforeIt() (gas: 1686913)\n[PASS] test_bracketsAroundABlocksFirstSwapDoNotInflateTheSample() (gas: 3380544)\n[PASS] test_eachPoolSamplesItsOwnDepth() (gas: 1139381)\n[PASS] test_liquidityAddedAndRemovedAroundATradeDoesNotShrinkItsShare() (gas: 1447542)\n[PASS] test_liquidityHeldThroughOneBlockDoesNotShrinkTheShare() (gas: 1490670)\n[PASS] test_liquidityHeldThroughThreeTradedBlocksCounts() (gas: 1435144)\n[PASS] test_liquidityRemovedBeforeTheFirstSampleOnlyLowersIt() (gas: 2249607)\n[PASS] test_onlyThePoolManagerCallsBeforeAddLiquidity() (gas: 39697)\n[PASS] test_theFirstTradedBlockMeasuresAgainstTheLiquidityItStartsWith() (gas: 822315)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 115.87ms (14.55ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 1006532, ~: 1007223)\nLogs:\n  Bound result 254000000000000000\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 488304, ~: 488427)\nLogs:\n  Bound result 1857\n  Bound result 999999999999004000001\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1102094, ~: 1102128)\nLogs:\n  Bound result 229\n  Bound result 312\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2619855)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123685)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 239394)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121434)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98327)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344748)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111179)\n[PASS] test_lastSurchargeSecond() (gas: 493834)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 3050462)\n[PASS] test_openingEdges() (gas: 493456)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1156075)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 493347)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 90078)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 119.86ms (274.36ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3537206)\nLogs:\n  smallest gas limit that converts: 313268\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 3824964)\nLogs:\n  smallest gas limit that plays and records the bounty: 397167\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15348541)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 143.62ms (164.55ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1457587)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1971256)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1232910)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1071568)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1049129)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 1003892)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1487683)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1320945)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1546122)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1614992)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1086318)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1852967)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1209879)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 180.61ms (31.37ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 168865847)\nLogs:\n  bot moves: 0\n  other moves: 42\n  captures among other moves: 11\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 330.65ms (330.47ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9781442, ~: 9671843)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 93045635)\nLogs:\n  moves played: 134\n  bids (incl. outbid ones): 169\n  most gas for a swap: 807516\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 712955)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1344781)\n[PASS] test_aTradeBidsForTheTurn() (gas: 507240)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 1006040)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1447893)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1812917)\n[PASS] test_anyTradeSizeBids() (gas: 473819)\n[PASS] test_lateTradeStillBidsNormally() (gas: 453453)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 171702)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 439544)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 956298)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1058301)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6591275)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 953519)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 809066)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179473)\n[PASS] test_theMainDuelMustPairImd() (gas: 294337)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1079368)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 435977)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1592213)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 736.45ms (935.62ms CPU time)\n\nRan 23 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10858942, ~: 10889314)\n[PASS] test_aBatchSpendsAtMostTenMinimumsExactly() (gas: 54123)\n[PASS] test_aFullChestTakesNoMore() (gas: 1094876)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 630295)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 850978)\n[PASS] test_bountyTable() (gas: 44705)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 830864)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 676894)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5627127)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 408707)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 834675)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 485621)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 387566)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48736)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41896)\n[PASS] test_fundChestWithEth() (gas: 252883)\n[PASS] test_fundChestWithTokens() (gas: 205789)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3614681)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 905418)\n[PASS] test_quietMovePaysNothing() (gas: 637765)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1274880)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 972242)\n[PASS] test_withdrawToRefusesTheZeroAddress() (gas: 610435)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 777.78ms (799.82ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 19999999000000000021\n  Bound result 19999999000000017192\n  Bound result 386549022720\n  Bound result 98\n  Bound result 19999999000000000301\n  Bound result 8\n  Bound result 39\n  Bound result 4629921925374754156\n  Bound result 19999999000000001096\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 19999999000000000209\n  Bound result 19999999000177362149\n  Bound result 900000\n  Bound result 17380275022719779\n  Bound result 13295\n  Bound result 1371698883\n  Bound result 106\n  Bound result 19999999000000000071\n  Bound result 19999999000000012501\n  Bound result 15600679758904\n  Bound result 3372497854775807539\n  Bound result 19999999000000020001\n  Bound result 19999999000000002320\n  Bound result 7932\n  Bound result 19999999000000006870\n  Bound result 6515626003710664071\n  Bound result 19999999000000995001\n  Bound result 749999999999250\n  Bound result 19999999000000011026\n  Bound result 15207\n  Bound result 19999999000000005716\n  Bound result 10000000000000000000\n  Bound result 80\n  Bound result 16\n  Bound result 749999999999250\n  Bound result 5326068082251959603\n  Bound result 19999999000000009525\n  Bound result 49425749022699434082\n  Bound result 19999999000000004909\n  Bound result 19999999000000003263\n  Bound result 19999999000000003533\n  Bound result 19999999000000007776\n  Bound result 19999999000000022484\n  Bound result 15\n  Bound result 19999999000000100001\n  Bound result 7616448877154347021\n  Bound result 21018\n  Bound result 15\n  Bound result 112108561573182545\n  Bound result 19999999000000015561\n  Bound result 7011749056432742262\n  Bound result 19999999063368430181\n  Bound result 19999999000000560001\n  Bound result 64\n  Bound result 17256293755346024653\n  Bound result 15\n  Bound result 80\n  Bound result 17462041093041794489\n  Bound result 108\n  Bound result 72624976668147840\n  Bound result 9384671937848548256\n  Bound result 19999999000000000126\n  Bound result 19999999000000009383\n  Bound result 19999999000000000225\n  Bound result 16916\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.13s (1.13s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8\n  Bound result 4649\n  Bound result 1\n  Bound result 7038\n  Bound result 120396004288981\n  Bound result 5\n  Bound result 8228\n  Bound result 6\n  Bound result 870060366358668890202810772\n  Bound result 4\n  Bound result 2738504042791640380511251\n  Bound result 9\n  Bound result 671217046808349282794304116\n  Bound result 2\n  Bound result 3949\n  Bound result 0\n  Bound result 100000000000000000\n  Bound result 2\n  Bound result 7\n  Bound result 196608\n  Bound result 18\n  Bound result 5\n  Bound result 500\n  Bound result 1357\n  Bound result 8\n  Bound result 999\n  Bound result 2\n  Bound result 6413\n  Bound result 6\n  Bound result 15\n  Bound result 7958\n  Bound result 229\n  Bound result 9\n  Bound result 4\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55899, ~: 55857)\nLogs:\n  Bound result 893409364866962332856807\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.65s (2.75s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4210605550\n  Bound result 9999999000000000012263\n  Bound result 4999999999000020765\n  Bound result 482656664672130512400\n  Bound result 25333134452981760\n  Bound result 47460125026787646792\n  Bound result 5275\n  Bound result 19999999999000011592\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000995001\n  Bound result 19999999999000000081\n  Bound result 19999999999000008611\n  Bound result 19999999999000007539\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000097\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000196609\n  Bound result 20000000000000000000\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 14211026072807217151\n  Bound result 9999\n  Bound result 19999999999000017973\n  Bound result 12\n  Bound result 19999999999000010929\n  Bound result 3111\n  Bound result 180000000000000017293\n  Bound result 12\n  Bound result 110\n  Bound result 9999999000000000001002\n  Bound result 12\n  Bound result 19999999999000015916\n  Bound result 100000000000000000000\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 7885362738380271025\n  Bound result 10019998000000000218742\n  Bound result 15\n  Bound result 9999999000000483266409\n  Bound result 9999999000000000003820\n  Bound result 1800\n  Bound result 19999999999000016313\n  Bound result 19999999999000004667\n  Bound result 9302618518017444791\n  Bound result 21713\n  Bound result 180000000000000007114\n  Bound result 12\n  Bound result 9999999000000000003820\n  Bound result 12\n  Bound result 19999999999000018708\n  Bound result 19999999999000014940\n  Bound result 17707567918181156739\n  Bound result 12\n  Bound result 5819675075174645730\n  Bound result 59\n  Bound result 29999996000000486279675\n  Bound result 180000000000000000465\n  Bound result 12\n  Bound result 19999999999000008854\n  Bound result 26\n  Bound result 25\n  Bound result 9303618518017422656\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 32224298516368066856\n  Bound result 8025029209421094333997\n  Bound result 11220\n  Bound result 9999998000000000004347\n  Bound result 12\n  Bound result 599999999400\n  Bound result 90\n  Bound result 8\n  Bound result 6301104690399990896\n  Bound result 244\n  Bound result 40\n  Bound result 1741\n  Bound result 180000000000000002491\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000013354\n  Bound result 6000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 4999999999000002001\n  Bound result 12\n  Bound result 88\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000004079\n  Bound result 19999999999001966081\n  Bound result 19999999999000001572\n  Bound result 180000000000000000032\n  Bound result 12\n  Bound result 19999999999000011533\n  Bound result 9999999000000000000017\n  swaps: 38\n  moves: 21\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.69s (3.68s CPU time)\n\nRan 22 test suites in 3.69s (10.59s CPU time): 163 tests passed, 0 failed, 0 skipped (163 total tests)\n","passed":true},{"durationMs":97,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":79,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":37,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":37,\"launch/hook.sepolia.json\":37,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":964,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":347,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":84,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/JitStrength.t.sol\":182,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":167,\"test/LaunchFiles.t.sol\":79,\"test/Money.t.sol\":400,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":38,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":19678,"exitCode":0,"name":"slither","output":"[high/medium] incorrect-exp at src/IMDuelHook.sol:255: IMDuelHook.teamOf(uint8,uint32,bool) (src/IMDuelHook.sol#255-257) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[high/medium] incorrect-exp at src/IMDuelHook.sol:255: IMDuelHook.teamOf(uint8,uint32,bool) (src/IMDuelHook.sol#255-257) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[medium/high] incorrect-equality at src/IMDuelHook.sol:574: IMDuelHook._reference(uint256,bool) (src/IMDuelHook.sol#574-580) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMDuelHook.sol:554: IMDuelHook._recordDepth(PoolId,uint256) (src/IMDuelHook.sol#554-559) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMDuelHook.sol:563: IMDuelHook._sample(uint160) (src/IMDuelHook.sol#563-569) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMDuelHook.sol:353: IMDuelHook._takeFee(PoolId,PoolKey,uint256,uint256,uint256,IMDuelHook.Game) (src/IMDuelHook.sol#353-365) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/IMDuelHook.sol:514: Reentrancy in IMDuelHook._swapClaims(PoolKey,Currency,uint256) (src/IMDuelHook.sol#514-533):\n[medium/medium] reentrancy-no-eth at src/IMDuelHook.sol:323: Reentrancy in IMDuelHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/IMDuelHook.sol#323-348):\n[medium/medium] reentrancy-no-eth at src/IMDuelHook.sol:484: Reentrancy in IMDuelHook._convert(Currency) (src/IMDuelHook.sol#484-500):\n[medium/medium] uninitialized-local at src/Bitboard.sol:643: Bitboard._targets(Bitboard.Pos,Bitboard.Gen,uint8,bool).ep (src/Bitboard.sol#643) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:480: Bitboard._anyLegal(Bitboard.Pos,bool).scratch (src/Bitboard.sol#480) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:585: IMDuelHook._pack(uint160).e (src/IMDuelHook.sol#585) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:425: Bitboard.isLegal(Bitboard.Pos,uint16,bool).scratch (src/Bitboard.sol#425) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:497: ChessEngineV5._queening(ChessEngineV5.Ctx,Bitboard.Pos,uint64,uint64,uint64,uint64,uint64).a (src/ChessEngineV5.sol#497) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:182: ChessEngineV5._choose(ChessEngineV5.Ctx,uint256,uint256,uint64[8],uint32,uint16).seen (src/ChessEngineV5.sol#182) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:400: Bitboard._legalTargets(Bitboard.Pos,Bitboard.Gen,Bitboard.Pos,uint8,bool).ep (src/Bitboard.sol#400) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:236: Bitboard.pieceAttacks(Bitboard.Pos,uint64,uint64,bool).a (src/Bitboard.sol#236) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:203: ChessEngineV5._choose(ChessEngineV5.Ctx,uint256,uint256,uint64[8],uint32,uint16).refined (src/ChessEngineV5.sol#203) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:580: Bitboard.mateInOne(Bitboard.Pos,bool,uint256).scratch (src/Bitboard.sol#580) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:873: IMDuelHook._repeated(PoolId,IMDuelHook.Game).seen (src/IMDuelHook.sol#873) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:414: ChessEngineV5._placement(ChessEngineV5.Ctx,uint8,uint8,uint8,uint8,bool,bool).near (src/ChessEngineV5.sol#414) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:276: ChessEngineV5._context(uint256,uint32,uint32,bool,bool).nonPawn (src/ChessEngineV5.sol#276) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:806: IMDuelHook._apply(PoolId,IMDuelHook.Game,uint16,Rules.Played,IMDuelHook.Trade).result (src/IMDuelHook.sol#806) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:377: ChessEngineV5._cheap(ChessEngineV5.Ctx,uint16).squeeze (src/ChessEngineV5.sol#377) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:810: IMDuelHook._apply(PoolId,IMDuelHook.Game,uint16,Rules.Played,IMDuelHook.Trade).reason (src/IMDuelHook.sol#810) is a local variable never initialized\n[medium/medium] unused-return at src/IMDuelHook.sol:422: IMDuelHook._withdraw(address,Currency,address) (src/IMDuelHook.sol#422-428) ignores return value by manager.unlock(abi.encode(uint8(0),abi.encode(to,c,amount))) (src/IMDuelHook.sol#426)\n[medium/medium] unused-return at src/IMDuelHook.sol:514: IMDuelHook._swapClaims(PoolKey,Currency,uint256) (src/IMDuelHook.sol#514-533) ignores return value by (sqrtPrice,None,None,None) = manager.getSlot0(key.toId()) (src/IMDuelHook.sol#519)\n[medium/medium] unused-return at src/IMDuelHook.sol:306: IMDuelHook.beforeSwap(address,PoolKey,SwapParams,bytes) (src/IMDuelHook.sol#306-321) ignores return value by (sqrtPrice,None,None,None) = manager.getSlot0(id) (src/IMDuelHook.sol#313)\n[medium/medium] unused-return at src/IMDuelHook.sol:443: IMDuelHook.convert(Currency) (src/IMDuelHook.sol#443-445) ignores return value by manager.unlock(abi.encode(uint8(2),abi.encode(address(0),c,uint256(0)))) (src/IMDuelHook.sol#444)\n[low/high] shadowing-local at src/ChessEngineV5.sol:817: ChessEngineV5._mop(ChessEngineV5.Ctx,uint8,uint8,uint8,bool,bool).at (src/ChessEngineV5.sol#705) shadows:\n[low/medium] missing-zero-check at src/IMDuelHook.sol:450: IMDuelHook.unlockCallback(bytes).who (src/IMDuelHook.sol#450) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/IMDuelHook.sol:432: Reentrancy in IMDuelHook.fundChest(PoolKey,bool,uint256) (src/IMDuelHook.sol#432-440):\n[low/medium] reentrancy-benign at src/IMDuelHook.sol:353: Reentrancy in IMDuelHook._takeFee(PoolId,PoolKey,uint256,uint256,uint256,IMDuelHook.Game) (src/IMDuelHook.sol#353-365):\n[low/medium] reentrancy-benign at src/IMDuelHook.sol:484: Reentrancy in IMDuelHook._convert(Currency) (src/IMDuelHook.sol#484-500):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:484: Reentrancy in IMDuelHook._convert(Currency) (src/IMDuelHook.sol#484-500):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:422: Reentrancy in IMDuelHook._withdraw(address,Currency,address) (src/IMDuelHook.sol#422-428):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:323: Reentrancy in IMDuelHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/IMDuelHook.sol#323-348):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:432: Reentrancy in IMDuelHook.fundChest(PoolKey,bool,uint256) (src/IMDuelHook.sol#432-440):\n[low/medium] return-bomb at src/IMDuelHook.sol:770: IMDuelHook._engine(uint256,bytes) (src/IMDuelHook.sol#770-776) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] timestamp at src/IMDuelHook.sol:616: IMDuelHook._play(PoolId,PoolKey,IMDuelHook.Game,bool,BalanceDelta,bytes,uint160,uint256) (src/IMDuelHook.sol#616-655) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:432: IMDuelHook.fundChest(PoolKey,bool,uint256) (src/IMDuelHook.sol#432-440) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:369: IMDuelHook._chestBps(IMDuelHook.Game) (src/IMDuelHook.sol#369-372) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:353: IMDuelHook._takeFee(PoolId,PoolKey,uint256,uint256,uint256,IMDuelHook.Game) (src/IMDuelHook.sol#353-365) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:383: IMDuelHook._addChest(PoolId,uint256,uint256) (src/IMDuelHook.sol#383-390) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:484: IMDuelHook._convert(Currency) (src/IMDuelHook.sol#484-500) uses timestamp for comparisons","passed":true},{"durationMs":1181,"exitCode":0,"name":"aderyn","output":"[high] contract-locks-ether at src/IMDuelHook.sol:48: Contract locks Ether without a withdraw function\n[high] incorrect-caret-operator at src/IMDuelHook.sol:256: Incorrect use of caret operator\n[high] unsafe-casting at src/Bitboard.sol:247: Unsafe Casting of integers\n[low] empty-require-revert at src/ChessEngineV5.sol:157: Empty `require()` / `revert()` Statement\n[low] internal-function-used-once at src/Bitboard.sol:199: Internal Function Used Only Once (9 places)\n[low] large-numeric-literal at src/ChessEngineV5.sol:34: Large Numeric Literal (26 places)\n[low] literal-instead-of-constant at src/Bitboard.sol:35: Literal Instead of Constant (408 places)\n[low] missing-inheritance at src/IMDuelToken.sol:7: Missing Inheritance\n[low] push-zero-opcode at src/Bitboard.sol:2: PUSH0 Opcode (8 places)\n[low] state-change-without-event at src/IMDuelHook.sol:290: State Change Without Event (2 places)\n[low] unchecked-return at src/IMDuelHook.sol:426: Unchecked Return (2 places)\n[low] uninitialized-local-variable at src/ChessEngineV5.sol:164: Uninitialized Local Variable (10 places)\n[low] unsafe-erc20-operation at src/IMDuelHook.sol:466: Unsafe ERC20 Operation\n[low] unspecific-solidity-pragma at src/ChessEngineV5.sol:2: Unspecific Solidity Pragma (4 places)\n[low] unused-state-variable at src/IMDuelHook.sol:79: Unused State Variable","passed":true},{"durationMs":16375,"exitCode":0,"name":"proof 87c3e492d172","output":"Compiling 90 files with Solc 0.8.26\nSolc 0.8.26 finished in 15.64s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\n\nRan 1 test for test/imd-proof-67287fdb/Proof_87c3e492d172.t.sol:DepthFirstSwapTest\n[PASS] test_victimShareMeasuredAgainstHonestDepth() (gas: 2258129)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.20ms (1.94ms CPU time)\n\nRan 1 test suite in 5.01ms (3.20ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"57378880e0fe1e0808e5cc879e0eeed4601440b52082ec2682ce5cd034b34002","verifiedTreeHash":"63949b48b0022647ac107b5103498c28d4796011","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":76596,"exitCode":0,"name":"build","output":"Compiling 112 files with Solc 0.8.26\nSolc 0.8.26 finished in 76.47s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:70:5:\n   |\n70 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3775,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 73829)\nLogs:\n  hook: 17628\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 767.59µs (651.56µs CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 159126)\n[PASS] test_sepoliaLaunchFile() (gas: 154500)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.98ms (1.36ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 239953)\n[PASS] test_moveCap() (gas: 239994)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 179942)\n[PASS] test_quietMoveLimit() (gas: 246212)\n[PASS] test_stalemate() (gas: 237766)\n[PASS] test_thirdRepetition() (gas: 963626)\n[PASS] test_tooFewPiecesToMate() (gas: 231591)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 5.82ms (3.69ms CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 5.99ms (565.02µs CPU time)\n\nRan 5 tests for test/JitStrength.t.sol:JitStrengthTest\n[PASS] test_eachPoolSamplesItsOwnDepth() (gas: 1132886)\n[PASS] test_liquidityAddedAndRemovedAroundATradeDoesNotShrinkItsShare() (gas: 1438143)\n[PASS] test_liquidityHeldThroughOneBlockDoesNotShrinkTheShare() (gas: 1477821)\n[PASS] test_liquidityHeldThroughThreeTradedBlocksCounts() (gas: 1424428)\n[PASS] test_theFirstTradedBlockMeasuresAgainstTheLiquidityItStartsWith() (gas: 815952)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 9.66ms (5.89ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1771027)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1178034)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2303660)\n[PASS] test_sliceSide() (gas: 646625)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 418496)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 18.05ms (12.75ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4923382)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2884337)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1914709)\n[PASS] test_anyoneCanConvert() (gas: 464503)\n[PASS] test_booksBalanceAcrossPools() (gas: 8663335)\n[PASS] test_crossBlockViaConvert() (gas: 4448978)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4613960)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 787341)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 501857)\n[PASS] test_noRouteNoDuel() (gas: 1250177)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1213059)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 25.72ms (55.14ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 25907580)\n[PASS] test_blankChainTokenBelowImd() (gas: 25835453)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 54.18ms (88.47ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22439603)\n[PASS] test_launchTokenAboveImd() (gas: 23691662)\nLogs:\n  first buy (opens game 0, bids for White): 389635\n\n[PASS] test_launchTokenBelowImd() (gas: 23639085)\nLogs:\n  first buy (opens game 0, bids for White): 385073\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 56.39ms (142.13ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2532287)\nLogs:\n  plain trade: 210439\n  trade that converts a batch: 274298\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27976648)\nLogs:\n  hook share of a moving trade: average: 282901\n  hook share of a moving trade: max: 313758\n\n[PASS] test_middlegameGas() (gas: 8202359)\nLogs:\n  first bid in a new pool: 273321\n  bidding trade: 194779\n  outbidding trade: 210781\n  plain trade: 185216\n  next block: play the turn and bid: 537587\n\n[PASS] test_openingGas() (gas: 3413416)\nLogs:\n  first bid in a new pool: 273321\n  bidding trade: 195396\n  outbidding trade: 210781\n  plain trade: 185216\n  next block: play the turn and bid: 514228\n\n[PASS] test_runningGameGas() (gas: 53462553)\nLogs:\n  running game, moving trades measured: 50\n  running game, moving trade average: 452812\n  running game, moving trade max: 538931\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 89.96ms (147.08ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1456913)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1992032)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1252567)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1092985)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1070568)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 1003286)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1497005)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1316573)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1554405)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1658042)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1107691)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1851735)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1252983)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 113.72ms (20.39ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4252940)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2420483)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8586833)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1013025)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3358740)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3122908)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2398627)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 3018355)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 4007883)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1558917)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3737236)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23802213)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 120.94ms (121.61ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4923187)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2884338)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1914710)\n[PASS] test_anyoneCanConvert() (gas: 464503)\n[PASS] test_booksBalanceAcrossPools() (gas: 8663337)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 787342)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 501845)\n[PASS] test_noRouteNoDuel() (gas: 1250179)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1213060)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 124.59ms (39.94ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 1010247, ~: 1010947)\nLogs:\n  Bound result 254000000000000000\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 488096, ~: 488229)\nLogs:\n  Bound result 1037\n  Bound result 999999999999382007408\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1115898, ~: 1115940)\nLogs:\n  Bound result 63\n  Bound result 244\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2619901)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123553)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 239266)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121368)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98261)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344594)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111113)\n[PASS] test_lastSurchargeSecond() (gas: 493618)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 3050248)\n[PASS] test_openingEdges() (gas: 493240)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1149731)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 493131)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 90012)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 124.79ms (283.62ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9149, ~: 9118)\nLogs:\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 11970, ~: 11970)\nLogs:\n  Bound result 140408634885699395999353210173794253356013074822392266714587117801872617862\n  Bound result 115651680602430496027571631798514113599913971590818171772742996898113896738059\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14604, ~: 14270)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13863, ~: 13724)\nLogs:\n  Bound result 340282366920938463463374607431767231456\n  Bound result 336879543251729078828740861357455220\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14038, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050514300\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007912567600000\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 144.58ms (209.26ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3525746)\nLogs:\n  smallest gas limit that converts: 313268\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 3817204)\nLogs:\n  smallest gas limit that plays and records the bounty: 397167\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15340033)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 158.18ms (186.24ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9739298, ~: 9705964)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 74993302)\nLogs:\n  moves played: 110\n  bids (incl. outbid ones): 141\n  most gas for a swap: 621406\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 712566)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1336972)\n[PASS] test_aTradeBidsForTheTurn() (gas: 507002)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 995129)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1449845)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1791289)\n[PASS] test_anyTradeSizeBids() (gas: 473603)\n[PASS] test_lateTradeStillBidsNormally() (gas: 453237)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 145185)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 439350)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 945365)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1078046)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6469951)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 953042)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 808633)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179407)\n[PASS] test_theMainDuelMustPairImd() (gas: 293233)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1068457)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 435783)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1570607)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 733.99ms (863.02ms CPU time)\n\nRan 23 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10869759, ~: 10927806)\n[PASS] test_aBatchSpendsAtMostTenMinimumsExactly() (gas: 53969)\n[PASS] test_aFullChestTakesNoMore() (gas: 1094242)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 630039)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 850564)\n[PASS] test_bountyTable() (gas: 44573)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 830472)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 676417)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5622444)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 408535)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 838597)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 485339)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 387372)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48714)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41874)\n[PASS] test_fundChestWithEth() (gas: 252795)\n[PASS] test_fundChestWithTokens() (gas: 205591)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3592670)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 904960)\n[PASS] test_quietMovePaysNothing() (gas: 637439)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1268507)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 971630)\n[PASS] test_withdrawToRefusesTheZeroAddress() (gas: 610127)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 769.95ms (789.18ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 584493866)\nLogs:\n  bot moves: 0\n  other moves: 149\n  captures among other moves: 25\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 968.29ms (968.15ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 19999999000000000021\n  Bound result 19999999000000017509\n  Bound result 386549022720\n  Bound result 98\n  Bound result 19999999000000000301\n  Bound result 8\n  Bound result 39\n  Bound result 2893925734761568126\n  Bound result 19999999000000001211\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 19999999000000000209\n  Bound result 19999999000000000788\n  Bound result 900000\n  Bound result 17380275022719779\n  Bound result 13376\n  Bound result 1437185598\n  Bound result 106\n  Bound result 19999999000000000071\n  Bound result 19999999000000012501\n  Bound result 15600679758904\n  Bound result 3372497854775807539\n  Bound result 19999999000000020001\n  Bound result 19999999000000000324\n  Bound result 8449\n  Bound result 19999999000000007015\n  Bound result 6515626003710664071\n  Bound result 19999999000000995001\n  Bound result 749999999999250\n  Bound result 19999999000000011443\n  Bound result 15382\n  Bound result 19999999000000007501\n  Bound result 10000000000000000000\n  Bound result 80\n  Bound result 16\n  Bound result 749999999999250\n  Bound result 47605325464897860659\n  Bound result 564387865581898281\n  Bound result 49425749022699434082\n  Bound result 19999999000000005259\n  Bound result 19999999000000003443\n  Bound result 19999999000000003748\n  Bound result 19999999000000000211\n  Bound result 17943753809444800\n  Bound result 15\n  Bound result 19999999000000100001\n  Bound result 7616448877154347021\n  Bound result 21729\n  Bound result 15\n  Bound result 112108561573182545\n  Bound result 19999999000000014960\n  Bound result 7011749056432742262\n  Bound result 19999999063368430181\n  Bound result 19999999000000560001\n  Bound result 64\n  Bound result 17256293755346024653\n  Bound result 15\n  Bound result 80\n  Bound result 17462041093041794489\n  Bound result 49\n  Bound result 72624976668147840\n  Bound result 9384671937848548256\n  Bound result 19999999000000000126\n  Bound result 19999999000000010061\n  Bound result 19999999000000000225\n  Bound result 29061427756277306518\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.12s (1.12s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8\n  Bound result 4649\n  Bound result 1\n  Bound result 7038\n  Bound result 120396004288981\n  Bound result 5\n  Bound result 8228\n  Bound result 6\n  Bound result 870060366358668890202810772\n  Bound result 4\n  Bound result 2738504042791640380511251\n  Bound result 9\n  Bound result 671217046808349282794304116\n  Bound result 2\n  Bound result 3949\n  Bound result 0\n  Bound result 100000000000000000\n  Bound result 2\n  Bound result 7\n  Bound result 196608\n  Bound result 18\n  Bound result 5\n  Bound result 500\n  Bound result 1357\n  Bound result 8\n  Bound result 999\n  Bound result 2\n  Bound result 6413\n  Bound result 6\n  Bound result 15\n  Bound result 7958\n  Bound result 229\n  Bound result 9\n  Bound result 4\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55899, ~: 55857)\nLogs:\n  Bound result 893409364866962332856807\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.51s (2.52s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 157198259\n  Bound result 9999999000000000004694\n  Bound result 4999999999000022597\n  Bound result 482656664672130512400\n  Bound result 25333134452981760\n  Bound result 47460125026787646792\n  Bound result 5159\n  Bound result 19999999999000011602\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000995001\n  Bound result 19999999999000000081\n  Bound result 19999999999000009887\n  Bound result 24333134452997109\n  Bound result 19999999999000007610\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000097\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000196609\n  Bound result 20000000000000000000\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 14211026072807217151\n  Bound result 9999\n  Bound result 19999999999000018323\n  Bound result 12\n  Bound result 19999999999000011204\n  Bound result 2380\n  Bound result 180000000000000016828\n  Bound result 12\n  Bound result 32\n  Bound result 9999999000000000001002\n  Bound result 12\n  Bound result 19999999999000016438\n  Bound result 100000000000000000000\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 7885362738380271025\n  Bound result 15\n  Bound result 9999999000000000008446\n  Bound result 9999999000000000004361\n  Bound result 1800\n  Bound result 19999999999000016488\n  Bound result 19999999999000004667\n  Bound result 9302618518017444791\n  Bound result 21406\n  Bound result 180000000000000006850\n  Bound result 12\n  Bound result 29999997000000000010057\n  Bound result 12\n  Bound result 19999999999000018866\n  Bound result 19999999999000014688\n  Bound result 17707567918181156739\n  Bound result 12\n  Bound result 5819675075174645730\n  Bound result 35\n  Bound result 175854943285123371047\n  Bound result 12\n  Bound result 19999999999000009112\n  Bound result 51\n  Bound result 25\n  Bound result 20029301618518017634495\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 32978478123407262732\n  Bound result 10955\n  Bound result 9999998000000000003730\n  Bound result 12\n  Bound result 599999999400\n  Bound result 108\n  Bound result 8\n  Bound result 352755970276556669\n  Bound result 244\n  Bound result 40\n  Bound result 1397\n  Bound result 180071775015237779198\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000012519\n  Bound result 6000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 4999999999000002001\n  Bound result 12\n  Bound result 88\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000004079\n  Bound result 19999999999001966081\n  Bound result 19999999999000001189\n  Bound result 180000000000000000032\n  Bound result 12\n  Bound result 19999999999000011310\n  Bound result 9999999000000000000017\n  swaps: 38\n  moves: 22\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.60s (3.59s CPU time)\n\nRan 22 test suites in 3.60s (10.76s CPU time): 159 tests passed, 0 failed, 0 skipped (159 total tests)\n","passed":true},{"durationMs":70,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":70,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":34,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":36,\"launch/hook.sepolia.json\":36,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":931,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":345,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":84,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/JitStrength.t.sol\":103,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":157,\"test/LaunchFiles.t.sol\":75,\"test/Money.t.sol\":400,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":38,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"63563b8be837a40384608cf30952375fedf451b9b2199b43975e80e2aca4386b","verifiedTreeHash":"c591e3de35a80cc4bc764ebb92d0ca91075a31b6","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":81833,"exitCode":0,"name":"build","output":"Compiling 113 files with Solc 0.8.26\nSolc 0.8.26 finished in 81.72s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:74:5:\n   |\n74 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3760,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 74690)\nLogs:\n  hook: 17884\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 735.23µs (611.47µs CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.04ms (488.69µs CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 162073)\n[PASS] test_sepoliaLaunchFile() (gas: 156460)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.84ms (1.31ms CPU time)\n\nRan 2 tests for test/Edges.t.sol:PreviewEdgesTest\n[PASS] test_aBidEarlyInTheWindowIsNotPreviewedUntilItsLastBlock() (gas: 633869)\n[PASS] test_noPreviewBeforeTheLastBlockOrWithoutABid() (gas: 633669)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 4.72ms (3.00ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1794857)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1185245)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2312963)\n[PASS] test_sliceSide() (gas: 647815)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 419601)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 5.95ms (8.34ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:BatchCapTest\n[PASS] test_aPileJustOverTheCapSpendsTenMinimums() (gas: 1669773)\n[PASS] test_aPileUnderOneMinimumOnlyConvertsOnRequest() (gas: 1424096)\n[PASS] test_nothingConvertsBeforeThreeSampledBlocks() (gas: 482448)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 9.23ms (7.37ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 240085)\n[PASS] test_moveCap() (gas: 240148)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 180030)\n[PASS] test_quietMoveLimit() (gas: 246366)\n[PASS] test_stalemate() (gas: 237898)\n[PASS] test_thirdRepetition() (gas: 964198)\n[PASS] test_tooFewPiecesToMate() (gas: 231723)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 14.38ms (6.68ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:DepthSampleEdgesTest\n[PASS] test_liquidityRemovedAfterABlocksFirstSwapDoesNotCountInThatBlock() (gas: 1671488)\n[PASS] test_liquidityRemovedBeforeABlocksFirstSwapCountsAtOnce() (gas: 1565483)\n[PASS] test_quietBlocksTakeNoSample() (gas: 1692293)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 18.11ms (9.14ms CPU time)\n\nRan 2 tests for test/Edges.t.sol:BatchBoundFuzzTest\n[PASS] testFuzz_batchBound(uint256,uint256) (runs: 1000, μ: 14575, ~: 14593)\nLogs:\n  Bound result 9223372036854775808000\n\n[PASS] test_batchAtTheEdges() (gas: 45131)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 26.22ms (23.53ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4960497)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2910338)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1922133)\n[PASS] test_anyoneCanConvert() (gas: 464742)\n[PASS] test_booksBalanceAcrossPools() (gas: 8648684)\n[PASS] test_crossBlockViaConvert() (gas: 4473657)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4638746)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 793428)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 502184)\n[PASS] test_noRouteNoDuel() (gas: 1262161)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1219396)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 35.75ms (47.59ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4960302)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2910339)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1922134)\n[PASS] test_anyoneCanConvert() (gas: 464742)\n[PASS] test_booksBalanceAcrossPools() (gas: 8648686)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 793429)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 502172)\n[PASS] test_noRouteNoDuel() (gas: 1262163)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1219397)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 71.10ms (26.02ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22687788)\n[PASS] test_launchTokenAboveImd() (gas: 23871208)\nLogs:\n  first buy (opens game 0, bids for White): 389763\n\n[PASS] test_launchTokenBelowImd() (gas: 24033367)\nLogs:\n  first buy (opens game 0, bids for White): 385201\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 74.17ms (140.88ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:AddCallbackEdgesTest\n[PASS] testFuzz_anAddIsNeverRefused(int24,int24,uint256,bool) (runs: 256, μ: 505997, ~: 494628)\nLogs:\n  Bound result 6458\n  Bound result 12268\n  Bound result 271894432683817523115463\n\n[PASS] test_addsIntoEmptyRangesAreAccepted() (gas: 770749)\n[PASS] test_zeroLiquidityFeeCollectionRunsAndPaysTheFees() (gas: 1857623)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 74.89ms (75.72ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 68129144)\n[PASS] test_blankChainTokenBelowImd() (gas: 68055011)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 93.05ms (142.94ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4212159)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2427962)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8594138)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1014196)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3333787)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3137388)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2406430)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 3025939)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 4015281)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1560088)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3745027)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23963154)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 137.12ms (101.73ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9154, ~: 9118)\nLogs:\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 12012, ~: 12058)\nLogs:\n  Bound result 3905690605402760688486569470973352707\n  Bound result 2175930215851458032844206630585034303747446649436\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14631, ~: 15266)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13868, ~: 13724)\nLogs:\n  Bound result 340282366920938463463374607431767211551\n  Bound result 336879543251729078828740865652351554\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14041, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050514300\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007912563601001\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 149.36ms (154.35ms CPU time)\n\nRan 9 tests for test/JitStrength.t.sol:JitStrengthTest\n[PASS] test_aBlocksFirstAddRecordsTheLiquidityBeforeIt() (gas: 1686913)\n[PASS] test_bracketsAroundABlocksFirstSwapDoNotInflateTheSample() (gas: 3380544)\n[PASS] test_eachPoolSamplesItsOwnDepth() (gas: 1139381)\n[PASS] test_liquidityAddedAndRemovedAroundATradeDoesNotShrinkItsShare() (gas: 1447542)\n[PASS] test_liquidityHeldThroughOneBlockDoesNotShrinkTheShare() (gas: 1490670)\n[PASS] test_liquidityHeldThroughThreeTradedBlocksCounts() (gas: 1435144)\n[PASS] test_liquidityRemovedBeforeTheFirstSampleOnlyLowersIt() (gas: 2249607)\n[PASS] test_onlyThePoolManagerCallsBeforeAddLiquidity() (gas: 39697)\n[PASS] test_theFirstTradedBlockMeasuresAgainstTheLiquidityItStartsWith() (gas: 822315)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 149.33ms (15.21ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1457587)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1971256)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1232910)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1071568)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1049129)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 1003892)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1487683)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1320945)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1546122)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1614992)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1086318)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1852967)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1209879)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 149.62ms (32.08ms CPU time)\n\nRan 3 tests for test/Edges.t.sol:OwnerShapesTest\n[PASS] testFuzz_ownerIsTheNamedAddressElseTheSigner(uint8,address,uint256,bytes) (runs: 256, μ: 440287, ~: 440207)\n[PASS] test_aBidThatDoesNotBeatTheTopKeepsItsOwner() (gas: 810299)\n[PASS] test_everyHookDataShape() (gas: 3118525)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 149.63ms (150.71ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 1006598, ~: 1007251)\nLogs:\n  Bound result 44503914653215535188\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 488308, ~: 488427)\nLogs:\n  Bound result 1037\n  Bound result 999999999999382007408\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1102092, ~: 1102128)\nLogs:\n  Bound result 229\n  Bound result 313\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2619855)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123685)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 239394)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121434)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98327)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344748)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111179)\n[PASS] test_lastSurchargeSecond() (gas: 493834)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 3050462)\n[PASS] test_openingEdges() (gas: 493456)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1156075)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 493347)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 90078)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 149.58ms (314.87ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2543571)\nLogs:\n  plain trade: 210590\n  trade that converts a batch: 274449\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27998922)\nLogs:\n  hook share of a moving trade: average: 283031\n  hook share of a moving trade: max: 313889\n\n[PASS] test_middlegameGas() (gas: 8203052)\nLogs:\n  first bid in a new pool: 273472\n  bidding trade: 194930\n  outbidding trade: 210932\n  plain trade: 185367\n  next block: play the turn and bid: 544398\n\n[PASS] test_openingGas() (gas: 3371499)\nLogs:\n  first bid in a new pool: 273472\n  bidding trade: 195550\n  outbidding trade: 210932\n  plain trade: 185367\n  next block: play the turn and bid: 442193\n\n[PASS] test_runningGameGas() (gas: 54197038)\nLogs:\n  running game, moving trades measured: 48\n  running game, moving trade average: 477875\n  running game, moving trade max: 700265\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 149.59ms (175.72ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3537206)\nLogs:\n  smallest gas limit that converts: 313268\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 3824964)\nLogs:\n  smallest gas limit that plays and records the bounty: 397167\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15348541)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 151.17ms (172.69ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 168865847)\nLogs:\n  bot moves: 0\n  other moves: 42\n  captures among other moves: 11\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 305.93ms (305.75ms CPU time)\n\nRan 23 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10894775, ~: 10889314)\n[PASS] test_aBatchSpendsAtMostTenMinimumsExactly() (gas: 54123)\n[PASS] test_aFullChestTakesNoMore() (gas: 1094876)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 630295)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 850978)\n[PASS] test_bountyTable() (gas: 44705)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 830864)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 676894)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5627127)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 408707)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 834675)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 485621)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 387566)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48736)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41896)\n[PASS] test_fundChestWithEth() (gas: 252883)\n[PASS] test_fundChestWithTokens() (gas: 205789)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3614681)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 905418)\n[PASS] test_quietMovePaysNothing() (gas: 637765)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1274880)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 972242)\n[PASS] test_withdrawToRefusesTheZeroAddress() (gas: 610435)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 794.70ms (817.37ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9724611, ~: 9710755)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 93045635)\nLogs:\n  moves played: 134\n  bids (incl. outbid ones): 169\n  most gas for a swap: 807516\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 712955)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1344781)\n[PASS] test_aTradeBidsForTheTurn() (gas: 507240)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 1006040)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1447893)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1812917)\n[PASS] test_anyTradeSizeBids() (gas: 473819)\n[PASS] test_lateTradeStillBidsNormally() (gas: 453453)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 171702)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 439544)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 956298)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1058301)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6591275)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 953519)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 809066)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179473)\n[PASS] test_theMainDuelMustPairImd() (gas: 294337)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1079368)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 435977)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1592213)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 804.71ms (976.40ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 6515626003710664071\n  Bound result 19999999000000017192\n  Bound result 25332747903959040\n  Bound result 98\n  Bound result 19999999000000000129\n  Bound result 8\n  Bound result 80\n  Bound result 4629921925374754154\n  Bound result 19999999495924113524\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 19304386864691798331\n  Bound result 19999999000177362150\n  Bound result 560000\n  Bound result 17380275022719779\n  Bound result 13295\n  Bound result 1371698883\n  Bound result 105\n  Bound result 19999999000000230001\n  Bound result 99999999999900000\n  Bound result 15600679758904\n  Bound result 19999999000000000018\n  Bound result 14999999999985\n  Bound result 19999999000000002320\n  Bound result 7854\n  Bound result 19999999002367473959\n  Bound result 9187201950435737471\n  Bound result 19999999000000000161\n  Bound result 19999999000000000111\n  Bound result 19999999000000010945\n  Bound result 3613676512\n  Bound result 19999999000000005632\n  Bound result 19999999000000001801\n  Bound result 39\n  Bound result 32\n  Bound result 24999499999975\n  Bound result 5238139219404748700\n  Bound result 19999999000000001553\n  Bound result 49425749022699434082\n  Bound result 19999999000000004867\n  Bound result 19999999000000003265\n  Bound result 19999999000000004010\n  Bound result 19999999000000007776\n  Bound result 19999999000000022484\n  Bound result 64\n  Bound result 19999999000000009001\n  Bound result 15672660589582542013\n  Bound result 21060\n  Bound result 15\n  Bound result 112108561573182545\n  Bound result 19999999000000015530\n  Bound result 15672660589582542013\n  Bound result 19999999063368430181\n  Bound result 19999999000000050001\n  Bound result 16\n  Bound result 17256293755346024653\n  Bound result 15\n  Bound result 120\n  Bound result 17462041093041794489\n  Bound result 59\n  Bound result 19999999000000000005\n  Bound result 9384671937848548256\n  Bound result 20000000000000000\n  Bound result 19999999000000009383\n  Bound result 19999999000000003001\n  Bound result 16876\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.16s (1.15s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 64\n  Bound result 4650\n  Bound result 7\n  Bound result 6\n  Bound result 120396004288981\n  Bound result 9\n  Bound result 523\n  Bound result 40\n  Bound result 4\n  Bound result 5417\n  Bound result 2738504042791640380511251\n  Bound result 5\n  Bound result 887220\n  Bound result 11200000000000000000\n  Bound result 3950\n  Bound result 15\n  Bound result 4000000000000000000\n  Bound result 1740\n  Bound result 480000\n  Bound result 7\n  Bound result 11400714819323198485\n  Bound result 931\n  Bound result 100\n  Bound result 1188\n  Bound result 2010\n  Bound result 2000000000000000000000000\n  Bound result 2\n  Bound result 6870\n  Bound result 3600\n  Bound result 2000011400714819323198475\n  Bound result 316\n  Bound result 1701\n  Bound result 1813\n  Bound result 5484\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55900, ~: 55857)\nLogs:\n  Bound result 11600724250090367571751012605121696\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.48s (2.51s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4210605550\n  Bound result 9999999000000000012263\n  Bound result 4999999999000020765\n  Bound result 482656664672130512400\n  Bound result 9999999000000000000091\n  Bound result 47460125026787646792\n  Bound result 5275\n  Bound result 19999999999000011592\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000000161\n  Bound result 19999999999000000028\n  Bound result 19999999999000009653\n  Bound result 19999999999000007797\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000000019\n  Bound result 97000000000000000000\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 7885362738380271025\n  Bound result 1050000000000000000\n  Bound result 19999999999000018331\n  Bound result 12\n  Bound result 19999999999000012188\n  Bound result 2183\n  Bound result 180000000000000017219\n  Bound result 12\n  Bound result 103\n  Bound result 900000000000000000000\n  Bound result 12\n  Bound result 4123494386\n  Bound result 187000000000000000001\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000009\n  Bound result 12\n  Bound result 12\n  Bound result 5819675075174645730\n  Bound result 1269202125828155561071\n  Bound result 48\n  Bound result 9999999000000000009559\n  Bound result 9999999000000000004011\n  Bound result 81\n  Bound result 19999999999000016257\n  Bound result 19999999999000004694\n  Bound result 9302618518017444791\n  Bound result 21571\n  Bound result 180000000000000008506\n  Bound result 12\n  Bound result 10162752525918694835210\n  Bound result 12\n  Bound result 19999999999000018660\n  Bound result 19999999999000015381\n  Bound result 19999999999000000601\n  Bound result 12\n  Bound result 1125899906842624\n  Bound result 8\n  Bound result 2767036944190885724160\n  Bound result 180000000000000000697\n  Bound result 12\n  Bound result 19999999999000008975\n  Bound result 28\n  Bound result 25\n  Bound result 7339264674327131720648\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 35734206886254894423\n  Bound result 9630795874171844455332\n  Bound result 11376\n  Bound result 9999998000000000004335\n  Bound result 12\n  Bound result 19999999999000010056\n  Bound result 109\n  Bound result 120\n  Bound result 5136055413954814332\n  Bound result 95\n  Bound result 60\n  Bound result 1741\n  Bound result 180000000000000002476\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000013319\n  Bound result 300\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 3193615530130082514\n  Bound result 12\n  Bound result 120\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000002531\n  Bound result 7011611194432742262\n  Bound result 19999999999000001485\n  Bound result 180084443867409285121\n  Bound result 12\n  Bound result 19999999999000012227\n  Bound result 9999999000000000000017\n  swaps: 38\n  moves: 24\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.55s (3.55s CPU time)\n\nRan 28 test suites in 3.55s (10.72s CPU time): 179 tests passed, 0 failed, 0 skipped (179 total tests)\n","passed":true},{"durationMs":61,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeAddLiquidity(address,(address,address,uint24,int24,address),(int24,int24,int256,bytes32),bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":79,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":37,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":37,\"launch/hook.sepolia.json\":37,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":964,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/Edges.t.sol\":334,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":347,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":84,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/JitStrength.t.sol\":182,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":167,\"test/LaunchFiles.t.sol\":79,\"test/Money.t.sol\":400,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":38,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"7e47cbf0667b1d2a18e1b7d15af3493f44e580cd2fa8eac4ee68db20d3be264c","verifiedTreeHash":"350b0ef63dc516eeb36d5d4b7b3f8cd9e323f767","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":76319,"exitCode":0,"name":"build","output":"Compiling 112 files with Solc 0.8.26\nSolc 0.8.26 finished in 76.17s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:70:5:\n   |\n70 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3746,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 73829)\nLogs:\n  hook: 17628\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 639.24µs (505.98µs CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.09ms (1.00ms CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 159126)\n[PASS] test_sepoliaLaunchFile() (gas: 154500)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.07ms (1.52ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 239953)\n[PASS] test_moveCap() (gas: 239994)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 179942)\n[PASS] test_quietMoveLimit() (gas: 246212)\n[PASS] test_stalemate() (gas: 237766)\n[PASS] test_thirdRepetition() (gas: 963626)\n[PASS] test_tooFewPiecesToMate() (gas: 231591)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 5.15ms (3.47ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1771027)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1178034)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2303660)\n[PASS] test_sliceSide() (gas: 646625)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 418496)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 5.54ms (7.95ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1456913)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1992032)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1252567)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1092985)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1070568)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 1003286)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1497005)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1316573)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1554405)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1658042)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1107691)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1851735)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1252983)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 19.55ms (31.07ms CPU time)\n\nRan 5 tests for test/JitStrength.t.sol:JitStrengthTest\n[PASS] test_eachPoolSamplesItsOwnDepth() (gas: 1132886)\n[PASS] test_liquidityAddedAndRemovedAroundATradeDoesNotShrinkItsShare() (gas: 1438143)\n[PASS] test_liquidityHeldThroughOneBlockDoesNotShrinkTheShare() (gas: 1477821)\n[PASS] test_liquidityHeldThroughThreeTradedBlocksCounts() (gas: 1424428)\n[PASS] test_theFirstTradedBlockMeasuresAgainstTheLiquidityItStartsWith() (gas: 815952)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 8.10ms (6.73ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 25907580)\n[PASS] test_blankChainTokenBelowImd() (gas: 25835453)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 42.91ms (72.44ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22439603)\n[PASS] test_launchTokenAboveImd() (gas: 23691662)\nLogs:\n  first buy (opens game 0, bids for White): 389635\n\n[PASS] test_launchTokenBelowImd() (gas: 23639085)\nLogs:\n  first buy (opens game 0, bids for White): 385073\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 53.10ms (142.71ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4923187)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2884338)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1914710)\n[PASS] test_anyoneCanConvert() (gas: 464503)\n[PASS] test_booksBalanceAcrossPools() (gas: 8663337)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 787342)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 501845)\n[PASS] test_noRouteNoDuel() (gas: 1250179)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1213060)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 75.43ms (28.51ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4923382)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2884337)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1914709)\n[PASS] test_anyoneCanConvert() (gas: 464503)\n[PASS] test_booksBalanceAcrossPools() (gas: 8663335)\n[PASS] test_crossBlockViaConvert() (gas: 4448978)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4613960)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 787341)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 501857)\n[PASS] test_noRouteNoDuel() (gas: 1250177)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1213059)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 112.71ms (76.61ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2532287)\nLogs:\n  plain trade: 210439\n  trade that converts a batch: 274298\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27976648)\nLogs:\n  hook share of a moving trade: average: 282901\n  hook share of a moving trade: max: 313758\n\n[PASS] test_middlegameGas() (gas: 8202359)\nLogs:\n  first bid in a new pool: 273321\n  bidding trade: 194779\n  outbidding trade: 210781\n  plain trade: 185216\n  next block: play the turn and bid: 537587\n\n[PASS] test_openingGas() (gas: 3413416)\nLogs:\n  first bid in a new pool: 273321\n  bidding trade: 195396\n  outbidding trade: 210781\n  plain trade: 185216\n  next block: play the turn and bid: 514228\n\n[PASS] test_runningGameGas() (gas: 53462553)\nLogs:\n  running game, moving trades measured: 50\n  running game, moving trade average: 452812\n  running game, moving trade max: 538931\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 117.72ms (151.00ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4252940)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2420483)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8586833)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1013025)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3358740)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3122908)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2398627)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 3018355)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 4007883)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1558917)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3737236)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23802213)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 118.96ms (93.31ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 1010247, ~: 1010947)\nLogs:\n  Bound result 44503914653215535188\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 488096, ~: 488229)\nLogs:\n  Bound result 334\n  Bound result 999999999999004000001\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1115898, ~: 1115940)\nLogs:\n  Bound result 306\n  Bound result 310\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2619901)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123553)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 239266)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121368)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98261)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344594)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111113)\n[PASS] test_lastSurchargeSecond() (gas: 493618)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 3050248)\n[PASS] test_openingEdges() (gas: 493240)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1149731)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 493131)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 90012)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 129.12ms (301.07ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3525746)\nLogs:\n  smallest gas limit that converts: 313268\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 3817204)\nLogs:\n  smallest gas limit that plays and records the bounty: 397167\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15340033)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 156.16ms (165.67ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9739298, ~: 9705964)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 74993302)\nLogs:\n  moves played: 110\n  bids (incl. outbid ones): 141\n  most gas for a swap: 621406\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 712566)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1336972)\n[PASS] test_aTradeBidsForTheTurn() (gas: 507002)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 995129)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1449845)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1791289)\n[PASS] test_anyTradeSizeBids() (gas: 473603)\n[PASS] test_lateTradeStillBidsNormally() (gas: 453237)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 145185)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 439350)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 945365)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1078046)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6469951)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 953042)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 808633)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179407)\n[PASS] test_theMainDuelMustPairImd() (gas: 293233)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1068457)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 435783)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1570607)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 746.77ms (898.05ms CPU time)\n\nRan 23 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10869759, ~: 10927806)\n[PASS] test_aBatchSpendsAtMostTenMinimumsExactly() (gas: 53969)\n[PASS] test_aFullChestTakesNoMore() (gas: 1094242)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 630039)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 850564)\n[PASS] test_bountyTable() (gas: 44573)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 830472)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 676417)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5622444)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 408535)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 838597)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 485339)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 387372)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48714)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41874)\n[PASS] test_fundChestWithEth() (gas: 252795)\n[PASS] test_fundChestWithTokens() (gas: 205591)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3592670)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 904960)\n[PASS] test_quietMovePaysNothing() (gas: 637439)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1268507)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 971630)\n[PASS] test_withdrawToRefusesTheZeroAddress() (gas: 610127)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 782.04ms (815.77ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 584493866)\nLogs:\n  bot moves: 0\n  other moves: 149\n  captures among other moves: 25\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.02s (1.02s CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 19999999000000000021\n  Bound result 19999999000000017509\n  Bound result 386549022720\n  Bound result 98\n  Bound result 19999999000000000301\n  Bound result 8\n  Bound result 39\n  Bound result 2893925734761568126\n  Bound result 19999999000000001211\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 19999999000000000209\n  Bound result 19999999000000000788\n  Bound result 900000\n  Bound result 17380275022719779\n  Bound result 13376\n  Bound result 1437185598\n  Bound result 106\n  Bound result 19999999000000000071\n  Bound result 19999999000000012501\n  Bound result 15600679758904\n  Bound result 3372497854775807539\n  Bound result 19999999000000020001\n  Bound result 19999999000000000324\n  Bound result 8449\n  Bound result 19999999000000007015\n  Bound result 6515626003710664071\n  Bound result 19999999000000995001\n  Bound result 749999999999250\n  Bound result 19999999000000011443\n  Bound result 15382\n  Bound result 19999999000000007501\n  Bound result 10000000000000000000\n  Bound result 80\n  Bound result 16\n  Bound result 749999999999250\n  Bound result 43638196850287706116\n  Bound result 564387865581898281\n  Bound result 49425749022699434082\n  Bound result 19999999000000005259\n  Bound result 19999999000000003443\n  Bound result 19999999000000003748\n  Bound result 19999999000000000211\n  Bound result 17943753809444800\n  Bound result 15\n  Bound result 19999999000000100001\n  Bound result 7616448877154347021\n  Bound result 21333\n  Bound result 15\n  Bound result 112108561573182545\n  Bound result 19999999000000014653\n  Bound result 7011749056432742262\n  Bound result 19999999063368430181\n  Bound result 19999999000000560001\n  Bound result 64\n  Bound result 17256293755346024653\n  Bound result 15\n  Bound result 80\n  Bound result 17462041093041794489\n  Bound result 44\n  Bound result 72624976668147840\n  Bound result 9384671937848548256\n  Bound result 19999999000000000126\n  Bound result 19999999000000010013\n  Bound result 19999999000000000225\n  Bound result 29061427756277306517\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.13s (1.13s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8\n  Bound result 4649\n  Bound result 1\n  Bound result 7038\n  Bound result 120396004288981\n  Bound result 5\n  Bound result 8228\n  Bound result 6\n  Bound result 870060366358668890202810772\n  Bound result 4\n  Bound result 2738504042791640380511251\n  Bound result 9\n  Bound result 671217046808349282794304116\n  Bound result 2\n  Bound result 3949\n  Bound result 0\n  Bound result 100000000000000000\n  Bound result 2\n  Bound result 7\n  Bound result 196608\n  Bound result 18\n  Bound result 5\n  Bound result 500\n  Bound result 1357\n  Bound result 8\n  Bound result 999\n  Bound result 2\n  Bound result 6413\n  Bound result 6\n  Bound result 15\n  Bound result 7958\n  Bound result 229\n  Bound result 9\n  Bound result 4\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55899, ~: 55857)\nLogs:\n  Bound result 893409364866962332856807\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.65s (2.66s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 157198259\n  Bound result 9999999000000000004694\n  Bound result 4999999999000022597\n  Bound result 482656664672130512400\n  Bound result 25333134452981760\n  Bound result 47460125026787646792\n  Bound result 5159\n  Bound result 19999999999000011602\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000995001\n  Bound result 19999999999000000081\n  Bound result 19999999999000009887\n  Bound result 24333134452997109\n  Bound result 19999999999000007610\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000097\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000196609\n  Bound result 20000000000000000000\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 14211026072807217151\n  Bound result 9999\n  Bound result 19999999999000018323\n  Bound result 12\n  Bound result 19999999999000011204\n  Bound result 2380\n  Bound result 180000000000000016828\n  Bound result 12\n  Bound result 32\n  Bound result 9999999000000000001002\n  Bound result 12\n  Bound result 19999999999000016438\n  Bound result 100000000000000000000\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 7885362738380271025\n  Bound result 15\n  Bound result 9999999000000000007127\n  Bound result 9999999000000000004261\n  Bound result 1800\n  Bound result 4294967039\n  Bound result 19999999999000012338\n  Bound result 9302618518017444791\n  Bound result 25385\n  Bound result 180000000000000006657\n  Bound result 12\n  Bound result 19999998000000000011388\n  Bound result 12\n  Bound result 19999999999000018891\n  Bound result 19999999999000014701\n  Bound result 17707567918181156739\n  Bound result 12\n  Bound result 5819675075174645730\n  Bound result 34\n  Bound result 19999997000000003005697\n  Bound result 180000000000000000510\n  Bound result 12\n  Bound result 19999999999000008984\n  Bound result 50\n  Bound result 25\n  Bound result 10029302618518017626049\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 12623305784244568322\n  Bound result 11462\n  Bound result 9999998000000000004379\n  Bound result 12\n  Bound result 599999999400\n  Bound result 84\n  Bound result 8\n  Bound result 3777\n  Bound result 244\n  Bound result 40\n  Bound result 1065\n  Bound result 180000000000000002475\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999107477464\n  Bound result 6000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 4999999999000002001\n  Bound result 12\n  Bound result 88\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000004079\n  Bound result 19999999999001966081\n  Bound result 19999999999000000861\n  Bound result 180000000000000000032\n  Bound result 12\n  Bound result 19999999999000010903\n  Bound result 9999999000000000000017\n  swaps: 38\n  moves: 22\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.54s (3.54s CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9149, ~: 9118)\nLogs:\n  Bound result 140408634885699395999353210173794253356013074822392266714587117801872617862\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 11970, ~: 11970)\nLogs:\n  Bound result 140408634885699395999353210173794253356013074822392266714587117801872617862\n  Bound result 115651680602430496027571631798514113599913971590818171772742996898113896738059\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14604, ~: 14270)\nLogs:\n  Bound result 10\n  Bound result 560000\n  Bound result 5647\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13863, ~: 13724)\nLogs:\n  Bound result 340282366920938463463374607431767231456\n  Bound result 336879543251729078828740861357455220\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14038, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050508702\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913123400244\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 3.55s (7.29s CPU time)\n\nRan 22 test suites in 3.56s (14.27s CPU time): 159 tests passed, 0 failed, 0 skipped (159 total tests)\n","passed":true},{"durationMs":86,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":70,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":36,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":36,\"launch/hook.sepolia.json\":36,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":931,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":345,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":84,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/JitStrength.t.sol\":103,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":157,\"test/LaunchFiles.t.sol\":75,\"test/Money.t.sol\":400,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":38,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":18951,"exitCode":0,"name":"slither","output":"[high/medium] incorrect-exp at src/IMDuelHook.sol:247: IMDuelHook.teamOf(uint8,uint32,bool) (src/IMDuelHook.sol#247-249) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[high/medium] incorrect-exp at src/IMDuelHook.sol:247: IMDuelHook.teamOf(uint8,uint32,bool) (src/IMDuelHook.sol#247-249) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[medium/high] incorrect-equality at src/IMDuelHook.sol:530: IMDuelHook._sample(uint160) (src/IMDuelHook.sol#530-536) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMDuelHook.sol:541: IMDuelHook._reference(uint256,bool) (src/IMDuelHook.sol#541-547) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/IMDuelHook.sol:327: IMDuelHook._takeFee(PoolId,PoolKey,uint256,uint256,uint256,IMDuelHook.Game) (src/IMDuelHook.sol#327-339) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/IMDuelHook.sol:458: Reentrancy in IMDuelHook._convert(Currency) (src/IMDuelHook.sol#458-474):\n[medium/medium] reentrancy-no-eth at src/IMDuelHook.sol:297: Reentrancy in IMDuelHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/IMDuelHook.sol#297-322):\n[medium/medium] reentrancy-no-eth at src/IMDuelHook.sol:488: Reentrancy in IMDuelHook._swapClaims(PoolKey,Currency,uint256) (src/IMDuelHook.sol#488-507):\n[medium/medium] uninitialized-local at src/Bitboard.sol:643: Bitboard._targets(Bitboard.Pos,Bitboard.Gen,uint8,bool).ep (src/Bitboard.sol#643) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:480: Bitboard._anyLegal(Bitboard.Pos,bool).scratch (src/Bitboard.sol#480) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:552: IMDuelHook._pack(uint160).e (src/IMDuelHook.sol#552) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:425: Bitboard.isLegal(Bitboard.Pos,uint16,bool).scratch (src/Bitboard.sol#425) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:497: ChessEngineV5._queening(ChessEngineV5.Ctx,Bitboard.Pos,uint64,uint64,uint64,uint64,uint64).a (src/ChessEngineV5.sol#497) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:182: ChessEngineV5._choose(ChessEngineV5.Ctx,uint256,uint256,uint64[8],uint32,uint16).seen (src/ChessEngineV5.sol#182) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:400: Bitboard._legalTargets(Bitboard.Pos,Bitboard.Gen,Bitboard.Pos,uint8,bool).ep (src/Bitboard.sol#400) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:236: Bitboard.pieceAttacks(Bitboard.Pos,uint64,uint64,bool).a (src/Bitboard.sol#236) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:203: ChessEngineV5._choose(ChessEngineV5.Ctx,uint256,uint256,uint64[8],uint32,uint16).refined (src/ChessEngineV5.sol#203) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Bitboard.sol:580: Bitboard.mateInOne(Bitboard.Pos,bool,uint256).scratch (src/Bitboard.sol#580) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:840: IMDuelHook._repeated(PoolId,IMDuelHook.Game).seen (src/IMDuelHook.sol#840) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:414: ChessEngineV5._placement(ChessEngineV5.Ctx,uint8,uint8,uint8,uint8,bool,bool).near (src/ChessEngineV5.sol#414) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:276: ChessEngineV5._context(uint256,uint32,uint32,bool,bool).nonPawn (src/ChessEngineV5.sol#276) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:773: IMDuelHook._apply(PoolId,IMDuelHook.Game,uint16,Rules.Played,IMDuelHook.Trade).result (src/IMDuelHook.sol#773) is a local variable never initialized\n[medium/medium] uninitialized-local at src/ChessEngineV5.sol:377: ChessEngineV5._cheap(ChessEngineV5.Ctx,uint16).squeeze (src/ChessEngineV5.sol#377) is a local variable never initialized\n[medium/medium] uninitialized-local at src/IMDuelHook.sol:777: IMDuelHook._apply(PoolId,IMDuelHook.Game,uint16,Rules.Played,IMDuelHook.Trade).reason (src/IMDuelHook.sol#777) is a local variable never initialized\n[medium/medium] unused-return at src/IMDuelHook.sol:488: IMDuelHook._swapClaims(PoolKey,Currency,uint256) (src/IMDuelHook.sol#488-507) ignores return value by (sqrtPrice,None,None,None) = manager.getSlot0(key.toId()) (src/IMDuelHook.sol#493)\n[medium/medium] unused-return at src/IMDuelHook.sol:417: IMDuelHook.convert(Currency) (src/IMDuelHook.sol#417-419) ignores return value by manager.unlock(abi.encode(uint8(2),abi.encode(address(0),c,uint256(0)))) (src/IMDuelHook.sol#418)\n[medium/medium] unused-return at src/IMDuelHook.sol:280: IMDuelHook.beforeSwap(address,PoolKey,SwapParams,bytes) (src/IMDuelHook.sol#280-295) ignores return value by (sqrtPrice,None,None,None) = manager.getSlot0(id) (src/IMDuelHook.sol#287)\n[medium/medium] unused-return at src/IMDuelHook.sol:396: IMDuelHook._withdraw(address,Currency,address) (src/IMDuelHook.sol#396-402) ignores return value by manager.unlock(abi.encode(uint8(0),abi.encode(to,c,amount))) (src/IMDuelHook.sol#400)\n[low/high] shadowing-local at src/ChessEngineV5.sol:817: ChessEngineV5._mop(ChessEngineV5.Ctx,uint8,uint8,uint8,bool,bool).at (src/ChessEngineV5.sol#705) shadows:\n[low/medium] missing-zero-check at src/IMDuelHook.sol:424: IMDuelHook.unlockCallback(bytes).who (src/IMDuelHook.sol#424) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/IMDuelHook.sol:327: Reentrancy in IMDuelHook._takeFee(PoolId,PoolKey,uint256,uint256,uint256,IMDuelHook.Game) (src/IMDuelHook.sol#327-339):\n[low/medium] reentrancy-benign at src/IMDuelHook.sol:458: Reentrancy in IMDuelHook._convert(Currency) (src/IMDuelHook.sol#458-474):\n[low/medium] reentrancy-benign at src/IMDuelHook.sol:406: Reentrancy in IMDuelHook.fundChest(PoolKey,bool,uint256) (src/IMDuelHook.sol#406-414):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:297: Reentrancy in IMDuelHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/IMDuelHook.sol#297-322):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:458: Reentrancy in IMDuelHook._convert(Currency) (src/IMDuelHook.sol#458-474):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:396: Reentrancy in IMDuelHook._withdraw(address,Currency,address) (src/IMDuelHook.sol#396-402):\n[low/medium] reentrancy-events at src/IMDuelHook.sol:406: Reentrancy in IMDuelHook.fundChest(PoolKey,bool,uint256) (src/IMDuelHook.sol#406-414):\n[low/medium] return-bomb at src/IMDuelHook.sol:737: IMDuelHook._engine(uint256,bytes) (src/IMDuelHook.sol#737-743) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] timestamp at src/IMDuelHook.sol:583: IMDuelHook._play(PoolId,PoolKey,IMDuelHook.Game,bool,BalanceDelta,bytes,uint160,uint256) (src/IMDuelHook.sol#583-622) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:327: IMDuelHook._takeFee(PoolId,PoolKey,uint256,uint256,uint256,IMDuelHook.Game) (src/IMDuelHook.sol#327-339) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:458: IMDuelHook._convert(Currency) (src/IMDuelHook.sol#458-474) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:357: IMDuelHook._addChest(PoolId,uint256,uint256) (src/IMDuelHook.sol#357-364) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:343: IMDuelHook._chestBps(IMDuelHook.Game) (src/IMDuelHook.sol#343-346) uses timestamp for comparisons\n[low/medium] timestamp at src/IMDuelHook.sol:406: IMDuelHook.fundChest(PoolKey,bool,uint256) (src/IMDuelHook.sol#406-414) uses timestamp for comparisons","passed":true},{"durationMs":1124,"exitCode":0,"name":"aderyn","output":"[high] contract-locks-ether at src/IMDuelHook.sol:47: Contract locks Ether without a withdraw function\n[high] incorrect-caret-operator at src/IMDuelHook.sol:248: Incorrect use of caret operator\n[high] unsafe-casting at src/Bitboard.sol:247: Unsafe Casting of integers\n[low] empty-require-revert at src/ChessEngineV5.sol:157: Empty `require()` / `revert()` Statement\n[low] internal-function-used-once at src/Bitboard.sol:199: Internal Function Used Only Once (9 places)\n[low] large-numeric-literal at src/ChessEngineV5.sol:34: Large Numeric Literal (26 places)\n[low] literal-instead-of-constant at src/Bitboard.sol:35: Literal Instead of Constant (408 places)\n[low] missing-inheritance at src/IMDuelToken.sol:7: Missing Inheritance\n[low] push-zero-opcode at src/Bitboard.sol:2: PUSH0 Opcode (8 places)\n[low] state-change-without-event at src/IMDuelHook.sol:280: State Change Without Event\n[low] unchecked-return at src/IMDuelHook.sol:400: Unchecked Return (2 places)\n[low] uninitialized-local-variable at src/ChessEngineV5.sol:164: Uninitialized Local Variable (10 places)\n[low] unsafe-erc20-operation at src/IMDuelHook.sol:440: Unsafe ERC20 Operation\n[low] unspecific-solidity-pragma at src/ChessEngineV5.sol:2: Unspecific Solidity Pragma (4 places)\n[low] unused-state-variable at src/IMDuelHook.sol:78: Unused State Variable","passed":true},{"durationMs":19713,"exitCode":0,"name":"proof 9537d3ff1425","output":"Compiling 90 files with Solc 0.8.26\nSolc 0.8.26 finished in 18.97s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\n\nRan 1 test for test/imd-proof-9136cde8/Proof_9537d3ff1425.t.sol:JitStrengthTest\n[PASS] test_aBidsStrengthDoesNotDependOnLiquidityAddedAndRemovedAroundIt() (gas: 1300739)\nLogs:\n  alice strength (bps): 8987\n  bob strength (bps), bracketed by JIT liquidity: 9000\n  attacker strength (bps): 9000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.21ms (1.10ms CPU time)\n\nRan 1 test suite in 3.78ms (2.21ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"82001ba14867d3ad649a6d83f9db57e74ac3d1fcf2de9a9351a9fccebf72f1f7","verifiedTreeHash":"2bccfcbffba173ad77ba9d1b4b62095517aee807","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":77355,"exitCode":0,"name":"build","output":"Compiling 111 files with Solc 0.8.26\nSolc 0.8.26 finished in 77.25s\nCompiler run successful with warnings:\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:22:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                      ^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:108:38:\n    |\n108 |             rook = ((FILE_A << f) | (RANK_1 << (8 * r))) ^ bit;\n    |                                      ^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:109:57:\n    |\n109 |             uint64 d = f >= r ? DIAG >> (8 * (f - r)) : DIAG << (8 * (r - f));\n    |                                                         ^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/Bitboard.sol:110:65:\n    |\n110 |             uint64 a = f + r <= 7 ? ANTI >> (8 * (7 - f - r)) : ANTI << (8 * (f + r - 7));\n    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:38:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (3149): The result type of the shift operation is equal to the type of the first operand (uint64) ignoring the (larger) type of the second operand (uint256) which might be unexpected. Silence this warning by either converting the first or the second operand to the type of the other.\n   --> src/ChessEngineV5.sol:537:69:\n    |\n537 |             uint64 ahead = c.white ? ~uint64(0) << ((r + 1) * 8) : (uint64(1) << (r * 8)) - 1;\n    |                                                                     ^^^^^^^^^^^^^^^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:18:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                  ^^^^^^\n\nWarning (6321): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.\n  --> test/Hostile.t.sol:62:26:\n   |\n62 |         returns (uint16, Rules.Played memory)\n   |                          ^^^^^^^^^^^^^^^^^^^\n\nWarning (2072): Unused local variable.\n  --> test/Game.t.sol:87:9:\n   |\n87 |         IMDuelHook.Game memory g = st();\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/LaunchFiles.t.sol:70:5:\n   |\n70 |     function test_engineLaunchFileDeploysTheEngineWithoutArguments() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":3873,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Size.t.sol:SizeTest\n[PASS] test_deployedCodeFitsTheBudgets() (gas: 73186)\nLogs:\n  hook: 17403\n  engine v5: 23339\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 787.35µs (685.22µs CPU time)\n\nRan 4 tests for test/Token.t.sol:TokenTest\n[PASS] test_allowances() (gas: 347653)\n[PASS] test_fixedSupplyToTheDeployer() (gas: 39384)\n[PASS] test_nothingPrivileged() (gas: 192691)\n[PASS] test_transfers() (gas: 188240)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 985.50µs (490.80µs CPU time)\n\nRan 3 tests for test/LaunchFiles.t.sol:LaunchFilesTest\n[PASS] test_engineLaunchFileDeploysTheEngineWithoutArguments() (gas: 7834)\n[PASS] test_ethereumLaunchFile() (gas: 158255)\n[PASS] test_sepoliaLaunchFile() (gas: 153655)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.95ms (2.26ms CPU time)\n\nRan 5 tests for test/Teams.t.sol:TeamsTest\n[PASS] test_aDynamicFeePoolPlaysWithAZeroLpFee() (gas: 1739826)\n[PASS] test_nativeEthIsATeamLikeAnyToken() (gas: 1153483)\n[PASS] test_poolsOnOneHookKeepSeparateGamesAndChests() (gas: 2248837)\n[PASS] test_sliceSide() (gas: 645447)\n[PASS] test_twoPlainTokensCannotDuel() (gas: 417313)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 13.53ms (12.12ms CPU time)\n\nRan 7 tests for test/Draws.t.sol:DrawsTest\n[PASS] test_checkmate() (gas: 239931)\n[PASS] test_moveCap() (gas: 239972)\n[PASS] test_ordinaryMoveDoesNotEndTheGame() (gas: 179920)\n[PASS] test_quietMoveLimit() (gas: 246190)\n[PASS] test_stalemate() (gas: 237744)\n[PASS] test_thirdRepetition() (gas: 963450)\n[PASS] test_tooFewPiecesToMate() (gas: 231569)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 15.24ms (4.23ms CPU time)\n\nRan 2 tests for test/LaunchAdmission.t.sol:LaunchAdmissionTest\n[PASS] test_blankChainTokenAboveImd() (gas: 31426026)\n[PASS] test_blankChainTokenBelowImd() (gas: 31353650)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 56.24ms (94.63ms CPU time)\n\nRan 3 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_launchPairedWithEth() (gas: 22193400)\n[PASS] test_launchTokenAboveImd() (gas: 23442523)\nLogs:\n  first buy (opens game 0, bids for White): 366430\n\n[PASS] test_launchTokenBelowImd() (gas: 23389720)\nLogs:\n  first buy (opens game 0, bids for White): 361713\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 60.69ms (157.23ms CPU time)\n\nRan 9 tests for test/Slice.t.sol:SliceTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4841127)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2823010)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1886986)\n[PASS] test_anyoneCanConvert() (gas: 461614)\n[PASS] test_booksBalanceAcrossPools() (gas: 8515045)\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 763804)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 498890)\n[PASS] test_noRouteNoDuel() (gas: 1250179)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1186640)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 108.11ms (30.61ms CPU time)\n\nRan 13 tests for test/Bidding.t.sol:BiddingTest\n[PASS] test_aBountyIsPaidFromTheMoversChest() (gas: 1426784)\n[PASS] test_aBuyOfTheOtherTeamBidsForItsNextMove() (gas: 1952577)\n[PASS] test_aBuyOfTheOtherTeamTimesTheSilentSideOutAndBids() (gas: 1222460)\n[PASS] test_aClosedWindowTakesNoBidsForItsMove() (gas: 1062878)\n[PASS] test_aMoveIsOpenForTurnBlocksBlocks() (gas: 1040461)\n[PASS] test_aNewTopMustPayMoreThanTenPercentMore() (gas: 974158)\n[PASS] test_aNextMoveBidCarriesIntoTheNextGame() (gas: 1466876)\n[PASS] test_aWindowWithoutBidsBecomesTheFirstBidsBlock() (gas: 1283692)\n[PASS] test_bidsCountAcrossTheWholeWindow() (gas: 1511150)\n[PASS] test_theMoveDependsOnlyOnTheWindowsLastBlock() (gas: 1621408)\n[PASS] test_theMoversOwnBuyAfterItsWindowBidsForItsNextMove() (gas: 1077584)\n[PASS] test_theOwnerIsTheHookDataAddressElseTheSigner() (gas: 1811511)\n[PASS] test_thePreviewIsTheMoveThatIsPlayed() (gas: 1222876)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 108.22ms (30.69ms CPU time)\n\nRan 8 tests for test/Strength.t.sol:StrengthTest\n[PASS] testFuzz_boundedAndMonotonic(uint256,uint256,uint256) (runs: 256, μ: 9157, ~: 9118)\nLogs:\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\n[PASS] testFuzz_depthMonotonic(uint256,uint256,uint256) (runs: 256, μ: 12013, ~: 12425)\nLogs:\n  Bound result 140408634885699395999353210173794253356013074822392266714587117801872617862\n  Bound result 115651680602430496027571631798514113599913971590818171772742996898113896738059\n\n[PASS] testFuzz_shiftKeepsTheShare(uint256,uint256,uint8) (runs: 256, μ: 14662, ~: 15266)\nLogs:\n  Bound result 28\n  Bound result 431359146674410236714672241392314090778194310760649159697657763987454\n  Bound result 3905690605402760688486569470973352707\n\n[PASS] testFuzz_tenfoldIsAboutThirtyPoints(uint128,uint128) (runs: 256, μ: 13856, ~: 13724)\nLogs:\n  Bound result 300000000000000000000\n  Bound result 297000000000005662\n\n[PASS] testFuzz_unscalablePaidFollowsTheCurve(uint256,uint256) (runs: 256, μ: 14027, ~: 14208)\nLogs:\n  Bound result 115790931316423822261616749298837820974191451965793907633817189432073050514300\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007912563649374\n\n[PASS] test_decidedPoints() (gas: 15577)\n[PASS] test_hugePaymentsDoNotRevert() (gas: 12854)\n[PASS] test_zeroInputs() (gas: 4493)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 107.97ms (218.56ms CPU time)\n\nRan 12 tests for test/Hostile.t.sol:HostileTest\n[PASS] test_aCallbackTokenOwnerLeavingADebtCannotFreezeTheDuel() (gas: 4208794)\n[PASS] test_aDeadEngineLeavesTheTurnQueuedAndTradingGoesOn() (gas: 2382749)\n[PASS] test_aGasBurningEngineCostsOneExpensiveTradeNotTheGame() (gas: 8555477)\n[PASS] test_aTokenReturningNothingFundsAChest() (gas: 1011842)\n[PASS] test_anEthOwnerCreditingTheHookCannotFreezeTheDuel() (gas: 3314594)\n[PASS] test_anEthOwnerLeavingADebtCannotFreezeTheDuel() (gas: 3078768)\n[PASS] test_anOwnerThatCannotReceiveWithdrawsElsewhere() (gas: 2367325)\n[PASS] test_blockedRecipientStaysOwedAndTradingContinues() (gas: 2990838)\n[PASS] test_brokenEngineFallsBackToALegalMove() (gas: 3976592)\n[PASS] test_feeOnTransferTokenFundsOnlyWhatArrives() (gas: 1557734)\n[PASS] test_reenteringTokenCannotBreakAClaim() (gas: 3705920)\n[PASS] test_starvingTheEngineNeverPlaysTheFallback() (gas: 23932899)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 108.32ms (100.69ms CPU time)\n\nRan 16 tests for test/FeeSchedule.t.sol:FeeScheduleTest\n[PASS] testFuzz_exactOutputDeliversTheOrderAndTakesHalfAPercent(uint256) (runs: 256, μ: 980144, ~: 980840)\nLogs:\n  Bound result 499999999999000017597\n\n[PASS] testFuzz_openingChestShareFollowsTheSchedule(uint256,uint256) (runs: 512, μ: 464530, ~: 464653)\nLogs:\n  Bound result 1962\n  Bound result 999999999999000049375\n\n[PASS] testFuzz_surchargeNeverRises(uint256,uint256) (runs: 256, μ: 1079207, ~: 1079259)\nLogs:\n  Bound result 292\n  Bound result 382\n\n[PASS] test_conversionSplitsTheImduelHalfKeptHalfBurned() (gas: 2575179)\n[PASS] test_convertWithAnEmptyPileDoesNothing() (gas: 123553)\n[PASS] test_exactOutputStoppedByItsPriceLimitIsRefused() (gas: 215686)\n[PASS] test_fundChestBeyondBalanceIsRefused() (gas: 121368)\n[PASS] test_fundChestOfZeroAddsNothing() (gas: 98261)\n[PASS] test_fundChestWithTheWrongEthValueIsRefused() (gas: 344594)\n[PASS] test_fundChestWithoutAllowanceIsRefused() (gas: 111113)\n[PASS] test_lastSurchargeSecond() (gas: 470038)\n[PASS] test_mainDuelConvertsAtMostOnceAndTenMinimumsPerBlock() (gas: 2998664)\n[PASS] test_openingEdges() (gas: 469660)\n[PASS] test_owedRewardOnlyEverReachesItsOwner() (gas: 1149576)\n[PASS] test_surchargeEndsAtThreeHundredSeconds() (gas: 469551)\n[PASS] test_withdrawWithNothingOwedDoesNothing() (gas: 89931)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 126.58ms (311.36ms CPU time)\n\nRan 3 tests for test/GasEstimate.t.sol:GasEstimateTest\n[PASS] test_atTheEstimateADueBatchConverts() (gas: 3837983)\nLogs:\n  smallest gas limit that converts: 310375\n\n[PASS] test_atTheEstimateTheBountyIsRecorded() (gas: 4170322)\nLogs:\n  smallest gas limit that plays and records the bounty: 390416\n\n[PASS] test_noGasLimitPlaysTheMoveWithoutItsBounty() (gas: 15567947)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 134.20ms (157.07ms CPU time)\n\nRan 11 tests for test/CrossBlock.t.sol:CrossBlockTest\n[PASS] test_aBatchCannotBeSoldAtAPushedPrice() (gas: 4841322)\nLogs:\n  attacker profit (IMD, 1e18): -36380852262017773\n\n[PASS] test_aBatchStopsAtItsPriceLimit() (gas: 2823009)\n[PASS] test_aFailedConversionNeverBreaksATrade() (gas: 1886985)\n[PASS] test_anyoneCanConvert() (gas: 461614)\n[PASS] test_booksBalanceAcrossPools() (gas: 8515043)\n[PASS] test_crossBlockViaConvert() (gas: 4383013)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390298682200\n\n[PASS] test_crossBlockViaFirstTrade() (gas: 4545174)\nLogs:\n  pile before (IMD, 1e18): 5002505331713439797\n  IMD pile spent in block N (1e18): 0\n  attacker profit (IMD at the home price, 1e18): -36513390291136661\n\n[PASS] test_imduelDuelsNeedNoSwap() (gas: 763803)\n[PASS] test_mainDuelSliceBuysImduelHalfToTheChestHalfBurned() (gas: 498902)\n[PASS] test_noRouteNoDuel() (gas: 1250177)\n[PASS] test_otherDuelsFeedTheMainChest() (gas: 1186639)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 140.38ms (52.05ms CPU time)\n\nRan 5 tests for test/HookGas.t.sol:HookGasTest\n[PASS] test_conversionGas() (gas: 2485776)\nLogs:\n  plain trade: 207571\n  trade that converts a batch: 271382\n\n[PASS] test_hookShareOfAMovingTrade() (gas: 27682885)\nLogs:\n  hook share of a moving trade: average: 276326\n  hook share of a moving trade: max: 307180\n\n[PASS] test_middlegameGas() (gas: 8148240)\nLogs:\n  first bid in a new pool: 270547\n  bidding trade: 191911\n  outbidding trade: 208007\n  plain trade: 182442\n  next block: play the turn and bid: 531060\n\n[PASS] test_openingGas() (gas: 3364403)\nLogs:\n  first bid in a new pool: 270547\n  bidding trade: 192524\n  outbidding trade: 208007\n  plain trade: 182583\n  next block: play the turn and bid: 507698\n\n[PASS] test_runningGameGas() (gas: 52971319)\nLogs:\n  running game, moving trades measured: 50\n  running game, moving trade average: 446235\n  running game, moving trade max: 532353\n\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 140.40ms (144.49ms CPU time)\n\nRan 23 tests for test/Game.t.sol:GameTest\n[PASS] testFuzz_swapsNeverRevert(uint256) (runs: 48, μ: 9594048, ~: 9552725)\n[PASS] test_aGamePlaysOutThroughSwaps() (gas: 74128344)\nLogs:\n  moves played: 110\n  bids (incl. outbid ones): 141\n  most gas for a swap: 614832\n\n[PASS] test_aSmallerTradeInTheBlockDoesNotTakeTheTurn() (gas: 686212)\n[PASS] test_aTimeoutTurnCanBeTakenInItsBlock() (gas: 1304091)\n[PASS] test_aTradeBidsForTheTurn() (gas: 483422)\n[PASS] test_aTurnClosesWithItsBlock() (gas: 965022)\n[PASS] test_anExpiredTurnBecomesATimeoutTurn() (gas: 1413164)\n[PASS] test_anOldTurnIsPlayedWithTheHistoryContractsHash() (gas: 1754655)\n[PASS] test_anyTradeSizeBids() (gas: 450023)\n[PASS] test_lateTradeStillBidsNormally() (gas: 429657)\n[PASS] test_onlyThePoolManagerAndTheHookCanCallIn() (gas: 145185)\n[PASS] test_ownerDefaultsToTxOrigin() (gas: 415770)\n[PASS] test_playedPositionsEnterTheRepetitionMemory() (gas: 915258)\n[PASS] test_rejectsBadConfig() (gas: 8975)\n[PASS] test_silentSidePlaysAtZeroStrength() (gas: 1047939)\n[PASS] test_strengthFollowsTheShareOfThePool() (gas: 6373797)\n[PASS] test_teamsSwapColoursEveryGame() (gas: 926666)\n[PASS] test_theBiggestTradeInTheBlockOwnsTheTurn() (gas: 782279)\n[PASS] test_theFirstPoolOpenedIsTheMainDuel() (gas: 179407)\n[PASS] test_theMainDuelMustPairImd() (gas: 292053)\n[PASS] test_theNextBlocksTradePlaysTheTurn() (gas: 1038350)\n[PASS] test_theOtherTeamCannotBidOnThisTurn() (gas: 412203)\n[PASS] test_whoPlaysTheTurnAndWhenDoesNotChangeTheMove() (gas: 1533973)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 715.16ms (858.70ms CPU time)\n\nRan 21 tests for test/Money.t.sol:MoneyTest\n[PASS] testFuzz_heldEqualsOwed(uint256) (runs: 48, μ: 10670805, ~: 10756018)\n[PASS] test_aFullChestTakesNoMore() (gas: 1070662)\n[PASS] test_aTradeStoppedByItsPriceLimitIsRefused() (gas: 582835)\n[PASS] test_blackCaptureIsPaidInItsTeamToken() (gas: 826940)\n[PASS] test_bountyTable() (gas: 44573)\n[PASS] test_checkmatePaysAQuarterOfTheChest() (gas: 806848)\n[PASS] test_chestShareGoesToTheChestWorthLess() (gas: 650063)\n[PASS] test_chestsStayAboutEqualInValue() (gas: 5518374)\n[PASS] test_exactOutputPaysTheFeeOnTheInput() (gas: 384955)\n[PASS] test_exactOutputWithTheChestShareInTheOutput() (gas: 808490)\n[PASS] test_feesCannotBeWithdrawnByAnyone() (gas: 461737)\n[PASS] test_firstTradeFundsChest0AndTheSlice() (gas: 363792)\n[PASS] test_fundChestNeedsTheRightValue() (gas: 48714)\n[PASS] test_fundChestOnlyForHookPools() (gas: 41852)\n[PASS] test_fundChestWithEth() (gas: 252795)\n[PASS] test_fundChestWithTokens() (gas: 205591)\n[PASS] test_openingSurchargeOnlyInTheMainDuel() (gas: 3485358)\n[PASS] test_payoutIsCappedAtTwiceTheTrade() (gas: 881351)\n[PASS] test_quietMovePaysNothing() (gas: 613837)\n[PASS] test_rewardsAreClaimedNeverPushed() (gas: 1245166)\n[PASS] test_whiteCaptureIsPaidInItsTeamTokenFromItsOwnChest() (gas: 948054)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 805.17ms (825.27ms CPU time)\n\nRan 1 test for test/Predict.t.sol:PredictTest\n[PASS] test_aBotCannotPickItsOwnCapturingMoves() (gas: 575514472)\nLogs:\n  bot moves: 0\n  other moves: 149\n  captures among other moves: 25\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 993.73ms (993.53ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantTest\n[PASS]\nInvariantTest invariants:\n[PASS] invariant_boardHasBothKingsAndPlyIsBounded\n[PASS] invariant_heldEqualsOwed\n InvariantTest invariants (runs: 24, calls: 2400, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | convert        | 329   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | fund           | 282   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | longPause      | 311   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | nextBlock      | 316   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | trade          | 262   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeAgain     | 325   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | tradeNextBlock | 286   | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | withdrawReward | 289   | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 19999999000000000031\n  Bound result 19999999000000017348\n  Bound result 38332894068056391680\n  Bound result 98\n  Bound result 19999999000000007001\n  Bound result 63\n  Bound result 80\n  Bound result 19999999000000001568\n  Bound result 19999999495924113525\n  Bound result 4780536499\n  Bound result 5033303399153660612\n  Bound result 19243497235015328446\n  Bound result 19999999000177362150\n  Bound result 230000\n  Bound result 17380275022719779\n  Bound result 13147\n  Bound result 1437185599\n  Bound result 90\n  Bound result 19999999000000200001\n  Bound result 19999999000000184201\n  Bound result 15600679758904\n  Bound result 1374389534720\n  Bound result 14999999999985\n  Bound result 19999999000000002324\n  Bound result 7527\n  Bound result 19999999000081008943\n  Bound result 19999999000000000021\n  Bound result 499999999999500\n  Bound result 19999999000000010056\n  Bound result 19999999000000011831\n  Bound result 16732\n  Bound result 19999999000000006049\n  Bound result 19999999000000000012\n  Bound result 80\n  Bound result 112\n  Bound result 19999999000000010056\n  Bound result 31759573706531258763\n  Bound result 19999999000000001198\n  Bound result 49425749022699434082\n  Bound result 19999999000000005178\n  Bound result 19999999000000003400\n  Bound result 19999999000000001669\n  Bound result 19999999000000007563\n  Bound result 19908107207707819244\n  Bound result 15\n  Bound result 19999999000000000061\n  Bound result 19999999000000000091\n  Bound result 21988\n  Bound result 24\n  Bound result 112108561573182545\n  Bound result 19999999000000012607\n  Bound result 19999999386547056641\n  Bound result 19999999063368430181\n  Bound result 19999999000000050001\n  Bound result 64\n  Bound result 17256293755346024653\n  Bound result 56\n  Bound result 11\n  Bound result 17462041093041794489\n  Bound result 12\n  Bound result 9241421688590303745\n  Bound result 9384671937848548256\n  Bound result 10000000000000000\n  Bound result 19999999000000009383\n  Bound result 281474976710656\n  Bound result 15915\n  Bound result 10130066139920559766\n  swaps: 42\n  moves: 17\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.11s (1.10s CPU time)\n\nRan 3 tests for test/TokenInvariant.t.sol:TokenInvariantTest\n[PASS]\nTokenInvariantTest invariants:\n[PASS] invariant_allowancesAreExactlyWhatWasApprovedLessWhatWasSpent\n[PASS] invariant_supplyIsFixedAndHeldByTheActors\n TokenInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| TokenHandler | approve            | 2052  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | approveZeroSpender | 2118  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transfer           | 1982  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| TokenHandler | transferFrom       | 2040  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4294902015\n  Bound result 4597\n  Bound result 0\n  Bound result 7038\n  Bound result 120396004288981\n  Bound result 10\n  Bound result 8874\n  Bound result 191\n  Bound result 0\n  Bound result 2\n  Bound result 2738504042791640380511251\n  Bound result 48879\n  Bound result 2\n  Bound result 0\n  Bound result 3950\n  Bound result 1290\n  Bound result 1809217764\n  Bound result 1741\n  Bound result 560000\n  Bound result 100\n  Bound result 150\n  Bound result 929\n  Bound result 120\n  Bound result 1896903457\n  Bound result 2655\n  Bound result 926\n  Bound result 71\n  Bound result 6412\n  Bound result 3600\n  Bound result 32\n  Bound result 167\n  Bound result 229\n  Bound result 4294894986\n  Bound result 5493\n\n[PASS] testFuzz_transferOfMoreThanTheBalanceIsRefused(uint256) (runs: 512, μ: 55898, ~: 55857)\nLogs:\n  Bound result 11203202727410804468796568358546730031247781132256939174\n\n[PASS] test_transferFromTheZeroAddressIsRefused() (gas: 82118)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 2.58s (2.66s CPU time)\n\nRan 1 test for test/InvariantDuels.t.sol:InvariantDuelsTest\n[PASS]\nInvariantDuelsTest invariants:\n[PASS] invariant_everyBoardIsSound\n[PASS] invariant_everyCurrencyBalances\n[PASS] invariant_rightsMatchTheBoard\n[PASS] invariant_turnsAreWellFormed\n InvariantDuelsTest invariants (runs: 24, calls: 2880, reverts: 0)\n\n╭--------------+-------------------+-------+---------+----------╮\n| Contract     | Selector          | Calls | Reverts | Discards |\n+===============================================================+\n| DuelsHandler | addLiquidity      | 208   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convert           | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | convertNextBlock  | 219   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | fund              | 234   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | longPause         | 228   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | nextBlock         | 223   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | pushThenNextBlock | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | removeLiquidity   | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | roundTrip         | 215   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | trade             | 216   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeAgain        | 221   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | tradeNextBlock    | 231   | 0       | 0        |\n|--------------+-------------------+-------+---------+----------|\n| DuelsHandler | withdrawReward    | 223   | 0       | 0        |\n╰--------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1086394136\n  Bound result 9999999000000000004596\n  Bound result 4999999999000022060\n  Bound result 482656664672130512400\n  Bound result 2770973894068056359039\n  Bound result 47460125026787646792\n  Bound result 5104\n  Bound result 19999999999000011591\n  Bound result 12\n  Bound result 12\n  Bound result 499999999500\n  Bound result 19999999999000000019\n  Bound result 19999999999000009823\n  Bound result 19999999999000007803\n  Bound result 80\n  Bound result 12\n  Bound result 180000000000000000097\n  Bound result 12\n  Bound result 12\n  Bound result 9999999000000000000046\n  Bound result 9999999000000006000001\n  Bound result 12\n  Bound result 3113425837\n  Bound result 12\n  Bound result 100092596403085913153\n  Bound result 12\n  Bound result 17789646555417576745\n  Bound result 12\n  Bound result 18225745714582542211\n  Bound result 50000000000000000000\n  Bound result 19999999999000018110\n  Bound result 12\n  Bound result 19999999999000010639\n  Bound result 2380\n  Bound result 180000000000000017069\n  Bound result 12\n  Bound result 39\n  Bound result 900000000000000000000\n  Bound result 12\n  Bound result 19999999999000013486\n  Bound result 189000000000000000001\n  Bound result 12\n  Bound result 15395487280442700617\n  Bound result 180000000000000000017\n  Bound result 12\n  Bound result 12\n  Bound result 19999999999000000169\n  Bound result 36748807801742949885\n  Bound result 24\n  Bound result 9999999000000087405701\n  Bound result 9999999000000000004561\n  Bound result 4000000000000000000\n  Bound result 19999999999000013790\n  Bound result 19999999999000004581\n  Bound result 9302618518017444791\n  Bound result 21390\n  Bound result 180000000000000007301\n  Bound result 12\n  Bound result 10482654664672130517218\n  Bound result 12\n  Bound result 19999999999000018450\n  Bound result 19999999999000013678\n  Bound result 84442493013196800\n  Bound result 12\n  Bound result 7885362738380271026\n  Bound result 87\n  Bound result 999999999999743\n  Bound result 180000000000000001031\n  Bound result 12\n  Bound result 19999999999000008687\n  Bound result 30\n  Bound result 25\n  Bound result 29972550810716367900652\n  Bound result 9999999000000000000007\n  Bound result 7542348211614510834354\n  Bound result 39026105433943628684\n  Bound result 2770972894068056364194\n  Bound result 11164\n  Bound result 9999998000000000003937\n  Bound result 12\n  Bound result 20000000000000000000\n  Bound result 32\n  Bound result 8\n  Bound result 41499263656392514951\n  Bound result 95\n  Bound result 40\n  Bound result 1506\n  Bound result 180000000000000003107\n  Bound result 12\n  Bound result 12\n  Bound result 12912673459957353403\n  Bound result 19999999999000012790\n  Bound result 1000\n  Bound result 153525780023700789978\n  Bound result 12\n  Bound result 120\n  Bound result 4999999999000010000\n  Bound result 12\n  Bound result 15\n  Bound result 9999999000000000013288\n  Bound result 12\n  Bound result 9075765443302474525\n  Bound result 12\n  Bound result 19999999999000002531\n  Bound result 7036944328885724022\n  Bound result 19999999999000001144\n  Bound result 180000000000000000028\n  Bound result 12\n  Bound result 19999999999000011254\n  Bound result 9999999000000000000097\n  swaps: 38\n  moves: 23\n  Bound result 12\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n  Bound result 1000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.69s (3.68s CPU time)\n\nRan 21 test suites in 3.69s (11.01s CPU time): 152 tests passed, 0 failed, 0 skipped (152 total tests)\n","passed":true},{"durationMs":86,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDuelHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"IMDuelHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"IMDuelHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"IMDuelHook.convert(address)\",\"IMDuelHook.convertBatch(address)\",\"IMDuelHook.fundChest((address,address,uint24,int24,address),bool,uint256)\",\"IMDuelHook.unlockCallback(bytes)\",\"IMDuelHook.withdraw(address,address)\",\"IMDuelHook.withdrawTo(address,address)\",\"IMDuelToken.approve(address,uint256)\",\"IMDuelToken.transfer(address,uint256)\",\"IMDuelToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":58,\"LICENSE\":16,\"assets/imduel.svg\":19,\"foundry.toml\":29,\"launch.json\":34,\"launch/deploy.production.json\":43,\"launch/deployed.json\":25,\"launch/engine.json\":10,\"launch/hook.json\":36,\"launch/hook.sepolia.json\":36,\"script/LaunchPolicy.sol\":43,\"src/Bitboard.sol\":719,\"src/Chess.sol\":34,\"src/ChessEngineV5.sol\":852,\"src/IChessEngine.sol\":29,\"src/IMDuelHook.sol\":860,\"src/IMDuelToken.sol\":62,\"src/Rules.sol\":45,\"src/Strength.sol\":47,\"test/Base.sol\":185,\"test/Bidding.t.sol\":248,\"test/Chessboard.sol\":79,\"test/CrossBlock.t.sol\":133,\"test/Draws.t.sol\":90,\"test/FeeSchedule.t.sol\":327,\"test/Game.t.sol\":336,\"test/GasEstimate.t.sol\":118,\"test/Harness.sol\":80,\"test/HookGas.t.sol\":151,\"test/Hostile.t.sol\":389,\"test/Invariant.t.sol\":153,\"test/InvariantDuels.t.sol\":484,\"test/Launch.t.sol\":158,\"test/LaunchAdmission.t.sol\":157,\"test/LaunchFiles.t.sol\":75,\"test/Money.t.sol\":350,\"test/Predict.t.sol\":102,\"test/Size.t.sol\":27,\"test/Slice.t.sol\":272,\"test/Strength.t.sol\":85,\"test/Teams.t.sol\":87,\"test/Token.t.sol\":82,\"test/TokenInvariant.t.sol\":155,\"test/Tokens.sol\":150,\"test/V4Fixture.sol\":100,\"test/data/chess.json\":1,\"test/data/conversion-validation.json\":770,\"test/data/conversion.json\":98,\"test/data/endings.json\":1,\"test/data/legal.json\":1,\"test/data/random.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b41053948ae65398ef44d51c036f87ace5517f29af9a52188c36c23058bc7b0e","verifiedTreeHash":"74fdfdd14f9cef9abb467891d02e52bafd60a0e9","verifierVersion":"0.1.0+d372f99e"}]}