{"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":"6dd01206-159b-4dd6-950e-b5c8168ed6e2","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"cff13967fd81c1be8d3b5262a5b678030a07e77d4c4da5a05bd57294a3ed6cae","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"e12e0170c9e65b34fb395773a98c9284575c3cc1a624f60debff881e4060ad0e","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"dfac14e4e1b12c600c538bdfafc522b8bb3f702f97c58cf58a0bd8bd8e67527a","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"f0cf3cfd6ca13d32a6312da2faeb0aa31585247d48bc8c5b83d90e5fbf28d783","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"66699f84b0ea1d90dfeccd15bba4b20c632a30e026f97998b022cbe6c78553fe","dependsOn":["adapt_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"bf8a47fcb64456f0c8b040e447bbdba6622ee5a87b5bec48c26fa19744490c5c","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"bc114029918ceeac018fd2e5eb3542b234d7b3bb120be1a026fd6c640ab1c7d4","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"38715955c6ff481e9dcf089188212d9b3f7ff9604f19e2cc8f6e325c4d1bc182","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"081d9a76055cea7b77c9e39e56396ceeae01818e01392c8be109449585315ed8","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"The Imdex 5 is an index of the five largest tokens paired with IMD on Ethereum, in one coin: pay IMD in to mint it, hand it back to redeem the holdings, and the IMD oracle refreshes the list each week.\n\nDeploy this repository exactly as it is, at commit 6ee29fbc20e869e0e74803166682249703e3b5b7, as a new evm_contracts launch on Ethereum mainnet (chain id 1). One contract, Imdex5, no constructor arguments. Contracts only: no launch token, pool or website.\nToken name: The Imdex 5\nToken symbol: IMDEX5\nTotal supply: 0 at deployment, no cap: a mint issues, a redeem burns, nothing else mints.\nWho can call what: anyone calls everything. No owner, admin, role or setting. Upgrades and pausing: none.\n\nHISTORY: this is the code of launch 1668 with the changes its audits asked for, already made and tested here (139 unit and fuzz tests and 8 mainnet fork tests pass; 23,230 bytes runtime):\n1. mint(shares, maxImdIn, minShares): reverts TooFewShares when fewer than minShares shares would be issued; the buyer keeps every IMD.\n2. Audit job 886e7c22 (1 medium, 3 low), all fixed: (medium) a residual coin, one that left the list and could not yet be sold, never blocks mint: the mint buys what its pool gives and pays whatever the pool cannot give at that pool's current price into the holders' idle IMD; (low) submit checks the attestation's validity window; (low) submit reads the quorum (at least 4 agreed) from the signed attestation; (low) the last holder pays no fee on redeemToImd either. THREAT_MODEL.md states the rules; read it first.\n\nFINDINGS IN THIS LAUNCH: fix every finding of medium or above with the smallest change that removes it, adding an argument or a check where the fix needs one, and list each in the README. Low and informational findings: document, do not redesign.\n\nKEEP EVERYTHING ELSE AS IT IS. solc 0.8.26, optimizer 200 runs, via_ir, cancun, bytecode_hash none. The constructor calls no contract. Stay under 24,576 bytes.\n\nMUST ATTACK: any mint that succeeds while issuing fewer than minShares; any path where a reverted mint still takes IMD; any way held differs from the real balance; a mint that dilutes holders in value, including through a residual's price being moved before a mint; a redeem that cannot pay; an expired or under-quorum answer changing the list.","parentJobId":null,"planHash":"87b3b8ff2c85378b9386804dccfa7c31237f15e8d360a12b7a9f81902bafc100","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"6dd01206-159b-4dd6-950e-b5c8168ed6e2","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2343-the-imdex-5"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52205","feedbackHash":"e2db53f7f60cc6ac6e01439bac02398069fde016cca4064892a118fe83b82d41","nodeKey":"adapt_contract_project","submissionHash":"cff13967fd81c1be8d3b5262a5b678030a07e77d4c4da5a05bd57294a3ed6cae","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52019","feedbackHash":"bf27717f42cf7ce973de28ad8b57014b25dc58d49c372f2b4d1a5733956ee417","nodeKey":"audit_economics","submissionHash":"e12e0170c9e65b34fb395773a98c9284575c3cc1a624f60debff881e4060ad0e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52200","feedbackHash":"323ecb835eaab0eb54648c747e88184c5fcc22c94e15e2f53a60c1ab601d1ea0","nodeKey":"audit_flow","submissionHash":"dfac14e4e1b12c600c538bdfafc522b8bb3f702f97c58cf58a0bd8bd8e67527a","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52270","feedbackHash":"5109a65a8ad29f834ab104baaeda173ea0de53552728381500e15ba754e8efe7","nodeKey":"audit_imported_code","submissionHash":"f0cf3cfd6ca13d32a6312da2faeb0aa31585247d48bc8c5b83d90e5fbf28d783","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51886","feedbackHash":"59e33de32b5924841cdb1392f07ea6a9d57f733bb4101f277330fe167c6d1ced","nodeKey":"audit_judge","submissionHash":"66699f84b0ea1d90dfeccd15bba4b20c632a30e026f97998b022cbe6c78553fe","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52159","feedbackHash":"0c6819163e742c0a6e6cb942abb2f0afd14e51f2b95fb122f6ee1ce4bd701b48","nodeKey":"audit_math","submissionHash":"bf8a47fcb64456f0c8b040e447bbdba6622ee5a87b5bec48c26fa19744490c5c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51245","feedbackHash":"9d86f4bdab5996dff96877cda535ed9c2e85b8fc241fadeebd3c5dc65f5ce4d8","nodeKey":"audit_permissions","submissionHash":"bc114029918ceeac018fd2e5eb3542b234d7b3bb120be1a026fd6c640ab1c7d4","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52152","feedbackHash":"80a3b91746f305aef8ec98cd87c68c6adddfd2857e1ee1243f9f0f7ece7b93dc","nodeKey":"manifest","submissionHash":"38715955c6ff481e9dcf089188212d9b3f7ff9604f19e2cc8f6e325c4d1bc182","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52615","feedbackHash":"1b07e841fbecc460eed8bda4d0b587ecae0ec28465955003d37ae7ad0522b1bd","nodeKey":"write_foundry_tests","submissionHash":"081d9a76055cea7b77c9e39e56396ceeae01818e01392c8be109449585315ed8","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"035440500eedfa21ed753b7300fb7a574057f88f1ba72844f6b37bcb6ea5a5cb","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"7260186299aa8565f2d94e89fd5ae61e8b7e30d2e8851a90c4c392fb9a7983a3","device":"b8fd8054ea57c5d8","findings":[{"description":"_mintMore charges a residual's shortfall (need - got) at _sqrtPrice read right after the index's own buy. That price is at or above the pre-buy price but not the undisturbed price: whoever moves the residual pool down before the mint lowers the charge. When the residual taxes transfers out of the PoolManager heavily (up to 100%, i.e. got = 0), holders' value per share at undisturbed prices falls. Not rated medium because on a real constant-product pool the dump that moves the price costs the mover pool fees, and buying back is taxed by the same rate, so the move costs more than the gain. Only a residual whose taxes are high and whose pool is thin relative to the residual holding is exposed. The bound is tax * need * (P_fair - P_moved). Documented, not redesigned (THREAT_MODEL 'Deliberately not findings' claims the move costs the mover what the buy returns; that holds for the coin delivered, not for the taxed shortfall).","line":418,"path":"src/Imdex5.sol","reproduction":"Imdex5Base mocks: alice mintFirst(1000e18); list moves to 4 coins and rebalance leaves coin 4 a residual (held 9607.79e18, worth 97.95 IMD). Etch TaxERC20 over coin 4, setTax(10000,false). Reset coin 4's pool to 100x the coin reserve (price /100, free in the mock). bob mint(supply, 10000e18, 0) succeeds, paying 945.86 IMD. Value per share at the pre-move prices: expected >= 1.02121 IMD, actual 0.97247 IMD (-4.8%). At an undisturbed pool the same mint does not dilute (test/Imdex5MustAttack.t.sol testFuzz_residualShortFillAtUndisturbedPriceDilutesNobody).","severity":"low","title":"A residual's short fill is charged at a spot price that a pre-mint price move lowers, diluting holders in value"},{"description":"Steps 1, 3 and 4 of _rebalance sell and buy at the pool's current spot price, each limited to a 1% sqrt-price (about 2% price) move from that spot, and value the cap with the same spot prices. Anyone can move a pool and then call rebalance in one transaction (and collect the 0.25 IMD reward), so every coin the index sells is sold at the moved price, and every coin it buys is bought at the moved price, within the band. With the 1.25% pool fee the round-trip cost roughly matches the gain at constant-product depths, so this is MEV bounded by the band rather than an outright drain. Design choice; documented.","line":477,"path":"src/Imdex5.sol","reproduction":"Analytical: a constant-product pool with reserves (x, y); the attacker sells x coins (price /4), calls rebalance, which sells about 1% of the moved coin reserve (0.02x) at P/4, then buys back. The index loses about 0.015xP of value against the attacker's fees of about 0.012xP; the attacker nets about 0.003xP plus the reward. No test: the mock PoolManager has no external swap path for an attacker contract.","severity":"low","title":"rebalance trades at spot within a 2% band and anyone can call it, so a caller can sandwich it atomically"},{"description":"Each rebalance keeps every old coin not in the next list that was not fully sold (limited sales move at most about 2% of price, so a holding large against its pool takes many weeks to sell). The next list can drop five more coins each week, so _coins can grow past 10 entries. mint, redeem and redeemToImd loop over all of them (a swap or a transfer each), so over many rotating weeks with thin pools the gas grows linearly. Not reachable quickly; documented.","line":492,"path":"src/Imdex5.sol","reproduction":"Rotate the list to five fresh coins every week while each dropped coin's pool absorbs under 1% of the index's holding per limited sale: after k weeks _coins.length is about 5 + 5k, and mint gas grows by about one swap per residual.","severity":"low","title":"Residuals accumulate without bound across rebalances, growing the gas of every mint and redeem"},{"description":"submit accepts any validly signed, unexpired, quorate attestation whose answer bytes hash to answerHash; it does not compare requestId, questionHash or chainId. Because answerHash only ever comes from the Intake's callback for the open request, a different attestation can match only if its answer is the same list, so the effect is identical. Tests: test_answerOtherThanDeliveredIsRefused, test_wrongSignerAndReplayAreRefused, test_expiredAnswerNeverChangesTheList, test_underQuorumSignedAnswerNeverChangesTheList.","line":311,"path":"src/Imdex5.sol","reproduction":"Two signed attestations with different requestIds but equal answer bytes: either one is accepted by submit after the Intake delivers the other. Same list adopted, no harm.","severity":"info","title":"submit does not bind the attestation to the request it answers"}],"hash":"081d9a76055cea7b77c9e39e56396ceeae01818e01392c8be109449585315ed8","nodeId":"0faa1eb9-1213-426d-bbb1-38945032df70","outcome":"completed","summary":"I added two test files and found no defect of medium or above. `forge build` and `forge test` pass with the verifier's seed: 168 tests pass, and the 7 mainnet fork tests skip because there's no RPC here. Nothing under `src/` was changed and nothing was committed.\n\n**`test/Imdex5MustAttack.t.sol`** — 21 unit and fuzz tests, one section per item on the brief's attack list:\n1. **Fewer than `minShares`:**\n   - Fuzzed short fills with random `minShares`: every mint either issues between `minShares` and `shares`, or reverts with every balance unchanged.\n   - The exact boundary: a short fill issuing `m` shares passes with a floor of `m` and fails with `TooFewShares(m)` at `m+1`.\n   - A floor above `shares` always reverts.\n2. **A reverted mint keeping IMD:** every revert path leaves the caller's IMD, shares, idle, fee and holdings exactly as they were. The paths are no shares yet, zero shares, a cost one wei over `maxImdIn`, `maxImdIn` of 0, too few shares, a dead pool, a coin that keeps 100% of transfers, and a caller who can't pay. A fuzz test also checks that a successful mint keeps only what it spends and refunds the rest.\n3. **`held` vs the real balance:** with every coin taxed at a fuzzed rate, plus a donation, `held` plus anything owed equals the actual balance through mint, both redeems and rebalance. Failed payments become owed and can be claimed.\n4. **Dilution:** fuzzed mints, including short fills and tiny mints, never lower any holding, the idle IMD or the total value per share at pre-mint prices. A residual that was dumped and then bought in full dilutes nobody, and neither does a taxed residual at an undisturbed price.\n5. **A redeem that can't pay:** `redeem` and `redeemToImd` still pay when every pool is dead and coins revert, return false or burn gas. The last holder takes everything and pays no fee.\n6. **Bad oracle answers:** these never change the list:\n   - an answer one second past expiry (exactly at expiry is still accepted)\n   - an answer issued too far in the future\n   - an answer whose signed copy says 3 agreed\n   - a delivery from a thin panel\n   - a wrong signer, a replay, an answer other than the one delivered, or a callback from anyone but the oracle intake\n\n**`test/Imdex5Floor.invariant.t.sol`** — an invariant suite (128 runs × 40 calls). Three actors mint with random floors and limits while pool prices are moved, liquidity is capped, coin taxes change and the list is rebalanced into residuals. It checks after every sequence:\n- no mint issues below its floor or pulls more than `maxImdIn`;\n- a reverted mint moves nothing;\n- no mint lowers a list coin or idle IMD per share;\n- a redeem in kind never fails;\n- coin and IMD balances equal what the books say;\n- zero supply means nothing is held.\n\n**Findings** (in `.imd-findings.json`, none medium or above, so no proof files):\n- **Low — residual price moved before a mint.** A residual's shortfall is charged at the pool price right after the index's buy, and someone can push that price down first. In a scratch test, a 100%-taxed residual whose price was dropped 100x (free in the mock) cut holders' value per share by 4.8%. I rated it low because on a real pool the price move costs fees and the taxed buyback, which exceeds the gain. The threat model says moving the price \"costs the mover what the buy returns\"; that holds for the coins delivered, not for the taxed shortfall. I reported this rather than writing a passing test for it.\n- **Low — `rebalance` can be sandwiched.** It trades at the current pool price within about a 2% band, and anyone can call it. My rough math says the profit after the 1.25% pool fee is small; I couldn't test it because the mock pool has no way for an attacker contract to swap.\n- **Low — residuals pile up.** Coins that left the list but couldn't be sold accumulate across rebalances, so mint and redeem gas grows over many weeks.\n- **Info — `submit` isn't tied to the request.** It doesn't check the request id; the effect is the same, because ","treeHash":"7f5ffafc67f57f5e5b4984badf1c62851a49f6e8","usage":{"cachedInputTokens":1515554,"inputTokens":36,"model":"claude-opus-5-5","outputTokens":43103,"runtime":"claude","turns":19,"wallClockMs":790236}},{"artifacts":[],"attempt":1,"bundleHash":"802d34b03796eb75d1e65d1be68cc639c077c9f2b1bea4072a70b5863e2efbb5","device":"7c748c02cd2ee98f","findings":[],"hash":"38715955c6ff481e9dcf089188212d9b3f7ff9604f19e2cc8f6e325c4d1bc182","nodeId":"52b29296-55c3-4327-9b48-12db7133d5cc","outcome":"completed","summary":"The manifest is written and verified. Only launch.json changed.\n\n**What I did**\n\n- Rewrote `launch.json` for the accepted tree. It names one contract, Imdex5, with an empty constructor argument list, which matches the no-argument constructor in `src/Imdex5.sol`. No `$owner` appears because the contract has no owner, admin, role or setting.\n- The previous manifest's notes still described launch 1636. The new notes describe this tree: the launch 1668 code, the minShares floor, the four 886e7c22 fixes, and the later 3bd5e1aa medium fix that the earlier contributor applied on top of commit 6ee29fb. Low and informational findings are listed as documented, not redesigned.\n\n**Checks**\n\n- Schema check passed: exactly the keys kind, contracts and notes; one unique identifier under 32 characters; every constructor argument a string; notes at 3,386 characters, under the 4,000 limit.\n- `forge build` and `forge test` with the verifier fuzz seed pass: 145 tests passed, 0 failed, 7 mainnet fork tests skipped because there is no fork URL offline.\n- Imdex5 runtime is 23,266 bytes, under the 24,576 limit, and the protected opcode scan has no DELEGATECALL, CALLCODE or SELFDESTRUCT to find.\n- `git status` shows launch.json as the only modified file.\n\nOne point worth knowing: the brief says to deploy commit 6ee29fb exactly, but the working tree at HEAD already carries the accepted 3bd5e1aa fix on top of it. The manifest describes the tree as it is, since that is what the build and verifier see.","treeHash":"ecdac317ac652b5afadae9633fce266889f6af97","usage":{"cachedInputTokens":280363,"inputTokens":162,"model":"claude-fable-5-1","outputTokens":4822,"runtime":"claude","turns":11,"wallClockMs":326884}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dd3018ab6b18e7bc","findings":[{"citation":"resolved","description":"Merged from audit_math (301d0676). Every inbound amount is measured (balance difference around take, line 576-578) but every outbound one is assumed exact: redeem (line 212 then _pay at 219), _payInKind (624-625) and _trySell (530, after the transfer to the PoolManager at 572) all subtract the amount passed. A coin whose transfer burns or taxes an extra slice from the sender (burn-on-send) delivers the full amount to the recipient, so payments and settlements succeed, while the contract's balance falls by amount*(1+t) and held by amount. After the first redeem held > balance; later redeemers are paid from an overstated held, and the last holder (paid 100%) gets an owed entry that claim() can never pay because safeTransfer reverts with an insufficient balance. Rated low, not medium: none of the five listed coins behaves this way (SwarmCity's 2% is taken from the recipient on transfers out of the PoolManager, which the suite models), the coin's burn is a cost the coin imposes on any holder, and the loss is bounded by t times the amounts transferred out and falls on whoever redeems last rather than being created. It is the one concrete way left for held to differ from the balance (THREAT_MODEL invariant 2), so it should be documented as a limit (a sender-debiting coin is not supported) or, if the author prefers, outbound transfers measured the way inbound ones are. Verified by running the specialist's proof (copied to test/scratch/SenderDebit.t.sol): it fails on this tree at 'held must equal the balance after a redeem'.","line":212,"path":"src/Imdex5.sol","reproduction":"Imdex5Base-style mocks; coin[4] etched as a token whose transfer() debits msg.sender an extra 2% when msg.sender is not the PoolManager. alice mintFirst(1000e18, [0,0,0,0,0]); bob mint(1000e18, 2000e18, 1000e18): held[c] == balanceOf(index). bob redeem(all his shares): expected held[c] == balance; actual held[c] = 19609765663300323561133, balance = 19219531326600647122267 (2% of bob's 19,513 coins burned from the index). alice redeem(all remaining): _pay(c, alice, held[c]) fails for lack of balance, owed[alice][c] = held[c], claim(c) reverts ERC20InsufficientBalance forever. forge test --match-path test/scratch/SenderDebit.t.sol fails as stated.","severity":"low","snippet":"held[token] -= amount;","title":"Outbound transfers are booked at the amount asked, so a coin that debits its sender more than it delivers leaves held above the real balance and the last redeemer owed coins the contract does not hold"},{"citation":"resolved","description":"Merged from write_foundry_tests (431c5d66) and audit_economics (517f7e40): same root cause. For a residual with a transfer tax (SwarmCity 2% out of the PoolManager, in the starting list) every mint delivers got = 0.98*need and charges the shortfall at slot0 read after the buy. That price is the pool's current price, which the minter (or the pool's LP, who can reset it at no cost) moves down before the mint. THREAT_MODEL says 'moving it first costs the mover what the buy returns', which holds for the coin delivered but not for the shortfall paid in IMD. Loss to holders is bounded by tax * residual fraction minted * (fair price - moved price), so about 2% of the residual's value for SwarmCity: low, document rather than redesign. A design-preserving mitigation would be to charge the shortfall at no less than the average price the buy actually paid (rIn / got) or the pre-buy price.","line":420,"path":"src/Imdex5.sol","reproduction":"test/scratch/Review.t.sol test_A_residualShortfallChargedAtDumpedPrice: coin 5 etched as PoolTaxERC20 (2% tax out of the PoolManager); alice mintFirst(1000e18); list drops coin 5 (_deliverList(_launches(4))), rebalance leaves held = 9217560446112264918031 at a fair price of about 0.0102 IMD; the residual pool's coin reserve is set to 1000x (price / 1000); bob mint(supply = 995e18, 9000e18, 0) succeeds. Observed: need 9217560446112264918031, got 9033209237190019619671, shortfall 184351208922245298360 units charged 1879488387154858 wei IMD (0.0019 IMD) into idleImd against a fair value of 1879453402595999999 wei (1.88 IMD). Expected: the shortfall is charged at no less than the price the pool traded at for the units it delivered.","severity":"low","snippet":"coin.token, need - got, _sqrtPrice(_key(coin.token, coin.hook)), Math.Rounding.Ceil","title":"A residual's short fill is charged at the pool price after the buy, which a pre-mint price move lowers; holders lose the taxed fraction of the residual at the moved price"},{"citation":"resolved","description":"From audit_economics (5b3aaab3), reproduced. _trySell (line 530-531) and _tryBuy (541-542) accept any (amountIn, out) pair, including out == 0 with amountIn > 0; the only bound on a rebalance swap is the 2% sqrt-price limit, which binds only when slot0 moves. A hook with BEFORE_SWAP_RETURNS_DELTA / AFTER_SWAP_RETURNS_DELTA (MARG's hook 0xf0457dD0...a0cc has flags 0x20cc: beforeSwap, afterSwap, both returns-delta) can take the index's input and return nothing without moving the price, and the rebalance records held -= amountIn, idleImd += 0 with only a Swapped event. _mintFirst refuses out == 0 and redeemToImd has minImdOut, but _rebalance has no floor. Precondition is a hook or pool that pays nothing for the index's swap, which the brief lists as untrusted but accepts as 'a pool's own hook fee': low, documented. A minimal design-preserving mitigation is to treat out == 0 as a skipped swap in _trySell/_tryBuy.","line":530,"path":"src/Imdex5.sol","reproduction":"test/scratch/Review.t.sol test_D_rebalanceBooksZeroOutputSale: alice mintFirst(1000e18); pm.setShortBy(key(coin5), 2^128-1) so coin 5's pool pays nothing; list drops coin 5; carol rebalance(). Observed: held[coin5] 19511716834983821943327 -> 9607794782811941356897 (9,903.9 coin5 sent to the pool), idleImd 0 -> 0, no revert, no SwapSkipped. Expected: a sale that returns nothing is skipped and the coin stays held for the holders.","severity":"low","snippet":"held[coin.token] -= amountIn;","title":"A rebalance sale or buy that returns nothing is still booked: a leaver's holding can leave for zero IMD through a hook that keeps the output"},{"citation":"resolved","description":"Merged from audit_permissions (501ae928), audit_economics (a2c4ddf0) and audit_math (fd1b69fe): one root cause, three pool states. A residual is kept in _coins (line 493) precisely because _trySell could not sell it, and every later rebalance tries the same sale through the same pool and hook. While the pool is dead or the hook rejects the index's swaps the sale is skipped and the residual re-pushed; while the pool has no liquidity, Uniswap v4 returns (0, 0) for the limited sale, held is unchanged and the coin is re-pushed too. In every one of these states _mintMore's residual branch fails every mint: BuyFailed (line 416) when the swap reverts, or TooExpensive when an empty pool fills got = 0 and leaves slot0 at the swap limit (MIN_SQRT_PRICE+1 or MAX_SQRT_PRICE-1), where _amountValue charges about 2^128 wei of IMD per wei of coin, more than any maxImdIn. The same applies to a list coin whose pool dies: the next list drops it, the sale fails and it becomes exactly such a residual. So the exits THREAT_MODEL states ('blocks mint until a rebalance drops it', 'until the pool works again or a rebalance sells the residual') do not exist while the pool is in that state; only the pool's LPs or hook owner (or every holder redeeming so supply reaches 0) can end it. No funds are lost: redeem and redeemToImd keep paying the residual in kind. This is the accepted trade-off of the 3bd5e1aa fix (settling at spot was exploitable), hence low, but the documentation should say that for such a residual the block has no end the index controls. Side effect worth noting: with an empty pool anyone can push its slot0 to the limit for free, which makes _value(residual) astronomically large in rebalance step 3, so cap = total/4 is huge and no list coin is trimmed that week.","line":416,"path":"src/Imdex5.sol","reproduction":"test/scratch/Review.t.sol test_E_deadResidualBlocksMintAcrossRebalances: alice mintFirst(1000e18); pm.setDead(key(coin5), true); list drops coin 5; rebalance: coins().length == 5, held[coin5] > 0 (sale skipped). bob mint(1e18, 1000e18, 0) reverts BuyFailed(coin5). Warp 7 days, deliver the same four-coin list, rebalance again: coins().length still 5; mint reverts BuyFailed(coin5) again; alice redeem(half) succeeds. Expected per THREAT_MODEL: a rebalance drops or sells it and mint resumes. For the empty-pool variant (not reproducible on the mock, which keeps a reserves price): _sqrtPrice == 4295128740 after the short buy, charged = mulDiv(mulDiv(need, 2^96, 4295128740, Ceil), 2^96, 4295128740, Ceil) ~= need * 2^128 -> TooExpensive for any maxImdIn.","severity":"low","snippet":"revert BuyFailed(coin.token);","title":"A residual whose pool stays dead, whose hook rejects the index, or whose liquidity is gone blocks mint with no on-chain exit: the documented way out (a rebalance sells it) never happens"},{"citation":"resolved","description":"Merged from audit_permissions (87fa168f, low, proof verified), write_foundry_tests (1032546e, info) and audit_flow (c5534a60, info): one root cause. submit compares only keccak256(a.answer) with the hash stored by onOracleResult; it never compares a.requestId with openRequest, a.questionHash with the pinned question, or a.chainId. The window and quorum checks added for audit 886e7c22 therefore apply to whichever signed attestation is presented, not to the one the Intake delivered. Once the delivered attestation has expired (86,400 s) the stored answerHash still stands for up to 7 days (until the next ask clears it), and any attestation signed by ORACLE_SIGNER in this contract's EIP-712 domain whose answer bytes are identical, whatever its requestId, questionHash or chainId, is accepted with its own window. Whoever can obtain such a signature (anyone who can file an Intake request naming this contract as consumer with a question whose answer is that list, or the oracle re-signing) adopts a list the contract's expiry check had already refused. Impact is bounded: the list adopted is byte-identical to the panel's quorate answer to this contract's own question and at most 7 days old, so no value moves; low. The README records the missing comparison as informational (57e3696c) for a still-valid attestation; the new point is that it voids the expiry guarantee of invariant 6. Minimal hardening that preserves the design: store the delivered a.requestId beside answerHash in onOracleResult and require a.requestId to equal it in submit.","line":312,"path":"src/Imdex5.sol","reproduction":"Specialist proof run as test/scratch/SubmitUnpinned.t.sol, fails on this code with 'next call did not revert as expected'. State: fund(2e18), ask(); the Intake delivers attestation D (agreed 5, answer = abi.encode([1282,1283,737]), expiresAt = now+86400). Warp now+86401: submit(D, sigD) reverts AttestationExpired (expected). Build O with requestId keccak('req-2'), questionHash keccak('some other question'), chainId 8453, same answer bytes, fresh issuedAt/expiresAt, signed by the oracle key over this contract's digest. Expected: submit(O, sigO) refused. Actual: it succeeds, nextList = the 3 launches, answerHash = 0, submitter rewarded 0.25 IMD.","severity":"low","snippet":"if (answerHash == 0 || keccak256(a.answer) != answerHash) revert WrongAnswer();","title":"submit binds the attestation only by answer bytes, so an expired answer can be revived by any other attestation in this contract's domain with the same bytes"},{"citation":"resolved","description":"From audit_flow (1f62cd32), reproduced. submit checks the attestation's window but stores only the decoded coins in _nextList; rebalance checks only that _nextList is non-empty, and nothing bounds the gap between the two. Meanwhile ask() reverts ListAwaitsRebalance, so no fresh answer can replace the pending one. Invariant 6 says only an unexpired answer can change the list; the list actually changes at rebalance time, from an answer that may have expired long before, at that moment's prices, and anyone chooses the moment. Impact is limited: anyone can call rebalance immediately after submit and is paid REWARD when feeImd allows, and the list adopted is the panel's own; low, documented. If the author wants the window to hold at adoption, store a.expiresAt in submit and have rebalance discard _nextList (and unblock ask) when block.timestamp is past it.","line":339,"path":"src/Imdex5.sol","reproduction":"test/scratch/Review.t.sol test_C2_pendingListAdoptedLongAfterExpiry: alice mintFirst(1000e18); _deliverList(_launches(4)) at t0 (attestation expiresAt t0+86400, submit succeeds). vm.warp(t0 + 30 days): bob ask() reverts ListAwaitsRebalance; carol rebalance() succeeds and listCount == 4. Expected: the pending list lapses with its attestation. Actual: an answer that expired 29 days earlier changes the list.","severity":"low","snippet":"if (_nextList.length == 0) revert NoNextList();","title":"A submitted list has no expiry: rebalance can adopt it weeks after its attestation expired, and ask() is blocked until someone does"},{"citation":"resolved","description":"From write_foundry_tests (66bc7101), reproduced on the mock. Steps 1, 3 and 4 of _rebalance sell and buy at the pool's spot price, each limited to a 1% sqrt-price (about 2%) move from that spot, and the cap in step 3 is valued with the same spot prices. The band is relative to whatever the price is when rebalance is called, so a caller who moves a pool and then calls rebalance in one transaction has the index sell a leaver at the moved price (or buy at a moved-up one). On a constant-product pool with the 1.25% fee the attacker's round-trip cost roughly matches the gain, and the index's loss is bounded by the band per rebalance, so this is bounded MEV rather than a drain: a design choice to document.","line":556,"path":"src/Imdex5.sol","reproduction":"test/scratch/Review.t.sol test_G_rebalanceSellsAtMovedPrice: alice mintFirst(1000e18); coin 5's pool coin reserve is set to 4x (price / 4) before the list drops coin 5; carol rebalance(). Observed: the sale of 19511716834983821943327 coin5 (fair value 202960099999999980488 wei IMD at the pre-move price) returned idleImd += 2 wei on the mock (the mock's sqrt-limit arithmetic stops the sale almost at once at the moved price); the sale happened at the moved price, not the fair one. Expected per design: the sale is bounded by a 2% move from the spot at call time, which it is; the spot itself is the caller's to set.","severity":"low","snippet":"uint256 p = _sqrtPrice(key);","title":"rebalance trades at the pool's current spot within a 2% band and anyone picks the moment, so the sale and buy prices can be moved first"},{"citation":"resolved","description":"From audit_economics (0becdcd9), reproduced. mintFirst is first-come. Any observer can front-run the launch's first mint with mintFirst(1_000_000 wei); the intended first mint then reverts and must be resubmitted as mint(shares, maxImdIn, minShares), priced at the same pools' spot. No dilution: mint rounds need up and tracks held internally, so the dust holder cannot inflate the share price by donating. By design; noted so the launch's first mint is sent with that in mind.","line":179,"path":"src/Imdex5.sol","reproduction":"test/scratch/Review.t.sol test_F_dustFirstMintFrontRun: bob mintFirst(1_000_000, zeros(5)) succeeds with totalSupply 995000 wei; alice mintFirst(1000e18, zeros(5)) reverts NotFirstMint.","severity":"info","snippet":"if (totalSupply() != 0) revert NotFirstMint();","title":"The intended first mint can be front-run by a dust mintFirst, after which it reverts NotFirstMint"},{"citation":"resolved","description":"From write_foundry_tests (ace81075). Each rebalance keeps every leaver that step 1 could not fully sell; a limited sale moves the price at most about 2%, so a holding large against its pool takes many weeks to sell, and each week's list may drop up to five more coins. mint, redeem and redeemToImd loop over all of _coins (a swap or a PAY_GAS transfer each), so with rotating thin-pool lists the gas grows about one swap per residual per week. Not reachable quickly (the top-five list changes slowly, and a residual shrinks 2% a week in value terms), and bounded in practice by the block gas limit only after about 100 residuals; documented, not redesigned.","line":493,"path":"src/Imdex5.sol","reproduction":"Trace: after k weeks of a list that rotates to five fresh coins while every dropped coin's pool absorbs under 1% of the index's holding per limited sale, _coins.length is about 5 + 5k (line 493 pushes each unsold leaver); _mintMore's loop (line 397) and redeem's loop (line 209) run once per entry.","severity":"info","snippet":"if (!_inList(next, old[i].token) && held[old[i].token] > 0) _coins.push(old[i]);","title":"Residuals accumulate without bound across rebalances, growing the gas of every mint, redeem and rebalance"},{"citation":"resolved","description":"From audit_math (26a8aa3b), confirmed by reading the mock. MockPoolManager caps an exact-out swap at maxIn and then reports the constant-product price of the post-trade reserves (a modest move). Uniswap v4 reports a short fill only when the price reaches sqrtPriceLimitX96; after it, slot0 sits at the limit, which for the index's unlimited residual buys is MIN_SQRT_PRICE+1 or MAX_SQRT_PRICE-1. _mintMore prices the shortfall at that post-trade sqrt price, so on v4 the thin-pool scenario reverts TooExpensive exactly as THREAT_MODEL line 31 states, while test/Imdex5Edges.t.sol test_aThinResidualPoolDoesNotStarveAFlooredMint and test/Imdex5ResidualSpot.t.sol test_aResidualShortFillIsChargedAtLeastItsFairValue pass only because the mock keeps a fair price. The fair-value short-fill path is reachable on v4 only through a transfer tax or a hook taking output, never through liquidity running out, and the fork suite does not cover a short residual fill. The contract's behaviour is consistent with THREAT_MODEL; the tests document one it does not have. Test-coverage note only.","line":177,"path":"test/mocks/Mocks.sol","reproduction":"Mock: pm.setMaxIn(key(R), 1e12); mint(100e18, 2000e18, 97e18) succeeds and idle grows by a fair charge (Imdex5Edges.t.sol line 701-715). Same state on v4 (a pool whose only liquidity range is exhausted by a 1e12-IMD buy): the swap returns a partial out with slot0.sqrtPriceX96 = 4295128740 and charged = (need - got) * 2^128 -> TooExpensive.","severity":"info","snippet":"if (amountIn > maxIn) {","title":"The mock pool's partial fill keeps a reserves-based price, so the thin-residual-pool tests pass on a behaviour Uniswap v4 cannot produce"}],"hash":"66699f84b0ea1d90dfeccd15bba4b20c632a30e026f97998b022cbe6c78553fe","nodeId":"288b3b7a-7312-4314-a456-7b9c20889c73","outcome":"completed","summary":"The review is complete and the findings file is written and validated.\n\n**Outcome:** no medium or higher defect survived reproduction. The code behaves as the threat model states on every must-attack item: a mint never issues fewer than minShares, a reverted mint returns every IMD, held only ever rises by what actually arrived, a redeem always pays or records what it owes, and an under-quorum answer never changes the list. The specialists' 16 reports collapsed into 7 low and 3 informational findings, each reproduced against the code.\n\n**What `.imd-findings.json` holds**\n\n- **Low, sender-debiting coin.** Outbound transfers are booked at the amount asked, so a coin that burns from the sender leaves held above the balance and the last redeemer owed coins that do not exist. The specialist proof fails on this tree as stated. Kept low: no listed coin behaves this way and the loss is the coin's own burn, misallocated rather than created.\n- **Low, residual shortfall price.** The taxed shortfall is charged at the post-buy spot, which a pre-mint dump lowers. Two specialists reported this; merged. My reproduction charged 0.0019 IMD for a shortfall worth 1.88 IMD after a 1000x move. Bounded by the tax fraction.\n- **Low, zero-output rebalance swap.** A hook that keeps the output has the sale booked with nothing back. Reproduced on the mock.\n- **Low, unsellable residual.** Three reports merged into one: a dead pool, a hook rejecting the index, or an empty pool blocks mint with no exit the index controls, and the threat model's \"until a rebalance sells it\" never happens. Reproduced across two rebalances.\n- **Low, submit binding.** Three reports merged: submit binds by answer bytes only, so an expired answer is revived by any same-bytes attestation in this domain. The specialist proof fails on this tree. Suggested one-line hardening is to store and compare the delivered requestId.\n- **Low, pending list has no expiry** and **low, rebalance at spot within the band.** Both reproduced; design choices to document.\n- **Info:** dust front-run of the first mint, unbounded residual accumulation, and the mock's partial-fill price differing from Uniswap v4 semantics in two existing tests.\n\nI dropped the ask-pre-debit note since the README already documents it. Coverage answers all 17 entry points plus three invariant rows. The runtime is 23,266 bytes, matching the README rather than the brief's figure, and under the limit. Only test/scratch/ and the findings file were written.","treeHash":null,"usage":{"cachedInputTokens":1261575,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":38159,"runtime":"claude","turns":22,"wallClockMs":938448}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"911c99a95f538613","findings":[{"citation":"resolved","description":"Area: Access Control x Asymmetry (trust gap). submit() binds the presented attestation to the Intake's delivery only through keccak256(a.answer). It never compares a.requestId, a.questionHash or a.chainId with the request the Intake answered, although OracleAttestation.sol's own doc says a consumer that pins its question (Imdex5 does, in body()) compares questionHash. The window check added for audit 886e7c22 (_verifyAttestation: expiresAt / issuedAt) is therefore per-attestation, not per-answer: once the delivered attestation has expired (validForSeconds 86400) the stored answerHash still stands for up to 7 days (until the next ask clears it), and any other attestation signed by ORACLE_SIGNER in this contract's EIP-712 domain whose answer bytes are identical is accepted with its own fresh window, whatever request, question or chainId it was issued for. Whoever can obtain such a signature (anyone who can file an Intake request naming this contract as consumer, or the oracle itself re-signing) can adopt a list the contract's expiry check had already refused. The README records the missing requestId/questionHash comparison as informational (57e3696c) for a still-valid attestation; the new point is that it also voids the expiry guarantee of invariant 6 ('unexpired'). Impact is bounded: the list adopted is byte-identical to the panel's own answer to this contract's own question, at most 7 days old, so no value moves; hence low. Documented limit, no redesign needed; a minimal hardening would be to store the delivered a.requestId (or questionHash) beside answerHash in onOracleResult and compare it in submit.","line":312,"path":"src/Imdex5.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Imdex5} from \"src/Imdex5.sol\";\nimport {OracleAttestation, OracleAttestationConsumer} from \"src/OracleAttestation.sol\";\nimport {IPoolManager} from \"src/Interfaces.sol\";\nimport {MockERC20, MockIntake, MockPoolManager, MockRegistry, MockSigner, ReentrantHook} from \"test/mocks/Mocks.sol\";\n\n/// @dev submit() pins neither questionHash, requestId nor chainId of the attestation: any signed\n/// attestation in this consumer's domain whose `answer` bytes hash to `answerHash` is accepted,\n/// including one issued later (fresh window) after the delivered one expired.\ncontract SubmitUnpinnedTest is Test {\n    uint256 constant KEY_PK = 0xA11CE;\n    address constant HOOK_G = 0x784FF9a3ac5d88A30bfff6F7f2a270161FBE6000;\n\n    Imdex5 index;\n    MockERC20 imd;\n    MockPoolManager pm;\n    MockRegistry regA;\n    MockRegistry regB;\n    MockIntake intake;\n    address alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        index = new Imdex5();\n        imd = MockERC20(index.IMD());\n        vm.etch(address(imd), address(new MockERC20()).code);\n        pm = MockPoolManager(index.POOL_MANAGER());\n        vm.etch(address(pm), address(new MockPoolManager()).code);\n        regA = MockRegistry(address(index.REGISTRY_A()));\n        vm.etch(address(regA), address(new MockRegistry()).code);\n        regB = MockRegistry(address(index.REGISTRY_B()));\n        vm.etch(address(regB), address(new MockRegistry()).code);\n        intake = MockIntake(index.INTAKE());\n        vm.etch(address(intake), address(new MockIntake()).code);\n        vm.etch(index.ORACLE_SIGNER(), address(new MockSigner(vm.addr(KEY_PK))).code);\n        vm.etch(HOOK_G, address(new ReentrantHook()).code);\n        Imdex5.Coin[] memory coins = index.coins();\n        for (uint256 i = 0; i < coins.length; ++i) {\n            vm.etch(coins[i].token, address(new MockERC20()).code);\n            regB.record(coins[i].launch, coins[i].token, coins[i].hook);\n        }\n        imd.mint(alice, 10e18);\n        vm.prank(alice);\n        imd.approve(address(index), type(uint256).max);\n    }\n\n    function _att(bytes32 reqId, bytes32 qHash, uint256 chainId) internal view returns (OracleAttestation.Attestation memory a) {\n        bytes32[] memory ids = new bytes32[](3);\n        ids[0] = bytes32(uint256(1282));\n        ids[1] = bytes32(uint256(1283));\n        ids[2] = bytes32(uint256(737));\n        a = OracleAttestation.Attestation({\n            requestId: reqId,\n            chainId: chainId,\n            questionHash: qHash,\n            answerType: OracleAttestation.ANSWER_BYTES32_LIST,\n            answer: abi.encode(ids),\n            figure: 0,\n            fromBlock: 100,\n            toBlock: 200,\n            blockHash: bytes32(uint256(7)),\n            panelJobId: keccak256(\"panel\"),\n            panelSize: 5,\n            quorum: 4,\n            agreed: 5,\n            issuedAt: uint64(vm.getBlockTimestamp()),\n            expiresAt: uint64(vm.getBlockTimestamp() + 86_400)\n        });\n    }\n\n    function _sign(OracleAttestation.Attestation memory a) internal view returns (bytes memory) {\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY_PK, index.attestationDigest(a));\n        return abi.encodePacked(r, s, v);\n    }\n\n    function test_expiredAnswerRevivedByAnotherAttestationWithSameAnswer() public {\n        vm.prank(alice);\n        index.fund(2e18);\n        vm.prank(alice);\n        index.ask();\n        OracleAttestation.Attestation memory delivered = _att(keccak256(\"req-1\"), keccak256(\"imdex question\"), 1);\n        bytes memory sigDelivered = _sign(delivered);\n        bytes32 id = intake.lastRequestId();\n        vm.prank(address(intake));\n        index.onOracleResult(id, delivered, \"\");\n        assertEq(index.answerHash(), keccak256(delivered.answer));\n\n        // nobody submits inside the 24h window; the delivered attestation is now expired\n        vm.warp(vm.getBlockTimestamp() + 86_401);\n        vm.prank(alice);\n        vm.expectRevert(abi.encodeWithSelector(OracleAttestationConsumer.AttestationExpired.selector, delivered.expiresAt));\n        index.submit(delivered, sigDelivered);\n\n        // a different attestation (other requestId, other questionHash, other chainId, fresh window)\n        // signed in this consumer's domain with the same answer bytes is accepted\n        OracleAttestation.Attestation memory other = _att(keccak256(\"req-2\"), keccak256(\"some other question\"), 8453);\n        bytes memory sigOther = _sign(other);\n        // expected once fixed: an attestation that is not the open request's answer is refused\n        vm.prank(alice);\n        vm.expectRevert();\n        index.submit(other, sigOther);\n        assertEq(index.nextList().length, 0, \"list adopted from an attestation for another request/question\");\n    }\n}","reproduction":"State: feeImd >= 0.75 IMD, ask() called, Intake delivers attestation D (agreed 5, answer = abi.encode([1282,1283,737]), expiresAt = now+86400) via onOracleResult -> answerHash = keccak256(D.answer). Warp to now+86401 (nobody submitted). submit(D, sigD) reverts AttestationExpired (expected). Build attestation O with requestId = keccak('req-2'), questionHash = keccak('some other question'), chainId = 8453, same answer bytes, issuedAt = now, expiresAt = now+86400, signed by the oracle signer over this contract's digest. Expected: submit(O, sigO) is refused (the open request's answer expired). Actual: submit(O, sigO) succeeds, nextList = the 3 launches, answerHash = 0, submitter rewarded 0.25 IMD. Test: test/scratch/SubmitUnpinned.t.sol (fails on this code: 'next call did not revert as expected').","severity":"low","snippet":"        if (answerHash == 0 || keccak256(a.answer) != answerHash) revert WrongAnswer();","title":"submit pins neither requestId nor questionHash: an expired answer can be revived by any other attestation in this domain with the same answer bytes, bypassing the validity window"},{"citation":"resolved","description":"Area: Asymmetry (list coin vs residual branch of _mintMore). For a list coin, THREAT_MODEL.md accepts that a dead pool blocks mint 'until a rebalance drops it'. For a residual (i >= listCount) the same revert applies, but the documented exit does not exist: a residual is kept in _coins precisely because _trySell could not sell it, and while its pool is dead every later rebalance skips the sale again (SwapSkipped) and re-pushes it with held > 0. The only exits are the pool's LPs adding liquidity again or the residual being re-listed, neither of which the index or its holders control. redeem and redeemToImd keep working, so no funds are frozen; shares cannot be created. This is the stated 3bd5e1aa trade-off and README/THREAT_MODEL already say 'until the pool works again or a rebalance sells the residual'; recorded here so the author documents that for a dead residual pool the second alternative never happens. Informational; document, do not redesign.","line":415,"path":"src/Imdex5.sol","reproduction":"State: supply > 0; coin X left the list at a rebalance while its pool was dead (MockPoolManager.setDead(key(X), true)), so X is at index >= listCount with held[X] > 0. Call mint(1e18, 1e21, 0): need = ceil(held[X] * 1e18 / supply) > 0, swapSelf reverts (dead pool), catch -> revert BuyFailed(X); every mint reverts identically. Call submit/rebalance in the next cycles with X absent from the list: step 1 _trySell(X) is skipped (dead pool), step 2 re-pushes X as residual; mint still reverts BuyFailed(X). Expected per THREAT_MODEL for a dead pool: 'blocks mint until a rebalance drops it'. Actual: no rebalance can drop it while the pool is dead.","severity":"info","snippet":"                } catch {\n                    revert BuyFailed(coin.token);","title":"A residual whose pool stays dead blocks mint with no on-chain way out: rebalance cannot sell it either, so BuyFailed persists until a third party restores that pool"}],"hash":"bc114029918ceeac018fd2e5eb3542b234d7b3bb120be1a026fd6c640ab1c7d4","nodeId":"9477556b-5a27-4fa4-8e55-57daad6bf6a2","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds two findings plus a 19-row coverage record. No source file was changed. The scratch test lives under `test/scratch/`, which is not kept.\n\n**Outcome: no medium-or-higher defect in the access control, trust gap or asymmetry area.** The permission model is exactly as the brief states. Anyone calls everything, the two Intake callbacks check the Intake address and the open request, `unlockCallback` checks the PoolManager and the entered guard, and `swapSelf` checks self. The full existing suite passes (145 tests).\n\n**Findings written**\n\n- **Low, `submit` at src/Imdex5.sol:312.** The presented attestation is tied to the Intake's delivery only by the hash of its answer bytes. Neither `requestId` nor `questionHash` nor `chainId` is compared. So once the delivered attestation has expired, any other attestation signed in this contract's domain with byte-identical answer bytes, with its own fresh window, is accepted for up to seven days. The expiry check added for audit 886e7c22 holds per attestation but not per answer. Impact is bounded because the adopted list is still the panel's answer to this contract's own question. A proof test under `test/scratch/SubmitUnpinned.t.sol` fails on this code as required.\n- **Info, `_mintMore` residual branch at src/Imdex5.sol:415.** For a list coin, the threat model's exit from a dead pool is the next rebalance dropping it. For a residual that exit never happens while its pool stays dead, since every rebalance skips the sale and re-pushes it. Mint stays blocked until a third party restores that pool. Redeem paths keep working, so nothing is frozen. The README already states the trade-off; this records that the second documented alternative does not apply.\n\n**What I checked and found holding**\n\n- Every MUST ATTACK item on the access side: a reverted mint returns the pulled IMD through the PoolManager's unlock revert, the `minShares` floor is enforced before minting, `held` only grows by measured receipts, redeem falls back to `owed`, and an expired or under-quorum answer is refused on its own attestation.\n- Rebalance caller sandwich is unprofitable at a 2% price stop against a 1.25% pool fee, and insufficient-gas griefing of the try/catch swaps cannot leave enough gas for the storage work that follows.\n- Static-analysis leads in my area were dismissed after tracing. The return bomb in `_pay` is capped by the 300k stipend. The `abi.encodePacked` lead is string building, not hashing.\n\n**Not reached in depth:** the economic rounding of the residual charge and the Uniswap v4 fork behaviour of zero-liquidity exact-output swaps. Those belong to the economics and periphery passes and I relied on the prior audits' conclusions there.","treeHash":null,"usage":{"cachedInputTokens":1254370,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":47224,"runtime":"claude","turns":29,"wallClockMs":952382}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"6b37e4ab65246705","findings":[{"citation":"resolved","description":"Invariant 2 (held[coin] equals the coin balance the contract actually holds) is kept by measuring every inbound amount (the balance difference after take) but every OUTBOUND transfer is assumed to debit the contract by exactly the amount passed: redeem() does held[token] -= amount and then _pay(token, to, amount) (lines 212/219), _payInKind does the same (line 624/625), and _trySell does held[coin.token] -= amountIn after transferring amountIn to the pool manager (line 530/572). A coin whose transfer burns or taxes an extra slice from the SENDER (burn-on-send, sender-side tax) delivers the full amount to the recipient, so every pool settlement and every payment succeeds, but the contract's balance drops by amount*(1+t) while held drops by amount. The suite models only recipient-side taxes (TaxERC20/PoolTaxERC20 subtract from the recipient), so this boundary is untested. After one ordinary redeem, held > balance; later redeemers are paid from a held figure that overstates what exists, and the last holder (paid 100%) gets an owed entry that claim() can never pay (safeTransfer reverts with insufficient balance). Loss is bounded by t times the amounts transferred out, and falls on whoever redeems last. The modeled coins (SwarmCity 2% on transfers out of the pool manager) are not of this kind, hence low; it is the one concrete way left for held to differ from the balance.","line":211,"path":"src/Imdex5.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Imdex5} from \"src/Imdex5.sol\";\nimport {IPoolManager} from \"src/Interfaces.sol\";\nimport {MockERC20, MockIntake, MockPoolManager, MockRegistry, MockSigner, ReentrantHook} from \"test/mocks/Mocks.sol\";\n\n/// @dev A coin whose transfer debits the sender 2% more than the recipient receives (a burn-on-send\n/// coin). Transfers out of the pool manager are untouched so the index's buys are credited exactly.\ncontract SenderDebitERC20 is MockERC20 {\n    address public immutable poolManager;\n\n    constructor(address pm) {\n        poolManager = pm;\n    }\n\n    function transfer(address to, uint256 amount) public override returns (bool) {\n        if (!super.transfer(to, amount)) return false;\n        if (msg.sender != poolManager) {\n            uint256 extra = amount * 2 / 100;\n            balanceOf[msg.sender] -= extra;\n            totalSupply -= extra;\n        }\n        return true;\n    }\n}\n\ncontract SenderDebitTest is Test {\n    address constant HOOK_G = 0x784FF9a3ac5d88A30bfff6F7f2a270161FBE6000;\n    Imdex5 index;\n    MockERC20 imd;\n    MockPoolManager pm;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n    address[] tokens;\n    address[] hooks;\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        index = new Imdex5();\n        imd = MockERC20(index.IMD());\n        vm.etch(address(imd), address(new MockERC20()).code);\n        pm = MockPoolManager(index.POOL_MANAGER());\n        vm.etch(address(pm), address(new MockPoolManager()).code);\n        vm.etch(HOOK_G, address(new ReentrantHook()).code);\n        Imdex5.Coin[] memory coins = index.coins();\n        for (uint256 i = 0; i < coins.length; ++i) {\n            vm.etch(coins[i].token, address(new MockERC20()).code);\n            tokens.push(coins[i].token);\n            hooks.push(coins[i].hook);\n            _setPool(coins[i].token, coins[i].hook, 1_000_000e18, 10_000e18);\n        }\n        // the fifth coin debits its sender on every transfer not made by the pool manager\n        vm.etch(tokens[4], address(new SenderDebitERC20(address(pm))).code);\n        imd.mint(alice, 10_000e18);\n        vm.prank(alice);\n        imd.approve(address(index), type(uint256).max);\n        imd.mint(bob, 10_000e18);\n        vm.prank(bob);\n        imd.approve(address(index), type(uint256).max);\n    }\n\n    function _key(address token, address hook_) internal view returns (IPoolManager.PoolKey memory) {\n        (address c0, address c1) = address(imd) < token ? (address(imd), token) : (token, address(imd));\n        return IPoolManager.PoolKey(c0, c1, index.POOL_FEE(), index.TICK_SPACING(), hook_);\n    }\n\n    function _setPool(address token, address hook_, uint256 coinReserve, uint256 imdReserve) internal {\n        IPoolManager.PoolKey memory key = _key(token, hook_);\n        (uint256 r0, uint256 r1) = key.currency0 == token ? (coinReserve, imdReserve) : (imdReserve, coinReserve);\n        pm.setPool(key, r0, r1);\n        MockERC20(token).mint(address(pm), coinReserve);\n        imd.mint(address(pm), imdReserve);\n    }\n\n    /// Invariant 2: held[coin] equals the balance the contract actually holds, on every path.\n    /// Fails on this tree: one ordinary redeem of a sender-debiting coin leaves held above the\n    /// balance, and the last holder is then owed coins nobody holds.\n    function test_heldTracksTheBalanceThroughRedeemsOfASenderDebitingCoin() public {\n        uint256[] memory minOut = new uint256[](5);\n        vm.prank(alice);\n        index.mintFirst(1000e18, minOut);\n        vm.prank(bob);\n        index.mint(1000e18, 2000e18, 1000e18);\n        address c = tokens[4];\n        assertEq(index.held(c), MockERC20(c).balanceOf(address(index)), \"held == balance after mints\");\n\n        uint256 bobShares = index.balanceOf(bob);\n        vm.prank(bob);\n        index.redeem(bobShares);\n        assertEq(index.held(c), MockERC20(c).balanceOf(address(index)), \"held must equal the balance after a redeem\");\n\n        uint256 heldBefore = index.held(c);\n        uint256 aliceShares = index.balanceOf(alice);\n        vm.prank(alice);\n        index.redeem(aliceShares);\n        assertEq(index.owed(alice, c), 0, \"the last holder must not be left owed\");\n        assertEq(MockERC20(c).balanceOf(alice), heldBefore, \"the last holder is paid the whole holding\");\n    }\n}","reproduction":"State: five list coins with 1,000,000 coin / 10,000 IMD pools; coin[4] (SC) replaced by a token whose transfer() debits msg.sender an extra 2% when msg.sender is not the pool manager (deliveries from the pool are exact). Calls: alice mintFirst(1000e18, [0,0,0,0,0]); bob mint(1000e18, 2000e18, 1000e18) -> held[c] == balanceOf(index) (exact). bob redeem(all his shares): held[c] falls by bob's pro-rata amount A, the balance falls by A + 2%*A -> held[c] > balance (expected: equal). alice redeem(all remaining shares): keepBps = BPS, _pay(c, alice, held[c]) fails (balance short by 2%*A), owed[alice][c] = held[c], alice receives 0 of c; claim(c) reverts ERC20InsufficientBalance forever. Expected: a redeem pays each holder their pro-rata share and the last holder in full. Concrete numbers from the attached test: after bob's redeem held[c] = 19609765663300323561133 while the contract's balance is 19219531326600647122267 (2% of bob's 19,513 coins burned from the sender). Test: test/scratch/SenderDebit.t.sol fails on this tree at 'held must equal the balance after a redeem' and passes once outbound transfers are measured (balance before/after) the way inbound ones are.","severity":"low","snippet":"            uint256 amount = Math.mulDiv(held[token], shares * keepBps, supply * BPS);\n            held[token] -= amount;","title":"A coin that debits its sender more than the recipient receives makes held exceed the real balance; the last redeemer is owed coins the contract does not hold"},{"citation":"resolved","description":"THREAT_MODEL.md line 30-31 accepts that a residual blocks mint 'until the pool works again or a rebalance sells the residual' and that a residual pool with no buy-side liquidity makes the shortfall charge astronomical (TooExpensive). The two accepted cases combine into a permanent one that is not stated: on Uniswap v4 a pool whose LPs have withdrawn all liquidity still trades (no revert), returns amountIn = 0 / amountOut = 0 and leaves sqrtPriceX96 at the swap's limit. In _rebalance step 1 the limited _trySell of such a coin therefore 'succeeds' with amountIn = 0, held is unchanged and the coin is re-pushed as a residual every week forever (line 493); redeem keeps working. In _mintMore the exact-out buy returns got = 0 < need and the shortfall is priced at _sqrtPrice read right after the swap, which is MIN_SQRT_PRICE + 1 (IMD < token, zeroForOne) or MAX_SQRT_PRICE - 1: _amountValue then yields about 2^128 wei of IMD per wei of coin (Q192 / (2^32)^2), so total > maxImdIn and every mint of any size reverts TooExpensive (or the inner mulDiv overflows and reverts for need - got >= 2^128). Nothing in the contract can remove the residual: there is no owner, rebalance cannot sell it, and only a full redemption by every holder (supply -> 0) clears held. mint is thus dead for as long as that one pool stays empty; the pool's LPs (whoever holds the launch's liquidity position) control that. Precision x boundary x invariant seam: the charge formula is exact at ordinary prices but at the price limit it is a 2^128 multiplier that no maxImdIn can cover. Documented, not a redesign: state it as permanent in THREAT_MODEL, or let a residual whose buy returns got == 0 be treated like a failed buy only for coins the pool has zero liquidity for and allow the residual to be dropped when held value at spot rounds to zero.","line":418,"path":"src/Imdex5.sol","reproduction":"State on mainnet v4: list adopts four coins at a rebalance while coin R (IMD < R so IMD is currency0) stays as a residual with held[R] = H > 0; R's pool has had all its liquidity removed (swap returns (0,0), price moves freely). Call rebalance() weekly: step 1 _trySell(R, H) -> amountIn 0, out 0, held[R] stays H, R re-pushed as residual; step 3/4 unaffected. Call mint(1e18, maxImdIn = any, 0): need = ceil(H*1e18/supply) > 0; swapSelf(R, buy, need, exactOut) returns rIn 0, rOut 0 -> got 0; _sqrtPrice(key) == MIN_SQRT_PRICE+1 = 4295128740; charged = mulDiv(mulDiv(need, 2^96, 4295128740, Ceil), 2^96, 4295128740, Ceil) ~= need * 2^128 (for need = 1e18 that is 3.4e56 wei IMD) -> total > maxImdIn -> revert TooExpensive(total). Expected per README: a residual blocks mint only until a rebalance sells it; actual: no rebalance ever sells it, so mint is blocked for the life of the index unless every holder redeems. Reproducible only on a fork (the mock's maxIn partial fill does not move the price to the limit, see finding 3); the arithmetic above is from _amountValue with sqrtP = 4295128740.","severity":"low","snippet":"                if (got < need) {\n                    charged += _amountValue(\n                        coin.token, need - got, _sqrtPrice(_key(coin.token, coin.hook)), Math.Rounding.Ceil\n                    );\n                }","title":"A residual whose pool has no liquidity left can never be sold by rebalance and blocks mint permanently through an astronomical shortfall charge"},{"citation":"resolved","description":"MockPoolManager caps an exact-out swap at maxIn and then reports the constant-product price of the post-trade reserves, a modest move. Uniswap v4 reports a short fill only when the price reaches sqrtPriceLimitX96; after it the pool's slot0 sits at the limit, which for the index's unlimited residual buys is MIN_SQRT_PRICE+1 or MAX_SQRT_PRICE-1. _mintMore prices the shortfall at that post-trade sqrt price (line 420), so on v4 the thin-pool scenario charges about 2^128 IMD per wei and reverts TooExpensive, exactly as THREAT_MODEL.md line 31 states, while test/Imdex5Edges.t.sol test_aThinResidualPoolDoesNotStarveAFlooredMint (line 701) and test/Imdex5ResidualSpot.t.sol test_aResidualShortFillIsChargedAtLeastItsFairValue (line 165) pass only because the mock keeps a fair price. The 'fair-value charge' path the two tests exercise is reachable on v4 only through a transfer tax or a hook taking output (price honest), never through liquidity running out. The fork suite (test/Fix3*.fork.t.sol) does not cover a short residual fill either. The edge is therefore untested against the real pool semantics; the contract's own behavior is consistent with THREAT_MODEL, the tests document a behavior it does not have.","line":177,"path":"test/mocks/Mocks.sol","reproduction":"Mock: pm.setMaxIn(key(R), 1e12); mint(100e18, 2000e18, 97e18) -> succeeds, idle grows by a fair charge (test line 701-715). Same state on v4 (a pool whose only liquidity range is exhausted by a 1e12-IMD buy): swap returns a partial out with slot0.sqrtPriceX96 = 4295128740; charged = (need-got) * 2^128 -> TooExpensive. Expected: the test suite asserts what the real pool does; actual: it asserts the opposite outcome for this input.","severity":"info","snippet":"            if (amountIn > maxIn) {\n                amountIn = maxIn;\n                amountOut = Math.mulDiv(rOut, amountIn, rIn + amountIn);\n            } else {","title":"The mock pool's partial fill keeps a reserves-based price, so the 'thin residual pool does not starve a floored mint' test passes on a behavior Uniswap v4 cannot produce"},{"citation":"resolved","description":"feeImd -= ORACLE_PRICE + REWARD (line 253) is applied before the Intake call, and the Intake is given an allowance of ORACLE_PRICE rather than a transfer. The contract never reads how much the Intake actually pulled. If the Intake's price for this action is ever below 0.5 IMD, or it charges in another form and pulls nothing, the difference stays in the contract's IMD balance with no bucket (invariant 1: 'nothing is unaccounted'), unreachable by any function since there is no sweep and feeImd is only increased by fund(), mint fees and redeem fees; a leftover allowance also persists. The return value handled (requestId) does not carry the amount. Information only: the Intake and its price are fixed by the brief, and the brief says the price is 0.5 IMD.","line":258,"path":"src/Imdex5.sol","reproduction":"State: feeImd = 1 IMD. Call ask() with an Intake that pulls 0.4 IMD (transferFrom(index, intake, 0.4e18)) and returns a request id. After: feeImd = 0.25 IMD, idleImd unchanged, reward 0.25 paid, contract IMD balance = idleImd + feeImd + 0.1 IMD. Expected: balance == idleImd + feeImd (invariant 1, test _assertImdAccounting); actual: 0.1 IMD unaccounted and unspendable; allowance[INTAKE] = 0.1e18 remains until the next forceApprove.","severity":"info","snippet":"        IERC20(IMD).forceApprove(INTAKE, ORACLE_PRICE);","title":"ask() debits feeImd by the full oracle price before the Intake pulls; any part the Intake does not pull is IMD no accounting bucket owns"}],"hash":"bf8a47fcb64456f0c8b040e447bbdba6622ee5a87b5bec48c26fa19744490c5c","nodeId":"a4f8dff5-6bab-4b70-9a1b-aa29dc96c741","outcome":"completed","summary":"Review complete. The findings file is written at `.imd-findings.json` with 4 findings and 20 coverage rows (all 17 entry points plus three invariant rows). No tracked file was changed; the scratch test and findings file are both git-ignored.\n\n**What I covered**\n\nThe Math Precision, Boundary and Numerical Gap checklists against `src/Imdex5.sol`, traced with concrete values: every rounding direction in mint, redeem, redeemToImd and rebalance, the residual shortfall charge in `_amountValue`, the sqrt-price limit arithmetic, the delta unpacking, overflow headroom in each mulDiv, the attestation window and quorum boundaries, and the three must-attack invariants (fewer than minShares, reverted mint keeping IMD, held versus balance). The existing 145 tests pass on this tree. I also read the five starting tokens' supplies from mainnet to bound the one overflow path.\n\n**Findings**\n\n- **Low, held exceeds the real balance** for a coin that debits its sender more than the recipient receives. Every outbound transfer in redeem, redeemToImd and rebalance assumes it debits exactly the amount passed, while inbound amounts are measured. After one ordinary redeem, held is 2% above the balance and the last holder is owed coins that claim can never pay. Reproduced by `test/scratch/SenderDebit.t.sol`, which fails on this tree. The modeled tax shape (SwarmCity, recipient-side) is unaffected, so this is low.\n- **Low, a residual with an empty pool blocks mint permanently.** On v4 an empty pool still trades, returns zero both ways, and leaves the price at the limit. Rebalance's limited sell then \"succeeds\" with nothing sold and re-pushes the residual forever, while every mint prices the shortfall at the limit price, about 2^128 IMD per wei, and reverts TooExpensive. The threat model states both halves but not that they combine into a permanent block.\n- **Info, test fidelity.** The mock pool's partial fill keeps a reserves-based price, so the thin-residual tests pass on behavior v4 cannot produce. On v4 the same input reverts, as the threat model itself says.\n- **Info, ask() accounting.** feeImd is debited by the full oracle price before the Intake pulls through an allowance, so any unpulled part becomes IMD no bucket owns.\n\n**Confirmed holding**\n\nNo path issues fewer than minShares, no reverted mint keeps IMD, the residual charge uses the post-buy price which a buy only raises, the `_amountValue` overflow needs 2^128 wei of one coin against supplies of 1e27 wei, and the oracle expiry, issuedAt tolerance and quorum checks sit on the correct side of each boundary.","treeHash":null,"usage":{"cachedInputTokens":1645954,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":54858,"runtime":"claude","turns":27,"wallClockMs":1170707}},{"artifacts":[],"attempt":1,"bundleHash":"c3261c6b8b9181f2400442fcd4ff50c6f10bcfeb0bae55a4207b92ba6032ef7c","device":"fa5c50e7abe46571","findings":[],"hash":"cff13967fd81c1be8d3b5262a5b678030a07e77d4c4da5a05bd57294a3ed6cae","nodeId":"6a06fee5-73ae-411e-9ed4-8d02105e9a91","outcome":"completed","summary":"Work is complete and verified. Summary:\n\n**The medium finding reproduced and is fixed.** On the code as it arrived, with the audit's setup (alice holds the whole index, coin 5 left the list as a residual worth about 98 IMD, its pool dumped 1,000x and refusing the index's buy), bob minted half the index and was charged 0.096 IMD for a residual half worth about 49 IMD. The fix is the one-line change the audit recommended in `src/Imdex5.sol`: the residual branch's `catch` now reverts `BuyFailed(coin)` instead of charging at spot. The short-fill path is unchanged, since there the pool just traded at the price read. Runtime grew to 23,266 bytes, still under the limit, and the scan found no forbidden opcodes and a nonpayable no-argument constructor.\n\n**Tests added and updated:**\n- New `test/Imdex5ResidualSpot.t.sol`: the attack now reverts and takes no IMD, fuzzed over any dump factor and mint size; a residual hook that burns gas or leaves a delta fails the mint; a dumped pool that still trades is bought in full with no dilution and `held` equal to the balance; a short fill is charged at least its fair value.\n- The edge test that pinned the old \"dead residual is charged at spot\" rule now asserts the new rule, with redeems still working and the mint resuming once the pool is back.\n- The three mainnet fork suites now skip when no fork is present. Before, a plain offline `forge test` failed 7 of them, which the no-network verifier would have hit.\n\n**Low and informational findings** are documented rather than redesigned, in the README security notes and THREAT_MODEL.md: the v4 price-limit `TooExpensive` bound, the residual fraction following requested shares after a list short fill, the request-id binding in `submit`, and the Intake pull assumption in `ask`. The README's stale statements about `submit` and dead residuals are corrected, and ADAPTATION.md lists every change, each finding's reproduction result, and the validation.\n\n**Validation with the verifier's seed:** 145 tests pass, 0 fail, 7 fork tests skipped. The fork tests themselves were not run, since there is no RPC here. I did not commit; the working tree holds the changes, and launch.json was left untouched as the manifest step's file.","treeHash":"38961c2af05a5660ef35bc453a0e99fc454c8811","usage":{"cachedInputTokens":2620803,"inputTokens":770,"model":"claude-fable-5-1","outputTokens":36207,"runtime":"claude","turns":54,"wallClockMs":1626540}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fdbedee33322a6ef","findings":[{"citation":"resolved","description":"submit() checks the attestation's validity window (_verifyAttestation: block.timestamp > a.expiresAt reverts) but stores only the decoded coins in _nextList. It keeps neither expiresAt nor issuedAt. The list itself changes in rebalance(), which checks only _nextList.length != 0. Nothing bounds the gap between submit and rebalance. Meanwhile ask() reverts ListAwaitsRebalance while _nextList is non-empty, so no fresh answer can replace the pending one. Threat-model invariant 6 says only an unexpired answer can change the list. In fact the list changes at rebalance time from an answer that may have expired long ago. Anyone can also choose the moment of adoption, for example right after a listed coin's pool has died, which then blocks mint until another full oracle cycle. Impact is limited because anyone can call rebalance immediately after submit and is paid REWARD for it, so this is rated low.","line":338,"path":"src/Imdex5.sol","reproduction":"1) ask() at t0; the Intake calls onOracleResult with an attestation, agreed=5, answer=[1282,1283,737,1075,X], issuedAt=t0, expiresAt=t0+86400. 2) submit(a, sig) at t0+1h succeeds: _nextList = 5 coins. 3) Nobody calls rebalance (feeImd < REWARD, so there is no reward). 4) vm.warp(t0+30 days); ask() reverts ListAwaitsRebalance, so no fresh answer can arrive. 5) rebalance() at t0+30 days succeeds: it sells and buys at that moment's prices and adopts the list from an attestation that expired 29 days earlier. Expected: the pending list lapses with its attestation (rebalance reverts or discards _nextList once now > the stored expiresAt, and ask() is allowed again). Actual: the expired answer changes the list. Minimal fix: store a.expiresAt in submit; in rebalance, if block.timestamp > stored expiry, delete _nextList and return (or revert); ask() then proceeds.","severity":"low","snippet":"    function rebalance() external nonReentrant {\n        if (_nextList.length == 0) revert NoNextList();\n        IPoolManager(POOL_MANAGER).unlock(abi.encode(Op.Rebalance, msg.sender, 0, 0, 0, new uint256[](0)));","title":"rebalance adopts a submitted list with no expiry: an answer valid only at submit can change the list weeks later, and ask() is blocked until it does"},{"citation":"resolved","description":"answerHash binds only keccak256(a.answer). submit() never compares a.requestId with openRequest, a.questionHash with the pinned question, or a.chainId with 1. Any attestation signed for this consumer that carries byte-identical answer bytes passes: one from an earlier request, or one answering a different question with the same encoded list. Its own agreed and expiresAt are then the ones checked. The adopted list is always exactly the bytes the Intake delivered, so no different list can be installed. What changes is which signed record the quorum and expiry checks look at: an answer whose delivered attestation expired can still be submitted with another valid attestation of the same bytes. Documenting this; no redesign required.","line":312,"path":"src/Imdex5.sol","reproduction":"Intake delivers attestation A1 for request R2 (answer L, expiresAt t1). At t > t1, submit(A1) reverts AttestationExpired. If the oracle signer has issued for this contract any other attestation A0 with answer bytes L and expiresAt >= t (a different requestId or questionHash), submit(A0, sig0) succeeds and installs L. Expected: only the attestation for openRequest (same requestId, pinned questionHash) is accepted. Actual: any same-bytes attestation is accepted.","severity":"info","snippet":"        if (answerHash == 0 || keccak256(a.answer) != answerHash) revert WrongAnswer();","title":"submit checks quorum and window on whichever signed attestation matches the answer bytes, not on the one the Intake delivered for openRequest"}],"hash":"dfac14e4e1b12c600c538bdfafc522b8bb3f702f97c58cf58a0bd8bd8e67527a","nodeId":"abeb4e1f-3723-4d2c-ae5b-2e8a9dccfb25","outcome":"completed","summary":"I found no medium-or-higher defect in this launch. The findings and a coverage row for every one of the 17 entry points are in `.imd-findings.json`, and I changed no files.\n\nI reviewed the tree as it stands at HEAD (`06fa97d`), not at `6ee29fb`. HEAD adds one later fix, for audit 3bd5e1aa: a mint now reverts with `BuyFailed` when a residual's buy reverts, instead of charging it at spot price. The existing suite passes: 145 tests, 7 fork tests skipped because no fork RPC was given.\n\n**The attacks you asked for:**\n- **Mint issuing fewer than `minShares`:** holds. `_mintMore` checks the floor after every buy and before minting.\n- **Reverted mint keeping IMD:** holds. The IMD is pulled in the same transaction, so any revert returns it.\n- **`held` differing from the real balance:** holds. Every change to `held` uses the amount actually received or sent. Coins owed after a failed transfer are tracked separately. A sale of a taxed coin fails its delta check and is caught.\n- **Mint diluting holders, including by moving a residual's price first:** holds. The share count rounds down and the coins bought round up. A residual's short fill is charged at the price after the mint's own buy. Pushing that price down first costs the attacker more in pool fees than the 2% shortfall can return.\n- **Redeem that cannot pay:** holds. A failed transfer becomes an amount owed to the holder, a failed sale is paid in kind, and the last holder pays no fee on either path.\n- **Expired or under-quorum answer changing the list:** `submit` enforces both the validity window and the four-member quorum, but `rebalance` does not (finding 1).\n\n**Findings:**\n1. **Low – an expired answer can still change the list.** `rebalance()` at `src/Imdex5.sol:338` adopts the pending list with no expiry check. `submit` verifies the window but keeps only the coins, and `ask()` is blocked while a list is pending.\n   - **Reproduction:** submit at t0+1h an attestation that expires at t0+1 day. At t0+30 days, `ask()` reverts `ListAwaitsRebalance` and `rebalance()` still succeeds with the expired answer.\n   - **Smallest fix:** store `expiresAt` in `submit`. In `rebalance`, once it has passed, discard the pending list so `ask()` works again.\n   - **Why low:** anyone can call `rebalance` right after `submit` and is paid a reward for it.\n2. **Info – `submit` checks whichever signed attestation has the same answer.** At `src/Imdex5.sol:312` it matches only the answer bytes, not `requestId` against the open request or the question hash. Another signed attestation with identical bytes, such as one from an earlier request, can stand in for an expired one. The list installed is always the one the oracle delivered.\n\nI followed up the static-analysis leads (reentrancy, strict equalities, unused returns, return bomb, packed encoding) and none became a finding. The nonReentrant guard, the pool-manager-only callback check and `swapSelf` accepting only the contract itself close the reentrancy paths. The other leads are harmless here. I wrote no proof tests, since neither finding is critical or high.\n\n**Not covered:**\n- Real Uniswap v4 hooks that adjust swap amounts themselves (return-delta hooks), beyond what the mocks simulate.\n- A fork run against mainnet.","treeHash":null,"usage":{"cachedInputTokens":777468,"inputTokens":20,"model":"claude-opus-5-5","outputTokens":33292,"runtime":"claude","turns":12,"wallClockMs":1016253}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"be3be4cc237417f9","findings":[{"citation":"resolved","description":"_trySell (and _tryBuy at line 541-542) accept any (amountIn, out) pair the swap returns, including out == 0 with amountIn > 0. The only bound on a rebalance swap is the 2% sqrt-price limit, which binds only when the pool's own price moves. A pool whose hook settles the swap itself (a BEFORE_SWAP_RETURNS_DELTA hook: MARG's hook 0xf0457dD0...a0cc carries flags 0x20cc = beforeSwap, afterSwap, beforeSwapReturnsDelta, afterSwapReturnsDelta; verified from mainnet bytecode permission bits) can take the index's input and return nothing without moving slot0, and the rebalance records held -= amountIn, idleImd += 0. _mintFirst refuses out == 0 (BuyFailed) and redeemToImd lets the redeemer set minImdOut, but _rebalance has no floor at all, not even out > 0. Impact: up to the leaver's full holding (step 1 sells all of it, limited only by price) or idleImd / listCount per list coin (step 4) is lost to the pool/hook with no event other than Swapped. Precondition: a pool or hook that pays nothing for the index's swap, which the brief lists as an untrusted actor but accepts as 'a pool's own hook fee'; hence low, documented not redesigned. A minimal mitigation that keeps the design is to skip a rebalance swap whose out == 0 (treat as SwapSkipped), mirroring _mintFirst.","line":530,"path":"src/Imdex5.sol","reproduction":"test/scratch/Econ.t.sol test_rebalanceSaleWithZeroOutputIsBooked: alice mintFirst(1000e18); the leaver (coin 5, tokens[4]) pool is set to pay nothing for the index's sale (mock pm.setShortBy(key, 2^128-1), i.e. a hook that keeps the output); the list drops coin 5 (_deliverList(_launches(4))); bob calls rebalance(). Observed: held[coin5] 19511716834983821943327 -> 9607794782811941356897 (9,903.9 coin5 sent to the pool), idleImd 0 -> 0: nothing arrived for it, no revert, no SwapSkipped. Expected: a sale that returns nothing is skipped (as _mintFirst reverts a buy that returns nothing) so the coin stays held for the holders.","severity":"low","snippet":"            held[coin.token] -= amountIn;\n            idleImd += out;","title":"Rebalance books a sale or buy that returns nothing: a leaver's whole holding can leave for zero IMD"},{"citation":"resolved","description":"For a residual coin with a transfer tax (SwarmCity, 2% on transfers out of the PoolManager, in the starting list), every mint delivers got = 0.98 * need and charges the 2% shortfall at slot0 read after the buy. slot0 after the buy is the pool's current price, which the minter can move down in the same block (sell the coin into the pool, mint, buy back) or set outright when the minter owns the pool's liquidity. THREAT_MODEL says 'moving it first costs the mover what the buy returns'; that holds for an outside sandwicher on a fee-charging pool, but not for the pool's own LP, and in any case the holders' loss is real while the minter's cost goes to the pool. The loss is bounded to the shortfall fraction (the tax, 2%) of the residual fraction minted, so it is low; documented, not redesigned. A design-preserving mitigation would charge the shortfall at max(price before the buy, price after), or at the average price the buy actually paid (rIn / got), which the minter cannot push below what they paid.","line":418,"path":"src/Imdex5.sol","reproduction":"test/scratch/Econ.t.sol test_taxedResidualShortfallChargedAtDumpedPrice: coin 5 is etched as PoolTaxERC20 (2% tax out of the PoolManager); alice mintFirst(1000e18); the list drops coin 5 and rebalance leaves a residual held = 9217560446112264918031 at fair price ~0.0102 IMD; the residual pool's price is moved down 1000x (pm.setPool then _setPool with 1000x coin reserve); bob mint(supply=995e18, 100000e18, 0). Observed: minted 995e18 (no short fill on list coins), got 9033209237190019619671, shortfall 184351208922245298360 units, charged 1843546075060584 wei IMD (0.0018 IMD) into idleImd versus fair value 1879453402595999999 wei (1.88 IMD) of the shortfall. Holders' idle gains 0.0018 IMD for 184 coin units (1.88 IMD) that the new shares now own half of. Expected: the shortfall is charged at no less than the price the pool actually traded at for the units it did deliver (rIn/got), which the minter cannot lower by dumping first.","severity":"low","snippet":"                if (got < need) {\n                    charged += _amountValue(\n                        coin.token, need - got, _sqrtPrice(_key(coin.token, coin.hook)), Math.Rounding.Ceil\n                    );\n                }","title":"Residual short fill is charged at the pool's marginal price after the buy, which a minter who dumped the pool first keeps low; holders lose the tax fraction of the residual"},{"citation":"resolved","description":"mintFirst is the only path at supply 0 and is first-come. Any observer can front-run the launch's first mint with mintFirst(1_000_000 wei) (fee 5,000 wei, 199,000 wei per coin, each buy returns nonzero coin units), setting supply to 995,000 wei; the intended first mint then reverts NotFirstMint and must be resubmitted as mint(shares, maxImdIn, minShares), which prices every coin at the pools' spot (the same pools, so no value loss, but a different call with different arguments and a failed transaction's gas). No holder dilution: mint rounds need up and tracks held internally, so the dust holder cannot inflate the share price by donating. Information only; the brief's first-mint rule is as designed.","line":179,"path":"src/Imdex5.sol","reproduction":"test/scratch/Econ.t.sol test_firstMintFrontRunWithDust: bob mintFirst(1_000_000, zeros(5)) succeeds with totalSupply 995000 wei; alice's mintFirst(1000e18, zeros(5)) reverts NotFirstMint. Expected (by design): the first caller wins; noted so the launch's first mint is sent with that in mind.","severity":"info","snippet":"        if (totalSupply() != 0) revert NotFirstMint();","title":"The first mint can be front-run with a dust mintFirst, making the intended first mint revert NotFirstMint"},{"citation":"resolved","description":"The 3bd5e1aa fix makes a residual whose buy reverts fail the whole mint. The documented way out is 'the pool works again or a rebalance sells the residual', but the rebalance's _trySell goes through the same hook and is skipped when it reverts, so a hook that rejects swaps whose sender is the index (a hook may read msg.sender of the PoolManager's callback) leaves a residual that can never be sold and a mint that never succeeds. redeem and redeemToImd keep paying it in kind, so no funds are lost; the index just cannot grow again. This is the accepted trade-off of the medium fix (spot settlement was worse) and is listed in THREAT_MODEL under 'deliberately not findings'; recorded here only because the acceptance text says 'until', while the block has no end when the hook discriminates by sender. Information.","line":415,"path":"src/Imdex5.sol","reproduction":"test/scratch/Perm.t.sol test_residualHookRejectingIndexBlocksMintAcrossRebalances (passes on this code, demonstrating the state): alice mintFirst(1000e18); list drops MARG (1283) so its limited sale leaves a residual held = heldM; MARG's hook is set to burn all gas only when the swap sender is the index (ReentrantHook.setMisbehave(MISBEHAVE_BURN, index)); bob mint(10e18, 1000e18, 0) reverts BuyFailed(MARG). Seven days later the same four-coin list is delivered and rebalance() runs: the residual's sale is skipped (SwapSkipped), held[MARG] == heldM, coins().length == 5; bob's mint reverts BuyFailed(MARG) again; alice's full redeem still pays the residual in kind (held -> 0). Expected per the documentation: a rebalance sells the residual and mint resumes; actual: while the hook rejects the index, no rebalance can sell it and mint never succeeds. No funds lost; information.","severity":"info","snippet":"                } catch {\n                    revert BuyFailed(coin.token);\n                }","title":"A residual whose hook rejects only the index's swaps blocks mint permanently, since the rebalance cannot sell it either"}],"hash":"e12e0170c9e65b34fb395773a98c9284575c3cc1a624f60debff881e4060ad0e","nodeId":"8a98bcbd-e26c-4133-bdbc-0af15063b137","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds 4 findings plus a 20-row coverage record. No repository file was changed; the findings file and `test/scratch/` are git-ignored.\n\n**Outcome: no medium-or-higher defect in the economics.** I traced every writer of the three accounting invariants (IMD balance equals idle plus fee plus owed, coin balance equals held plus owed, no per-share coin dilution on mint) and each holds on every path, including reverted mints, short fills, taxed coins, failed payments and the last-holder paths of both redeems. The oracle path rejects expired and under-quorum answers and cannot be replayed, since the answer hash is cleared before the effect and a new ask clears a stale one.\n\n**Findings, all low or informational, each with a mock reproduction run here:**\n\n- **Low, rebalance books a zero-output swap** at `src/Imdex5.sol:530`. A leaver's sale that returns nothing is recorded as sold: in the test, half the holding (9,904 coins) left for 0 IMD with no revert or skip. The 2% limit only binds when the pool price moves; a delta-returning hook does not move it, and MARG's hook carries those permission bits (checked from mainnet bytecode). The brief accepts hook fees, so this is documented, with a design-preserving fix of skipping swaps whose output is zero, as the first mint already does.\n- **Low, residual shortfall charged at a dumpable price** at `src/Imdex5.sol:418`. With a 2% taxed residual and its pool dumped 1000x before the mint, the shortfall worth 1.88 IMD was charged at 0.0018 IMD. Loss is bounded to the tax fraction of the minted residual part. Suggested fix charges at the average price the buy actually paid.\n- **Info, dust front-run of the first mint** at line 179. No value loss, but the launch's first mint should expect it.\n- **Info, residual with a sender-discriminating hook blocks mint permanently** at line 415. Confirmed across a second rebalance; redeems keep paying. Already an accepted trade-off of the earlier medium fix.\n\n**Coverage:** all 17 entry points answered, 14 hold, 3 carry findings, none unreached. Not reached in depth: mainnet fork behaviour of the MARG hook's fee logic (no owner selector found, fee policy unverified), which is why finding 1 stays low rather than medium.","treeHash":null,"usage":{"cachedInputTokens":2022790,"inputTokens":452,"model":"claude-fable-5-1","outputTokens":51618,"runtime":"claude","turns":29,"wallClockMs":961265}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f9a12c57a094ca8d","findings":[{"citation":"resolved","description":"Fix 886e7c22 made a residual (a coin that left the list and is not yet sold) never block `mint`: `_mintMore` buys what the residual's pool gives and charges the rest at the pool's spot price (`_sqrtPrice`, slot0 read now) into `idleImd`. When the residual's `swapSelf` *reverts* (the `catch` branch: a hook that rejects the index's swap, a swap path that needs more than `SWAP_GAS` = 1,000,000 gas, or a hook leaving a delta so `BadDelta` fires) `got` is 0 and the minter is charged `need` at whatever the spot price is at that moment. Nothing bounds that price: it is the state of a thin pool that anyone can move in the same block (or the same transaction, since the minter may be a contract). The minter still receives shares backed pro rata by the untouched `held[residual]`, so the holders' residual coins are shared with the new shares for almost nothing. The successful-swap path is safe (a pool is path-independent, so dumping then letting the mint buy nets the attacker only fees) and the partial-fill path reverts (v4 leaves the price at the sqrt limit, so the charge is astronomical and `TooExpensive` fires); only the revert path is exposed, and it is the only path on which the 'never blocks mint' guarantee is actually delivered for a non-taxed coin. Concrete economics: residual holding worth R IMD at the fair price, attacker dumps the residual pool by factor k (cost about 2.5% of the dump volume, recovered on the re-buy), makes the index's buy revert, mints `shares = totalSupply` and is charged R/k instead of R; holders lose R*(1-1/k)/2. The threat model accepts 'a thin residual pool can be moved' on the grounds that 'moving the price costs the mover', which holds for the successful-buy path but not for this one, where the mover pays only pool fees and gas. Minimal fix: do not settle a residual whose buy reverted at spot: `revert BuyFailed(coin.token)` in the `catch` (a residual then blocks mint only while its pool rejects swaps outright, which the threat model already accepts for a dead list coin, and the taxed-coin shortfall keeps the spot charge since the pool just traded at that price). Alternatives that keep mint unblocked (a stored reference price) can themselves be set low by sandwiching the public `rebalance`, so they are not recommended as the smallest change. The proof test models the revert with a mock pool whose swap reverts while its slot0 still reads; on mainnet the same state is a hook rule or a swap that cannot finish inside SWAP_GAS (about 100 initialized ticks of dust liquidity between the dumped price and the fair price cost more than 1,000,000 gas to cross).","line":414,"path":"src/Imdex5.sol","reproduction":"State: alice is the only holder (mintFirst 1,000 IMD, ~199 IMD of each of five coins); the oracle lists four coins; `rebalance` sells part of coin 5 and keeps the rest as a residual (listCount 4, coins().length 5, held[coin5] worth ~98 IMD at the pool price 0.01 IMD/coin). Attacker: dump coin 5's pool so the spot price is 1/1000 of before, and make the index's buy of coin 5 revert (mock: pool.dead = true; slot0 still readable). Then `mint(shares = totalSupply, maxImdIn = 100,000e18, minShares = 0)` from bob. Actual: the mint succeeds, bob gets 100% of the previous supply (half the index), held[coin5] is unchanged, and idleImd grows by 0.098 IMD for the residual half (plus bob's idle share); bob paid 944 IMD for a half-index whose fair value includes 49 IMD of the residual; alice's claim on the residual halves and she is compensated with 0.098 IMD. Expected: the mint reverts, or the charge is at least the residual half's fair value (~98 IMD at the undisturbed price). Run: forge test --match-path test/scratch/ResidualSpotCharge.t.sol -vv (fails now; passes with `revert BuyFailed(coin.token)` in the catch branch at src/Imdex5.sol:411-413).","severity":"medium","snippet":"                if (got < need) {\n                    charged += _amountValue(\n                        coin.token, need - got, _sqrtPrice(_key(coin.token, coin.hook)), Math.Rounding.Ceil\n                    );","title":"A failed residual buy in mint is settled at the residual pool's movable spot price, so a minter can take the residual's value from holders"},{"citation":"resolved","description":"The residual buy is an exact-output swap with the price limit at MIN_SQRT_PRICE+1 or MAX_SQRT_PRICE-1. In Uniswap v4 an exact-output swap that the pool cannot fill does not revert: it fills what it can and leaves `slot0.sqrtPriceX96` at the limit. `_mintMore` then charges `need - got` at that limit price: `_amountValue` with sqrtP = 4,295,128,740 (or 1.46e48) values one wei of the coin at about 3.4e38 IMD, so `total > maxImdIn` and the mint reverts `TooExpensive`. The same happens whenever `need` exceeds the coin the pool can still deliver (a large mint against a thin residual pool, or a pool whose LP withdrew its concentrated liquidity on the buy side). The README (lines 216-219) and THREAT_MODEL.md still describe the pre-fix behaviour (dead pool -> every mint reverts) and the post-fix guarantee (never blocks) inconsistently. The mock PoolManager does not reproduce v4's limit-price semantics on a partial fill (it leaves the price where the fill stopped), so the existing suite cannot see this. Document the bound (a mint can request at most what the residual pool can deliver) or, together with the medium fix, treat `got < need` with `got == 0` as `BuyFailed`.","line":405,"path":"src/Imdex5.sol","reproduction":"Mainnet state: coin X is a residual with held[X] = 1,000 X; its v4 pool has 500 X of liquidity on the buy side. Bob calls mint(shares = totalSupply, maxImdIn = 1e24, minShares = 0): the exact-output swap for need = 1,000 X delivers 500 X and leaves sqrtPriceX96 at the limit; charged = _amountValue(X, 500e18, 4295128740, Ceil) ~ 1.7e56 IMD; total > maxImdIn; revert TooExpensive. Every mint of that size reverts until the pool is refilled or a rebalance sells the residual. Expected per THREAT_MODEL.md: 'A residual never blocks mint'.","severity":"low","snippet":"                try this.swapSelf{gas: SWAP_GAS}(coin.token, coin.hook, true, need, true, false) returns (","title":"'A residual never blocks mint' holds only for a taxed coin or a reverting pool: a residual pool with no liquidity left in the buy direction still blocks every mint through TooExpensive"},{"citation":"resolved","description":"`need` for every coin, including residuals processed after the list, is `held * shares / supply`. When a list coin fills short, `minted` is reduced, but the residual still buys (or is charged for) `held * shares / supply`, a larger fraction than the `minted` shares own. The excess coin or IMD stays with existing holders (the README accepts this for coins 'bought beyond the issued fraction'), but for a residual the charge into idleImd is pure overpayment by the minter with no price floor from `minShares`. Document, or compute residual `need` from `minted` (residuals come after the list, so `minted` is final by then).","line":398,"path":"src/Imdex5.sol","reproduction":"supply 1,000 shares, held[A] (list) = 1,000 A, held[R] (residual) = 1,000 R at 1 IMD each. A's pool is bounded so a request for 500 A delivers 250 A. mint(shares = 500, maxImdIn = large, minShares = 0): minted = 250; the residual loop still buys need = 500 R (or charges 500 IMD if its buy reverts). Actual: the minter pays for 500 R and gets 250 shares that own 250 R. Expected: the residual fraction follows the shares issued (250).","severity":"low","snippet":"            uint256 need = Math.mulDiv(held[coin.token], shares, supply, Math.Rounding.Ceil);","title":"Residual and idle charges use the requested `shares` even after a list coin's short fill reduced `minted`, so the minter overpays for the residual fraction"},{"citation":"resolved","description":"Since fix 886e7c22, `submit` calls `_verifyAttestation`, which reverts `AttestationExpired` past `expiresAt` and `AttestationNotYetValid` for an `issuedAt` more than five minutes ahead, and requires `agreed >= 4` in the signed struct. README.md lines 223-226 state the opposite. README.md lines 216-219 say a leftover whose pool is dead makes every `mint` revert, while `_mintMore` now skips a reverting residual buy and charges spot. The adapter and the next audit read the README as the rules; it should match the code.","line":223,"path":"README.md","reproduction":"Read README.md:223-226 and src/Imdex5.sol:314 (`_verifyAttestation(a, signature)`), and README.md:216-219 against src/Imdex5.sol:400-419. Expected: the documentation describes the shipped behaviour.","severity":"info","snippet":"`submit` checks only the stored hash and the signature, as the brief asks, not the attestation's","title":"README still says submit does not check expiresAt and that a residual with a dead pool reverts every mint; both are no longer what the code does"},{"citation":"resolved","description":"`submit` accepts any attestation signed for this consumer, inside its window, with agreed >= 4, whose answer bytes hash to the stored `answerHash`. It does not compare `a.requestId` with `openRequest` or `a.questionHash` with the hash of `body()`. Because the stored hash comes only from the Intake's callback for this contract's own request, the list adopted is always the one the Intake delivered, so there is no change of outcome; a still-valid earlier attestation with byte-identical answer is interchangeable. Noted for completeness: if a future Intake version ever accepts a request body naming this contract as consumer from a third party, the request-id check would be the remaining defence. No change needed now.","line":311,"path":"src/Imdex5.sol","reproduction":"Deliver answer A for request R1 (onOracleResult from the Intake). Present an attestation for a different requestId R0 with the same `answer` bytes, agreed 5, signed by the oracle for this contract and unexpired. Actual: accepted. Expected under the current design: identical list, so acceptable; a stricter consumer would require a.requestId == openRequest.","severity":"info","snippet":"        if (answerHash == 0 || keccak256(a.answer) != answerHash) revert WrongAnswer();","title":"submit binds the attestation to the delivered answer only, not to the open request id or question hash"},{"citation":"resolved","description":"`ask` subtracts ORACLE_PRICE + REWARD from `feeImd`, approves the Intake for ORACLE_PRICE and calls `requestWithFailure`. The accounting invariant (IMD balance == feeImd + idleImd) relies on the Intake pulling exactly ORACLE_PRICE inside that call. The Intake at 0xa43e...DE82 could not be read in this review (no fork RPC), so this is a stated trust assumption rather than a defect: if it pulled less, the difference would sit in the contract unaccounted (not lost, but unreachable), and the approval would remain spendable later.","line":257,"path":"src/Imdex5.sol","reproduction":"Mock Intake whose requestWithFailure pulls 0: after ask(), imd.balanceOf(index) == feeImd + idleImd + 0.5e18 and allowance(index, INTAKE) == 0.5e18. Expected on mainnet: the Intake pulls exactly 0.5 IMD in the same call (the mock in test/mocks/Mocks.sol does).","severity":"info","snippet":"        IERC20(IMD).forceApprove(INTAKE, ORACLE_PRICE);","title":"ask() debits feeImd by the oracle price before the Intake pulls it; an Intake that pulls less leaves unaccounted IMD and a dangling approval"}],"hash":"f0cf3cfd6ca13d32a6312da2faeb0aa31585247d48bc8c5b83d90e5fbf28d783","nodeId":"082e0614-f6c5-4513-ad2e-066548020325","outcome":"completed","summary":"Review complete. Findings are in `.imd-findings.json` (one medium, two low, three info), all with path, line and snippet verified against the tree. The git tree is unchanged; only the ignored findings file and `test/scratch/` were created.\n\n**Scope read.** All three source files were read in full: `src/Imdex5.sol`, `src/OracleAttestation.sol`, `src/Interfaces.sol`, plus THREAT_MODEL.md, the README's mint, redeem, oracle, rebalance and security sections, the test base and mocks, and the two protected tests. The 139 unit and fuzz tests pass here. Not reached: the live Uniswap v4 PoolManager, the two launch hooks, the registries and the Intake (no fork RPC), so the slot-6 and nonzero-delta constants, hook behaviour and the Intake's exact pull are checked against known v4 values and the mocks only. The 8 fork tests were not run.\n\n**Medium: a failed residual buy in `mint` is settled at the residual pool's movable spot price** (`src/Imdex5.sol:414`). When the residual's `swapSelf` reverts, the minter is charged the whole `need` at the pool's current slot0 price, which anyone can move first. Holders' residual coins are then shared with the new shares for nearly nothing. The successful-swap path is safe through pool path independence, and a partial fill reverts through an astronomical limit-price charge, so only the revert path is exposed. The proof `test/scratch/ResidualSpotCharge.t.sol` is self-contained and fails now:\n\n```\nbob charged for residual (IMD): 0.098   fair value: 98 IMD   holders diluted\n```\n\nIt passes with the minimal fix, verified by temporarily applying `revert BuyFailed(coin.token)` in the catch branch and restoring the file. The mock models the revert with a dead pool whose price still reads; on mainnet that state is a hook rule or a swap path that needs more than the 1,000,000 gas budget.\n\n**Low findings, documented not redesigned.**\n- The \"a residual never blocks mint\" guarantee fails when the residual pool has no buy-side liquidity: v4 leaves the price at the sqrt limit on a partial exact-output fill, so the charge is about 3.4e38 IMD per wei and `TooExpensive` fires (`src/Imdex5.sol:405`). The mock cannot show this.\n- Residual `need` follows the requested `shares` even after a list coin's short fill reduced `minted`, so the minter overpays for the residual fraction (`src/Imdex5.sol:398`).\n\n**Info.** README lines 216 to 226 still describe pre-fix behaviour (no expiry check in `submit`, dead-pool residual reverting every mint). `submit` binds to the delivered answer, not the request id or question hash, which is harmless under the Intake binding. `ask` debits the oracle price before the Intake pulls it, a trust assumption on the unreachable Intake.\n\n**Attacked without a finding.** Minting below `minShares` is blocked by the check at line 429. A reverted mint returns the IMD because the pull and the unlock share one transaction. `held` matches balances on every path traced, including taxed coins, which fail `BadDelta` on sale and are measured by balance diff on purchase. Redeem never blocks: failures become `owed`. Expired, future-dated or under-quorum attestations revert in `_verifyAttestation` and the `agreed` check at line 313. Reentrancy is closed by the guard, the pool-manager check on `unlockCallback` and the self-check on `swapSelf`.","treeHash":null,"usage":{"cachedInputTokens":1435550,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":54137,"runtime":"claude","turns":25,"wallClockMs":1045324}}],"verification":[{"checks":[{"durationMs":162262,"exitCode":0,"name":"build","output":"Compiling 66 files with Solc 0.8.26\nSolc 0.8.26 finished in 162.08s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/Imdex5.sol:602:5:\n    |\n602 |     function _amountValue(address token, uint256 amount, uint256 sqrtP, Math.Rounding r)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/Fix3.fork.t.sol:76:5:\n   |\n76 |     function _checkBacked(Imdex5.Coin[] memory cs, string memory when) internal {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/Fix3Rebalance.fork.t.sol:44:5:\n   |\n44 |     function _backed(string memory when) internal {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":90601,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/Fix3.fork.t.sol:Fix3ForkTest\n[SKIP] test_fixed_with_1000_IMD() (gas: 0)\n[SKIP] test_fixed_with_100_IMD() (gas: 0)\n[SKIP] test_fixed_with_10_IMD() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 721.50µs (119.96µs CPU time)\n\nRan 3 tests for test/Fix3Rebalance.fork.t.sol:Fix3RebalanceForkTest\n[SKIP] test_dropTheTaxedCoin_fourRemain() (gas: 0)\n[SKIP] test_reorderSameFive() (gas: 0)\n[SKIP] test_shrinkToThree_bigFund() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 720.06µs (90.06µs CPU time)\n\nRan 1 test for test/Fix3Floor.fork.t.sol:Fix3FloorForkTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 727.19µs (0.00ns CPU time)\n\nRan 2 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_callbackSelectorIsCanonical() (gas: 4542)\n[PASS] test_digestMatchesTheProtocol() (gas: 13358)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.25ms (114.20µs CPU time)\n\nRan 9 tests for test/Imdex5ShortFill.t.sol:Imdex5ShortFillTest\n[PASS] testFuzz_mintUsesTheLeastFilledCoinAndChargesEveryBuy(uint256,uint16[5]) (runs: 256, μ: 1633862, ~: 1641383)\nLogs:\n  Bound result 479319975029788206071\n  Bound result 1\n  Bound result 10\n  Bound result 21\n  Bound result 1352\n  Bound result 109\n\n[PASS] test_fullFillPassesFloor() (gas: 742398)\n[PASS] test_mintRevertsAndRollsBackEarlierBuysWhenACoinDeliversZero() (gas: 1286732)\n[PASS] test_mintRevertsWhenANonzeroFillRoundsSharesToZero() (gas: 1196107)\n[PASS] test_shortFillChargesIdleImdForTheSharesIssuedOnly() (gas: 2600194)\n[PASS] test_shortFillMintsTheDeliveredFraction() (gas: 868257)\n[PASS] test_shortFillStillEnforcesMaxImdInAndRollsBack() (gas: 1739642)\n[PASS] test_sliverFillBelowFloorRevertsAndRollsBack() (gas: 1192319)\n[PASS] test_sliverFillWithoutFloorIssuesASliver() (gas: 1286570)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 336.78ms (339.36ms CPU time)\n\nRan 48 tests for test/Imdex5.t.sol:Imdex5Test\n[PASS] testFuzz_mintThenRedeemNeverPaysMoreThanDeposited(uint256,uint256) (runs: 256, μ: 2402243, ~: 2412435)\nLogs:\n  Bound result 4999033965134907737473\n  Bound result 4974038795309233198785\n\n[PASS] test_askPaysIntakeAndCaller() (gas: 1137820)\n[PASS] test_askReturnsWithoutFees() (gas: 155189)\n[PASS] test_askSevenDayInterval() (gas: 1189679)\n[PASS] test_bodyIsTheJsonTheBriefDescribes() (gas: 30573)\n[PASS] test_closeRequestAfterTwoDays() (gas: 1027162)\n[PASS] test_deployment() (gas: 94831)\n[PASS] test_feeImdOnlyLeavesForOracleAndRewards() (gas: 4930320)\n[PASS] test_fundAddsToFeeImd() (gas: 147750)\n[PASS] test_hookCannotReenter() (gas: 5142465)\n[PASS] test_mintBuysProportionallyAndRefunds() (gas: 1830201)\n[PASS] test_mintFirstBuysEqualPartsAndTakesFee() (gas: 1104043)\n[PASS] test_mintFirstKeepsWhatAPoolCouldNotTakeAsIdle() (gas: 1324714)\n[PASS] test_mintFirstRequiresZeroSupplyAndRightLength() (gas: 1022021)\n[PASS] test_mintFirstRevertsOnMinOut() (gas: 727109)\n[PASS] test_mintFirstRevertsWhenABuyFails() (gas: 814471)\n[PASS] test_mintFirstRevertsWhenABuyReturnsNothing() (gas: 2113122)\n[PASS] test_mintNeverIssuesSharesForNothing() (gas: 327985)\n[PASS] test_mintRequiresSupply() (gas: 40062)\n[PASS] test_mintRevertsOverMaxImdIn() (gas: 1732850)\n[PASS] test_mintRevertsWhenABuyFailsButScalesANonzeroShortFill() (gas: 2275588)\n[PASS] test_mintRoundsAgainstTheMinter() (gas: 1711530)\n[PASS] test_onOracleFailureOnlyFromIntake() (gas: 1064889)\n[PASS] test_onOracleResultStoresOnlyTheOpenRequestFromTheIntake() (gas: 1302614)\n[PASS] test_rebalanceNeedsAList() (gas: 41318)\n[PASS] test_rebalanceSellsAdoptsAndBuys() (gas: 5261907)\n[PASS] test_rebalanceSkipsADeadPool() (gas: 2983154)\n[PASS] test_rebalanceSkipsAHookThatLeavesAnUnsettledDelta() (gas: 3880126)\n[PASS] test_rebalanceSurvivesAHookThatBurnsAllGas() (gas: 5495285)\n[PASS] test_rebalanceTrimsAHoldingOverAQuarter() (gas: 3461572)\n[PASS] test_rebalanceWithNothingHeld() (gas: 2266050)\n[PASS] test_redeemCannotBeBlockedByACoin() (gas: 1575554)\n[PASS] test_redeemLastSharesPaysEverything() (gas: 2144299)\n[PASS] test_redeemPaysInKindLessHalfPercent() (gas: 1347307)\n[PASS] test_redeemRejectsZeroAndTooMany() (gas: 986033)\n[PASS] test_redeemSurvivesCoinsThatBurnAllGas() (gas: 4399409)\n[PASS] test_redeemToImdChargesTheFeeWhileOthersHold() (gas: 1668651)\n[PASS] test_redeemToImdPaysAShortFillInKindLessHalfPercent() (gas: 1780655)\n[PASS] test_redeemToImdPaysInKindWhenASaleFails() (gas: 2968070)\n[PASS] test_redeemToImdRevertsBelowMinOut() (gas: 1783406)\n[PASS] test_redeemToImdSellsAndTheLastHolderPaysNoFee() (gas: 1751812)\n[PASS] test_redeemToImdSurvivesAHookThatBurnsGas() (gas: 2457600)\n[PASS] test_submitRejectsASignedAttestationWithoutQuorum() (gas: 1128741)\n[PASS] test_submitRejectsAnExpiredAttestation() (gas: 1089458)\n[PASS] test_submitRejectsBadLists() (gas: 4717094)\n[PASS] test_submitRejectsWrongAnswerAndForgedSignature() (gas: 1645920)\n[PASS] test_submitStoresTheNextListAndRewards() (gas: 1527045)\n[PASS] test_unlockCallbackAndSwapSelfAreNotCallable() (gas: 103370)\nSuite result: ok. 48 passed; 0 failed; 0 skipped; finished in 600.92ms (770.73ms CPU time)\n\nRan 26 tests for test/Imdex5Revised.t.sol:Imdex5RevisedTest\n[PASS] testFuzz_mintFirstKeepsAPartialFillIdle(uint256,uint256) (runs: 256, μ: 1103697, ~: 1103692)\nLogs:\n  Bound result 33965134907737472\n  Bound result 6759061846639756\n\n[PASS] testFuzz_redeemToImdPaysADeadCoinExactlyAsRedeemDoes(uint256) (runs: 256, μ: 1991239, ~: 1995835)\nLogs:\n  Bound result 356401548816689025405\n\n[PASS] testFuzz_redeemToImdPaysAShortFillInKindUnderTheRedeemRule(uint256,uint256) (runs: 256, μ: 1827002, ~: 1828801)\nLogs:\n  Bound result 753612501597462832046\n  Bound result 6830\n\n[PASS] test_aCoinThatBurnsItsGasIsOwedAndTheIdleImdStillPaid() (gas: 1632521)\n[PASS] test_askAndCloseAtTheirExactBoundaries() (gas: 1205484)\n[PASS] test_askIsBlockedWhileAListAwaitsRebalance() (gas: 3288904)\n[PASS] test_claimThatFailsKeepsTheDebt() (gas: 1296876)\n[PASS] test_hookCannotCallSwapSelfOrTheOracleCallbacks() (gas: 3481850)\n[PASS] test_hookCannotCloseOrAnswerTheOpenRequestDuringASwap() (gas: 4132057)\n[PASS] test_lastRedeemerToImdTakesAllOfADeadCoin() (gas: 1750522)\n[PASS] test_margUsesItsOwnHookAndTheOthersShareG() (gas: 48913)\n[PASS] test_mintFirstPartialFillIsRedeemedProRataNotTwice() (gas: 1658725)\n[PASS] test_mintFirstRefusesAPoolThatReturnsNothingOnALargeAmount() (gas: 744323)\n[PASS] test_mintFirstRefusesDustThatBuysNothing() (gas: 2164280)\n[PASS] test_mintFirstRevertsWholeWhenTheHookMisbehaves() (gas: 992464202)\n[PASS] test_mintRevertsWholeWhenTheHookBurnsGasForTheIndex() (gas: 993092341)\n[PASS] test_mintRevertsWholeWhenTheHookLeavesADeltaUnsettled() (gas: 1344666)\n[PASS] test_mintSkipsAListCoinHeldAtZeroAndTheNextRebalanceBuysIt() (gas: 5541187)\n[PASS] test_onOracleResultNeedsExactlyFourAgreed() (gas: 1159008)\n[PASS] test_owedAccumulatesAcrossRedeemsAndIsPaidOnce() (gas: 2200097)\n[PASS] test_rebalanceSkipsEveryBurningSwapAndStillAdoptsTheList() (gas: 3728449)\n[PASS] test_redeemSurvivesFiveGasBurningCoinsWithOrdinaryGas() (gas: 5815403)\n[PASS] test_redeemToImdPaysInKindWhenTheHookLeavesADeltaUnsettled() (gas: 2231678)\n[PASS] test_submitRejectsALaunchWithoutAHookOrAToken() (gas: 1853595)\n[PASS] test_submitTakesAnAttestationOnce() (gas: 1461700)\n[PASS] test_submitUsesTheRegistryArtifactsNotTheStartingList() (gas: 1560383)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 688.79ms (1.03s CPU time)\n\nRan 7 tests for test/Imdex5TaxedCoin.t.sol:Imdex5TaxedCoinTest\n[PASS] testFuzz_taxedCoinLifecycle(uint256,uint256,uint256) (runs: 256, μ: 7860079, ~: 7865038)\nLogs:\n  Bound result 360930050014973385143\n  Bound result 321970452318407739623\n  Bound result 514248859715124976171\n\n[PASS] test_firstMintCreditsOnlyWhatArrives() (gas: 1252895)\n[PASS] test_firstMintMinOutChecksTheNetReceipt() (gas: 1358270)\n[PASS] test_lastHolderCanReceiveEveryCoinAfterAnImdExit() (gas: 2638525)\n[PASS] test_outstandingOwedIsNotCountedAsANewReceiptAndRemainsClaimable() (gas: 5186559)\n[PASS] test_taxedCoinFullLifecycle() (gas: 7853807)\n[PASS] test_taxedRebalanceBuyCreditsOnlyNewReceipts() (gas: 5580720)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 707.00ms (721.22ms CPU time)\n\nRan 35 tests for test/Imdex5Edges.t.sol:Imdex5EdgesTest\n[PASS] testFuzz_mintBuysExactlyTheRoundedUpShare(uint256) (runs: 512, μ: 1918206, ~: 1918030)\nLogs:\n  Bound result 7649\n\n[PASS] testFuzz_mintFirstMintsExactlyTheRest(uint256) (runs: 512, μ: 1007756, ~: 1011513)\nLogs:\n  Bound result 4000000000000000000015\n\n[PASS] testFuzz_onOracleResultForAnotherRequestIsIgnored(bytes32,uint16) (runs: 256, μ: 1028600, ~: 1028683)\n[PASS] testFuzz_onOracleResultFromAStrangerChangesNothing(address,bytes32,uint16) (runs: 256, μ: 1075426, ~: 1075635)\n[PASS] testFuzz_redeemNeverPaysAboveProRata(uint256,uint256) (runs: 512, μ: 1557658, ~: 1558156)\nLogs:\n  Bound result 4999020000000000000001\n  Bound result 128\n\n[PASS] testFuzz_splittingARedeemStaysUnderProRata(uint256,uint256) (runs: 256, μ: 1748386, ~: 1748840)\nLogs:\n  Bound result 887912176048210770809\n  Bound result 6830\n\n[PASS] test_aLaterAskReplacesAnUnsubmittedAnswer() (gas: 1887604)\n[PASS] test_aReenteringCoinCannotReenterAndIsNotPaidTwice() (gas: 2668691)\n[PASS] test_aReenteringCoinCannotReenterMintOrRebalanceFromRedeem() (gas: 3865512)\n[PASS] test_aThinResidualPoolDoesNotStarveAFlooredMint() (gas: 3594832)\n[PASS] test_anUnsubmittedAnswerDoesNotSurviveAFailedLaterAsk() (gas: 1356525)\n[PASS] test_askRevertsWholeWhenTheIntakeRefuses() (gas: 334213)\n[PASS] test_askThresholdIsExactlyThreeQuartersOfAnImd() (gas: 1101757)\n[PASS] test_closeRequestNeedsAnOpenOne() (gas: 1003747)\n[PASS] test_closingARequestDoesNotResetTheInterval() (gas: 1161894)\n[PASS] test_mintCannotBeFreeWhenTheIndexHoldsValue() (gas: 1767082)\n[PASS] test_onOracleResultAfterCloseIsIgnored() (gas: 1098689)\n[PASS] test_onOracleResultWithFiveEntriesFitsTheStipend() (gas: 1144000)\n[PASS] test_oneGasBurningCoinDoesNotBlockRedeemGivenGas() (gas: 1666458)\n[PASS] test_rebalanceBuyMovesAPoolAtMostTwoPercent() (gas: 3682417)\n[PASS] test_rebalanceBuyStopsAtAQuarterWeight() (gas: 4013413)\n[PASS] test_rebalanceDoesNotTrimWithFewerThanFourCoins() (gas: 3257627)\n[PASS] test_rebalanceSellMovesAPoolAtMostTwoPercent() (gas: 3286485)\n[PASS] test_rebalanceTrimsToAQuarterNotBelow() (gas: 3775227)\n[PASS] test_redeemHalfPercentStaysWithRemainingHolders() (gas: 1555463)\n[PASS] test_redeemIdleImdThatCannotBeSentIsOwed() (gas: 1393763)\n[PASS] test_redeemToATokenWithoutCodeBecomesOwedAndClaimableLater() (gas: 1265903)\n[PASS] test_residualsAreRedeemedAndADeadOneBlocksMintWithoutTakingImd() (gas: 5290738)\n[PASS] test_rewardsNeverDipIntoIdleImd() (gas: 2723895)\n[PASS] test_sharesTransferLikeAnyErc20AndMoveNoHoldings() (gas: 1462846)\n[PASS] test_submitAndRebalancePayNoRewardWithoutFees() (gas: 3243874)\n[PASS] test_submitRejectsATamperedAnswerEvenWithAValidSignatureElsewhere() (gas: 1142590)\n[PASS] test_submitRejectsAnAttestationSignedForAnotherChain() (gas: 1444342)\n[PASS] test_submitRejectsAnAttestationSignedForAnotherConsumer() (gas: 1109787)\n[PASS] test_submitRejectsMalformedAnswerBytes() (gas: 1347909)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 707.30ms (1.65s CPU time)\n\nRan 9 tests for test/Imdex5TaxEverywhere.t.sol:Imdex5TaxEverywhereTest\n[PASS] testFuzz_everyCoinTaxedLifecycle(uint16[5],uint256,uint256,uint256) (runs: 200, μ: 9131709, ~: 9136225)\nLogs:\n  Bound result 1\n  Bound result 778\n  Bound result 1115\n  Bound result 1381\n  Bound result 2827\n  Bound result 499000000000000005082\n  Bound result 499000000000404098527\n  Bound result 899000000000000011630\n\n[PASS] testFuzz_theMostTaxedCoinDecidesTheMint(uint8,uint16,uint16,uint256) (runs: 200, μ: 2671240, ~: 2707341)\nLogs:\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 499000000000000000098\n\n[PASS] test_aCoinTaxingItsOwnSettlementIsNeverSoldAndIsPaidInKind() (gas: 6635123)\n[PASS] test_aCoinTaxingItsOwnSettlementStaysAResidualThroughARebalance() (gas: 7210236)\n[PASS] test_aCoinThatKeepsEverythingFailsALaterMintWholeAndRedeemsStillPay() (gas: 6569197)\n[PASS] test_aCoinThatKeepsEverythingFailsTheFirstMintWhole() (gas: 1464541)\n[PASS] test_aCoinThatKeepsEverythingFailsTheOneWeiMint() (gas: 3414783)\n[PASS] test_aDonationNeitherChangesHeldNorInflatesAMintOrARedeem() (gas: 2474375)\n[PASS] test_taxOnTopOfAPartialFillCreditsTheNetAndMintsThatFraction() (gas: 5236267)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 891.25ms (1.52s CPU time)\n\nRan 21 tests for test/Imdex5MustAttack.t.sol:Imdex5MustAttackTest\n[PASS] testFuzz_dustMintsRoundAgainstTheMinter(uint256) (runs: 200, μ: 1914025, ~: 1914200)\nLogs:\n  Bound result 22508\n\n[PASS] testFuzz_heldTracksBalanceThroughEveryPath(uint16,uint256) (runs: 64, μ: 7840758, ~: 7853306)\nLogs:\n  Bound result 224\n  Bound result 1283\n\n[PASS] testFuzz_mintKeepsOnlyWhatItSpends(uint256,uint256) (runs: 200, μ: 2881823, ~: 2881832)\nLogs:\n  Bound result 10837816\n  Bound result 3449\n\n[PASS] testFuzz_mintNeverDilutesPerShare(uint256,uint256,uint256) (runs: 300, μ: 2981055, ~: 2997818)\nLogs:\n  Bound result 4\n  Bound result 1\n  Bound result 1974378574\n\n[PASS] testFuzz_mintNeverIssuesBelowTheFloor(uint256,uint256,uint256,uint256) (runs: 300, μ: 2176939, ~: 2212163)\nLogs:\n  Bound result 3\n  Bound result 32\n  Bound result 749999999999999999\n  Bound result 749999999999999205\n\n[PASS] testFuzz_redeemAlwaysPaysProRata(uint256,bool) (runs: 200, μ: 3356203, ~: 3297156)\nLogs:\n  Bound result 650486461166159682105\n\n[PASS] testFuzz_residualDumpedThenBoughtInFullDilutesNobodyInCoins(uint256,uint256) (runs: 100, μ: 4740792, ~: 4740887)\nLogs:\n  Bound result 999\n  Bound result 189000000000000000000\n\n[PASS] testFuzz_residualShortFillAtUndisturbedPriceDilutesNobody(uint16,uint256) (runs: 100, μ: 5214888, ~: 5214865)\nLogs:\n  Bound result 10\n  Bound result 189000000000000000000\n\n[PASS] testFuzz_underQuorumDeliveryIsIgnored(uint16) (runs: 50, μ: 1081361, ~: 1081454)\nLogs:\n  Bound result 0\n\n[PASS] test_answerOtherThanDeliveredIsRefused() (gas: 1126082)\n[PASS] test_callbackFromAnyoneElseIsIgnored() (gas: 1062537)\n[PASS] test_expiredAnswerNeverChangesTheList() (gas: 1455673)\n[PASS] test_floorAboveRequestAlwaysReverts() (gas: 1981011)\n[PASS] test_floorBoundaryIsExact() (gas: 3487052)\n[PASS] test_futureIssuedAnswerIsRefused() (gas: 1093115)\n[PASS] test_owedCoinsAreTheOnlyGapBetweenHeldAndBalance() (gas: 1740375)\n[PASS] test_redeemPaysWhenEveryCoinAndPoolMisbehaves() (gas: 4088826)\n[PASS] test_residualShortFillDoesNotCutSharesBelowFloor() (gas: 4811141)\n[PASS] test_revertedMintsTakeNothing_everyPath() (gas: 9266033)\n[PASS] test_underQuorumSignedAnswerNeverChangesTheList() (gas: 1092175)\n[PASS] test_wrongSignerAndReplayAreRefused() (gas: 1491573)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 891.36ms (5.05s CPU time)\n\nRan 6 tests for test/Imdex5ResidualSpot.t.sol:Imdex5ResidualSpotTest\n[PASS] testFuzz_aDeadResidualFailsTheMintAtAnyPrice(uint256,uint256) (runs: 256, μ: 4309611, ~: 4309599)\nLogs:\n  Bound result 737472\n  Bound result 1990000000000000000000\n\n[PASS] testFuzz_aDumpedResidualThatTradesIsBoughtInFull(uint256,uint256) (runs: 256, μ: 4304834, ~: 4304925)\nLogs:\n  Bound result 472\n  Bound result 995000000000000000000\n\n[PASS] test_aDumpedResidualWhoseBuyRevertsCannotBeMintedAtSpot() (gas: 4696640)\n[PASS] test_aResidualHookThatBurnsGasFailsTheMint() (gas: 5736996)\n[PASS] test_aResidualHookThatLeavesADeltaFailsTheMint() (gas: 4162296)\n[PASS] test_aResidualShortFillIsChargedAtLeastItsFairValue() (gas: 4140327)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 891.35ms (1.64s CPU time)\n\nRan 1 test for test/Imdex5TaxEverywhere.t.sol:Imdex5AllCoinsTaxedInvariantTest\n[PASS]\nImdex5AllCoinsTaxedInvariantTest invariants:\n[PASS] invariant_taxed_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_taxed_coinBalancesAreHeldPlusOwed\n[PASS] invariant_taxed_everyHoldingIsListed\n[PASS] invariant_taxed_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_taxed_zeroSupplyMeansNothingHeld\n Imdex5AllCoinsTaxedInvariantTest invariants (runs: 96, calls: 3840, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 215   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 217   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 230   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 213   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 431   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 214   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 239   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 213   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 224   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 196   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 222   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 193   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 191   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 208   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| TaxKnobs      | setTax           | 202   | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 47000000000000000000\n  Bound result 19\n  Bound result 10001\n  Bound result 8066\n  Bound result 20996\n  Bound result 2\n  Bound result 3691\n  Bound result 2000000000000000000000\n  Bound result 31337\n  Bound result 12716\n  Bound result 2940\n  Bound result 9337\n  Bound result 12345\n  Bound result 1322307\n  Bound result 936294420916058687643\n  Bound result 191787475000343521937\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.28s (2.27s CPU time)\n\nRan 1 test for test/Imdex5.invariant.t.sol:Imdex5InvariantTest\n[PASS]\nImdex5InvariantTest invariants:\n[PASS] invariant_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_coinBalancesAreHeldPlusOwed\n[PASS] invariant_feeImdLeavesOnlyForTheOracleAndRewards\n[PASS] invariant_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_listShape\n[PASS] invariant_noFreeMintWhileValueIsHeld\n[PASS] invariant_requestStateIsConsistent\n[PASS] invariant_zeroSupplyMeansNothingHeld\n Imdex5InvariantTest invariants (runs: 96, calls: 3840, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 178   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 214   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | closeRequest     | 210   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverFailure   | 210   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 202   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 187   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 398   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 199   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 218   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 250   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 180   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 211   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 196   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 192   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 200   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 189   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 190   | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3001\n  Bound result 13949\n  Bound result 128000\n  Bound result 499999999999999999801\n  Bound result 1983\n  Bound result 259200\n  Bound result 168623979896987713927\n  Bound result 1283\n  Bound result 633\n  Bound result 4315\n  Bound result 400887\n  Bound result 3394\n  Bound result 172800\n  Bound result 4285\n  Bound result 9160528332957214075891\n  Bound result 10001\n  Bound result 50\n  Bound result 3289\n  Bound result 27657485\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.94s (2.93s CPU time)\n\nRan 1 test for test/Imdex5Floor.invariant.t.sol:Imdex5FloorInvariantTest\n[PASS]\nImdex5FloorInvariantTest invariants:\n[PASS] invariant_heldIsTheRealBalance\n[PASS] invariant_mintNeverDilutesListCoinsOrIdle\n[PASS] invariant_noMintBelowTheFloor\n[PASS] invariant_noSharesMeansNothingHeld\n[PASS] invariant_redeemAlwaysPays\n[PASS] invariant_revertedMintMovesNothing\n Imdex5FloorInvariantTest invariants (runs: 128, calls: 5120, reverts: 456)\n\n╭--------------------+-------------+-------+---------+----------╮\n| Contract           | Selector    | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5FloorHandler | claim       | 483   | 0       | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | mint        | 1384  | 0       | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | mintFirst   | 489   | 0       | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | movePrice   | 454   | 0       | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | rebalanceTo | 456   | 456     | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | redeem      | 451   | 0       | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | redeemToImd | 436   | 0       | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | setMaxIn    | 488   | 0       | 0        |\n|--------------------+-------------+-------+---------+----------|\n| Imdex5FloorHandler | setTax      | 479   | 0       | 0        |\n╰--------------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 199000000000000000000\n  Bound result 2979\n  Bound result 17\n  Bound result 5457\n  Bound result 15545\n  Bound result 700\n  Bound result 4171\n  Bound result 383\n  Bound result 9305\n  Bound result 2774\n  Bound result 688604\n  Bound result 792754\n  Bound result 994999999999999990694\n  Bound result 980\n  Bound result 4294967295\n  Bound result 294\n  Bound result 2456\n  Bound result 2827\n  Bound result 14\n  Bound result 18\n  Bound result 7958\n  Bound result 242\n  Bound result 9257\n  Bound result 268\n  Bound result 12\n  Bound result 14\n  Bound result 99\n  Bound result 0\n  Bound result 2\n  Bound result 300\n  Bound result 3\n  Bound result 1742\n  Bound result 686998936330154333486039\n  Bound result 3\n  Bound result 9911\n  Bound result 1459\n  Bound result 563\n  Bound result 585\n  Bound result 1001\n  Bound result 1\n  Bound result 970299\n  Bound result 2\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.01s (4.00s CPU time)\n\nRan 1 test for test/Imdex5.invariant.t.sol:Imdex5TaxedCoinInvariantTest\n[PASS]\nImdex5TaxedCoinInvariantTest invariants:\n[PASS] invariant_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_coinBalancesAreHeldPlusOwed\n[PASS] invariant_feeImdLeavesOnlyForTheOracleAndRewards\n[PASS] invariant_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_listShape\n[PASS] invariant_noFreeMintWhileValueIsHeld\n[PASS] invariant_requestStateIsConsistent\n[PASS] invariant_zeroSupplyMeansNothingHeld\n Imdex5TaxedCoinInvariantTest invariants (runs: 256, calls: 128000, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 6718  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 6623  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | closeRequest     | 6870  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverFailure   | 6846  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 6826  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 6803  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 13419 | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 6820  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 6831  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 6698  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 6786  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 6591  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 6747  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 6661  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 6676  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 6628  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 6677  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 6780  | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1948279459872595484217\n  Bound result 752110275\n  Bound result 172800\n  Bound result 8835\n  Bound result 38810938075980998578\n  Bound result 750000000000000000\n  Bound result 16635\n  Bound result 1697532609\n  Bound result 43530627193678166891\n  Bound result 20174\n  Bound result 361556\n  Bound result 1305\n  Bound result 13\n  Bound result 552383986483686246\n  Bound result 1594617256\n  Bound result 691200\n  Bound result 250000000000000000\n  Bound result 2956\n  Bound result 10497\n  Bound result 80\n  Bound result 3591435838178500359581\n  Bound result 31337\n  Bound result 2633555362228097863846\n  Bound result 100000000000000000000\n  Bound result 807\n  Bound result 953186985\n  Bound result 2956\n  Bound result 448373551239569028659\n  Bound result 85911266903948174118\n  Bound result 22071\n  Bound result 1938538062571637158833\n  Bound result 95\n  Bound result 5\n  Bound result 12345\n  Bound result 550987\n  Bound result 18527113593816942971\n  Bound result 20\n  Bound result 3877076125143274317614\n  Bound result 2416834239762048934994\n  Bound result 371636861\n  Bound result 6659\n  Bound result 1633\n  Bound result 1023571680255820084873\n  Bound result 40\n  Bound result 14264337593543950336\n  Bound result 50000000000000000000\n  Bound result 36\n  Bound result 1\n  Bound result 5780\n  Bound result 850448119186131123508\n  Bound result 1071326568876807487076\n  Bound result 50000000000000000000\n  Bound result 415\n  Bound result 10100\n  Bound result 20726\n  Bound result 23006\n  Bound result 2892\n  Bound result 271413092188967988962\n  Bound result 2957397979\n  Bound result 1250517891\n  Bound result 14750\n  Bound result 4\n  Bound result 1123925216489101295729\n  Bound result 7898068231658186500857\n  Bound result 2094785305743711310654\n  Bound result 1734506410040964833337\n  Bound result 3170\n  Bound result 56487115291264184622\n  Bound result 13632\n  Bound result 14732\n  Bound result 5000\n  Bound result 1307715931579556096952\n  Bound result 6164\n  Bound result 18099\n  Bound result 1800000000\n  Bound result 1589\n  Bound result 2208115898131567519186\n  Bound result 481394542578861703372\n  Bound result 16891\n  Bound result 1808\n  Bound result 1245847749713451364919\n  Bound result 3465\n  Bound result 5\n  Bound result 230\n  Bound result 995000000000000000000\n  Bound result 2706776648380683983730\n  Bound result 32\n  Bound result 360660944\n  Bound result 1000000\n  Bound result 14915818222866739513\n  Bound result 5000\n  Bound result 490076\n  Bound result 3335669237430257793\n  Bound result 1843336625924681959\n  Bound result 3\n  Bound result 32954822965573246595\n  Bound result 100000000000000\n  Bound result 1522329087574283868318\n  Bound result 89523411\n  Bound result 603136\n  Bound result 90000000000000000000\n  Bound result 4244\n  Bound result 13887\n  Bound result 1206011551258662910848\n  Bound result 24\n  Bound result 283224\n  Bound result 1239591430292953511620\n  Bound result 2850730474493387521043\n  Bound result 671587915\n  Bound result 5\n  Bound result 97\n  Bound result 8586\n  Bound result 2000\n  Bound result 139027953588876168535\n  Bound result 9795\n  Bound result 12\n  Bound result 307199\n  Bound result 100000000000000000000\n  Bound result 9284\n  Bound result 8\n  Bound result 20000000000000000\n  Bound result 2\n  Bound result 15375\n  Bound result 21000000000000000\n  Bound result 30000000\n  Bound result 4784\n  Bound result 50000000000000000000\n  Bound result 22053\n  Bound result 1665765230811824344776\n  Bound result 50000000000000000000\n  Bound result 18884\n  Bound result 249\n  Bound result 14247\n  Bound result 855\n  Bound result 2970\n  Bound result 851\n  Bound result 200\n  Bound result 123000000000000000000\n  Bound result 659918\n  Bound result 624638639334879113\n  Bound result 6663779118241774121\n  Bound result 7839032744\n  Bound result 703925411261518837\n  Bound result 499999999999999999997\n  Bound result 203289172076171001287\n  Bound result 12454\n  Bound result 18331\n  Bound result 4450\n  Bound result 7294\n  Bound result 100\n  Bound result 4244\n  Bound result 5529230516486899440059\n  Bound result 9310\n  Bound result 19520\n  Bound result 21000000000000000\n  Bound result 519747808000691602\n  Bound result 20980\n  Bound result 9900\n  Bound result 9204226756301786945797\n  Bound result 365155468262211884\n  Bound result 18016\n  Bound result 1250000000000000000\n  Bound result 371636862\n  Bound result 6402\n  Bound result 59184867599014848\n  Bound result 8885\n  Bound result 10117\n  Bound result 48000000000000000000\n  Bound result 3\n  Bound result 300000\n  Bound result 204800\n  Bound result 542999\n  Bound result 30000000\n  Bound result 900\n  Bound result 16980\n  Bound result 77743803797300503\n  Bound result 24576\n  Bound result 3001\n  Bound result 5\n  Bound result 599796025732405\n  Bound result 21207\n  Bound result 551\n  Bound result 300000\n  Bound result 237290857027636800291\n  Bound result 0\n  Bound result 250000000000000000000\n  Bound result 19\n  Bound result 12501\n  Bound result 5158543369183268\n  Bound result 228681474080292323691\n  Bound result 795000000000000000000\n  Bound result 7429891598952176\n  Bound result 9116\n  Bound result 36123354462361165914\n  Bound result 400\n  Bound result 180494988157783212211\n  Bound result 3055356038390169185859\n  Bound result 152824361729742328289\n  Bound result 6161\n  Bound result 550263234503526376\n  Bound result 185792768511016276591\n  Bound result 99\n  Bound result 19387\n  Bound result 11824\n  Bound result 1282\n  Bound result 2474\n  Bound result 10537\n  Bound result 10000\n  Bound result 37000000000000000000\n  Bound result 6780\n  Bound result 125967040277133470970\n  Bound result 612642\n  Bound result 2\n  Bound result 13243\n  Bound result 5493\n  Bound result 41235539224657880483\n  Bound result 5\n  Bound result 1282\n  Bound result 6402\n  Bound result 207615780419589962\n  Bound result 8150\n  Bound result 426400\n  Bound result 1800000000\n  Bound result 417022858915270720\n  Bound result 16297\n  Bound result 18\n  Bound result 499999999999999999983\n  Bound result 2965\n  Bound result 12\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 90.40s (90.39s CPU time)\n\nRan 16 test suites in 90.42s (105.34s CPU time): 167 tests passed, 0 failed, 7 skipped (174 total tests)\n","passed":true},{"durationMs":100,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Imdex5.approve(address,uint256)\",\"Imdex5.ask()\",\"Imdex5.claim(address)\",\"Imdex5.closeRequest()\",\"Imdex5.fund(uint256)\",\"Imdex5.mint(uint256,uint256,uint256)\",\"Imdex5.mintFirst(uint256,uint256[])\",\"Imdex5.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"Imdex5.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"Imdex5.rebalance()\",\"Imdex5.redeem(uint256)\",\"Imdex5.redeemToImd(uint256,uint256)\",\"Imdex5.submit((bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"Imdex5.swapSelf(address,address,bool,uint256,bool,bool)\",\"Imdex5.transfer(address,uint256)\",\"Imdex5.transferFrom(address,address,uint256)\",\"Imdex5.unlockCallback(bytes)\"],\"files\":{\".gitignore\":2,\"ADAPTATION.md\":244,\"README.md\":315,\"THREAT_MODEL.md\":44,\"foundry.toml\":19,\"launch.json\":10,\"src/Imdex5.sol\":663,\"src/Interfaces.sol\":61,\"src/OracleAttestation.sol\":221,\"test/Fix3.fork.t.sol\":97,\"test/Fix3Floor.fork.t.sol\":67,\"test/Fix3Rebalance.fork.t.sol\":151,\"test/Imdex5.invariant.t.sol\":544,\"test/Imdex5.t.sol\":1070,\"test/Imdex5Base.sol\":175,\"test/Imdex5Edges.t.sol\":741,\"test/Imdex5Floor.invariant.t.sol\":335,\"test/Imdex5MustAttack.t.sol\":595,\"test/Imdex5ResidualSpot.t.sol\":182,\"test/Imdex5Revised.t.sol\":503,\"test/Imdex5ShortFill.t.sol\":226,\"test/Imdex5TaxEverywhere.t.sol\":531,\"test/Imdex5TaxedCoin.t.sol\":252,\"test/OracleConsumerConformance.t.sol\":74,\"test/mocks/AttackMocks.sol\":85,\"test/mocks/Mocks.sol\":337,\"test/mocks/PoolTaxERC20.sol\":25,\"test/mocks/TaxERC20.sol\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"081d9a76055cea7b77c9e39e56396ceeae01818e01392c8be109449585315ed8","verifiedTreeHash":"7f5ffafc67f57f5e5b4984badf1c62851a49f6e8","verifierVersion":"0.1.0+a26ee00d"},{"checks":[{"durationMs":81129,"exitCode":0,"name":"build","output":"Compiling 64 files with Solc 0.8.26\nSolc 0.8.26 finished in 81.03s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/Imdex5.sol:602:5:\n    |\n602 |     function _amountValue(address token, uint256 amount, uint256 sqrtP, Math.Rounding r)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/Fix3.fork.t.sol:76:5:\n   |\n76 |     function _checkBacked(Imdex5.Coin[] memory cs, string memory when) internal {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/Fix3Rebalance.fork.t.sol:44:5:\n   |\n44 |     function _backed(string memory when) internal {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":56490,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Fix3Floor.fork.t.sol:Fix3FloorForkTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 273.78µs (0.00ns CPU time)\n\nRan 3 tests for test/Fix3Rebalance.fork.t.sol:Fix3RebalanceForkTest\n[SKIP] test_dropTheTaxedCoin_fourRemain() (gas: 0)\n[SKIP] test_reorderSameFive() (gas: 0)\n[SKIP] test_shrinkToThree_bigFund() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 464.78µs (140.22µs CPU time)\n\nRan 2 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_callbackSelectorIsCanonical() (gas: 4542)\n[PASS] test_digestMatchesTheProtocol() (gas: 13358)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 519.60µs (76.55µs CPU time)\n\nRan 3 tests for test/Fix3.fork.t.sol:Fix3ForkTest\n[SKIP] test_fixed_with_1000_IMD() (gas: 0)\n[SKIP] test_fixed_with_100_IMD() (gas: 0)\n[SKIP] test_fixed_with_10_IMD() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 1.10ms (112.91µs CPU time)\n\nRan 9 tests for test/Imdex5ShortFill.t.sol:Imdex5ShortFillTest\n[PASS] testFuzz_mintUsesTheLeastFilledCoinAndChargesEveryBuy(uint256,uint16[5]) (runs: 256, μ: 1633958, ~: 1641444)\nLogs:\n  Bound result 479319975029788206071\n  Bound result 1\n  Bound result 10\n  Bound result 21\n  Bound result 1352\n  Bound result 109\n\n[PASS] test_fullFillPassesFloor() (gas: 742398)\n[PASS] test_mintRevertsAndRollsBackEarlierBuysWhenACoinDeliversZero() (gas: 1286732)\n[PASS] test_mintRevertsWhenANonzeroFillRoundsSharesToZero() (gas: 1196107)\n[PASS] test_shortFillChargesIdleImdForTheSharesIssuedOnly() (gas: 2600194)\n[PASS] test_shortFillMintsTheDeliveredFraction() (gas: 868257)\n[PASS] test_shortFillStillEnforcesMaxImdInAndRollsBack() (gas: 1739642)\n[PASS] test_sliverFillBelowFloorRevertsAndRollsBack() (gas: 1192319)\n[PASS] test_sliverFillWithoutFloorIssuesASliver() (gas: 1286570)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 114.03ms (122.48ms CPU time)\n\nRan 48 tests for test/Imdex5.t.sol:Imdex5Test\n[PASS] testFuzz_mintThenRedeemNeverPaysMoreThanDeposited(uint256,uint256) (runs: 256, μ: 2401927, ~: 2412435)\nLogs:\n  Bound result 4999033965134907737473\n  Bound result 4974038795309233198785\n\n[PASS] test_askPaysIntakeAndCaller() (gas: 1137820)\n[PASS] test_askReturnsWithoutFees() (gas: 155189)\n[PASS] test_askSevenDayInterval() (gas: 1189679)\n[PASS] test_bodyIsTheJsonTheBriefDescribes() (gas: 30573)\n[PASS] test_closeRequestAfterTwoDays() (gas: 1027162)\n[PASS] test_deployment() (gas: 94831)\n[PASS] test_feeImdOnlyLeavesForOracleAndRewards() (gas: 4930320)\n[PASS] test_fundAddsToFeeImd() (gas: 147750)\n[PASS] test_hookCannotReenter() (gas: 5142465)\n[PASS] test_mintBuysProportionallyAndRefunds() (gas: 1830201)\n[PASS] test_mintFirstBuysEqualPartsAndTakesFee() (gas: 1104043)\n[PASS] test_mintFirstKeepsWhatAPoolCouldNotTakeAsIdle() (gas: 1324714)\n[PASS] test_mintFirstRequiresZeroSupplyAndRightLength() (gas: 1022021)\n[PASS] test_mintFirstRevertsOnMinOut() (gas: 727109)\n[PASS] test_mintFirstRevertsWhenABuyFails() (gas: 814471)\n[PASS] test_mintFirstRevertsWhenABuyReturnsNothing() (gas: 2113122)\n[PASS] test_mintNeverIssuesSharesForNothing() (gas: 327985)\n[PASS] test_mintRequiresSupply() (gas: 40062)\n[PASS] test_mintRevertsOverMaxImdIn() (gas: 1732850)\n[PASS] test_mintRevertsWhenABuyFailsButScalesANonzeroShortFill() (gas: 2275588)\n[PASS] test_mintRoundsAgainstTheMinter() (gas: 1711530)\n[PASS] test_onOracleFailureOnlyFromIntake() (gas: 1064889)\n[PASS] test_onOracleResultStoresOnlyTheOpenRequestFromTheIntake() (gas: 1302614)\n[PASS] test_rebalanceNeedsAList() (gas: 41318)\n[PASS] test_rebalanceSellsAdoptsAndBuys() (gas: 5261907)\n[PASS] test_rebalanceSkipsADeadPool() (gas: 2983154)\n[PASS] test_rebalanceSkipsAHookThatLeavesAnUnsettledDelta() (gas: 3880126)\n[PASS] test_rebalanceSurvivesAHookThatBurnsAllGas() (gas: 5495285)\n[PASS] test_rebalanceTrimsAHoldingOverAQuarter() (gas: 3461572)\n[PASS] test_rebalanceWithNothingHeld() (gas: 2266050)\n[PASS] test_redeemCannotBeBlockedByACoin() (gas: 1575554)\n[PASS] test_redeemLastSharesPaysEverything() (gas: 2144299)\n[PASS] test_redeemPaysInKindLessHalfPercent() (gas: 1347307)\n[PASS] test_redeemRejectsZeroAndTooMany() (gas: 986033)\n[PASS] test_redeemSurvivesCoinsThatBurnAllGas() (gas: 4399409)\n[PASS] test_redeemToImdChargesTheFeeWhileOthersHold() (gas: 1668651)\n[PASS] test_redeemToImdPaysAShortFillInKindLessHalfPercent() (gas: 1780655)\n[PASS] test_redeemToImdPaysInKindWhenASaleFails() (gas: 2968070)\n[PASS] test_redeemToImdRevertsBelowMinOut() (gas: 1783406)\n[PASS] test_redeemToImdSellsAndTheLastHolderPaysNoFee() (gas: 1751812)\n[PASS] test_redeemToImdSurvivesAHookThatBurnsGas() (gas: 2457600)\n[PASS] test_submitRejectsASignedAttestationWithoutQuorum() (gas: 1128741)\n[PASS] test_submitRejectsAnExpiredAttestation() (gas: 1089458)\n[PASS] test_submitRejectsBadLists() (gas: 4717094)\n[PASS] test_submitRejectsWrongAnswerAndForgedSignature() (gas: 1645920)\n[PASS] test_submitStoresTheNextListAndRewards() (gas: 1527045)\n[PASS] test_unlockCallbackAndSwapSelfAreNotCallable() (gas: 103370)\nSuite result: ok. 48 passed; 0 failed; 0 skipped; finished in 269.11ms (312.36ms CPU time)\n\nRan 35 tests for test/Imdex5Edges.t.sol:Imdex5EdgesTest\n[PASS] testFuzz_mintBuysExactlyTheRoundedUpShare(uint256) (runs: 512, μ: 1918210, ~: 1918030)\nLogs:\n  Bound result 7649\n\n[PASS] testFuzz_mintFirstMintsExactlyTheRest(uint256) (runs: 512, μ: 1008130, ~: 1011513)\nLogs:\n  Bound result 3928081281691226751660\n\n[PASS] testFuzz_onOracleResultForAnotherRequestIsIgnored(bytes32,uint16) (runs: 256, μ: 1028592, ~: 1028683)\n[PASS] testFuzz_onOracleResultFromAStrangerChangesNothing(address,bytes32,uint16) (runs: 256, μ: 1075429, ~: 1075635)\n[PASS] testFuzz_redeemNeverPaysAboveProRata(uint256,uint256) (runs: 512, μ: 1557383, ~: 1558156)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 995000000000000000\n\n[PASS] testFuzz_splittingARedeemStaysUnderProRata(uint256,uint256) (runs: 256, μ: 1748389, ~: 1748840)\nLogs:\n  Bound result 33965134907737472\n  Bound result 993966034865092262528\n\n[PASS] test_aLaterAskReplacesAnUnsubmittedAnswer() (gas: 1887604)\n[PASS] test_aReenteringCoinCannotReenterAndIsNotPaidTwice() (gas: 2668691)\n[PASS] test_aReenteringCoinCannotReenterMintOrRebalanceFromRedeem() (gas: 3865512)\n[PASS] test_aThinResidualPoolDoesNotStarveAFlooredMint() (gas: 3594832)\n[PASS] test_anUnsubmittedAnswerDoesNotSurviveAFailedLaterAsk() (gas: 1356525)\n[PASS] test_askRevertsWholeWhenTheIntakeRefuses() (gas: 334213)\n[PASS] test_askThresholdIsExactlyThreeQuartersOfAnImd() (gas: 1101757)\n[PASS] test_closeRequestNeedsAnOpenOne() (gas: 1003747)\n[PASS] test_closingARequestDoesNotResetTheInterval() (gas: 1161894)\n[PASS] test_mintCannotBeFreeWhenTheIndexHoldsValue() (gas: 1767082)\n[PASS] test_onOracleResultAfterCloseIsIgnored() (gas: 1098689)\n[PASS] test_onOracleResultWithFiveEntriesFitsTheStipend() (gas: 1144000)\n[PASS] test_oneGasBurningCoinDoesNotBlockRedeemGivenGas() (gas: 1666458)\n[PASS] test_rebalanceBuyMovesAPoolAtMostTwoPercent() (gas: 3682417)\n[PASS] test_rebalanceBuyStopsAtAQuarterWeight() (gas: 4013413)\n[PASS] test_rebalanceDoesNotTrimWithFewerThanFourCoins() (gas: 3257627)\n[PASS] test_rebalanceSellMovesAPoolAtMostTwoPercent() (gas: 3286485)\n[PASS] test_rebalanceTrimsToAQuarterNotBelow() (gas: 3775227)\n[PASS] test_redeemHalfPercentStaysWithRemainingHolders() (gas: 1555463)\n[PASS] test_redeemIdleImdThatCannotBeSentIsOwed() (gas: 1393763)\n[PASS] test_redeemToATokenWithoutCodeBecomesOwedAndClaimableLater() (gas: 1265903)\n[PASS] test_residualsAreRedeemedAndADeadOneBlocksMintWithoutTakingImd() (gas: 5290738)\n[PASS] test_rewardsNeverDipIntoIdleImd() (gas: 2723895)\n[PASS] test_sharesTransferLikeAnyErc20AndMoveNoHoldings() (gas: 1462846)\n[PASS] test_submitAndRebalancePayNoRewardWithoutFees() (gas: 3243874)\n[PASS] test_submitRejectsATamperedAnswerEvenWithAValidSignatureElsewhere() (gas: 1142590)\n[PASS] test_submitRejectsAnAttestationSignedForAnotherChain() (gas: 1444342)\n[PASS] test_submitRejectsAnAttestationSignedForAnotherConsumer() (gas: 1109787)\n[PASS] test_submitRejectsMalformedAnswerBytes() (gas: 1347909)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 276.76ms (1.06s CPU time)\n\nRan 9 tests for test/Imdex5TaxEverywhere.t.sol:Imdex5TaxEverywhereTest\n[PASS] testFuzz_everyCoinTaxedLifecycle(uint16[5],uint256,uint256,uint256) (runs: 200, μ: 9132189, ~: 9136230)\nLogs:\n  Bound result 860\n  Bound result 133\n  Bound result 1265\n  Bound result 300\n  Bound result 1824\n  Bound result 260931199186922457893\n  Bound result 490727274760918786319\n  Bound result 763027475850161101537\n\n[PASS] testFuzz_theMostTaxedCoinDecidesTheMint(uint8,uint16,uint16,uint256) (runs: 200, μ: 2671218, ~: 2707336)\nLogs:\n  Bound result 3\n  Bound result 2\n  Bound result 1\n  Bound result 500000000000000000000\n\n[PASS] test_aCoinTaxingItsOwnSettlementIsNeverSoldAndIsPaidInKind() (gas: 6635123)\n[PASS] test_aCoinTaxingItsOwnSettlementStaysAResidualThroughARebalance() (gas: 7210236)\n[PASS] test_aCoinThatKeepsEverythingFailsALaterMintWholeAndRedeemsStillPay() (gas: 6569197)\n[PASS] test_aCoinThatKeepsEverythingFailsTheFirstMintWhole() (gas: 1464541)\n[PASS] test_aCoinThatKeepsEverythingFailsTheOneWeiMint() (gas: 3415197)\n[PASS] test_aDonationNeitherChangesHeldNorInflatesAMintOrARedeem() (gas: 2474375)\n[PASS] test_taxOnTopOfAPartialFillCreditsTheNetAndMintsThatFraction() (gas: 5236267)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 377.14ms (761.02ms CPU time)\n\nRan 26 tests for test/Imdex5Revised.t.sol:Imdex5RevisedTest\n[PASS] testFuzz_mintFirstKeepsAPartialFillIdle(uint256,uint256) (runs: 256, μ: 1103696, ~: 1103692)\nLogs:\n  Bound result 33965134907737472\n  Bound result 6759061846639756\n\n[PASS] testFuzz_redeemToImdPaysADeadCoinExactlyAsRedeemDoes(uint256) (runs: 256, μ: 1991240, ~: 1995825)\nLogs:\n  Bound result 168081281691226846738\n\n[PASS] testFuzz_redeemToImdPaysAShortFillInKindUnderTheRedeemRule(uint256,uint256) (runs: 256, μ: 1826904, ~: 1828801)\nLogs:\n  Bound result 753612501597462832046\n  Bound result 6830\n\n[PASS] test_aCoinThatBurnsItsGasIsOwedAndTheIdleImdStillPaid() (gas: 1632521)\n[PASS] test_askAndCloseAtTheirExactBoundaries() (gas: 1205484)\n[PASS] test_askIsBlockedWhileAListAwaitsRebalance() (gas: 3288904)\n[PASS] test_claimThatFailsKeepsTheDebt() (gas: 1296876)\n[PASS] test_hookCannotCallSwapSelfOrTheOracleCallbacks() (gas: 3481850)\n[PASS] test_hookCannotCloseOrAnswerTheOpenRequestDuringASwap() (gas: 4132057)\n[PASS] test_lastRedeemerToImdTakesAllOfADeadCoin() (gas: 1750522)\n[PASS] test_margUsesItsOwnHookAndTheOthersShareG() (gas: 48913)\n[PASS] test_mintFirstPartialFillIsRedeemedProRataNotTwice() (gas: 1658725)\n[PASS] test_mintFirstRefusesAPoolThatReturnsNothingOnALargeAmount() (gas: 744323)\n[PASS] test_mintFirstRefusesDustThatBuysNothing() (gas: 2164280)\n[PASS] test_mintFirstRevertsWholeWhenTheHookMisbehaves() (gas: 992464202)\n[PASS] test_mintRevertsWholeWhenTheHookBurnsGasForTheIndex() (gas: 993092341)\n[PASS] test_mintRevertsWholeWhenTheHookLeavesADeltaUnsettled() (gas: 1344666)\n[PASS] test_mintSkipsAListCoinHeldAtZeroAndTheNextRebalanceBuysIt() (gas: 5541187)\n[PASS] test_onOracleResultNeedsExactlyFourAgreed() (gas: 1159008)\n[PASS] test_owedAccumulatesAcrossRedeemsAndIsPaidOnce() (gas: 2200097)\n[PASS] test_rebalanceSkipsEveryBurningSwapAndStillAdoptsTheList() (gas: 3728449)\n[PASS] test_redeemSurvivesFiveGasBurningCoinsWithOrdinaryGas() (gas: 5815403)\n[PASS] test_redeemToImdPaysInKindWhenTheHookLeavesADeltaUnsettled() (gas: 2231678)\n[PASS] test_submitRejectsALaunchWithoutAHookOrAToken() (gas: 1853595)\n[PASS] test_submitTakesAnAttestationOnce() (gas: 1461700)\n[PASS] test_submitUsesTheRegistryArtifactsNotTheStartingList() (gas: 1560383)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 409.30ms (843.52ms CPU time)\n\nRan 6 tests for test/Imdex5ResidualSpot.t.sol:Imdex5ResidualSpotTest\n[PASS] testFuzz_aDeadResidualFailsTheMintAtAnyPrice(uint256,uint256) (runs: 256, μ: 4309615, ~: 4309599)\nLogs:\n  Bound result 10217\n  Bound result 1283\n\n[PASS] testFuzz_aDumpedResidualThatTradesIsBoughtInFull(uint256,uint256) (runs: 256, μ: 4304820, ~: 4304921)\nLogs:\n  Bound result 46\n  Bound result 994999000000000006831\n\n[PASS] test_aDumpedResidualWhoseBuyRevertsCannotBeMintedAtSpot() (gas: 4696640)\n[PASS] test_aResidualHookThatBurnsGasFailsTheMint() (gas: 5736996)\n[PASS] test_aResidualHookThatLeavesADeltaFailsTheMint() (gas: 4162296)\n[PASS] test_aResidualShortFillIsChargedAtLeastItsFairValue() (gas: 4140327)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 409.32ms (538.50ms CPU time)\n\nRan 7 tests for test/Imdex5TaxedCoin.t.sol:Imdex5TaxedCoinTest\n[PASS] testFuzz_taxedCoinLifecycle(uint256,uint256,uint256) (runs: 256, μ: 7859777, ~: 7865031)\nLogs:\n  Bound result 360930050014973385143\n  Bound result 321970452318407739623\n  Bound result 514248859715124976171\n\n[PASS] test_firstMintCreditsOnlyWhatArrives() (gas: 1252895)\n[PASS] test_firstMintMinOutChecksTheNetReceipt() (gas: 1358270)\n[PASS] test_lastHolderCanReceiveEveryCoinAfterAnImdExit() (gas: 2638525)\n[PASS] test_outstandingOwedIsNotCountedAsANewReceiptAndRemainsClaimable() (gas: 5186559)\n[PASS] test_taxedCoinFullLifecycle() (gas: 7853807)\n[PASS] test_taxedRebalanceBuyCreditsOnlyNewReceipts() (gas: 5580720)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 409.40ms (423.83ms CPU time)\n\nRan 1 test for test/Imdex5TaxEverywhere.t.sol:Imdex5AllCoinsTaxedInvariantTest\n[PASS]\nImdex5AllCoinsTaxedInvariantTest invariants:\n[PASS] invariant_taxed_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_taxed_coinBalancesAreHeldPlusOwed\n[PASS] invariant_taxed_everyHoldingIsListed\n[PASS] invariant_taxed_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_taxed_zeroSupplyMeansNothingHeld\n Imdex5AllCoinsTaxedInvariantTest invariants (runs: 96, calls: 3840, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 215   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 217   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 230   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 213   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 431   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 214   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 239   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 213   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 224   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 196   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 222   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 193   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 191   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 208   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| TaxKnobs      | setTax           | 202   | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 45000000000000000000\n  Bound result 499999999999999999941\n  Bound result 10001\n  Bound result 8035\n  Bound result 21273\n  Bound result 5\n  Bound result 3719\n  Bound result 200000\n  Bound result 294164\n  Bound result 12687\n  Bound result 2940\n  Bound result 9337\n  Bound result 244572990811080708212\n  Bound result 128304\n  Bound result 1990291074542133917908\n  Bound result 191787475000343521937\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.28s (1.28s CPU time)\n\nRan 1 test for test/Imdex5.invariant.t.sol:Imdex5InvariantTest\n[PASS]\nImdex5InvariantTest invariants:\n[PASS] invariant_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_coinBalancesAreHeldPlusOwed\n[PASS] invariant_feeImdLeavesOnlyForTheOracleAndRewards\n[PASS] invariant_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_listShape\n[PASS] invariant_noFreeMintWhileValueIsHeld\n[PASS] invariant_requestStateIsConsistent\n[PASS] invariant_zeroSupplyMeansNothingHeld\n Imdex5InvariantTest invariants (runs: 96, calls: 3840, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 178   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 214   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | closeRequest     | 210   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverFailure   | 210   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 202   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 187   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 398   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 199   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 218   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 250   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 180   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 211   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 196   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 192   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 200   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 189   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 190   | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 98000000000000000000\n  Bound result 13945\n  Bound result 128002\n  Bound result 499999999999999999801\n  Bound result 83059999999999999903\n  Bound result 5000000000000000000000\n  Bound result 168623979896987713927\n  Bound result 1283\n  Bound result 19\n  Bound result 633\n  Bound result 4472\n  Bound result 400887\n  Bound result 5809\n  Bound result 172800\n  Bound result 12029034692083795\n  Bound result 9160528332957214075891\n  Bound result 2092\n  Bound result 50\n  Bound result 159065277810454727585\n  Bound result 27657485\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.69s (1.69s CPU time)\n\nRan 1 test for test/Imdex5.invariant.t.sol:Imdex5TaxedCoinInvariantTest\n[PASS]\nImdex5TaxedCoinInvariantTest invariants:\n[PASS] invariant_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_coinBalancesAreHeldPlusOwed\n[PASS] invariant_feeImdLeavesOnlyForTheOracleAndRewards\n[PASS] invariant_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_listShape\n[PASS] invariant_noFreeMintWhileValueIsHeld\n[PASS] invariant_requestStateIsConsistent\n[PASS] invariant_zeroSupplyMeansNothingHeld\n Imdex5TaxedCoinInvariantTest invariants (runs: 256, calls: 128000, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 6718  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 6623  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | closeRequest     | 6870  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverFailure   | 6846  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 6826  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 6803  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 13419 | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 6820  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 6831  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 6698  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 6786  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 6591  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 6747  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 6661  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 6676  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 6628  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 6677  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 6780  | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1948279459872595484217\n  Bound result 752110275\n  Bound result 172800\n  Bound result 38810938075980998578\n  Bound result 50000000000000000000\n  Bound result 16925\n  Bound result 604799\n  Bound result 8517\n  Bound result 361556\n  Bound result 1809584828809460813841\n  Bound result 4700\n  Bound result 13\n  Bound result 552383986483686246\n  Bound result 6121\n  Bound result 92327363653598192168\n  Bound result 2000000000000000000\n  Bound result 500000000000000000\n  Bound result 2970\n  Bound result 1442643772\n  Bound result 80\n  Bound result 691200\n  Bound result 749999999999999999\n  Bound result 69198320112528054026\n  Bound result 100000000000000000000\n  Bound result 759\n  Bound result 98\n  Bound result 518991\n  Bound result 448373551239569028659\n  Bound result 85911266903948174118\n  Bound result 22022\n  Bound result 99\n  Bound result 12345\n  Bound result 550987\n  Bound result 18527113593816942971\n  Bound result 824882116\n  Bound result 69251740215811937354\n  Bound result 1282992874699049879426\n  Bound result 304\n  Bound result 6641\n  Bound result 1750\n  Bound result 24362982194349809566\n  Bound result 40\n  Bound result 16696\n  Bound result 14264337593543950336\n  Bound result 50000000000000000000\n  Bound result 6431100696113791424\n  Bound result 1\n  Bound result 5865\n  Bound result 50590258710550212871\n  Bound result 1071326568876807487076\n  Bound result 39000000000000000000\n  Bound result 490\n  Bound result 10100\n  Bound result 20656\n  Bound result 21775\n  Bound result 1550\n  Bound result 271413092188967988962\n  Bound result 4209833798\n  Bound result 10602\n  Bound result 14960\n  Bound result 14473\n  Bound result 45586924784608609874\n  Bound result 825574019181123389393\n  Bound result 16134446248347384736\n  Bound result 1967177037100036847961\n  Bound result 40154351402929523115\n  Bound result 13632\n  Bound result 14937\n  Bound result 845000000000000000000\n  Bound result 767\n  Bound result 19370\n  Bound result 23189\n  Bound result 19051628225580285733\n  Bound result 1658\n  Bound result 4282813352766059161\n  Bound result 8529295168671728072194\n  Bound result 17428\n  Bound result 721582932263909576515\n  Bound result 3000\n  Bound result 3595\n  Bound result 5638\n  Bound result 1075\n  Bound result 3000000000000000000\n  Bound result 7728905084183689302668\n  Bound result 32\n  Bound result 6388\n  Bound result 1000000\n  Bound result 30937376181477312938\n  Bound result 102400\n  Bound result 490076\n  Bound result 3335669237430257793\n  Bound result 834\n  Bound result 228\n  Bound result 17961\n  Bound result 6\n  Bound result 27701357943844710613\n  Bound result 89523411\n  Bound result 360742\n  Bound result 38909672803529606512\n  Bound result 4242\n  Bound result 512960003\n  Bound result 40\n  Bound result 10205\n  Bound result 283224\n  Bound result 11515653705596244105\n  Bound result 3706535452212364912995\n  Bound result 855068926\n  Bound result 1341\n  Bound result 50000000000000000000\n  Bound result 1019\n  Bound result 100\n  Bound result 41\n  Bound result 7\n  Bound result 183028254442870\n  Bound result 537600\n  Bound result 400\n  Bound result 10181\n  Bound result 2\n  Bound result 21788952636611022928\n  Bound result 23000000000000000000\n  Bound result 2505\n  Bound result 3482\n  Bound result 18\n  Bound result 4688790709890208958\n  Bound result 5635110525057462027\n  Bound result 4923\n  Bound result 828417\n  Bound result 1053155827545688853\n  Bound result 48552335375343992926\n  Bound result 553405045192209964\n  Bound result 10000000000000000000\n  Bound result 17804\n  Bound result 410006647586948566\n  Bound result 7680745843779349382\n  Bound result 2573814764234317572078\n  Bound result 1153\n  Bound result 3713\n  Bound result 2283\n  Bound result 97\n  Bound result 123000000000000000000\n  Bound result 4294967295\n  Bound result 3631375067277807321\n  Bound result 2027391056008656366\n  Bound result 7839032744\n  Bound result 731893163682423720\n  Bound result 499999999999999999997\n  Bound result 22061\n  Bound result 11034\n  Bound result 18891\n  Bound result 537\n  Bound result 7294\n  Bound result 99\n  Bound result 4242\n  Bound result 794\n  Bound result 9443\n  Bound result 20122\n  Bound result 18\n  Bound result 519747808000691602\n  Bound result 1359\n  Bound result 9900\n  Bound result 4117158291754143160838\n  Bound result 330658756642820537\n  Bound result 22033\n  Bound result 4000000\n  Bound result 3349\n  Bound result 38551278651741427576\n  Bound result 3379332460081442372\n  Bound result 9010\n  Bound result 11739\n  Bound result 50000000000000000000\n  Bound result 300000\n  Bound result 24576\n  Bound result 542999\n  Bound result 318438579673448119\n  Bound result 344999999999999999999\n  Bound result 19641\n  Bound result 1025405536380764458\n  Bound result 17\n  Bound result 98000000000000000000\n  Bound result 599796025732405\n  Bound result 21969\n  Bound result 777\n  Bound result 300000\n  Bound result 1171476427756699447\n  Bound result 0\n  Bound result 594442504046786251\n  Bound result 260434613628649785111\n  Bound result 2864\n  Bound result 24028641005746603\n  Bound result 307416935746618868\n  Bound result 795000000000000000000\n  Bound result 16936734027377378\n  Bound result 7807\n  Bound result 71760150903931604\n  Bound result 21000000000000000\n  Bound result 601845710771861512\n  Bound result 290316426374143743254\n  Bound result 831373247392602783\n  Bound result 6457\n  Bound result 19443\n  Bound result 333284359459953125\n  Bound result 200000000000000000000\n  Bound result 19798\n  Bound result 11916\n  Bound result 1282\n  Bound result 2542263819672456920411\n  Bound result 9008\n  Bound result 50\n  Bound result 1000000000000000\n  Bound result 6902\n  Bound result 125967040277133470970\n  Bound result 612642\n  Bound result 2\n  Bound result 257\n  Bound result 41235539224657880483\n  Bound result 5\n  Bound result 1282\n  Bound result 20362\n  Bound result 104317026176293280\n  Bound result 13699\n  Bound result 230394\n  Bound result 50000000000000000000\n  Bound result 401406142068791176\n  Bound result 16356\n  Bound result 200\n  Bound result 494999999999999999999\n  Bound result 2907\n  Bound result 12\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 56.38s (56.37s CPU time)\n\nRan 14 test suites in 56.38s (61.62s CPU time): 145 tests passed, 0 failed, 7 skipped (152 total tests)\n","passed":true},{"durationMs":66,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Imdex5.approve(address,uint256)\",\"Imdex5.ask()\",\"Imdex5.claim(address)\",\"Imdex5.closeRequest()\",\"Imdex5.fund(uint256)\",\"Imdex5.mint(uint256,uint256,uint256)\",\"Imdex5.mintFirst(uint256,uint256[])\",\"Imdex5.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"Imdex5.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"Imdex5.rebalance()\",\"Imdex5.redeem(uint256)\",\"Imdex5.redeemToImd(uint256,uint256)\",\"Imdex5.submit((bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"Imdex5.swapSelf(address,address,bool,uint256,bool,bool)\",\"Imdex5.transfer(address,uint256)\",\"Imdex5.transferFrom(address,address,uint256)\",\"Imdex5.unlockCallback(bytes)\"],\"files\":{\".gitignore\":2,\"ADAPTATION.md\":244,\"README.md\":315,\"THREAT_MODEL.md\":44,\"foundry.toml\":19,\"launch.json\":10,\"src/Imdex5.sol\":663,\"src/Interfaces.sol\":61,\"src/OracleAttestation.sol\":221,\"test/Fix3.fork.t.sol\":97,\"test/Fix3Floor.fork.t.sol\":67,\"test/Fix3Rebalance.fork.t.sol\":151,\"test/Imdex5.invariant.t.sol\":544,\"test/Imdex5.t.sol\":1070,\"test/Imdex5Base.sol\":175,\"test/Imdex5Edges.t.sol\":741,\"test/Imdex5ResidualSpot.t.sol\":182,\"test/Imdex5Revised.t.sol\":503,\"test/Imdex5ShortFill.t.sol\":226,\"test/Imdex5TaxEverywhere.t.sol\":531,\"test/Imdex5TaxedCoin.t.sol\":252,\"test/OracleConsumerConformance.t.sol\":74,\"test/mocks/AttackMocks.sol\":85,\"test/mocks/Mocks.sol\":337,\"test/mocks/PoolTaxERC20.sol\":25,\"test/mocks/TaxERC20.sol\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"38715955c6ff481e9dcf089188212d9b3f7ff9604f19e2cc8f6e325c4d1bc182","verifiedTreeHash":"ecdac317ac652b5afadae9633fce266889f6af97","verifierVersion":"0.1.0+a26ee00d"},{"checks":[{"durationMs":137864,"exitCode":0,"name":"build","output":"Compiling 64 files with Solc 0.8.26\nSolc 0.8.26 finished in 137.67s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n   --> src/Imdex5.sol:602:5:\n    |\n602 |     function _amountValue(address token, uint256 amount, uint256 sqrtP, Math.Rounding r)\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/Fix3.fork.t.sol:76:5:\n   |\n76 |     function _checkBacked(Imdex5.Coin[] memory cs, string memory when) internal {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to view\n  --> test/Fix3Rebalance.fork.t.sol:44:5:\n   |\n44 |     function _backed(string memory when) internal {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":90605,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/Fix3.fork.t.sol:Fix3ForkTest\n[SKIP] test_fixed_with_1000_IMD() (gas: 0)\n[SKIP] test_fixed_with_100_IMD() (gas: 0)\n[SKIP] test_fixed_with_10_IMD() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 3.74ms (6.46ms CPU time)\n\nRan 3 tests for test/Fix3Rebalance.fork.t.sol:Fix3RebalanceForkTest\n[SKIP] test_dropTheTaxedCoin_fourRemain() (gas: 0)\n[SKIP] test_reorderSameFive() (gas: 0)\n[SKIP] test_shrinkToThree_bigFund() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 3 skipped; finished in 3.63ms (6.57ms CPU time)\n\nRan 1 test for test/Fix3Floor.fork.t.sol:Fix3FloorForkTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 5.33ms (0.00ns CPU time)\n\nRan 2 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_callbackSelectorIsCanonical() (gas: 4542)\n[PASS] test_digestMatchesTheProtocol() (gas: 13358)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 6.55ms (143.66µs CPU time)\n\nRan 9 tests for test/Imdex5ShortFill.t.sol:Imdex5ShortFillTest\n[PASS] testFuzz_mintUsesTheLeastFilledCoinAndChargesEveryBuy(uint256,uint16[5]) (runs: 256, μ: 1633958, ~: 1641444)\nLogs:\n  Bound result 499000000000000000822\n  Bound result 2062\n  Bound result 1777\n  Bound result 16\n  Bound result 1502\n  Bound result 9900\n\n[PASS] test_fullFillPassesFloor() (gas: 742398)\n[PASS] test_mintRevertsAndRollsBackEarlierBuysWhenACoinDeliversZero() (gas: 1286732)\n[PASS] test_mintRevertsWhenANonzeroFillRoundsSharesToZero() (gas: 1196107)\n[PASS] test_shortFillChargesIdleImdForTheSharesIssuedOnly() (gas: 2600194)\n[PASS] test_shortFillMintsTheDeliveredFraction() (gas: 868257)\n[PASS] test_shortFillStillEnforcesMaxImdInAndRollsBack() (gas: 1739642)\n[PASS] test_sliverFillBelowFloorRevertsAndRollsBack() (gas: 1192319)\n[PASS] test_sliverFillWithoutFloorIssuesASliver() (gas: 1286570)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 432.98ms (431.44ms CPU time)\n\nRan 35 tests for test/Imdex5Edges.t.sol:Imdex5EdgesTest\n[PASS] testFuzz_mintBuysExactlyTheRoundedUpShare(uint256) (runs: 512, μ: 1918210, ~: 1918030)\nLogs:\n  Bound result 7649\n\n[PASS] testFuzz_mintFirstMintsExactlyTheRest(uint256) (runs: 512, μ: 1008130, ~: 1011513)\nLogs:\n  Bound result 3928081281691226751660\n\n[PASS] testFuzz_onOracleResultForAnotherRequestIsIgnored(bytes32,uint16) (runs: 256, μ: 1028592, ~: 1028683)\n[PASS] testFuzz_onOracleResultFromAStrangerChangesNothing(address,bytes32,uint16) (runs: 256, μ: 1075429, ~: 1075635)\n[PASS] testFuzz_redeemNeverPaysAboveProRata(uint256,uint256) (runs: 512, μ: 1557383, ~: 1558156)\nLogs:\n  Bound result 2425738167667669001633\n  Bound result 402\n\n[PASS] testFuzz_splittingARedeemStaysUnderProRata(uint256,uint256) (runs: 256, μ: 1748389, ~: 1748840)\nLogs:\n  Bound result 33965134907737472\n  Bound result 993966034865092262528\n\n[PASS] test_aLaterAskReplacesAnUnsubmittedAnswer() (gas: 1887604)\n[PASS] test_aReenteringCoinCannotReenterAndIsNotPaidTwice() (gas: 2668691)\n[PASS] test_aReenteringCoinCannotReenterMintOrRebalanceFromRedeem() (gas: 3865512)\n[PASS] test_aThinResidualPoolDoesNotStarveAFlooredMint() (gas: 3594832)\n[PASS] test_anUnsubmittedAnswerDoesNotSurviveAFailedLaterAsk() (gas: 1356525)\n[PASS] test_askRevertsWholeWhenTheIntakeRefuses() (gas: 334213)\n[PASS] test_askThresholdIsExactlyThreeQuartersOfAnImd() (gas: 1101757)\n[PASS] test_closeRequestNeedsAnOpenOne() (gas: 1003747)\n[PASS] test_closingARequestDoesNotResetTheInterval() (gas: 1161894)\n[PASS] test_mintCannotBeFreeWhenTheIndexHoldsValue() (gas: 1767082)\n[PASS] test_onOracleResultAfterCloseIsIgnored() (gas: 1098689)\n[PASS] test_onOracleResultWithFiveEntriesFitsTheStipend() (gas: 1144000)\n[PASS] test_oneGasBurningCoinDoesNotBlockRedeemGivenGas() (gas: 1666458)\n[PASS] test_rebalanceBuyMovesAPoolAtMostTwoPercent() (gas: 3682417)\n[PASS] test_rebalanceBuyStopsAtAQuarterWeight() (gas: 4013413)\n[PASS] test_rebalanceDoesNotTrimWithFewerThanFourCoins() (gas: 3257627)\n[PASS] test_rebalanceSellMovesAPoolAtMostTwoPercent() (gas: 3286485)\n[PASS] test_rebalanceTrimsToAQuarterNotBelow() (gas: 3775227)\n[PASS] test_redeemHalfPercentStaysWithRemainingHolders() (gas: 1555463)\n[PASS] test_redeemIdleImdThatCannotBeSentIsOwed() (gas: 1393763)\n[PASS] test_redeemToATokenWithoutCodeBecomesOwedAndClaimableLater() (gas: 1265903)\n[PASS] test_residualsAreRedeemedAndADeadOneBlocksMintWithoutTakingImd() (gas: 5290738)\n[PASS] test_rewardsNeverDipIntoIdleImd() (gas: 2723895)\n[PASS] test_sharesTransferLikeAnyErc20AndMoveNoHoldings() (gas: 1462846)\n[PASS] test_submitAndRebalancePayNoRewardWithoutFees() (gas: 3243874)\n[PASS] test_submitRejectsATamperedAnswerEvenWithAValidSignatureElsewhere() (gas: 1142590)\n[PASS] test_submitRejectsAnAttestationSignedForAnotherChain() (gas: 1444342)\n[PASS] test_submitRejectsAnAttestationSignedForAnotherConsumer() (gas: 1109787)\n[PASS] test_submitRejectsMalformedAnswerBytes() (gas: 1347909)\nSuite result: ok. 35 passed; 0 failed; 0 skipped; finished in 433.14ms (1.64s CPU time)\n\nRan 26 tests for test/Imdex5Revised.t.sol:Imdex5RevisedTest\n[PASS] testFuzz_mintFirstKeepsAPartialFillIdle(uint256,uint256) (runs: 256, μ: 1103696, ~: 1103692)\nLogs:\n  Bound result 194927474405502257178\n  Bound result 6830\n\n[PASS] testFuzz_redeemToImdPaysADeadCoinExactlyAsRedeemDoes(uint256) (runs: 256, μ: 1991240, ~: 1995825)\nLogs:\n  Bound result 168081281691226846738\n\n[PASS] testFuzz_redeemToImdPaysAShortFillInKindUnderTheRedeemRule(uint256,uint256) (runs: 256, μ: 1826904, ~: 1828801)\nLogs:\n  Bound result 994033965134907737472\n  Bound result 19492773117656784733246\n\n[PASS] test_aCoinThatBurnsItsGasIsOwedAndTheIdleImdStillPaid() (gas: 1632521)\n[PASS] test_askAndCloseAtTheirExactBoundaries() (gas: 1205484)\n[PASS] test_askIsBlockedWhileAListAwaitsRebalance() (gas: 3288904)\n[PASS] test_claimThatFailsKeepsTheDebt() (gas: 1296876)\n[PASS] test_hookCannotCallSwapSelfOrTheOracleCallbacks() (gas: 3481850)\n[PASS] test_hookCannotCloseOrAnswerTheOpenRequestDuringASwap() (gas: 4132057)\n[PASS] test_lastRedeemerToImdTakesAllOfADeadCoin() (gas: 1750522)\n[PASS] test_margUsesItsOwnHookAndTheOthersShareG() (gas: 48913)\n[PASS] test_mintFirstPartialFillIsRedeemedProRataNotTwice() (gas: 1658725)\n[PASS] test_mintFirstRefusesAPoolThatReturnsNothingOnALargeAmount() (gas: 744323)\n[PASS] test_mintFirstRefusesDustThatBuysNothing() (gas: 2164280)\n[PASS] test_mintFirstRevertsWholeWhenTheHookMisbehaves() (gas: 992464202)\n[PASS] test_mintRevertsWholeWhenTheHookBurnsGasForTheIndex() (gas: 993092341)\n[PASS] test_mintRevertsWholeWhenTheHookLeavesADeltaUnsettled() (gas: 1344666)\n[PASS] test_mintSkipsAListCoinHeldAtZeroAndTheNextRebalanceBuysIt() (gas: 5541187)\n[PASS] test_onOracleResultNeedsExactlyFourAgreed() (gas: 1159008)\n[PASS] test_owedAccumulatesAcrossRedeemsAndIsPaidOnce() (gas: 2200097)\n[PASS] test_rebalanceSkipsEveryBurningSwapAndStillAdoptsTheList() (gas: 3728449)\n[PASS] test_redeemSurvivesFiveGasBurningCoinsWithOrdinaryGas() (gas: 5815403)\n[PASS] test_redeemToImdPaysInKindWhenTheHookLeavesADeltaUnsettled() (gas: 2231678)\n[PASS] test_submitRejectsALaunchWithoutAHookOrAToken() (gas: 1853595)\n[PASS] test_submitTakesAnAttestationOnce() (gas: 1461700)\n[PASS] test_submitUsesTheRegistryArtifactsNotTheStartingList() (gas: 1560383)\nSuite result: ok. 26 passed; 0 failed; 0 skipped; finished in 445.90ms (1.17s CPU time)\n\nRan 7 tests for test/Imdex5TaxedCoin.t.sol:Imdex5TaxedCoinTest\n[PASS] testFuzz_taxedCoinLifecycle(uint256,uint256,uint256) (runs: 256, μ: 7859777, ~: 7865031)\nLogs:\n  Bound result 360930050014973385143\n  Bound result 321970452318407739623\n  Bound result 514248859715124976171\n\n[PASS] test_firstMintCreditsOnlyWhatArrives() (gas: 1252895)\n[PASS] test_firstMintMinOutChecksTheNetReceipt() (gas: 1358270)\n[PASS] test_lastHolderCanReceiveEveryCoinAfterAnImdExit() (gas: 2638525)\n[PASS] test_outstandingOwedIsNotCountedAsANewReceiptAndRemainsClaimable() (gas: 5186559)\n[PASS] test_taxedCoinFullLifecycle() (gas: 7853807)\n[PASS] test_taxedRebalanceBuyCreditsOnlyNewReceipts() (gas: 5580720)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 509.32ms (532.83ms CPU time)\n\nRan 6 tests for test/Imdex5ResidualSpot.t.sol:Imdex5ResidualSpotTest\n[PASS] testFuzz_aDeadResidualFailsTheMintAtAnyPrice(uint256,uint256) (runs: 256, μ: 4309615, ~: 4309599)\nLogs:\n  Bound result 832046\n  Bound result 6830\n\n[PASS] testFuzz_aDumpedResidualThatTradesIsBoughtInFull(uint256,uint256) (runs: 256, μ: 4304820, ~: 4304921)\nLogs:\n  Bound result 472\n  Bound result 995000000000000000000\n\n[PASS] test_aDumpedResidualWhoseBuyRevertsCannotBeMintedAtSpot() (gas: 4696640)\n[PASS] test_aResidualHookThatBurnsGasFailsTheMint() (gas: 5736996)\n[PASS] test_aResidualHookThatLeavesADeltaFailsTheMint() (gas: 4162296)\n[PASS] test_aResidualShortFillIsChargedAtLeastItsFairValue() (gas: 4140327)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 597.83ms (1.03s CPU time)\n\nRan 9 tests for test/Imdex5TaxEverywhere.t.sol:Imdex5TaxEverywhereTest\n[PASS] testFuzz_everyCoinTaxedLifecycle(uint16[5],uint256,uint256,uint256) (runs: 200, μ: 9132189, ~: 9136230)\nLogs:\n  Bound result 2672\n  Bound result 608\n  Bound result 1048\n  Bound result 1212\n  Bound result 2827\n  Bound result 499000000000000004890\n  Bound result 499000000000157198261\n  Bound result 899000000000000010360\n\n[PASS] testFuzz_theMostTaxedCoinDecidesTheMint(uint8,uint16,uint16,uint256) (runs: 200, μ: 2671218, ~: 2707336)\nLogs:\n  Bound result 3\n  Bound result 2\n  Bound result 1\n  Bound result 500000000000000000000\n\n[PASS] test_aCoinTaxingItsOwnSettlementIsNeverSoldAndIsPaidInKind() (gas: 6635123)\n[PASS] test_aCoinTaxingItsOwnSettlementStaysAResidualThroughARebalance() (gas: 7210236)\n[PASS] test_aCoinThatKeepsEverythingFailsALaterMintWholeAndRedeemsStillPay() (gas: 6569197)\n[PASS] test_aCoinThatKeepsEverythingFailsTheFirstMintWhole() (gas: 1464541)\n[PASS] test_aCoinThatKeepsEverythingFailsTheOneWeiMint() (gas: 3415197)\n[PASS] test_aDonationNeitherChangesHeldNorInflatesAMintOrARedeem() (gas: 2474375)\n[PASS] test_taxOnTopOfAPartialFillCreditsTheNetAndMintsThatFraction() (gas: 5236267)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 625.51ms (1.08s CPU time)\n\nRan 48 tests for test/Imdex5.t.sol:Imdex5Test\n[PASS] testFuzz_mintThenRedeemNeverPaysMoreThanDeposited(uint256,uint256) (runs: 256, μ: 2401927, ~: 2412435)\nLogs:\n  Bound result 4999000000000118661051\n  Bound result 1283\n\n[PASS] test_askPaysIntakeAndCaller() (gas: 1137820)\n[PASS] test_askReturnsWithoutFees() (gas: 155189)\n[PASS] test_askSevenDayInterval() (gas: 1189679)\n[PASS] test_bodyIsTheJsonTheBriefDescribes() (gas: 30573)\n[PASS] test_closeRequestAfterTwoDays() (gas: 1027162)\n[PASS] test_deployment() (gas: 94831)\n[PASS] test_feeImdOnlyLeavesForOracleAndRewards() (gas: 4930320)\n[PASS] test_fundAddsToFeeImd() (gas: 147750)\n[PASS] test_hookCannotReenter() (gas: 5142465)\n[PASS] test_mintBuysProportionallyAndRefunds() (gas: 1830201)\n[PASS] test_mintFirstBuysEqualPartsAndTakesFee() (gas: 1104043)\n[PASS] test_mintFirstKeepsWhatAPoolCouldNotTakeAsIdle() (gas: 1324714)\n[PASS] test_mintFirstRequiresZeroSupplyAndRightLength() (gas: 1022021)\n[PASS] test_mintFirstRevertsOnMinOut() (gas: 727109)\n[PASS] test_mintFirstRevertsWhenABuyFails() (gas: 814471)\n[PASS] test_mintFirstRevertsWhenABuyReturnsNothing() (gas: 2113122)\n[PASS] test_mintNeverIssuesSharesForNothing() (gas: 327985)\n[PASS] test_mintRequiresSupply() (gas: 40062)\n[PASS] test_mintRevertsOverMaxImdIn() (gas: 1732850)\n[PASS] test_mintRevertsWhenABuyFailsButScalesANonzeroShortFill() (gas: 2275588)\n[PASS] test_mintRoundsAgainstTheMinter() (gas: 1711530)\n[PASS] test_onOracleFailureOnlyFromIntake() (gas: 1064889)\n[PASS] test_onOracleResultStoresOnlyTheOpenRequestFromTheIntake() (gas: 1302614)\n[PASS] test_rebalanceNeedsAList() (gas: 41318)\n[PASS] test_rebalanceSellsAdoptsAndBuys() (gas: 5261907)\n[PASS] test_rebalanceSkipsADeadPool() (gas: 2983154)\n[PASS] test_rebalanceSkipsAHookThatLeavesAnUnsettledDelta() (gas: 3880126)\n[PASS] test_rebalanceSurvivesAHookThatBurnsAllGas() (gas: 5495285)\n[PASS] test_rebalanceTrimsAHoldingOverAQuarter() (gas: 3461572)\n[PASS] test_rebalanceWithNothingHeld() (gas: 2266050)\n[PASS] test_redeemCannotBeBlockedByACoin() (gas: 1575554)\n[PASS] test_redeemLastSharesPaysEverything() (gas: 2144299)\n[PASS] test_redeemPaysInKindLessHalfPercent() (gas: 1347307)\n[PASS] test_redeemRejectsZeroAndTooMany() (gas: 986033)\n[PASS] test_redeemSurvivesCoinsThatBurnAllGas() (gas: 4399409)\n[PASS] test_redeemToImdChargesTheFeeWhileOthersHold() (gas: 1668651)\n[PASS] test_redeemToImdPaysAShortFillInKindLessHalfPercent() (gas: 1780655)\n[PASS] test_redeemToImdPaysInKindWhenASaleFails() (gas: 2968070)\n[PASS] test_redeemToImdRevertsBelowMinOut() (gas: 1783406)\n[PASS] test_redeemToImdSellsAndTheLastHolderPaysNoFee() (gas: 1751812)\n[PASS] test_redeemToImdSurvivesAHookThatBurnsGas() (gas: 2457600)\n[PASS] test_submitRejectsASignedAttestationWithoutQuorum() (gas: 1128741)\n[PASS] test_submitRejectsAnExpiredAttestation() (gas: 1089458)\n[PASS] test_submitRejectsBadLists() (gas: 4717094)\n[PASS] test_submitRejectsWrongAnswerAndForgedSignature() (gas: 1645920)\n[PASS] test_submitStoresTheNextListAndRewards() (gas: 1527045)\n[PASS] test_unlockCallbackAndSwapSelfAreNotCallable() (gas: 103370)\nSuite result: ok. 48 passed; 0 failed; 0 skipped; finished in 625.48ms (533.63ms CPU time)\n\nRan 1 test for test/Imdex5TaxEverywhere.t.sol:Imdex5AllCoinsTaxedInvariantTest\n[PASS]\nImdex5AllCoinsTaxedInvariantTest invariants:\n[PASS] invariant_taxed_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_taxed_coinBalancesAreHeldPlusOwed\n[PASS] invariant_taxed_everyHoldingIsListed\n[PASS] invariant_taxed_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_taxed_zeroSupplyMeansNothingHeld\n Imdex5AllCoinsTaxedInvariantTest invariants (runs: 96, calls: 3840, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 215   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 217   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 230   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 213   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 431   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 214   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 239   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 213   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 224   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 196   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 222   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 193   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 191   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 208   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| TaxKnobs      | setTax           | 202   | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 45000000000000000000\n  Bound result 499999999999999999941\n  Bound result 10001\n  Bound result 8035\n  Bound result 21273\n  Bound result 5\n  Bound result 3719\n  Bound result 200000\n  Bound result 294164\n  Bound result 12687\n  Bound result 2940\n  Bound result 9337\n  Bound result 244572990811080708212\n  Bound result 128304\n  Bound result 1990291074542133917908\n  Bound result 191787475000343521937\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.99s (1.97s CPU time)\n\nRan 1 test for test/Imdex5.invariant.t.sol:Imdex5InvariantTest\n[PASS]\nImdex5InvariantTest invariants:\n[PASS] invariant_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_coinBalancesAreHeldPlusOwed\n[PASS] invariant_feeImdLeavesOnlyForTheOracleAndRewards\n[PASS] invariant_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_listShape\n[PASS] invariant_noFreeMintWhileValueIsHeld\n[PASS] invariant_requestStateIsConsistent\n[PASS] invariant_zeroSupplyMeansNothingHeld\n Imdex5InvariantTest invariants (runs: 96, calls: 3840, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 178   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 214   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | closeRequest     | 210   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverFailure   | 210   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 202   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 187   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 398   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 199   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 216   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 218   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 250   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 180   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 211   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 196   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 192   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 200   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 189   | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 190   | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 98000000000000000000\n  Bound result 13945\n  Bound result 128002\n  Bound result 499999999999999999801\n  Bound result 83059999999999999903\n  Bound result 5000000000000000000000\n  Bound result 168623979896987713927\n  Bound result 1283\n  Bound result 19\n  Bound result 633\n  Bound result 4472\n  Bound result 400887\n  Bound result 5809\n  Bound result 172800\n  Bound result 12029034692083795\n  Bound result 9160528332957214075891\n  Bound result 2092\n  Bound result 50\n  Bound result 159065277810454727585\n  Bound result 27657485\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.62s (2.60s CPU time)\n\nRan 1 test for test/Imdex5.invariant.t.sol:Imdex5TaxedCoinInvariantTest\n[PASS]\nImdex5TaxedCoinInvariantTest invariants:\n[PASS] invariant_actorsNeverExtractMoreImdThanTheyPutIn\n[PASS] invariant_coinBalancesAreHeldPlusOwed\n[PASS] invariant_feeImdLeavesOnlyForTheOracleAndRewards\n[PASS] invariant_imdBalanceIsIdlePlusFeePlusOwed\n[PASS] invariant_listShape\n[PASS] invariant_noFreeMintWhileValueIsHeld\n[PASS] invariant_requestStateIsConsistent\n[PASS] invariant_zeroSupplyMeansNothingHeld\n Imdex5TaxedCoinInvariantTest invariants (runs: 256, calls: 128000, reverts: 0)\n\n╭---------------+------------------+-------+---------+----------╮\n| Contract      | Selector         | Calls | Reverts | Discards |\n+===============================================================+\n| Imdex5Handler | ask              | 6718  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | claim            | 6623  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | closeRequest     | 6870  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverFailure   | 6846  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | deliverResult    | 6826  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | fund             | 6803  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mint             | 13419 | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | mintFirst        | 6820  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | rebalance        | 6831  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeem           | 6698  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | redeemToImd      | 6786  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setCoinFailMode  | 6591  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setHookMisbehave | 6747  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | setPoolMaxIn     | 6661  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | submit           | 6676  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | togglePool       | 6628  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | transferShares   | 6677  | 0       | 0        |\n|---------------+------------------+-------+---------+----------|\n| Imdex5Handler | warp             | 6780  | 0       | 0        |\n╰---------------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1948279459872595484217\n  Bound result 752110275\n  Bound result 172800\n  Bound result 38810938075980998578\n  Bound result 50000000000000000000\n  Bound result 16925\n  Bound result 604799\n  Bound result 8517\n  Bound result 361556\n  Bound result 1809584828809460813841\n  Bound result 4700\n  Bound result 13\n  Bound result 552383986483686246\n  Bound result 6121\n  Bound result 92327363653598192168\n  Bound result 2000000000000000000\n  Bound result 500000000000000000\n  Bound result 2970\n  Bound result 1442643772\n  Bound result 80\n  Bound result 691200\n  Bound result 749999999999999999\n  Bound result 48268669333576862027\n  Bound result 100000000000000000000\n  Bound result 759\n  Bound result 98\n  Bound result 518991\n  Bound result 448373551239569028659\n  Bound result 85911266903948174118\n  Bound result 22022\n  Bound result 99\n  Bound result 12345\n  Bound result 550987\n  Bound result 18527113593816942971\n  Bound result 824882116\n  Bound result 69251740215811937354\n  Bound result 1282992874699049879426\n  Bound result 304\n  Bound result 6641\n  Bound result 1750\n  Bound result 24362982194349809566\n  Bound result 40\n  Bound result 16696\n  Bound result 14264337593543950336\n  Bound result 50000000000000000000\n  Bound result 6431100696113791424\n  Bound result 1\n  Bound result 5865\n  Bound result 50590258710550212871\n  Bound result 1071326568876807487076\n  Bound result 39000000000000000000\n  Bound result 490\n  Bound result 10100\n  Bound result 20656\n  Bound result 21775\n  Bound result 1550\n  Bound result 271413092188967988962\n  Bound result 4209833798\n  Bound result 10602\n  Bound result 14960\n  Bound result 14473\n  Bound result 45586924784608609874\n  Bound result 825574019181123389393\n  Bound result 16134446248347384736\n  Bound result 1967177037100036847961\n  Bound result 40154351402929523115\n  Bound result 13632\n  Bound result 14937\n  Bound result 845000000000000000000\n  Bound result 767\n  Bound result 19370\n  Bound result 23189\n  Bound result 19051628225580285733\n  Bound result 1658\n  Bound result 4282813352766059161\n  Bound result 8529295168671728072194\n  Bound result 17428\n  Bound result 721582932263909576515\n  Bound result 3000\n  Bound result 3595\n  Bound result 5638\n  Bound result 1075\n  Bound result 3000000000000000000\n  Bound result 7728905084183689302668\n  Bound result 32\n  Bound result 6388\n  Bound result 1000000\n  Bound result 39100560725231980871\n  Bound result 102400\n  Bound result 490076\n  Bound result 3335669237430257793\n  Bound result 834\n  Bound result 228\n  Bound result 17961\n  Bound result 6\n  Bound result 27701357943844710613\n  Bound result 89523411\n  Bound result 360742\n  Bound result 38909672803529606512\n  Bound result 4242\n  Bound result 512960003\n  Bound result 40\n  Bound result 10205\n  Bound result 283224\n  Bound result 11515653705596244105\n  Bound result 3706535452212364912995\n  Bound result 855068926\n  Bound result 1341\n  Bound result 50000000000000000000\n  Bound result 1019\n  Bound result 100\n  Bound result 41\n  Bound result 7\n  Bound result 183028254442870\n  Bound result 537600\n  Bound result 400\n  Bound result 10181\n  Bound result 2\n  Bound result 21788952636611022928\n  Bound result 23000000000000000000\n  Bound result 2505\n  Bound result 3482\n  Bound result 18\n  Bound result 811512346982607269\n  Bound result 5635110525057462027\n  Bound result 4923\n  Bound result 828417\n  Bound result 1717813820887655166\n  Bound result 9304548040534138794\n  Bound result 1650799499265167058\n  Bound result 10000000000000000000\n  Bound result 17806\n  Bound result 44673645782500742\n  Bound result 7131045176731027579\n  Bound result 16331\n  Bound result 1153\n  Bound result 3713\n  Bound result 2283\n  Bound result 97\n  Bound result 123000000000000000000\n  Bound result 4294967295\n  Bound result 404860954079752088\n  Bound result 4298921846365373037\n  Bound result 7839032744\n  Bound result 150685449461098080\n  Bound result 499999999999999999997\n  Bound result 22061\n  Bound result 11034\n  Bound result 18891\n  Bound result 537\n  Bound result 7294\n  Bound result 99\n  Bound result 4242\n  Bound result 414\n  Bound result 9437\n  Bound result 20059\n  Bound result 18\n  Bound result 519747808000691602\n  Bound result 49834609737248065868\n  Bound result 9900\n  Bound result 4236827511228639289856\n  Bound result 2004742469452796\n  Bound result 2777\n  Bound result 4000000\n  Bound result 3349\n  Bound result 20558\n  Bound result 14275775234445590\n  Bound result 8980\n  Bound result 11849\n  Bound result 50000000000000000000\n  Bound result 300000\n  Bound result 24576\n  Bound result 542999\n  Bound result 277102476838428016\n  Bound result 344999999999999999999\n  Bound result 19951\n  Bound result 209879485014438494\n  Bound result 17\n  Bound result 98000000000000000000\n  Bound result 599796025732405\n  Bound result 22142\n  Bound result 675\n  Bound result 300000\n  Bound result 8669378657565447230\n  Bound result 0\n  Bound result 5784109118423099725\n  Bound result 230434613628650746785\n  Bound result 2862\n  Bound result 29230874566652138\n  Bound result 2244311458269623947\n  Bound result 795000000000000000000\n  Bound result 63717000366761426\n  Bound result 7333\n  Bound result 1597348956607419\n  Bound result 3148763282087456\n  Bound result 4918333879207383231\n  Bound result 4304049555627815293114\n  Bound result 2641125619270734481\n  Bound result 6714\n  Bound result 1\n  Bound result 6058134637377280690\n  Bound result 200000000000000000000\n  Bound result 18705\n  Bound result 11625\n  Bound result 1282\n  Bound result 2379\n  Bound result 10182\n  Bound result 50\n  Bound result 1000000000000000\n  Bound result 6916\n  Bound result 125967040277133470970\n  Bound result 612642\n  Bound result 1\n  Bound result 5479\n  Bound result 41235539224657880483\n  Bound result 5\n  Bound result 1282\n  Bound result 19967\n  Bound result 1266520864399308758\n  Bound result 13576\n  Bound result 230394\n  Bound result 50000000000000000000\n  Bound result 1314045897371625\n  Bound result 16380\n  Bound result 200\n  Bound result 494999999999999999999\n  Bound result 2907\n  Bound result 12\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 90.42s (90.41s CPU time)\n\nRan 14 test suites in 90.43s (98.72s CPU time): 145 tests passed, 0 failed, 7 skipped (152 total tests)\n","passed":true},{"durationMs":109,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Imdex5.approve(address,uint256)\",\"Imdex5.ask()\",\"Imdex5.claim(address)\",\"Imdex5.closeRequest()\",\"Imdex5.fund(uint256)\",\"Imdex5.mint(uint256,uint256,uint256)\",\"Imdex5.mintFirst(uint256,uint256[])\",\"Imdex5.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"Imdex5.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"Imdex5.rebalance()\",\"Imdex5.redeem(uint256)\",\"Imdex5.redeemToImd(uint256,uint256)\",\"Imdex5.submit((bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"Imdex5.swapSelf(address,address,bool,uint256,bool,bool)\",\"Imdex5.transfer(address,uint256)\",\"Imdex5.transferFrom(address,address,uint256)\",\"Imdex5.unlockCallback(bytes)\"],\"files\":{\".gitignore\":2,\"ADAPTATION.md\":244,\"README.md\":315,\"THREAT_MODEL.md\":44,\"foundry.toml\":19,\"launch.json\":10,\"src/Imdex5.sol\":663,\"src/Interfaces.sol\":61,\"src/OracleAttestation.sol\":221,\"test/Fix3.fork.t.sol\":97,\"test/Fix3Floor.fork.t.sol\":67,\"test/Fix3Rebalance.fork.t.sol\":151,\"test/Imdex5.invariant.t.sol\":544,\"test/Imdex5.t.sol\":1070,\"test/Imdex5Base.sol\":175,\"test/Imdex5Edges.t.sol\":741,\"test/Imdex5ResidualSpot.t.sol\":182,\"test/Imdex5Revised.t.sol\":503,\"test/Imdex5ShortFill.t.sol\":226,\"test/Imdex5TaxEverywhere.t.sol\":531,\"test/Imdex5TaxedCoin.t.sol\":252,\"test/OracleConsumerConformance.t.sol\":74,\"test/mocks/AttackMocks.sol\":85,\"test/mocks/Mocks.sol\":337,\"test/mocks/PoolTaxERC20.sol\":25,\"test/mocks/TaxERC20.sol\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":9165,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/Imdex5.sol:370: Reentrancy in Imdex5._mintFirst(address,uint256,uint256[]) (src/Imdex5.sol#370-389):\n[high/medium] reentrancy-balance at src/Imdex5.sol:391: Reentrancy in Imdex5._mintMore(address,uint256,uint256,uint256) (src/Imdex5.sol#391-444):\n[high/medium] reentrancy-balance at src/Imdex5.sol:391: Reentrancy in Imdex5._mintMore(address,uint256,uint256,uint256) (src/Imdex5.sol#391-444):\n[medium/high] incorrect-equality at src/Imdex5.sol:630: Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Imdex5.sol:446: Imdex5._redeemToImd(address,uint256,uint256,uint256) (src/Imdex5.sol#446-475) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Imdex5.sol:370: Imdex5._mintFirst(address,uint256,uint256[]) (src/Imdex5.sol#370-389) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Imdex5.sol:602: Imdex5._amountValue(address,uint256,uint256,Math.Rounding) (src/Imdex5.sol#602-610) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Imdex5.sol:630: Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Imdex5.sol:630: Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/Imdex5.sol:391: Imdex5._mintMore(address,uint256,uint256,uint256) (src/Imdex5.sol#391-444) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/Imdex5.sol:477: Reentrancy in Imdex5._rebalance() (src/Imdex5.sol#477-523):\n[medium/medium] reentrancy-no-eth at src/Imdex5.sol:477: Reentrancy in Imdex5._rebalance() (src/Imdex5.sol#477-523):\n[medium/medium] reentrancy-no-eth at src/Imdex5.sol:370: Reentrancy in Imdex5._mintFirst(address,uint256,uint256[]) (src/Imdex5.sol#370-389):\n[medium/medium] reentrancy-no-eth at src/Imdex5.sol:202: Reentrancy in Imdex5.redeem(uint256) (src/Imdex5.sol#202-223):\n[medium/medium] reentrancy-no-eth at src/Imdex5.sol:446: Reentrancy in Imdex5._redeemToImd(address,uint256,uint256,uint256) (src/Imdex5.sol#446-475):\n[medium/medium] reentrancy-no-eth at src/Imdex5.sol:477: Reentrancy in Imdex5._rebalance() (src/Imdex5.sol#477-523):\n[medium/medium] uninitialized-local at src/Imdex5.sol:652: Imdex5._lookup(uint64).registry (src/Imdex5.sol#652) is a local variable never initialized\n[medium/medium] unused-return at src/Imdex5.sol:338: Imdex5.rebalance() (src/Imdex5.sol#338-343) ignores return value by IPoolManager(POOL_MANAGER).unlock(abi.encode(Op.Rebalance,msg.sender,0,0,0,new uint256[](0))) (src/Imdex5.sol#340)\n[medium/medium] unused-return at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) ignores return value by IPoolManager(POOL_MANAGER).settle() (src/Imdex5.sol#573)\n[medium/medium] unused-return at src/Imdex5.sol:228: Imdex5.redeemToImd(uint256,uint256) (src/Imdex5.sol#228-234) ignores return value by IPoolManager(POOL_MANAGER).unlock(abi.encode(Op.RedeemToImd,msg.sender,shares,minImdOut,supply,new uint256[](0))) (src/Imdex5.sol#232-233)\n[medium/medium] unused-return at src/Imdex5.sol:191: Imdex5.mint(uint256,uint256,uint256) (src/Imdex5.sol#191-197) ignores return value by IPoolManager(POOL_MANAGER).unlock(abi.encode(Op.Mint,msg.sender,shares,maxImdIn,minShares,new uint256[](0))) (src/Imdex5.sol#195-196)\n[medium/medium] unused-return at src/Imdex5.sol:178: Imdex5.mintFirst(uint256,uint256[]) (src/Imdex5.sol#178-184) ignores return value by IPoolManager(POOL_MANAGER).unlock(abi.encode(Op.MintFirst,msg.sender,imdIn,0,0,minOut)) (src/Imdex5.sol#183)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: before = IERC20(outCur).balanceOf(address(this)) (src/Imdex5.sol#576)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: IPoolManager(POOL_MANAGER).exttload(NONZERO_DELTA_COUNT_SLOT) != 0 (src/Imdex5.sol#581)\n[low/medium] calls-loop at src/Imdex5.sol:537: Imdex5._tryBuy(Imdex5.Coin,uint256) (src/Imdex5.sol#537-546) has external calls inside a loop: (amountIn,out) = this.swapSelf{gas: SWAP_GAS}(coin.token,coin.hook,true,imdAmount,false,true) (src/Imdex5.sol#538-545)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: delta = IPoolManager(POOL_MANAGER).swap(key,IPoolManager.SwapParams(zeroForOne,int256(amount),limit),) (src/Imdex5.sol#560-561)\n[low/medium] calls-loop at src/Imdex5.sol:446: Imdex5._redeemToImd(address,uint256,uint256,uint256) (src/Imdex5.sol#446-475) has external calls inside a loop: (amountIn,sold) = this.swapSelf{gas: SWAP_GAS}(coin.token,coin.hook,false,amount,false,false) (src/Imdex5.sol#455-463)\n[low/medium] calls-loop at src/Imdex5.sol:651: Imdex5._lookup(uint64) (src/Imdex5.sol#651-662) has external calls inside a loop: artifacts = registry.artifactsOf(launch) (src/Imdex5.sol#656)\n[low/medium] calls-loop at src/Imdex5.sol:590: Imdex5._sqrtPrice(IPoolManager.PoolKey) (src/Imdex5.sol#590-593) has external calls inside a loop: uint256(uint160(uint256(IPoolManager(POOL_MANAGER).extsload(slot)))) (src/Imdex5.sol#592)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: IPoolManager(POOL_MANAGER).sync(inCur) (src/Imdex5.sol#571)\n[low/medium] calls-loop at src/Imdex5.sol:630: Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642) has external calls inside a loop: (ok,ret) = token.call{gas: PAY_GAS}(abi.encodeCall(IERC20.transfer,(to,amount))) (src/Imdex5.sol#633)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: IPoolManager(POOL_MANAGER).settle() (src/Imdex5.sol#573)\n[low/medium] calls-loop at src/Imdex5.sol:391: Imdex5._mintMore(address,uint256,uint256,uint256) (src/Imdex5.sol#391-444) has external calls inside a loop: (rIn,rOut) = this.swapSelf{gas: SWAP_GAS}(coin.token,coin.hook,true,need,true,false) (src/Imdex5.sol#409-417)\n[low/medium] calls-loop at src/Imdex5.sol:651: Imdex5._lookup(uint64) (src/Imdex5.sol#651-662) has external calls inside a loop: REGISTRY_B.isRecorded(launch) (src/Imdex5.sol#654)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: delta = IPoolManager(POOL_MANAGER).swap(key,IPoolManager.SwapParams(zeroForOne,- int256(amount),limit),) (src/Imdex5.sol#560-561)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: amountOut = IERC20(outCur).balanceOf(address(this)) - before (src/Imdex5.sol#578)\n[low/medium] calls-loop at src/Imdex5.sol:548: Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583) has external calls inside a loop: IPoolManager(POOL_MANAGER).take(outCur,address(this),amountOut) (src/Imdex5.sol#577)\n[low/medium] calls-loop at src/Imdex5.sol:651: Imdex5._lookup(uint64) (src/Imdex5.sol#651-662) has external calls inside a loop: REGISTRY_A.isRecorded(launch) (src/Imdex5.sol#653)\n[low/medium] calls-loop at src/Imdex5.sol:630: Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642) has external calls inside a loop: (ok,ret) = token.call{gas: PAY_GAS}(abi.encodeCall(IERC20.transfer,(to,amount))) (src/Imdex5.sol#633)\n[low/medium] calls-loop at src/Imdex5.sol:526: Imdex5._trySell(Imdex5.Coin,uint256) (src/Imdex5.sol#526-535) has external calls inside a loop: (amountIn,out) = this.swapSelf{gas: SWAP_GAS}(coin.token,coin.hook,false,amount,false,true) (src/Imdex5.sol#527-534)\n[low/medium] reentrancy-benign at src/Imdex5.sol:477: Reentrancy in Imdex5._rebalance() (src/Imdex5.sol#477-523):\n[low/medium] reentrancy-benign at src/Imdex5.sol:446: Reentrancy in Imdex5._redeemToImd(address,uint256,uint256,uint256) (src/Imdex5.sol#446-475):\n[low/medium] reentrancy-benign at src/Imdex5.sol:630: Reentrancy in Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642):\n[low/medium] reentrancy-benign at src/Imdex5.sol:526: Reentrancy in Imdex5._trySell(Imdex5.Coin,uint256) (src/Imdex5.sol#526-535):\n[low/medium] reentrancy-benign at src/Imdex5.sol:247: Reentrancy in Imdex5.ask() (src/Imdex5.sol#247-272):\n[low/medium] reentrancy-benign at src/Imdex5.sol:338: Reentrancy in Imdex5.rebalance() (src/Imdex5.sol#338-343):\n[low/medium] reentrancy-benign at src/Imdex5.sol:537: Reentrancy in Imdex5._tryBuy(Imdex5.Coin,uint256) (src/Imdex5.sol#537-546):\n[low/medium] reentrancy-events at src/Imdex5.sol:537: Reentrancy in Imdex5._tryBuy(Imdex5.Coin,uint256) (src/Imdex5.sol#537-546):\n[low/medium] reentrancy-events at src/Imdex5.sol:446: Reentrancy in Imdex5._redeemToImd(address,uint256,uint256,uint256) (src/Imdex5.sol#446-475):\n[low/medium] reentrancy-events at src/Imdex5.sol:526: Reentrancy in Imdex5._trySell(Imdex5.Coin,uint256) (src/Imdex5.sol#526-535):\n[low/medium] reentrancy-events at src/Imdex5.sol:630: Reentrancy in Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642):\n[low/medium] reentrancy-events at src/Imdex5.sol:477: Reentrancy in Imdex5._rebalance() (src/Imdex5.sol#477-523):\n[low/medium] reentrancy-events at src/Imdex5.sol:548: Reentrancy in Imdex5._swap(address,address,bool,uint256,bool,bool) (src/Imdex5.sol#548-583):\n[low/medium] reentrancy-events at src/Imdex5.sol:477: Reentrancy in Imdex5._rebalance() (src/Imdex5.sol#477-523):\n[low/medium] return-bomb at src/Imdex5.sol:630: Imdex5._pay(address,address,uint256) (src/Imdex5.sol#630-642) tries to limit the gas of an external call that controls implicit decoding\n[low/medium] timestamp at src/Imdex5.sol:276: Imdex5.onOracleResult(bytes32,OracleAttestation.Attestation,bytes) (src/Imdex5.sol#276-287) uses timestamp for comparisons\n[low/medium] timestamp at src/Imdex5.sol:300: Imdex5.closeRequest() (src/Imdex5.sol#300-306) uses timestamp for comparisons\n[low/medium] timestamp at src/Imdex5.sol:290: Imdex5.onOracleFailure(bytes32,uint8,bytes32,uint16,uint16,bytes) (src/Imdex5.sol#290-297) uses timestamp for comparisons\n[low/medium] timestamp at src/Imdex5.sol:247: Imdex5.ask() (src/Imdex5.sol#247-272) uses timestamp for comparisons\n[low/medium] timestamp at src/OracleAttestation.sol:157: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/OracleAttestation.sol#157-165) uses timestamp for comparisons","passed":true},{"durationMs":1118,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/Imdex5.sol:156: `abi.encodePacked()` Hash Collision\n[high] reentrancy-state-change at src/Imdex5.sol:259: Reentrancy: State change after external call\n[low] costly-loop at src/Imdex5.sol:209: Costly operations inside loop (11 places)\n[low] internal-function-used-once at src/OracleAttestation.sol:210: Internal Function Used Only Once\n[low] large-numeric-literal at src/Imdex5.sol:35: Large Numeric Literal (3 places)\n[low] require-revert-in-loop at src/Imdex5.sol:322: Loop Contains `require`/`revert` (4 places)\n[low] unchecked-return at src/Imdex5.sol:183: Unchecked Return (5 places)\n[low] unsafe-erc20-operation at src/Imdex5.sol:633: Unsafe ERC20 Operation\n[low] unused-import at src/Imdex5.sol:7: Unused Import","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"cff13967fd81c1be8d3b5262a5b678030a07e77d4c4da5a05bd57294a3ed6cae","verifiedTreeHash":"38961c2af05a5660ef35bc453a0e99fc454c8811","verifierVersion":"0.1.0+a26ee00d"}]}