{"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":"b8fd4c2b-e0a5-48bd-951f-222b3f3a342c","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"b4c12f92d7bf2cac1482bd7299012086b538b20fc8b4b6329f72f509590c2d26","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"75e1a145acab7387ce9877f7381ccf05c30724daf83f27864ee0f3d027ad26c5","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"5319631485c374335c52f91fca79e73e83c846cd602d0a27d63f8a3cb07e93ec","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"d3a4f7bab1b1a2ba614e5bbb5661ec5356f9706513402a1ee8cc41014f11c5a8","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"e1485e02a8ec4c4ae2b26dc7bd977664e92bc284a9c4e9c53098a07c72962d61","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"cb8af8ec1b982a6c66617baa086bbb44b314461e54e17f201addab49d5696564","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"7f69bf5074d9956aeff0b25ac237258be6117d31290993276400139d3079177b","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"d8ca9f6614dde638afe3bc970064203d364f18dce553dedbd81c3f03fb37cbd5","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Basket Protocol vault: an index vault for Stock Tokens on Robinhood Chain (chain id 4663). Contracts only: no launch token, pool or website. BASK is the vault's own ERC-20 share (18 decimals). Say \"Stock Tokens\", never \"tokenized\".\nToken name: Basket\nToken symbol: BASK\nTotal supply: 0 at deployment, no cap: deposit mints, redeem burns\n\nBUILD RULES\n- Simplest code that satisfies this text: add no feature, role, setting or safeguard.\n- solc 0.8.26, optimizer on, 200 runs, via_ir, evm cancun, bytecode_hash none; custom errors.\n- If BaskVault exceeds 24,000 bytes of runtime, move views into BaskLens(address vault = $contract:BaskVault); never drop a check.\n- Constructors call no other contract.\n- No proxy, delegatecall, selfdestruct, rescue or sweep. User-facing state changes are nonReentrant and emit events.\n\nMANIFEST\n1. BaskVault(address owner_, address guardian_): owner_ = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3, guardian_ = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68, written as these literals. Reverts if either is zero or they are equal.\n\nOutside contracts (tests mock exactly these under test/; no fork tests, no vm.env):\n- Token: ERC-20; may have oraclePaused() returns bool.\n- Feed: decimals() <= 18, latestRoundData(); answer = USD per whole token.\n- Pool: Uniswap v3 style token0(), token1(), observe(uint32[]).\n\nASSETS: (token, feed, pool, quoteFeed, minLiquidity, open, retired, hasPause, centre), at most maxAssets. managed[token] is the accounting balance; value never uses balanceOf.\nListing checks (proposal and execution): token not listed; token and feed decimals() <= 18; feed not used by another unretired asset; answer > 0 and under maxAge. At listing: open, centre = answer, hasPause = oraclePaused() returns a bool.\nGenesis: until finalizeGenesis() (once, needs 3+ assets), the owner lists assets with their pools at once; deposits open at finalize.\nAnyone may remove a retired asset with managed and totalOwed 0; its token may then be listed again.\n\nPROPOSALS (owner): list an asset with its pool; new feed (centre = new answer); re-centre on the answer at execution, under maxAge; reopen (cancelled by any later close); retire (closed both times); set an asset's pool, quoteFeed and minLiquidity, or none; resync (managed += balanceOf - managed - totalOwed, if above 0); new guardian; raise NAV_CAP; set feeRecipient (not zero or the vault); change a setting within its bounds. A proposal waits 2 days, then only the owner executes it; it lapses 7 days later; the owner or guardian may cancel it, the guardian not its own replacement. A retired asset is closed for good, voids its pending proposals, then takes only resync, is 0 in NAV and skipped by every deposit check even with managed > 0.\n\nSETTINGS (start; bounds): band 4 (2-100); maxAge 80 hours, noPoolAge 26 hours (1 hour-30 days); freshCount 0 (0-10), freshHours 4 (1-48); hours Mon-Fri from-to UTC (seconds of day; start 0-0 = always open); poolWindow 1800 s (300-86400); poolDeviation 300 bps (50-2000); feedGas, pauseGas 100,000, poolGas 150,000, balanceGas 50,000, payGas 250,000 (each 20,000-500,000); maxAssets 250; directLimit 50. A change must keep maxAssets >= asset count, maxAssets * (balanceGas + 60,000) <= 28,000,000 and directLimit * (balanceGas + payGas + 70,000) <= 28,000,000.\n\nPRICE is valid only if the feed read succeeds (feedGas), answer > 0, centre / band <= answer <= centre * band, updatedAt <= now, now - updatedAt <= maxAge, oraclePaused() returns false if hasPause (pauseGas), and: with a pool, its observe over poolWindow (poolGas; Uniswap OracleLibrary.consult) succeeds with mean liquidity >= minLiquidity and its mean-tick price per whole token in whole quote tokens, times the quoteFeed price (> 0, under maxAge), is within poolDeviation of the feed price in USD; with no pool, now - updatedAt <= noPoolAge. value(amount) = amount * answer * 1e18 / 10^(token decimals + feed decimals), rounded down. USD amounts below are dollars times 1e18.\n\ndeposit(tokens[], amounts[], receiver, minSharesOut, deadline) requires:\n- deposits open, not paused, inside hours; each token listed, open, once, amount > 0, vault balance >= totalOwed[token]; receiver not the vault;\n- freshCount or more unretired assets updated within freshHours;\n- a valid price for each token and every unretired asset with managed > 0; no unretired asset short or unreadable.\nPull the tokens; each vault balance must rise by exactly its amount. NAV = sum of value(managed) before; v = sum of value(amounts).\ngross = v if totalSupply is 0, else v * totalSupply / NAV rounded down (revert if NAV is 0). fee = gross * 50 / 10000, rounded up, minted to feeRecipient; no fee while unset. The receiver gets gross - fee; on the first deposit 1e15 of that goes to address(0xdEaD) instead. It must be > 0 and >= minSharesOut. NAV + v <= NAV_CAP (starts 1,000,000; lowering cancels pending raises; never above 10,000,000,000).\n\nredeem(shares, receiver, minAmountsOut[], deadline), receiver not zero, reads no price, ignores every pause and never reverts because of an asset. fee = shares * 50 / 10000 rounded up, transferred to feeRecipient; no fee while unset. net = shares - fee is burned. Per asset with managed > 0: available = balanceOf(vault) - totalOwed[token], floor 0 (balanceGas static call, 32 bytes copied; else unreadable: available = managed); leg = min(managed, available) * net / totalSupplyBeforeBurn, rounded down; require leg >= minAmountsOut[i] (missing entry = 0); managed -= leg. If at most directLimit assets have managed > 0, each leg is paid to receiver by an external function only the vault may call, given payGas, reverting unless the transfer succeeds, returns nothing or true, and the vault balance falls by exactly leg; if that fails, or above directLimit, owed[receiver][token] and totalOwed[token] grow by leg. claim(tokens[], to), to not zero, pays each min(caller's owed, vault balance) by the same function with no gas limit.\n\nLOSSES. An asset is short when available < managed. Nothing lowers managed automatically. flagDeficit(token), by anyone, records shortfall and time if larger than recorded, or clears the record if not short. recognizeLoss(token), by anyone 7 days or more later, lowers managed by min(recorded, current shortfall) and clears the record. A deposit clears unretired records.\n\nRoles:\n- Owner (two-step transfer, never to the guardian, no renounce): genesis, proposals, cancel; at once: close an asset to deposits, pause and unpause deposits, lower NAV_CAP.\n- Guardian: pause deposits, close an asset, cancel as stated.\n- Nobody can move assets, block redeem or claim, mint outside deposit, change a fee or upgrade.\n\nVIEWS: all assets (config, answer, updatedAt, pool price, managed, short, totalOwed); settings; previewDeposit; previewRedeem; depositStatus(tokens[]): reason and asset at fault; pending proposals.\n\nREVIEW. Accepted, add no mechanism: (1) profit from feed lag under poolDeviation; (2) the owner pairs each token with its true feed and pool; (3) no per-asset limit; (4) moving a thin pool can stop deposits; (5) depositors after a retire share its tokens. MUST ATTACK: redeem with paused, blocked or upgraded tokens (maxAssets assets in any state: under 28,000,000 gas); any way a role or a setting blocks redeem.","parentJobId":null,"planHash":"386313458b695e0faa444a96b46bc99e5d1c8b9c1611ecfe0703bf418be08373","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"b8fd4c2b-e0a5-48bd-951f-222b3f3a342c","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1020-basket"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52254","feedbackHash":"433bcdfe0cd67a2803a8d3287d734ee2349daac616821aa58b696c698739f360","nodeKey":"audit_economics","submissionHash":"b4c12f92d7bf2cac1482bd7299012086b538b20fc8b4b6329f72f509590c2d26","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52120","feedbackHash":"b6624156b9c26039ecae19d7c94cc3b0027bb4572039742181efacc8add5372f","nodeKey":"audit_flow","submissionHash":"75e1a145acab7387ce9877f7381ccf05c30724daf83f27864ee0f3d027ad26c5","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51442","feedbackHash":"bf484b90ac6fcda3c806d9898e53ced3698879fa95f62e01b8243a0341136483","nodeKey":"audit_judge","submissionHash":"791418525a4f42be31cef1a1d792a33d07ed6efb4b0d61cafbd02077b2b168e8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51162","feedbackHash":"a8fc8327cdc210cb1a461f9f80021e29b79550070cb6cb7a892096a122f7e9b0","nodeKey":"audit_judge","submissionHash":"5319631485c374335c52f91fca79e73e83c846cd602d0a27d63f8a3cb07e93ec","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52121","feedbackHash":"1c2b499f09c33eb07268b57166ad26800c182bd584da9e7a1be195dd0137306e","nodeKey":"audit_math","submissionHash":"d3a4f7bab1b1a2ba614e5bbb5661ec5356f9706513402a1ee8cc41014f11c5a8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52124","feedbackHash":"2f3ec97e6edad4a857c0bbf5755caa774ced09bb3d461c4fb2138141f6354514","nodeKey":"audit_permissions","submissionHash":"e1485e02a8ec4c4ae2b26dc7bd977664e92bc284a9c4e9c53098a07c72962d61","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51212","feedbackHash":"d39d14c97f635955231d9c8bac74a9b889f04e5ed9cd80cf5afc9b4dd5fa910e","nodeKey":"build_contract_project","submissionHash":"1efaa88c53aaf45144531d4b7dee093fdb2ccbceccfca0007d2a3cab2903648b","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51453","feedbackHash":"0c4812868d3238eea8fdfa2e882bce92ede970f805151e8f2406188474aa0f22","nodeKey":"build_contract_project","submissionHash":"cb8af8ec1b982a6c66617baa086bbb44b314461e54e17f201addab49d5696564","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51003","feedbackHash":"0658bb0451073e6e806542b97f7eea2acc70947b6fbf05fcdb80a4f6962656d1","nodeKey":"manifest","submissionHash":"01561caf813d7f56714771750232230198d5aba866e60c258429714eb8f39cc1","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51220","feedbackHash":"2537c1877537d090eaeca9dab96366c042d1e6d33b601ed541d5186a56773f68","nodeKey":"manifest","submissionHash":"7f69bf5074d9956aeff0b25ac237258be6117d31290993276400139d3079177b","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51436","feedbackHash":"53c670dd6ec3314a258d95d11068f6ebb696203368a0356bddbb60c990c97915","nodeKey":"write_foundry_tests","submissionHash":"d79b7e6efb7f6dbd332c56871a34f59be05f9dd272470e5c0d36b8c26bde2eec","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52370","feedbackHash":"f6e7509a8e41834249ae08098bcabc55f398a19631f5b6210e9a5fa8c4becb76","nodeKey":"write_foundry_tests","submissionHash":"d8ca9f6614dde638afe3bc970064203d364f18dce553dedbd81c3f03fb37cbd5","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"f6ec58cef221cae34e08587271d617e73b295039b01a8555ce3188aad3e9afca","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"c389978066e1399d4436541acd87b777b0e3fdaa32f5395255acfe59d614a081","device":"2d977abd7ffb09d4","findings":[],"hash":"01561caf813d7f56714771750232230198d5aba866e60c258429714eb8f39cc1","nodeId":"b4a0eb40-afee-4a7e-a700-fe87016a4990","outcome":"completed","summary":"Updated [launch.json](/Users/zhuminquan/.identitymd-2/work/b8fd4c2b-e0a5-48bd-951f-222b3f3a342c/b4a0eb40-afee-4a7e-a700-fe87016a4990/launch.json), preserving the required constructor literals and clarifying BASK’s uncapped supply.\n\n- Manifest and constructor ABI checks passed.\n- `forge build` succeeded with existing lint warnings.\n- All 66 tests passed, including hostile redemption gas tests.\n- Runtime: 23,424 bytes.\n\nOnly `launch.json` changed for submission.","treeHash":"1cd9bc3a0418a6f7b9e13c9736d0dcd40138abff","usage":{"cachedInputTokens":153856,"inputTokens":30598,"model":"gpt-6-astra","outputTokens":2671,"runtime":"codex","turns":3,"wallClockMs":153487}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"87f02002d6a2b915","findings":[],"hash":"147e53e869ba6d33199e648a8ebdedc124bcade139731b3fb86c185eadaa14f9","nodeId":"b4a0eb40-afee-4a7e-a700-fe87016a4990","outcome":"failed","summary":"the task produced no changes; the agent's last message was: The existing [launch.json](/home/identitymd/.identitymd/work/b8fd4c2b-e0a5-48bd-951f-222b3f3a342c/b4a0eb40-afee-4a7e-a700-fe87016a4990/launch.json) already matches the schema, compiled constructor, and required literal addresses. Preserved unchanged.\n\n- `forge build`: passed.\n- `forge test`: 78 passed, 0 failed.\n- Runtime: 23,736 bytes; no lens required.\n\nNo submitted files changed.","treeHash":null,"usage":{"cachedInputTokens":314880,"inputTokens":44733,"model":"gpt-6-astra","outputTokens":3001,"runtime":"codex","turns":3,"wallClockMs":133941}},{"artifacts":[],"attempt":1,"bundleHash":"198918bd7a20e9f070d218443ed16b2212e7714c8a2936bfd72b86f042aa8e84","device":"613f0b69bde9876a","findings":[],"hash":"1efaa88c53aaf45144531d4b7dee093fdb2ccbceccfca0007d2a3cab2903648b","nodeId":"9111e8dd-57e1-447d-b7c1-dc670bc4a7ca","outcome":"completed","summary":"Implemented the vault, deployment manifest, vendored dependencies, tests, and operating documentation.\n\n- `forge build`, `forge test`, and `forge fmt --check` pass.\n- 66 tests pass.\n- Runtime: 23,424 bytes.\n- Worst measured redemption call: 27.91 million gas, below 28 million.\n\nDeployment setup and responsibilities are documented in `README.md`; attack results are in `SECURITY.md`.","treeHash":"496ad7cd89b7e843ed9fa218a57d69590fd7748e","usage":{"cachedInputTokens":3641600,"inputTokens":165219,"model":"gpt-6-astra","outputTokens":63914,"runtime":"codex","turns":8,"wallClockMs":2614309}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"771f83f312eace21","findings":[],"hash":"5319631485c374335c52f91fca79e73e83c846cd602d0a27d63f8a3cb07e93ec","nodeId":"a20a7480-c823-416d-ba30-351c8cb1bd6b","outcome":"completed","summary":"Review settled. The findings file is written with an empty findings list and a 27-row coverage record. The tree has no other changes.\n\n**Earlier high finding (settings inequalities vs the 28M redeem budget) is fixed.** The vault now keeps a held-asset count and an index bitmap, updated on every managed zero crossing and relocated on swap-and-pop removal, so redeem skips idle assets without cold reads and no longer scans holdings twice. I ran the unchanged pinned proof and the four specialist proofs against the revised code and all pass. I also probed every regime the brief's two inequalities bound, with fees, maximum quantities and full minima arrays:\n\n| Scenario | Gas |\n| --- | --- |\n| 254 listed, 45 direct, payGas 500k (pinned proof) | 27,055,311 |\n| 50 held deferred at balanceGas 500k (tightest) | 27,908,870 |\n| 26 direct of 50 at 500k/500k | 27,374,297 |\n| 350 held deferred at balanceGas 20k | 26,869,367 |\n| 254 direct at 20k/20k | 24,707,122 |\n\nA 400-run fuzz over deposit, redeem, loss, resync, retire, remove and relist kept the held count and every bitmap bit equal to the managed balances, with no stale bits beyond the array length. Idle-slot minima semantics are unchanged.\n\n**Earlier deposit-debt finding is fixed.** An unretired asset with zero managed but claims above its balance no longer blocks deposits of other assets. Input tokens still need balance to cover claims, matching the brief.\n\n**The four disputed advisories stand as scope decisions, not defects.** Managed dust blocking removal, the vault as a redeem receiver, positional minima reordering, and split dilution before Resync all follow from rules the brief states explicitly and are now documented in the README. I did not restate them as findings.\n\n**No new defects found.** The static-analysis leads were checked and are false positives for this code. All 106 project tests pass.","treeHash":null,"usage":{"cachedInputTokens":1822158,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":27763,"runtime":"claude","turns":23,"wallClockMs":619244}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a5c5e95a2ed07117","findings":[{"citation":"resolved","description":"The brief requires redeem to stay under 28,000,000 gas with maxAssets assets in any state and says no role or setting may block redeem. _changedSettings enforces `maxAssets * (balanceGas + 60,000) <= 28M` and `directLimit * (balanceGas + payGas + 70,000) <= 28M` as two independent inequalities. A single redeem pays both costs at once: it loops over every listed asset (two cold SLOADs per asset in the count loop plus the second loop) and additionally spends balanceGas + payGas plus about 50k of storage writes on each of the directLimit active legs. With balanceGas 20,000, maxAssets 350, directLimit 47 and payGas 500,000 (each change accepted by the vault's own validation: 350*80,000 = 28,000,000 and 47*590,000 = 27,730,000), a vault holding 47 Stock Tokens whose upgraded code burns all gas in balanceOf and transfer, with 303 further listed but empty assets, needs 28,445,086 gas to redeem. Given a 28,000,000 budget the call runs out of gas and reverts, so every holder's redeem is blocked by a setting plus hostile tokens, exactly the case the brief says must be attacked. The existing RedemptionGas tests never combine the maximum asset count with the maximum payment allowance (the 500k/500k case uses only 49 assets, the 350-asset case uses no direct legs). Minimal fix that keeps the design: validate the two terms jointly, e.g. require `maxAssets * (balanceGas + 60,000) + directLimit * (payGas + 70,000) <= 28,000,000` (or any joint bound the author derives), so that the per-asset loop cost and the direct-payment cost cannot sum past the budget.","line":437,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\nimport {BaskTypes as T} from \"src/BaskTypes.sol\";\n\n/// @dev Hostile \"upgraded\" Stock Token: once hostile, balanceOf and transfer consume all gas given to them.\ncontract BurnToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) internal balances;\n    mapping(address => mapping(address => uint256)) public allowance;\n    bool public hostile;\n\n    function mint(address to, uint256 amount) external {\n        balances[to] += amount;\n    }\n\n    function setHostile(bool v) external {\n        hostile = v;\n    }\n\n    function approve(address to, uint256 amount) external returns (bool) {\n        allowance[msg.sender][to] = amount;\n        return true;\n    }\n\n    function balanceOf(address who) external view returns (uint256) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        return balances[who];\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        require(allowance[from][msg.sender] >= amount, \"allowance\");\n        balances[from] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        balances[msg.sender] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n}\n\ncontract SimpleFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer;\n    uint256 public updatedAt;\n\n    function set(uint256 time) external {\n        answer = 100e8;\n        updatedAt = time;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// @title Redeem must stay under 28,000,000 gas with maxAssets assets in any state.\n/// The vault validates `maxAssets * (balanceGas + 60k) <= 28M` and `directLimit * (balanceGas + payGas + 70k) <= 28M`\n/// separately. Both hold for balanceGas 20k, maxAssets 350, directLimit 47, payGas 500k, but a redeem over 350 listed\n/// assets with 47 hostile direct legs needs about 28.45M gas and runs out of gas at the 28M budget.\n/// The test asks the vault which settings it accepts (so it also passes once the bound or the overhead is fixed),\n/// then builds the worst case those settings allow.\ncontract RedeemGasJointTest is Test {\n    BaskVault private vault;\n    address private owner = makeAddr(\"owner\");\n    address private guardian = makeAddr(\"guardian\");\n    address private alice = makeAddr(\"alice\");\n    address private receiver = makeAddr(\"receiver\");\n    address[] private tokens;\n    uint256 private shares;\n\n    function _trySetting(T.Setting key, uint256 value) private returns (bool) {\n        vm.prank(owner);\n        try vault.propose(T.Action.Setting, address(0), abi.encode(key, value)) returns (uint256 id) {\n            vm.warp(vault.proposal(id).readyAt);\n            vm.prank(owner);\n            try vault.execute(id) {\n                return true;\n            } catch {\n                return false;\n            }\n        } catch {\n            return false;\n        }\n    }\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        _trySetting(T.Setting.BalanceGas, 20_000);\n        _trySetting(T.Setting.MaxAssets, 350);\n        _trySetting(T.Setting.DirectLimit, 47);\n        _trySetting(T.Setting.PayGas, 500_000);\n        T.Settings memory s = vault.settings();\n        // The vault's own validation accepted everything above on the current code.\n        assertLe(s.maxAssets * (s.balanceGas + 60_000), 28_000_000);\n        assertLe(s.directLimit * (s.balanceGas + s.payGas + 70_000), 28_000_000);\n\n        uint256 count = s.maxAssets;\n        uint256 active = s.directLimit < count ? s.directLimit : count;\n        bytes memory tokenCode = address(new BurnToken()).code;\n        bytes memory feedCode = address(new SimpleFeed()).code;\n        address[] memory deposited = new address[](active);\n        uint256[] memory amounts = new uint256[](active);\n        for (uint256 i; i < count; ++i) {\n            address token = address(uint160(0x300000 + i));\n            address feed = address(uint160(0x400000 + i));\n            vm.etch(token, tokenCode);\n            vm.etch(feed, feedCode);\n            SimpleFeed(feed).set(vm.getBlockTimestamp());\n            tokens.push(token);\n            vm.prank(owner);\n            vault.genesisList(token, feed, address(0), address(0), 0);\n            if (i < active) {\n                BurnToken(token).mint(alice, 1e18);\n                vm.prank(alice);\n                BurnToken(token).approve(address(vault), type(uint256).max);\n                deposited[i] = token;\n                amounts[i] = 1e18;\n            }\n        }\n        vm.prank(owner);\n        vault.finalizeGenesis();\n        vm.prank(alice);\n        shares = vault.deposit(deposited, amounts, alice, 0, vm.getBlockTimestamp());\n        // The held Stock Tokens are then upgraded to hostile code: reads and transfers burn all gas.\n        for (uint256 i; i < active; ++i) {\n            BurnToken(tokens[i]).setHostile(true);\n        }\n    }\n\n    function testRedeemFitsIn28MillionGasAtAcceptedSettings() public {\n        for (uint256 i; i < tokens.length; ++i) {\n            vm.cool(tokens[i]);\n        }\n        vm.cool(address(vault));\n        bytes memory input =\n            abi.encodeCall(vault.redeem, (shares / 2, receiver, new uint256[](0), vm.getBlockTimestamp()));\n        vm.prank(alice);\n        uint256 start = gasleft();\n        (bool ok, bytes memory data) = address(vault).call{gas: 28_000_000}(input);\n        uint256 used = start - gasleft();\n        emit log_named_uint(\"redeem gas used under a 28,000,000 budget\", used);\n        assertTrue(ok, \"redeem must succeed within 28,000,000 gas at settings the vault accepts\");\n        uint256[] memory legs = abi.decode(data, (uint256[]));\n        assertEq(legs.length, tokens.length);\n        assertEq(vault.balanceOf(alice), shares - shares / 2);\n    }\n}","reproduction":"1. Deploy BaskVault(owner, guardian). 2. Owner proposes and, after 2 days each, executes Setting changes in this order: BalanceGas=20_000, MaxAssets=350, DirectLimit=47, PayGas=500_000 (all pass _changedSettings). 3. Owner genesisLists 350 tokens with 8-decimal feeds answering 100e8 and finalizes genesis. 4. A depositor deposits 1e18 of the first 47 tokens in one deposit. 5. The 47 held tokens are upgraded so balanceOf and transfer execute INVALID (burn all gas). 6. The depositor calls redeem(shares/2, freshReceiver, [], now) with 28,000,000 gas. Expected: success with 350 legs, failed payments recorded as owed. Actual: out of gas; the call reverts after consuming 28,002,802 gas. The same call given 40,000,000 gas succeeds and reports 28,445,086 gas used. Reproduced by test/scratch/RedeemGasJoint.t.sol (fails on this tree).","severity":"high","snippet":"            s.maxAssets < assetTokens.length || s.maxAssets > 28_000_000 / (s.balanceGas + 60_000)\n                || s.directLimit > 28_000_000 / (s.balanceGas + s.payGas + 70_000)","title":"Redeem exceeds the 28,000,000 gas bound at settings the vault accepts: the two gas inequalities are checked separately, not jointly"},{"citation":"resolved","description":"deposit rejects receiver == address(this) but redeem only rejects address(0). When receiver is the vault, pay() calls token.transfer(vault, leg); a standard ERC-20 self-transfer succeeds and leaves the balance unchanged, so `beforeBalance - afterBalance != amount` reverts pay and redeem records owed[address(vault)][token] += leg and totalOwed[token] += leg for every asset with managed > 0. claim() pays only msg.sender's own owed and the vault never calls itself, so this totalOwed can never return to zero. removeRetired requires totalOwed == 0, so any asset held at the time of such a redeem can never be removed after retirement, its maxAssets slot is never freed, and the brief's guarantee that a removed token 'may then be listed again' is defeated for it. The cost to a griefer is one wei of each asset (a redeem of the smallest share amount that yields leg >= 1). The same unclaimable-dust effect also arises on the deferred path (count > directLimit) when receiver is any address that will never call claim, which is inherent in the spec's owed design; the self-receiver variant is the one reachable on the direct path with honest tokens and is cheap to close. Minimal fix: in redeem, `if (receiver == address(0) || receiver == address(this)) revert InvalidAddress();` mirroring deposit.","line":619,"path":"src/BaskVault.sol","reproduction":"1. Genesis with 3 plain ERC-20s at 100 USD, finalize. 2. Alice deposits 10e18 of token0 and transfers 1e18 BASK to Mallory. 3. Mallory calls redeem(1e18, address(vault), [], now). Result: legs[0] = 1e16 wei of token0, pay reverts on the exact-debit check, owed[vault][token0] = totalOwed[token0] = 1e16. 4. Owner closes and retires token0; Alice redeems all her BASK; the issuer burns the vault's remaining token0 balance; flagDeficit, wait 7 days, recognizeLoss gives managed[token0] = 0. 5. removeRetired(token0) reverts InvalidAsset because totalOwed[token0] is still 1e16 and no call path can reduce it. Expected per brief: a retired asset with managed 0 whose claims have been settled can be removed and its token relisted. Demonstrated by test/scratch/VaultReceiver.t.sol (passes, asserting the stuck state).","severity":"low","snippet":"        if (receiver == address(0)) revert InvalidAddress();","title":"redeem accepts the vault itself as receiver; the exact-debit check then turns every leg into owed[vault] that nobody can ever claim, permanently blocking removeRetired for those assets"}],"hash":"75e1a145acab7387ce9877f7381ccf05c30724daf83f27864ee0f3d027ad26c5","nodeId":"d278b0b0-9370-4fef-962f-354b0f2dcbb4","outcome":"completed","summary":"The review is complete. Findings and coverage are in `.imd-findings.json` at the repository root. No tracked file was changed; the only new files are the findings file and two scratch tests under test/scratch/.\n\n**What I found**\n\n- **High. Redeem can exceed the 28,000,000 gas budget at settings the vault itself accepts.** The two gas inequalities in `_changedSettings` (src/BaskVault.sol:437) are checked separately, but one redeem pays both costs at once: the per-asset loop over every listed asset plus the balance read and payment allowance on each direct leg. With balanceGas 20,000, maxAssets 350, directLimit 47 and payGas 500,000, which the vault accepts step by step, a vault holding 47 upgraded Stock Tokens that burn gas needs 28,445,086 gas to redeem. Under a 28,000,000 budget the call runs out of gas and every holder's redeem reverts. This is the brief's required attack case. The proof test fails on this tree and passes on a throwaway copy patched with a joint bound, so it holds the fix to the right behaviour. The existing gas tests never combine the maximum asset count with the maximum payment allowance.\n- **Low. Redeem accepts the vault as receiver, creating owed balances nobody can claim.** The self-transfer fails the exact-debit check in `pay`, so each leg is recorded as owed to the vault (src/BaskVault.sol:619). Since only the owing address can claim, totalOwed never returns to zero and `removeRetired` is blocked forever for every asset held at that moment, defeating the guarantee that a removed token may be listed again. Cost to a griefer is one wei per asset. Deposit already rejects the vault as receiver; redeem does not.\n\n**Coverage**\n\nAll 21 listed entry points have a row. Redeem and removeRetired point at the findings above. Every other entry point holds after tracing its guards, state changes and failure paths, including the proposal lifecycle, feed and epoch bookkeeping, deficit and loss flow, claim recovery, and the self-only payment helper. I also checked the Uniswap consult port, ABI offsets and bounded return copies in BaskOracle, the FullMath and TickMath ports, and the runtime size and opcode constraints. The static-analysis leads were all false positives or intentional, and none became findings on their own.\n\n**Not pursued**\n\nA permissionless `removeRetired` reorders the asset list and so shifts a pending redeem's positional minimums. It is documented in the README and the attacker gains nothing directly, so I left it out rather than pad the report.","treeHash":null,"usage":{"cachedInputTokens":3484937,"inputTokens":642,"model":"claude-fable-5-1","outputTokens":71900,"runtime":"claude","turns":42,"wallClockMs":1186475}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2b9b0095482c54e6","findings":[{"citation":"resolved","description":"Merged from audit_economics, audit_math, audit_flow and audit_permissions (same root cause, four proofs, all reproduced). The brief requires redeem with maxAssets assets in any state to fit in 28,000,000 gas and says no setting may block redeem. _changedSettings enforces the two inequalities the brief states, maxAssets * (balanceGas + 60,000) <= 28M and directLimit * (balanceGas + payGas + 70,000) <= 28M, as independent checks. One redeem pays both costs at once: directLimit held assets whose balanceOf and transfer burn their whole allowance each cost balanceGas + payGas plus about 55,000 of storage writes (managed, cold owed[receiver][token], cold totalOwed[token]) and cold account/slot accesses, and every remaining listed asset with managed == 0 still costs about 4,700-5,400 gas across the count loop (lines 630-632, two cold SLOADs) and the payout loop (warm re-reads, minAmountsOut check, amounts[i] store). The 70,000 per direct leg in the second inequality leaves only ~14,000 of slack per direct asset, which cannot cover 6 or more idle assets per direct asset. The brief fixes both inequalities, so the defect is that redeem's per-asset overhead is larger than the inequalities assume; the fix must cut that overhead (for example drop the separate counting loop by keeping a held-asset counter, or otherwise bring the idle-asset and direct-leg overhead under the brief's 60,000/70,000 allowances) or, if the author prefers a tighter bound, that is a scope decision with the requester. Note the joint bound proposed by audit_flow (maxAssets*(balanceGas+60k) + directLimit*(payGas+70k) <= 28M) is wrong as written: it rejects the brief's own default settings (27.5M + 16M). Existing RedemptionGas tests never combine a large maxAssets with a large payGas (254 direct legs only at payGas 20,000; payGas 500,000 only with at most 50 assets). Impact: once the owner installs such settings through ordinary Setting proposals and the held Stock Tokens are upgraded to expensive or bricked code (the must-attack scenario), every holder's redeem reverts out of gas at the 28M budget regardless of share amount, because the loop visits every listed asset; recovery needs a 2-day owner proposal lowering payGas or directLimit. Default settings (payGas 250,000, directLimit 50, 250 assets) fit: measured about 18.8M in the same harness.","line":436,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\nimport {BaskTypes as T} from \"src/BaskTypes.sol\";\n\n/// @dev Stock Token whose upgraded code burns all the gas it is given in balanceOf and transfer.\ncontract HostileToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) internal balances;\n    mapping(address => mapping(address => uint256)) public allowance;\n    bool public hostile;\n\n    function mint(address to, uint256 amount) external {\n        balances[to] += amount;\n    }\n\n    function setHostile(bool v) external {\n        hostile = v;\n    }\n\n    function approve(address to, uint256 amount) external returns (bool) {\n        allowance[msg.sender][to] = amount;\n        return true;\n    }\n\n    function balanceOf(address who) external view returns (uint256) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        return balances[who];\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        require(allowance[from][msg.sender] >= amount, \"allowance\");\n        balances[from] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        balances[msg.sender] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n}\n\ncontract SimpleFeed {\n    uint8 public constant decimals = 8;\n    uint256 public updatedAt;\n\n    function set(uint256 time) external {\n        updatedAt = time;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, 100e8, updatedAt, updatedAt, 1);\n    }\n}\n\n/// @title Redeem must stay under 28,000,000 gas with maxAssets assets in any state, at every setting the vault accepts.\n/// The vault checks `maxAssets * (balanceGas + 60k) <= 28M` and `directLimit * (balanceGas + payGas + 70k) <= 28M`\n/// separately, but one redeem pays both: directLimit hostile direct legs plus the loop cost of every other listed asset.\n/// Each test asks the vault which settings it accepts (so a fix that tightens the bound or cuts redeem's overhead both\n/// make it pass), then builds the worst case those settings allow and requires redeem to succeed inside 28M gas.\ncontract RedeemGasBoundTest is Test {\n    BaskVault private vault;\n    address private owner = makeAddr(\"owner\");\n    address private guardian = makeAddr(\"guardian\");\n    address private alice = makeAddr(\"alice\");\n    address private receiver = makeAddr(\"receiver\");\n    address[] private tokens;\n    address[] private feeds;\n    uint256 private shares;\n\n    function _trySetting(T.Setting key, uint256 value) private returns (bool) {\n        vm.prank(owner);\n        try vault.propose(T.Action.Setting, address(0), abi.encode(key, value)) returns (uint256 id) {\n            vm.warp(vault.proposal(id).readyAt);\n            vm.prank(owner);\n            try vault.execute(id) {\n                return true;\n            } catch {}\n        } catch {}\n        return false;\n    }\n\n    function _build() private {\n        T.Settings memory s = vault.settings();\n        assertLe(s.maxAssets * (s.balanceGas + 60_000), 28_000_000);\n        assertLe(s.directLimit * (s.balanceGas + s.payGas + 70_000), 28_000_000);\n        uint256 count = s.maxAssets;\n        uint256 active = s.directLimit < count ? s.directLimit : count;\n        if (active == 0) active = 1;\n        bytes memory tokenCode = address(new HostileToken()).code;\n        bytes memory feedCode = address(new SimpleFeed()).code;\n        address[] memory deposited = new address[](active);\n        uint256[] memory amounts = new uint256[](active);\n        for (uint256 i; i < count; ++i) {\n            address token = address(uint160(0x100000 + i));\n            address feed = address(uint160(0x200000 + i));\n            vm.etch(token, tokenCode);\n            vm.etch(feed, feedCode);\n            SimpleFeed(feed).set(vm.getBlockTimestamp());\n            tokens.push(token);\n            feeds.push(feed);\n            vm.prank(owner);\n            vault.genesisList(token, feed, address(0), address(0), 0);\n            if (i < active) {\n                HostileToken(token).mint(alice, 1e18);\n                vm.prank(alice);\n                HostileToken(token).approve(address(vault), type(uint256).max);\n                deposited[i] = token;\n                amounts[i] = 1e18;\n            }\n        }\n        vm.prank(owner);\n        vault.finalizeGenesis();\n        vm.prank(alice);\n        shares = vault.deposit(deposited, amounts, alice, 0, vm.getBlockTimestamp());\n        // The held Stock Tokens are upgraded to code that burns every unit of gas on reads and transfers.\n        for (uint256 i; i < count; ++i) {\n            HostileToken(tokens[i]).setHostile(true);\n        }\n    }\n\n    function _redeemWithin28M() private {\n        for (uint256 i; i < tokens.length; ++i) {\n            vm.cool(tokens[i]);\n            vm.cool(feeds[i]);\n        }\n        vm.cool(address(vault));\n        bytes memory input =\n            abi.encodeCall(vault.redeem, (shares / 2, receiver, new uint256[](0), vm.getBlockTimestamp()));\n        vm.prank(alice);\n        uint256 start = gasleft();\n        (bool ok, bytes memory data) = address(vault).call{gas: 28_000_000}(input);\n        uint256 used = start - gasleft();\n        emit log_named_uint(\"maxAssets\", vault.settings().maxAssets);\n        emit log_named_uint(\"directLimit\", vault.settings().directLimit);\n        emit log_named_uint(\"balanceGas\", vault.settings().balanceGas);\n        emit log_named_uint(\"payGas\", vault.settings().payGas);\n        emit log_named_uint(\"redeem gas used under a 28,000,000 budget\", used);\n        assertTrue(ok, \"redeem must succeed within 28,000,000 gas at settings the vault accepts\");\n        uint256[] memory legs = abi.decode(data, (uint256[]));\n        assertEq(legs.length, tokens.length);\n        assertEq(vault.balanceOf(alice), shares - shares / 2);\n        assertGt(vault.owed(receiver, tokens[0]), 0, \"hostile legs are owed, not lost\");\n    }\n\n    /// balanceGas 20,000, maxAssets 350 (350 * 80,000 = 28,000,000), payGas 500,000, directLimit 47\n    /// (47 * 590,000 = 27,730,000): both inequalities hold, redeem needs about 28.44M gas.\n    function testRedeemFitsIn28M_350Assets_47Direct_PayGas500k() public {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        _trySetting(T.Setting.DirectLimit, 0);\n        _trySetting(T.Setting.BalanceGas, 20_000);\n        _trySetting(T.Setting.MaxAssets, 350);\n        _trySetting(T.Setting.PayGas, 500_000);\n        _trySetting(T.Setting.DirectLimit, 47);\n        _build();\n        _redeemWithin28M();\n    }\n\n    /// Default balanceGas 50,000 and maxAssets 254 (254 * 110,000 = 27,940,000), payGas 500,000, directLimit 45\n    /// (45 * 620,000 = 27,900,000): both inequalities hold, redeem needs about 28.14M gas.\n    function testRedeemFitsIn28M_254Assets_45Direct_PayGas500k() public {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        _trySetting(T.Setting.DirectLimit, 0);\n        _trySetting(T.Setting.PayGas, 500_000);\n        _trySetting(T.Setting.MaxAssets, 254);\n        _trySetting(T.Setting.DirectLimit, 45);\n        _build();\n        _redeemWithin28M();\n    }\n}","reproduction":"1. Deploy BaskVault(owner, guardian) at t=1,800,000,000. Owner proposes and, after 2 days each, executes Setting proposals in this order: DirectLimit=0, BalanceGas=20,000, MaxAssets=350, PayGas=500,000, DirectLimit=47. Every one passes _changedSettings (350*80,000 = 28,000,000; 47*590,000 = 27,730,000). 2. genesisList 350 tokens (18 decimals, 8-decimal feeds answering 100e8, no pool), finalizeGenesis. 3. Alice deposits 1e18 of the first 47 tokens in one call (47 assets with managed > 0, count 47 <= directLimit 47 so redeem pays directly). 4. All 350 tokens are upgraded so balanceOf and transfer execute INVALID (burn all gas given). 5. Cool all accounts; Alice calls redeem(shares/2, receiver, [], now) with 28,000,000 gas. Expected per brief: success, every hostile leg recorded as owed. Actual: out of gas, call reverts after consuming 28,000,299; with a 40,000,000 budget the same call succeeds and uses 28,440,957. Variant with default balanceGas: DirectLimit=0, PayGas=500,000, MaxAssets=254, DirectLimit=45 (254*110,000 = 27,940,000; 45*620,000 = 27,900,000): out of gas at 28M, needs 28,143,446. Run: forge test --match-path test/scratch/RedeemGasBound.t.sol -vv (both tests fail on this tree). The four specialist proofs (.imd/reads/proofs/Proof_*.t.sol) were also run and all six of their tests fail the same way.","severity":"high","snippet":"        if (\n            s.maxAssets < assetTokens.length || s.maxAssets > 28_000_000 / (s.balanceGas + 60_000)\n                || s.directLimit > 28_000_000 / (s.balanceGas + s.payGas + 70_000)\n        ) revert InvalidSetting();","title":"Settings inequalities are checked separately, so an accepted maxAssets/directLimit/payGas combination makes redeem run out of gas at the 28,000,000 budget when held tokens are upgraded or broken"},{"citation":"resolved","description":"From audit_math; reproduced. Every redemption leg is floor(min(managed, available) * net / supplyBefore) and net is always strictly below supplyBefore: the 1e15 shares minted to 0xdEaD on the first deposit are never redeemed and, with a fee recipient set, net = shares - ceil(shares/200). Hence leg < managed on every redeem and managed stays >= 1 raw unit forever. Only recognizeLoss lowers managed otherwise and it needs a real on-chain shortfall (available < managed); nobody can move the vault's tokens to create one. removeRetired requires managed == 0 (line 448), so the lifecycle the brief describes (retire, holders redeem, anyone removes, token may be listed again) only works when the issuer burns or confiscates the vault's balance. A retired asset that keeps working stays in assetTokens permanently, occupies one of the maxAssets slots, costs a balanceGas read in every redeem, and counts toward directLimit while its dust leg is nonzero. The same rounding means a 1-raw-unit deposit of any open asset alongside a real amount flips managed > 0 irreversibly, making that asset's price mandatory for every future deposit and raising the held count toward directLimit. This follows from the brief's leg formula and dead shares, so changing it is a scope decision (for example letting the last redeemer take the full remainder, or allowing removal below a dust threshold); reported so the author and requester can decide.","line":642,"path":"src/BaskVault.sol","reproduction":"Fixture: three 18-decimal tokens, 8-decimal feeds at 100e8, genesis finalized, no fee recipient. 1. alice deposits 10e18 of token0: receives 1000e18 - 1e15 shares, managed[token0] = 10e18. 2. alice redeems all her shares: leg = floor(10e18 * (1000e18 - 1e15) / 1000e18) = 10e18 - 1e13, managed[token0] = 1e13, alice holds 0 shares. 3. owner closes token0, proposes Retire, executes after 2 days. 4. removeRetired(token0). Expected: the retired asset with no holder entitlement is removed. Actual: reverts InvalidAsset because managed[token0] == 1e13 and no call can lower it. test/scratch/Repro.t.sol::testManagedNeverZeroBlocksRemoveRetired passes asserting this state.","severity":"low","snippet":"                leg = FullMath.mulDiv(m < available ? m : available, net, supply);","title":"managed[token] never returns to zero through redemptions, so removeRetired is unreachable for any asset that was ever held unless its issuer destroys the vault's balance"},{"citation":"resolved","description":"Merged from audit_flow and audit_permissions; reproduced. deposit rejects receiver == address(this) (line 547) but redeem only rejects address(0). With receiver = vault, pay() calls token.transfer(vault, leg): a standard ERC-20 self-transfer succeeds and leaves the balance unchanged, so beforeBalance - afterBalance != amount reverts pay (line 603) and redeem records owed[address(vault)][token] += leg and totalOwed[token] += leg (lines 655-656). claim() pays only msg.sender's own claims and the vault never calls itself, so totalOwed[token] can never return to zero and removeRetired (line 448) reverts for that asset forever. Cost to a griefer: a few wei of BASK per asset. The deferred path (count > directLimit) reaches the same stuck totalOwed with any receiver that never claims, which is inherent in the owed design; the self-receiver variant is reachable on the direct path with honest tokens and is cheap to close by mirroring deposit's check. Impact overlaps finding 2 (removeRetired already unreachable for ever-held assets) but has a different cause and fix.","line":619,"path":"src/BaskVault.sol","reproduction":"Fixture: three tokens at $100, genesis finalized; alice deposits 10e18 of each (supply 3000e18). alice calls redeem(1000, address(vault), [], now). Each leg = floor(10e18 * 1000 / 3000e18) = 3 wei; pay(token, vault, 3) reverts on the exact-debit check. Expected: no permanent claim against the vault itself. Actual: owed[vault][token0] == 3 and totalOwed[token0] == 3 with no code path that reduces them; after retire and write-off, removeRetired(token0) reverts InvalidAsset. test/scratch/Repro.t.sol::testRedeemToVaultInflatesTotalOwed passes asserting the stuck state.","severity":"low","snippet":"        if (receiver == address(0)) revert InvalidAddress();","title":"redeem accepts the vault itself as receiver; the exact-debit check then turns every leg into owed[vault] that nobody can claim, permanently blocking removeRetired for those assets"},{"citation":"resolved","description":"From audit_economics; reproduced. The brief defines short as available < managed (available = balance - totalOwed, floor 0) and applies 'vault balance >= totalOwed[token]' only to the tokens being deposited. _snapshot instead returns Deficit for any unretired asset whose balance is below its claims, including one with managed == 0. In that state flagDeficit computes a shortfall of 0 and clears the record, recognizeLoss has nothing to write down, and the only exits are a donation covering the claims or close plus a 2-day Retire proposal. Reachable without privileged action: claims exist (failed direct payment or directLimit 0), the issuer burns or freezes the vault's balance, anyone flags and 7 days later recognises the loss, leaving managed 0 and totalOwed > balance; every deposit of every other asset then reverts DepositUnavailable(Deficit, token). Redeem is unaffected. The README documents 'even when managed is zero', so this is a deliberate reading that deviates from the brief's definition of short; minimal fix is to apply the balance >= totalOwed requirement only to input tokens and keep the short test as bal - debt < m.","line":494,"path":"src/BaskVault.sol","reproduction":"Fixture with 3 assets; owner sets DirectLimit = 0 by proposal. alice deposits 10e18 token0 and 10e18 token1, then redeems half her shares: token0 leg becomes a claim, totalOwed[token0] > 0. The issuer burns the vault's whole token0 balance. flagDeficit(token0); warp 7 days; recognizeLoss(token0): managed[token0] == 0, balance 0, totalOwed > 0. depositStatus([token1]) returns (Deficit, token0) and deposit([token1],[1e18], alice, 0, now) reverts DepositUnavailable(Deficit, token0). A further flagDeficit(token0) records 0. Expected per brief: token0 is not short and not an input, so the token1 deposit proceeds. test/scratch/Repro.t.sol::testZeroManagedWithOwedBlocksDeposit passes asserting this.","severity":"low","snippet":"            if (bal < debt || bal - debt < m) return (T.Reason.Deficit, token, 0, answers);","title":"An unretired asset with managed == 0 but vault balance below totalOwed blocks every deposit although it is not short and no loss can be recognised"},{"citation":"resolved","description":"From audit_permissions; reproduced. minAmountsOut is matched to assets by position in assetTokens and removeRetired (lines 446-459) is callable by anyone and moves the last asset into the removed slot. A redeemer who fetched the order and set minima can be front-run by anyone calling removeRetired on a removable asset (one that was never held, closed and retired is removable at once): the minimum set for the last asset now applies to nothing and the slot of the retired asset, whose minimum had to be 0, now holds the last asset, so the slippage floor for that asset is silently lost. It can only weaken minima, never make the redeem revert. It matters when a loss lands on that asset between submission and execution. The README documents the swap-and-pop, but the user cannot control the ordering race. Possible fixes within the design: key minima by token address, or let the redeemer pass the expected asset count/order hash so a reordering reverts.","line":644,"path":"src/BaskVault.sol","reproduction":"Fixture: three tokens; alice deposits 10e18 of tokens 1 and 2; owner closes and retires token0 (managed 0, totalOwed 0). assetTokens = [t0, t1, t2]. alice prepares redeem(allShares, alice, [0, 5e18, 5e18], now). bob front-runs with removeRetired(t0): assetTokens becomes [t2, t1]. t2 then loses 9e18 of its vault balance. alice's redeem executes: position 0 is t2 with minimum 0 and position 2 is skipped, so the call succeeds paying about 1e18 of t2 and 10e18 of t1. Expected: revert Slippage because alice demanded at least 5e18 of t2. test/scratch/Repro.t.sol::testFrontRunRemoveRetiredReorders passes asserting out[0] < 5e18.","severity":"low","snippet":"            if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();","title":"Permissionless removeRetired swap-and-pops assetTokens, so a front-run silently reorders a pending redeem's positional minAmountsOut"},{"citation":"resolved","description":"From audit_economics; reproduced. NAV prices managed[token], never balanceOf, and managed only rises through deposit or an owner Resync proposal that waits 2 days, exactly as the brief specifies. For a Stock Token a balance increase at the vault is a routine corporate action: a 2-for-1 split halves the feed answer at the moment the balance doubles, and an in-kind dividend mints extra tokens. Until Resync executes, _snapshot values the old managed quantity at the new lower price, so NAV is stated below the vault's actual holdings while the price checks pass (feed fresh and inside the band). gross = v * totalSupply / NAV then mints shares at a discount to anyone who deposits, and after Resync those shares redeem pro rata from the real balance. The pending Resync proposal is public, so the same capture is available by depositing ahead of its execution. Nothing in the vault detects the balance change; the only mitigations are operational (close the asset or pause deposits before the ex-date). This is a consequence of the mandated managed accounting plus the proposal delay, distinct from the accepted feed-lag profit bounded by poolDeviation: here the gap is 50% of the asset's value for a 2:1 split. Reported as a documented economic risk, not a code deviation; removing it would need a scope decision.","line":499,"path":"src/BaskVault.sol","reproduction":"Fixture: 3 assets, 18-decimal tokens, 8-decimal feeds at 100e8. alice deposits 10e18 token0 and holds 999.999e18 BASK. Split: mint 10e18 token0 to the vault and set feed0 to 50e8 at now (refresh the others). bob deposits 10e18 token0 (true value $500 against $1,000 of holdings) and receives exactly 1000e18 BASK, more than alice. Owner proposes Resync(token0), waits 2 days, executes: managed = 30e18. bob redeems 1000e18 BASK and receives 15e18 token0 for 10e18 deposited; alice is left with 15e18 of the 20e18 she held after the split. Expected: bob priced on real holdings (500e18 BASK, 10e18 back). test/scratch/Repro.t.sol::testSplitUnderstatesNav passes asserting bob's 1000e18 shares and 15e18 payout.","severity":"low","snippet":"                nav += O.value(m, answers[i], a.tokenDecimals, a.feedDecimals);","title":"Balance-increasing corporate actions (split, in-kind dividend) understate NAV for at least 2 days until Resync executes; depositors in that window take value from existing holders"}],"hash":"791418525a4f42be31cef1a1d792a33d07ed6efb4b0d61cafbd02077b2b168e8","nodeId":"a20a7480-c823-416d-ba30-351c8cb1bd6b","outcome":"completed","summary":"The review is complete. No tracked file was modified; the only new files are the findings record and my scratch tests.\n\n**Outcome: one high finding, five low findings, written to `.imd-findings.json` with a coverage row for all 21 entry points.**\n\n**Merged high finding, with proof.** All four specialists reported the same root cause and I reproduced every one of their proofs plus my own. The two settings inequalities in `_changedSettings` are checked independently, but a single redeem pays both costs: the direct hostile legs plus the loop cost of every idle listed asset. With settings the vault accepts, such as balanceGas 20,000, maxAssets 350, payGas 500,000 and directLimit 47, a redeem over 47 upgraded tokens and 303 empty assets needs 28,440,957 gas and reverts out of gas at the brief's 28,000,000 budget. A second variant at default balanceGas with 254 assets and 45 direct legs needs 28,143,446. This is the must-attack case the brief names. I kept it at high because every holder's redemption is blocked until the owner runs a 2-day setting proposal. My proof is `test/scratch/RedeemGasBound.t.sol`. I also flagged that the joint bound audit_flow proposed as a fix rejects the brief's own default settings, so the fix must reduce redeem's per-asset overhead, or the bound is a scope decision with the requester.\n\n**Low findings, all reproduced in `test/scratch/Repro.t.sol`:**\n- managed never returns to zero through redemptions (net is always below supply), so a retired asset that was ever held can never be removed unless its issuer destroys the vault's balance.\n- redeem accepts the vault itself as receiver; the self-transfer fails the exact-debit check and leaves an unclaimable totalOwed forever (merged from two specialists).\n- an asset with managed 0 but balance below totalOwed blocks every deposit although the brief's definition says it is not short.\n- a permissionless removeRetired front-run reorders the positional minAmountsOut of a pending redeem, silently dropping a slippage floor.\n- a split or in-kind dividend understates NAV until the 2-day Resync executes, so depositors in that window take value from holders. Recorded as a documented consequence of the mandated accounting, not a code deviation.\n\n**Own pass.** I traced every entry point, the oracle and pool arithmetic against Uniswap's consult, the reentrancy surface, the share accounting and the overflow invariant on managed plus totalOwed, and the constructor and runtime size. I found nothing beyond the specialists' set. All slither and aderyn lines were checked and are false positives. The existing 84-test suite passes on this tree.","treeHash":null,"usage":{"cachedInputTokens":1292498,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":52768,"runtime":"claude","turns":29,"wallClockMs":856555}},{"artifacts":[],"attempt":2,"bundleHash":"ee4345633ace3dcfefa79d4e09dd4f43a335c7f954b021e4c0586226f86bf941","device":"9d0fa5452eaa233b","findings":[],"hash":"7f69bf5074d9956aeff0b25ac237258be6117d31290993276400139d3079177b","nodeId":"b4a0eb40-afee-4a7e-a700-fe87016a4990","outcome":"completed","summary":"Updated only [launch.json](/home/imd/.identitymd-265/work/b8fd4c2b-e0a5-48bd-951f-222b3f3a342c/b4a0eb40-afee-4a7e-a700-fe87016a4990/launch.json), clarifying deployment scope while preserving both approved literal addresses.\n\nSchema and constructor ABI checks passed. `forge build` passed; `forge test`: 78 passed, 0 failed. Runtime is 23,736 bytes; no lens required.","treeHash":"edc6c11942bb6db755e5d103ef212a459b9237bb","usage":{"cachedInputTokens":201344,"inputTokens":27744,"model":"gpt-6-astra","outputTokens":2956,"runtime":"codex","turns":3,"wallClockMs":119356}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"584bd638e7e022f0","findings":[{"citation":"resolved","description":"The brief requires redeem to fit in 28,000,000 gas with maxAssets assets in any state, and the two setting inequalities are the only thing enforcing it. They bound two separate worst cases: every asset doing a balanceGas read (maxAssets * (balanceGas + 60,000)) and every direct payment burning its allowance (directLimit * (balanceGas + payGas + 70,000)). They do not bound the combination the vault actually allows: directLimit holdings whose upgraded token burns all of balanceGas and payGas, plus the remaining maxAssets - directLimit listed assets with managed == 0. Those idle assets still cost about 5,400 gas each (cold SLOAD of assetTokens[i] and managed[token] in the count loop at lines 630-632, warm re-reads, minAmountsOut check and amounts[i] store in the payout loop), and the direct-leg bound leaves only about 12,000 gas of margin per direct asset, so a basket near both limits exceeds 28M. Measured with a mock whose balanceOf and transfer execute invalid() (or a plain gas-burning work loop, same result): balanceGas 50,000, payGas 500,000, directLimit 45, maxAssets 254 (45*620,000 = 27.9M and 254*110,000 = 27.94M both pass the checks), 45 holdings hostile, 209 idle: redeem needs 28,143,232 gas and reverts out of gas with a 28,000,000 budget; the same 45 holdings in a 45-asset vault need 27,012,136. balanceGas 20,000, payGas 500,000, directLimit 47, maxAssets 350: 28,440,536 gas. Deposits and shares are unaffected; the owner can recover only by a 2-day setting proposal lowering payGas or directLimit, so this is a broken guarantee under reachable settings rather than a permanent lock, but it is exactly the must-attack case the brief names (upgraded tokens, maxAssets assets, 28M).","line":437,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\nimport {BaskTypes as T} from \"src/BaskTypes.sol\";\n\n/// @dev Minimal Stock Token mock. When `hostile` is set, every balanceOf and transfer burns all gas it is given,\n/// which is what an upgraded or bricked token implementation can do.\ncontract ProofToken {\n    uint8 public constant decimals = 18;\n    bool public hostile;\n    mapping(address => uint256) private balances;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balances[to] += amount;\n    }\n\n    function setHostile(bool v) external {\n        hostile = v;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        return true;\n    }\n\n    function balanceOf(address who) external view returns (uint256) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        return balances[who];\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        allowance[from][msg.sender] -= amount;\n        balances[from] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        balances[msg.sender] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n}\n\ncontract ProofFeed {\n    uint8 public constant decimals = 8;\n    int256 public constant answer = 100e8;\n    uint256 public updatedAt;\n\n    function set(uint256 time) external {\n        updatedAt = time;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// @notice Redemption must fit in 28,000,000 gas with maxAssets assets in any state.\n/// With legal settings balanceGas = 50,000, payGas = 500,000, directLimit = 45 and maxAssets = 254\n/// (45 * 620,000 = 27.9M <= 28M and 254 * 110,000 = 27.94M <= 28M), a basket of 45 gas-burning\n/// upgraded holdings plus 209 idle listed assets needs about 28.14M gas, so redeem runs out of gas.\n/// The test tolerates a fix that tightens the setting bounds: it builds the largest basket the vault\n/// accepts and still requires redeem to succeed inside 28M gas.\ncontract RedeemGasBudgetProofTest is Test {\n    BaskVault private vault;\n    address private owner = makeAddr(\"owner\");\n    address private guardian = makeAddr(\"guardian\");\n    address private alice = makeAddr(\"alice\");\n    address private receiver = makeAddr(\"receiver\");\n    address[] private tokens;\n    address[] private feeds;\n\n    /// @dev Applies a setting if the vault accepts it; returns whether it did.\n    function _trySetting(T.Setting key, uint256 value) private returns (bool) {\n        vm.prank(owner);\n        try vault.propose(T.Action.Setting, address(0), abi.encode(key, value)) returns (uint256 id) {\n            vm.warp(block.timestamp + 2 days);\n            vm.prank(owner);\n            try vault.execute(id) {\n                return true;\n            } catch {}\n        } catch {}\n        return false;\n    }\n\n    /// @dev Largest value at most `from` the vault accepts for the setting.\n    function _largest(T.Setting key, uint256 from, uint256 floor) private {\n        for (uint256 v = from; v > floor; --v) {\n            if (_trySetting(key, v)) return;\n        }\n    }\n\n    function testRedeemFitsIn28MGasWithMaxAssetsAndMaxDirectLimit() public {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        _trySetting(T.Setting.MaxAssets, 3);\n        _trySetting(T.Setting.DirectLimit, 0);\n        _trySetting(T.Setting.PayGas, 500_000);\n        _largest(T.Setting.MaxAssets, 254, 3);\n        _largest(T.Setting.DirectLimit, 45, 0);\n        T.Settings memory s = vault.settings();\n        uint256 count = s.maxAssets;\n        uint256 active = s.directLimit == 0 ? 1 : s.directLimit;\n        if (active > count) active = count;\n\n        bytes memory tokenCode = address(new ProofToken()).code;\n        bytes memory feedCode = address(new ProofFeed()).code;\n        address[] memory deposited = new address[](active);\n        uint256[] memory amounts = new uint256[](active);\n        for (uint256 i; i < count; ++i) {\n            address token = address(uint160(0x100000 + i));\n            address feed = address(uint160(0x200000 + i));\n            vm.etch(token, tokenCode);\n            vm.etch(feed, feedCode);\n            ProofFeed(feed).set(block.timestamp);\n            tokens.push(token);\n            feeds.push(feed);\n            vm.prank(owner);\n            vault.genesisList(token, feed, address(0), address(0), 0);\n            if (i < active) {\n                ProofToken(token).mint(alice, 1e18);\n                vm.prank(alice);\n                ProofToken(token).approve(address(vault), type(uint256).max);\n                deposited[i] = token;\n                amounts[i] = 1e18;\n            }\n        }\n        vm.prank(owner);\n        vault.finalizeGenesis();\n        vm.prank(alice);\n        uint256 shares = vault.deposit(deposited, amounts, alice, 0, block.timestamp);\n\n        // Every Stock Token is upgraded to an implementation that burns all gas on reads and transfers.\n        for (uint256 i; i < count; ++i) {\n            ProofToken(tokens[i]).setHostile(true);\n            vm.cool(tokens[i]);\n            vm.cool(feeds[i]);\n        }\n        vm.cool(address(vault));\n\n        bytes memory input = abi.encodeCall(vault.redeem, (shares / 2, receiver, new uint256[](0), block.timestamp));\n        vm.prank(alice);\n        uint256 start = gasleft();\n        (bool ok, bytes memory data) = address(vault).call{gas: 28_000_000}(input);\n        uint256 used = start - gasleft();\n        emit log_named_uint(\"assets\", count);\n        emit log_named_uint(\"direct holdings\", active);\n        emit log_named_uint(\"redeem gas used\", used);\n        assertTrue(ok, \"redeem must succeed within 28,000,000 gas with maxAssets assets in any state\");\n        uint256[] memory legs = abi.decode(data, (uint256[]));\n        assertEq(legs.length, count);\n        assertGt(vault.owed(receiver, tokens[0]), 0);\n    }\n}","reproduction":"1. new BaskVault(owner, guardian). Owner executes Setting proposals in this order: MaxAssets=3, DirectLimit=0, PayGas=500000, MaxAssets=254, DirectLimit=45 (every one is accepted by _changedSettings). 2. genesisList 254 ERC-20 mocks (18 decimals, feed 8 decimals answer 100e8, no pool); finalizeGenesis; one depositor deposits 1e18 of the first 45 tokens. 3. Upgrade all 254 tokens so balanceOf and transfer burn all gas they are given (invalid(), or any work loop longer than the allowance). 4. The depositor calls redeem(shares/2, receiver, [], block.timestamp) with 28,000,000 gas. Expected per the brief: succeeds, legs recorded as owed. Actual: out of gas at 28,000,296; a 40,000,000 budget shows real usage of 28,143,232. Variant: BalanceGas=20000, PayGas=500000, MaxAssets=350, DirectLimit=47, 47 hostile holdings: 28,440,536 gas. Control: the same 45 hostile holdings with maxAssets=45 need 27,012,136 and succeed. Scratch test test/scratch/RedeemGasBudgetProof.t.sol reproduces it and passes once the direct-limit bound also covers the idle assets (for example 100,000 instead of 70,000 per direct leg: 43 direct holdings, 26,955,895 gas).","severity":"medium","snippet":"            s.maxAssets < assetTokens.length || s.maxAssets > 28_000_000 / (s.balanceGas + 60_000)\n                || s.directLimit > 28_000_000 / (s.balanceGas + s.payGas + 70_000)","title":"Legal settings let maxAssets idle assets plus directLimit gas-burning holdings push redeem past 28,000,000 gas"},{"citation":"resolved","description":"NAV prices managed[token], never balanceOf, and managed only rises through deposit or an owner Resync proposal that waits 2 days. For a Stock Token a balance increase at the vault is a routine event, not a donation: a 2-for-1 split that rebases or mints balances halves the feed answer at the same moment, and an in-kind dividend mints extra tokens. From that moment until the Resync executes, _snapshot values the old managed quantity at the new lower price, so NAV is stated below the vault's actual holdings while the deposit price check still passes (the feed is fresh and inside the band, and a pool, if any, is arbitraged to the same post-split price). gross = v * totalSupply / NAV then mints shares at a discount to anyone who deposits, and redeem later pays those shares pro rata from the real balance after Resync. With a 2:1 split on a vault holding 10 token0 at $100: NAV is reported as $500 for holdings worth $1,000; a depositor who adds 10 token0 ($500) receives 1000 BASK, equal to the existing holder's 999.999 BASK, and after Resync redeems 15 token0 for the 10 deposited, a $250 transfer from the existing holder. The Resync proposal is itself public for 2 days, so the same capture is available by front-running its execution for any accumulated donation. The owner or guardian can only mitigate operationally by closing the asset or pausing deposits before the ex-date; nothing in the vault detects the balance change. This is a consequence of the specified managed accounting plus the proposal delay, and is distinct from the accepted feed-lag profit (1), which is bounded by poolDeviation; this gap is unbounded (50% of the asset's value for a 2:1 split).","line":499,"path":"src/BaskVault.sol","reproduction":"Fixture: 3 assets, 18-decimal tokens, 8-decimal feeds at 100e8; alice deposits 10e18 token0 and holds 999.999e18 BASK. Split: mint 10e18 token0 to the vault and set feeds[0] to 50e8 at block.timestamp (refresh the other feeds). bob deposits 10e18 token0 (true value $500 against $1,000 of holdings) and receives 1000e18 BASK. Owner proposes Resync(token0), waits 2 days, executes: managed = 30e18. bob redeems 1000e18 BASK: receives 15e18 token0 for 10e18 deposited; managed falls to 15e18 for alice who held 20e18 after the split. Expected: bob's shares priced on the vault's real holdings (he should receive 500e18 BASK and 10e18 back). Actual: bob gains 5e18 token0, alice loses 5e18. Scratch test test/scratch/EconRepro.t.sol testSplitUnderstatesNavUntilResyncAndDepositorCapturesHalf reproduces the numbers.","severity":"medium","snippet":"                nav += O.value(m, answers[i], a.tokenDecimals, a.feedDecimals);","title":"Balance-increasing corporate actions (split, in-kind dividend) understate NAV for at least 2 days until Resync; depositors in the window take value from holders"},{"citation":"resolved","description":"The brief defines short as available < managed and applies the vault balance >= totalOwed[token] requirement to the tokens being deposited. _snapshot instead returns Deficit for any unretired asset whose balance is below its totalOwed, including one whose managed is already 0. In that state the asset is not short (available 0, managed 0), flagDeficit records a shortfall of 0 and recognizeLoss has nothing to write down, so the only exits are a donation covering the claims or a close plus 2-day Retire proposal. Reachable without privileged action once claims exist: after a failed direct payment or directLimit = 0 creates totalOwed, an issuer confiscation or freeze that leaves balance below the claims, followed by the permissionless flagDeficit and recognizeLoss, leaves managed at 0 with totalOwed > balance, and every deposit of every other asset reverts with DepositUnavailable(Deficit, token).","line":494,"path":"src/BaskVault.sol","reproduction":"Fixture with 3 assets; owner sets DirectLimit = 0. alice deposits 10e18 token0 and 10e18 token1, then redeems half her shares: token0 leg becomes a claim, totalOwed[token0] > 0. The issuer burns the vault's whole token0 balance. Anyone calls flagDeficit(token0), waits 7 days, calls recognizeLoss(token0): managed[token0] = 0, balance 0, totalOwed > 0. depositStatus([token1]) returns (Deficit, token0) and deposit([token1],[1e18], alice, 0, now) reverts with DepositUnavailable(Deficit, token0). Expected per the brief: token0 is not short and is not an input, so the token1 deposit proceeds. flagDeficit(token0) afterwards records 0, so recognizeLoss cannot unblock it. Scratch test test/scratch/EconRepro.t.sol testZeroManagedAssetWithOutstandingClaimsBlocksAllDeposits reproduces it.","severity":"low","snippet":"            if (bal < debt || bal - debt < m) return (T.Reason.Deficit, token, 0, answers);","title":"Asset with managed == 0 but vault balance below totalOwed blocks every deposit although it is not short and no loss can be recognised"}],"hash":"b4c12f92d7bf2cac1482bd7299012086b538b20fc8b4b6329f72f509590c2d26","nodeId":"724dc9ea-c95e-456e-b660-6bc719372bf9","outcome":"completed","summary":"The review is complete. The findings file is at `.imd-findings.json` with three substantiated findings and 25 coverage rows. No source, test, or configuration file was modified; only my scratch tests under `test/scratch/` and the findings file were created.\n\n**Findings**\n\n1. **Medium, with proof.** Legal settings let redeem exceed the 28,000,000 gas budget. The two setting inequalities bound two separate worst cases but not their combination: `directLimit` holdings whose upgraded token burns all of `balanceGas` and `payGas`, plus the remaining idle listed assets, which still cost about 5,400 gas each. With balanceGas 50k, payGas 500k, directLimit 45 and maxAssets 254, all accepted by the vault, redeem needs 28,143,232 gas and reverts out of gas at 28M. The same 45 hostile holdings in a 45-asset vault need 27,012,136. A second legal combination needs 28,440,536. The self-contained proof fails on the current code and passes on a copy with the direct-leg bound widened. This is the must-attack case the brief names, recoverable only by a 2-day setting proposal.\n\n2. **Medium.** Balance-increasing corporate actions understate NAV until Resync. A 2-for-1 split or in-kind dividend raises the vault balance and lowers the feed at the same moment, but NAV prices `managed`, which only moves after a 2-day Resync proposal. In the repro, a depositor adds 10 tokens against holdings of 20 and takes 15 out after Resync. The existing holder loses 5 tokens. The pool deviation check does not catch it. This is distinct from the accepted feed-lag item and unbounded by poolDeviation.\n\n3. **Low.** An asset with zero managed but a balance below its outstanding claims blocks every deposit with reason Deficit, though the brief defines short as available below managed and applies the totalOwed requirement only to input tokens. In that state flagDeficit records zero and recognizeLoss cannot unblock it.\n\n**Coverage.** All 21 entry points have a row. Redeem and deposit carry findings. The other 19 hold after tracing checks, state changes and failure paths from the economic, invariant and flow-gap guides. Four invariant rows were added: token balance equals managed plus totalOwed, deposit-then-redeem returns at most the input minus fees, claims never change available, and no role or setting can block redeem except through the gas budget in finding 1.\n\n**Not reached.** I did not run long fuzz campaigns or probe pool quote math under extreme ticks beyond reading it against the Uniswap formulas, and I did not evaluate Robinhood Chain's actual block gas limit, which decides whether finding 1 locks funds in practice or only breaks the stated guarantee.","treeHash":null,"usage":{"cachedInputTokens":3418742,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":80497,"runtime":"claude","turns":44,"wallClockMs":1123759}},{"artifacts":[],"attempt":1,"bundleHash":"3fff13a22f268e08df9ba50c3fda4864159f6e9e0a4a1d455d3590b5da90f9d8","device":"77620edf9366f370","findings":[],"hash":"cb8af8ec1b982a6c66617baa086bbb44b314461e54e17f201addab49d5696564","nodeId":"9111e8dd-57e1-447d-b7c1-dc670bc4a7ca","outcome":"completed","summary":"Fixed redemption gas exhaustion and the unrelated-deposit blocking issue. Recorded all six verdicts in [.imd-responses.json](.imd-responses.json); four design-dependent advisories remain unchanged and are documented.\n\nValidation passed: `forge build`, all 78 tests, and `forge fmt --check`. Both supplied gas proofs now pass. Vault runtime is 23,736 bytes.","treeHash":"cf0af8992ee539afe1bd7317b370f96feff2dafd","usage":{"cachedInputTokens":2268672,"inputTokens":82024,"model":"gpt-6-astra","outputTokens":8978,"runtime":"codex","turns":5,"wallClockMs":653892}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bdd9b74dce66953d","findings":[{"citation":"resolved","description":"The brief requires that redeem with maxAssets assets in any state (paused, blocked, upgraded) fits under 28,000,000 gas and that no setting can block redeem. The two inequalities in _changedSettings are meant to guarantee this, but each bounds only one cost: the first assumes every asset costs balanceGas + 60,000 with no direct payment, the second assumes only directLimit assets exist. The real worst case is the sum of both: directLimit held assets each paid directly (balanceGas + payGas + about 55,000 of storage and call overhead, all consumed when the token burns its allowance) PLUS the remaining maxAssets - directLimit listed assets with managed == 0, which still cost about 4,700 gas each (two cold SLOADs in the counting loop, warm re-reads and the minAmountsOut check in the paying loop). With payGas at its legal maximum of 500,000 the direct term alone uses nearly the whole 28,000,000 and the empty-asset term pushes the total over it. Measured with the proof harness (every token's balanceOf/transfer burns its full allowance, which is what an upgraded or bricked Stock Token does): maxAssets 250, balanceGas 50,000, payGas 500,000, directLimit 45 (250*110,000 = 27,500,000 and 45*620,000 = 27,900,000, both accepted) needs 28,121,549 gas; maxAssets 350, balanceGas 20,000, payGas 500,000, directLimit 47 needs 28,440,469 gas; maxAssets 250, balanceGas 52,000, payGas 500,000, directLimit 45 needs 28,211,551 gas. A redeem given 28,000,000 gas reverts out-of-gas, for every share amount, because the loop always visits every listed asset. Every holder's redemption is blocked until the owner lowers payGas or directLimit through a 2-day proposal; the existing RedemptionGas tests never combine a large payGas with a large maxAssets (the 254-direct case uses payGas 20,000, the 500,000 cases use at most 50 assets).","line":437,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\nimport {BaskTypes as T} from \"src/BaskTypes.sol\";\n\n/// Minimal Stock Token mock: normal until `setHostile(true)`, then every read and\n/// transfer burns all the gas it is given (an upgraded, broken token).\ncontract HostileToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) internal balances;\n    mapping(address => mapping(address => uint256)) public allowance;\n    bool public hostile;\n\n    function mint(address to, uint256 amount) external {\n        balances[to] += amount;\n    }\n\n    function setHostile(bool v) external {\n        hostile = v;\n    }\n\n    function approve(address to, uint256 amount) external returns (bool) {\n        allowance[msg.sender][to] = amount;\n        return true;\n    }\n\n    function balanceOf(address who) external view returns (uint256) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        return balances[who];\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        if (hostile) {\n            assembly (\"memory-safe\") { invalid() }\n        }\n        balances[msg.sender] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balances[from] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n}\n\ncontract SimpleFeed {\n    uint8 public constant decimals = 0;\n    uint256 public updatedAt;\n\n    function set(uint256 time) external {\n        updatedAt = time;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, 100, updatedAt, updatedAt, 1);\n    }\n}\n\n/// The brief requires: redeem with maxAssets assets in any state fits in 28,000,000 gas,\n/// for every setting combination the vault accepts. The two setting inequalities are checked\n/// independently, so an accepted combination (maxAssets at its bound, payGas 500,000,\n/// directLimit at its bound) lets `directLimit` hostile direct payments plus the remaining\n/// empty assets exceed 28,000,000 gas and the redemption runs out of gas.\ncontract GasBudgetProofTest is Test {\n    BaskVault private vault;\n    address private owner = makeAddr(\"gas owner\");\n    address private guardian = makeAddr(\"gas guardian\");\n    address private alice = makeAddr(\"gas depositor\");\n    address private receiver = makeAddr(\"gas receiver\");\n    address[] private tokens;\n    address[] private feeds;\n    uint256 private shares;\n\n    /// Proposes and executes a setting if the vault accepts it; returns whether it was applied.\n    function _trySetting(T.Setting key, uint256 value) private returns (bool applied) {\n        vm.prank(owner);\n        (bool ok, bytes memory ret) =\n            address(vault).call(abi.encodeCall(vault.propose, (T.Action.Setting, address(0), abi.encode(key, value))));\n        if (!ok) return false;\n        uint256 id = abi.decode(ret, (uint256));\n        vm.warp(block.timestamp + 2 days);\n        vm.prank(owner);\n        (ok,) = address(vault).call(abi.encodeCall(vault.execute, (id)));\n        return ok;\n    }\n\n    /// Builds the worst case the current settings allow: maxAssets listed assets, directLimit of\n    /// them held (so each is paid directly), every token hostile.\n    function _build() private {\n        T.Settings memory s = vault.settings();\n        uint256 count = s.maxAssets;\n        uint256 active = s.directLimit < count ? s.directLimit : count;\n        if (active == 0) active = 1; // a fix that rejects the setting leaves directLimit 0; still deposit one asset\n        bytes memory tokenCode = address(new HostileToken()).code;\n        bytes memory feedCode = address(new SimpleFeed()).code;\n        address[] memory deposited = new address[](active);\n        uint256[] memory amounts = new uint256[](active);\n        for (uint256 i; i < count; ++i) {\n            address token = address(uint160(0x100000 + i));\n            address feed = address(uint160(0x200000 + i));\n            vm.etch(token, tokenCode);\n            vm.etch(feed, feedCode);\n            SimpleFeed(feed).set(block.timestamp);\n            tokens.push(token);\n            feeds.push(feed);\n            vm.prank(owner);\n            vault.genesisList(token, feed, address(0), address(0), 0);\n            if (i < active) {\n                HostileToken(token).mint(alice, 1e18);\n                vm.prank(alice);\n                HostileToken(token).approve(address(vault), type(uint256).max);\n                deposited[i] = token;\n                amounts[i] = 1e18;\n            }\n        }\n        vm.prank(owner);\n        vault.finalizeGenesis();\n        vm.prank(alice);\n        shares = vault.deposit(deposited, amounts, alice, 0, block.timestamp);\n        for (uint256 i; i < tokens.length; ++i) {\n            HostileToken(tokens[i]).setHostile(true);\n        }\n    }\n\n    function _redeemFitsBudget() private returns (bool ok, uint256 gasUsed) {\n        for (uint256 i; i < tokens.length; ++i) {\n            vm.cool(tokens[i]);\n            vm.cool(feeds[i]);\n        }\n        vm.cool(address(vault));\n        bytes memory input = abi.encodeCall(vault.redeem, (shares / 2, receiver, new uint256[](0), block.timestamp));\n        vm.prank(alice);\n        uint256 start = gasleft();\n        (ok,) = address(vault).call{gas: 28_000_000}(input);\n        gasUsed = start - gasleft();\n        emit log_named_uint(\"maxAssets\", vault.settings().maxAssets);\n        emit log_named_uint(\"directLimit\", vault.settings().directLimit);\n        emit log_named_uint(\"payGas\", vault.settings().payGas);\n        emit log_named_uint(\"balanceGas\", vault.settings().balanceGas);\n        emit log_named_uint(\"redeem gas used\", gasUsed);\n    }\n\n    /// Default balanceGas 50,000 and maxAssets 250 (250 * 110,000 = 27,500,000 <= 28,000,000);\n    /// payGas raised to 500,000 and directLimit 45 (45 * 620,000 = 27,900,000 <= 28,000,000).\n    /// Both inequalities hold, yet the redemption needs about 28,120,000 gas.\n    function testRedeemFitsBudget_Default250_PayGas500k_Direct45() public {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        _trySetting(T.Setting.DirectLimit, 0);\n        _trySetting(T.Setting.PayGas, 500_000);\n        _trySetting(T.Setting.DirectLimit, 45);\n        _build();\n        (bool ok,) = _redeemFitsBudget();\n        assertTrue(ok, \"redeem must fit in 28,000,000 gas under accepted settings\");\n    }\n\n    /// balanceGas 20,000 and maxAssets 350 (350 * 80,000 = 28,000,000);\n    /// payGas 500,000 and directLimit 47 (47 * 590,000 = 27,730,000). Needs about 28,440,000 gas.\n    function testRedeemFitsBudget_Max350_PayGas500k_Direct47() public {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        _trySetting(T.Setting.DirectLimit, 0);\n        _trySetting(T.Setting.BalanceGas, 20_000);\n        _trySetting(T.Setting.MaxAssets, 350);\n        _trySetting(T.Setting.PayGas, 500_000);\n        _trySetting(T.Setting.DirectLimit, 47);\n        _build();\n        (bool ok,) = _redeemFitsBudget();\n        assertTrue(ok, \"redeem must fit in 28,000,000 gas under accepted settings\");\n    }\n}","reproduction":"1. Deploy BaskVault; owner proposes and executes Setting(DirectLimit, 0), Setting(PayGas, 500000), Setting(DirectLimit, 45). All are accepted by _changedSettings (45 * (50000 + 500000 + 70000) = 27,900,000 <= 28,000,000; maxAssets stays 250 with 250 * 110,000 = 27,500,000). 2. genesisList 250 tokens (no pool), finalizeGenesis, deposit 1e18 of the first 45 tokens so exactly 45 assets have managed > 0 (count 45 <= directLimit 45 => direct payments). 3. Every token's balanceOf and transfer now hit INVALID (upgraded/bricked token). 4. Holder calls redeem(shares/2, receiver, [], deadline) with 28,000,000 gas. Expected per brief: the call succeeds and legs are recorded as owed. Actual: the call consumes all 28,000,000 gas and reverts (needs 28,121,549 with cold access); with maxAssets 350 / balanceGas 20,000 / directLimit 47 it needs 28,440,469. Fully default settings (payGas 250,000, directLimit 50) need only 18,785,259 and succeed. Run: forge test --match-path test/scratch/GasBudgetProof.t.sol -vv","severity":"high","snippet":"            s.maxAssets < assetTokens.length || s.maxAssets > 28_000_000 / (s.balanceGas + 60_000)\n                || s.directLimit > 28_000_000 / (s.balanceGas + s.payGas + 70_000)","title":"Setting bounds are checked independently, so an accepted maxAssets/directLimit/payGas combination makes redeem run out of gas at the 28,000,000 budget when the held tokens are broken"},{"citation":"resolved","description":"Seam between precision, boundary and invariant. Each redemption leg is floor(min(managed, available) * net / supplyBefore) (src/BaskVault.sol:642, `leg = FullMath.mulDiv(m < available ? m : available, net, supply);`). net is always strictly below supplyBefore: the 1e15 shares minted to 0xdEaD on the first deposit are never redeemed, and with a fee recipient set net = shares - ceil(shares/200) < shares. Hence every leg is strictly smaller than managed, and managed stays >= 1 raw unit forever after the first deposit into an asset; nothing else lowers managed except recognizeLoss, which needs an actual on-chain shortfall (available < managed), and the owner cannot move tokens to create one. removeRetired requires managed == 0, so the lifecycle the brief specifies (retire -> holders redeem -> anyone removes -> token may be listed again) is impossible for any asset that was ever held: the retired asset can never be removed or re-listed, it stays in assetTokens consuming one of the at most 350 slots, and because its managed is nonzero it still incurs a full balanceGas read, mulDiv and SSTOREs in every redeem and counts toward the directLimit comparison. Over the vault's life every retired-and-held asset accumulates this cost permanently. The same rounding also lets anyone flip managed > 0 permanently on any open asset with a 1-raw-unit deposit alongside a real amount, which then makes that asset's price mandatory for every future deposit and raises the direct-payment count toward directLimit; those are spec-consistent consequences, but the irreversibility is the defect.","line":448,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\nimport {BaskTypes as T} from \"src/BaskTypes.sol\";\n\ncontract PlainToken {\n    uint8 public immutable decimals;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    constructor(uint8 d) {\n        decimals = d;\n    }\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function approve(address to, uint256 amount) external returns (bool) {\n        allowance[msg.sender][to] = amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n}\n\ncontract PlainFeed {\n    uint8 public immutable decimals;\n    int256 public answer;\n    uint256 public updatedAt;\n\n    constructor(uint8 d, int256 a) {\n        decimals = d;\n        answer = a;\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 a, uint256 t) external {\n        answer = a;\n        updatedAt = t;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// After any deposit into an asset, `managed[token]` can never return to zero through\n/// redemptions: every leg is floor(managed * net / supplyBefore) with net < supplyBefore\n/// (1e15 dead shares never redeem), so at least 1 raw unit always remains. `removeRetired`\n/// requires managed == 0, so a retired asset that was ever held can never be removed or\n/// re-listed, and it keeps costing a full balance read + storage writes in every redeem.\ncontract RemoveRetiredProofTest is Test {\n    BaskVault private vault;\n    PlainToken[] private tokens;\n    PlainFeed[] private feeds;\n    address private owner = makeAddr(\"owner\");\n    address private guardian = makeAddr(\"guardian\");\n    address private alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        for (uint256 i; i < 3; ++i) {\n            PlainToken t = new PlainToken(18);\n            PlainFeed f = new PlainFeed(8, 100e8);\n            tokens.push(t);\n            feeds.push(f);\n            vm.prank(owner);\n            vault.genesisList(address(t), address(f), address(0), address(0), 0);\n            t.mint(alice, 1_000e18);\n            vm.prank(alice);\n            t.approve(address(vault), type(uint256).max);\n        }\n        vm.prank(owner);\n        vault.finalizeGenesis();\n    }\n\n    function _one(address token) private pure returns (address[] memory a) {\n        a = new address[](1);\n        a[0] = token;\n    }\n\n    function _amount(uint256 x) private pure returns (uint256[] memory a) {\n        a = new uint256[](1);\n        a[0] = x;\n    }\n\n    function _execute(uint256 id) private {\n        vm.warp(vault.proposal(id).readyAt);\n        for (uint256 i; i < feeds.length; ++i) {\n            feeds[i].set(100e8, block.timestamp);\n        }\n        vm.prank(owner);\n        vault.execute(id);\n    }\n\n    function testRetiredAssetRemovableAfterHoldersRedeemEverything() public {\n        address token = address(tokens[0]);\n        // Alice is the only depositor; she deposits 10 tokens, then redeems every share she holds.\n        vm.prank(alice);\n        uint256 shares = vault.deposit(_one(token), _amount(10e18), alice, 0, block.timestamp);\n        vm.prank(alice);\n        vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n        assertEq(vault.balanceOf(alice), 0);\n        assertEq(vault.totalSupply(), 1e15, \"only the dead shares remain\");\n\n        // Retire the asset (closed at proposal and at execution).\n        vm.prank(owner);\n        vault.close(token);\n        vm.prank(owner);\n        uint256 id = vault.propose(T.Action.Retire, token, \"\");\n        _execute(id);\n        assertTrue(vault.asset(token).retired);\n        assertEq(vault.totalOwed(token), 0);\n\n        // The vault holds only the floor-rounding residue of alice's redemption (1e15/1e18 of 10 tokens).\n        emit log_named_uint(\"managed residue after full redeem\", vault.managed(token));\n\n        // Expected per brief: \"Anyone may remove a retired asset with managed and totalOwed 0\".\n        // Actual: managed is 1e13 (never 0 through redeems), so removeRetired reverts InvalidAsset\n        // and the token can never be removed nor listed again.\n        vault.removeRetired(token);\n        assertEq(vault.assetCount(), 2);\n    }\n}","reproduction":"1. Genesis with three 18-decimal tokens priced 100e8 on 8-decimal feeds; finalizeGenesis. 2. alice deposits 10e18 of token A -> receives 1000e18 - 1e15 shares, 1e15 go to 0xdEaD, managed[A] = 10e18. 3. alice redeems every share she holds: leg = floor(10e18 * (1000e18 - 1e15) / 1000e18) = 10e18 - 1e13, so managed[A] = 1e13, totalOwed[A] = 0, alice holds 0 shares. 4. owner closes A, proposes Retire(A), executes after 2 days (A retired, no holder has any claim on it). 5. Anyone calls removeRetired(A). Expected per brief: the retired asset with no outstanding entitlement is removed and A may be listed again. Actual: reverts InvalidAsset because managed[A] = 1e13 != 0, and no permissionless or owner action can ever bring it to 0 (redeem legs floor strictly below managed; recognizeLoss needs available < managed, but the vault still holds the full 1e13). Run: forge test --match-path test/scratch/RemoveRetiredProof.t.sol -vv","severity":"medium","snippet":"        if (!assets[token].retired || managed[token] != 0 || totalOwed[token] != 0) revert InvalidAsset();","title":"managed[token] can never return to zero through redemptions, so removeRetired is unreachable for any asset that was ever deposited and retired assets permanently occupy capacity and redeem gas"}],"hash":"d3a4f7bab1b1a2ba614e5bbb5661ec5356f9706513402a1ee8cc41014f11c5a8","nodeId":"7ff5cc10-91d8-49ae-9c44-623ae62b4d59","outcome":"completed","summary":"Review complete. The findings file is written at the repository root and no source, config or test file outside `test/scratch/` was changed.\n\n**What I found**\n\n1. **High: the two setting inequalities do not bound the real redeem cost.** `_changedSettings` checks `maxAssets * (balanceGas + 60,000)` and `directLimit * (balanceGas + payGas + 70,000)` separately, but a redeem pays both: `directLimit` direct attempts plus the per-asset cost of every other listed asset. With payGas at its legal maximum, an accepted configuration lets a redeem of hostile or upgraded tokens exceed the 28,000,000 budget and revert out of gas for every holder.\n\n   | Accepted settings | Gas needed |\n   | --- | --- |\n   | maxAssets 250, balanceGas 50k, payGas 500k, directLimit 45 | 28,121,549 |\n   | maxAssets 350, balanceGas 20k, payGas 500k, directLimit 47 | 28,440,469 |\n   | maxAssets 250, balanceGas 52k, payGas 500k, directLimit 45 | 28,211,551 |\n   | fully default settings | 18,785,259 |\n\n   The proof test `test/scratch/GasBudgetProof.t.sol` fails now and derives its worst case from whatever settings the vault accepts, so it passes once either the bound or the loop cost is fixed.\n\n2. **Medium: `managed` can never reach zero through redemptions.** Every leg is floored and net shares are always strictly below supply (dead shares and fees), so at least one raw unit remains forever. `removeRetired` requires zero, so a retired asset that was ever held can never be removed or re-listed and keeps costing a full balance read plus storage writes in every redeem. Proof in `test/scratch/RemoveRetiredProof.t.sol` fails now with `InvalidAsset`.\n\n**What held in my area**\n\nValue scaling, the band and age checks, the Uniswap consult arithmetic, the deposit and redeem rounding directions, fee rounding, the first-deposit minimum, the NAV cap check, and the vendored FullMath and TickMath all traced correctly. The remaining accepted gas configurations that I measured, including the tight 50-asset case with fees and a 50-entry minimum array, stay under the budget with about 78k to spare.\n\n**Coverage**\n\nAll 21 entry points have rows, plus five invariant rows. Two entry points carry finding 1 (redeem, execute) and one carries finding 2 (removeRetired). Nothing was left unreached.","treeHash":null,"usage":{"cachedInputTokens":2423313,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":66869,"runtime":"claude","turns":33,"wallClockMs":1112600}},{"artifacts":[],"attempt":1,"bundleHash":"1f2a17249ac41ab8ebfd0d355376762c37a1d333c402c914f44553f8ee744d70","device":"563355f47e653bac","findings":[],"hash":"d79b7e6efb7f6dbd332c56871a34f59be05f9dd272470e5c0d36b8c26bde2eec","nodeId":"abd56ba4-9a21-46dd-9b09-dd94642546db","outcome":"completed","summary":"Added failure-path tests, two stateful invariants, 2,000 fuzz cases, and a 250-asset retired-token redemption gas test.\n\n`forge build` succeeds; all 84 tests pass, including 16,384 randomized invariant calls. Changes are limited to `test/`. No confirmed contract defects found.","treeHash":"331d88bbbd524dc106810539872323e328bad683","usage":{"cachedInputTokens":2135936,"inputTokens":120775,"model":"gpt-6-astra","outputTokens":26805,"runtime":"codex","turns":7,"wallClockMs":1177333}},{"artifacts":[],"attempt":1,"bundleHash":"fb1bd9166eb894f9e2f9122ea2d966a348a533afea41f04241e1b59dbaed5b6f","device":"df98a348cb33e978","findings":[],"hash":"d8ca9f6614dde638afe3bc970064203d364f18dce553dedbd81c3f03fb37cbd5","nodeId":"abd56ba4-9a21-46dd-9b09-dd94642546db","outcome":"completed","summary":"Corrected the invariant handler’s debt expectations and added regression plus 1,000-case fuzz coverage for loss and claim recovery.\n\n`forge build` and `forge test` pass, including 16,384 invariant calls with no unexpected reverts. Only `test/` changed.","treeHash":"b69850d19bdf672449b71524545de62f4080c62a","usage":{"cachedInputTokens":1813248,"inputTokens":103813,"model":"gpt-6-astra","outputTokens":7850,"runtime":"codex","turns":6,"wallClockMs":413104}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"03845cacb54c3a73","findings":[{"citation":"resolved","description":"The brief requires that redeem with maxAssets assets in any state fits under 28,000,000 gas, and relies on the two settings inequalities in _changedSettings (lines 436-439) to bound it. The direct-payment inequality only budgets directLimit * (balanceGas + payGas + 70,000) and ignores the other (maxAssets - directLimit) listed assets that redeem still iterates twice (the count loop at lines 630-632 and the leg loop at lines 636-658: two cold SLOADs of assetTokens[i] and managed[token] each, plus the minAmountsOut check and amounts[] write). With maxAssets = 350 (balanceGas 20,000) those idle assets alone cost about 1.3M gas, which the 70,000 per direct asset slack does not cover once payGas is large. The owner can reach these settings through ordinary Setting proposals, each of which passes _changedSettings. Once set, a redeem in which the directLimit held tokens are hostile (upgraded code that burns all gas in balanceOf and transfer) consumes 28.1M-28.6M gas and runs out of gas when given exactly 28,000,000. Shares cannot be redeemed in smaller pieces to reduce the cost because the loop is per asset, not per share. Measured on this tree (scratch harness, cold accounts, hostile tokens burn all gas): maxAssets 350 / directLimit 49 / balanceGas 20,000 / payGas 480,000 -> 28,607,662; 350 / 56 / 20,000 / 410,000 -> 28,556,844; 350 / 47 / 20,000 / 500,000 -> 28,444,975; 350 / 76 / 20,000 / 278,000 -> 28,183,209. All four pass both inequalities (350*80,000 = 28,000,000; 49*570,000 = 27,930,000; 56*500,000 = 28,000,000; 47*590,000 = 27,730,000; 76*368,000 = 27,968,000). The shipped RedemptionGas tests never combine a large maxAssets with a large payGas and so do not exercise this corner (254 direct attempts are tested only at payGas 20,000, and payGas 500,000 only with 26-49 assets). Fix direction: charge the idle-asset iteration in the bound (for example require directLimit * (balanceGas + payGas + 70,000) + (maxAssets - directLimit) * perIdleAssetCost <= 28,000,000, or cap directLimit against maxAssets), or cut the per-asset overhead in redeem so that the stated 70,000 per direct asset covers it. Nothing else in redeem can be made to revert by a role or setting: fee transfer, mulDiv, managed/owed arithmetic and the pay sandbox were traced and hold.","line":438,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\nimport {BaskTypes as T} from \"src/BaskTypes.sol\";\n\n/// @dev A Stock Token whose upgraded code burns every unit of gas it is given, in balanceOf and transfer.\ncontract BurningToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) internal balances;\n    mapping(address => mapping(address => uint256)) public allowance;\n    bool public burnAll;\n\n    function mint(address to, uint256 amount) external {\n        balances[to] += amount;\n    }\n\n    function setBurn(bool v) external {\n        burnAll = v;\n    }\n\n    function approve(address to, uint256 amount) external returns (bool) {\n        allowance[msg.sender][to] = amount;\n        return true;\n    }\n\n    function _burn() internal view {\n        if (!burnAll) return;\n        while (true) {\n            assembly (\"memory-safe\") {\n                pop(keccak256(0, 32))\n            }\n        }\n    }\n\n    function balanceOf(address who) external view returns (uint256) {\n        _burn();\n        return balances[who];\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        _burn();\n        allowance[from][msg.sender] -= amount;\n        balances[from] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        _burn();\n        balances[msg.sender] -= amount;\n        balances[to] += amount;\n        return true;\n    }\n}\n\ncontract StaticFeed {\n    uint8 public constant decimals = 8;\n    int256 public constant answer = 100e8;\n    uint256 public updatedAt;\n\n    function set(uint256 t) external {\n        updatedAt = t;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// @notice Settings that satisfy both brief inequalities still let a redeem exceed 28,000,000 gas.\n///   maxAssets * (balanceGas + 60,000)            = 350 * 80,000  = 28,000,000\n///   directLimit * (balanceGas + payGas + 70,000) =  49 * 570,000 = 27,930,000\n/// With 350 listed assets, 49 of them held and hostile, redeem(…) runs out of gas when given 28,000,000.\ncontract RedeemGasBoundTest is Test {\n    BaskVault private vault;\n    address private owner = makeAddr(\"owner\");\n    address private guardian = makeAddr(\"guardian\");\n    address private alice = makeAddr(\"alice\");\n    address[] private tokens;\n    address[] private feeds;\n\n    function _setting(T.Setting key, uint256 value) private {\n        vm.prank(owner);\n        uint256 id = vault.propose(T.Action.Setting, address(0), abi.encode(key, value));\n        vm.warp(block.timestamp + 2 days);\n        vm.prank(owner);\n        vault.execute(id);\n    }\n\n    function _setup(uint256 count, uint256 active, uint256 balanceGas, uint256 payGas, uint256 directLimit) private {\n        vm.warp(1_800_000_000);\n        vault = new BaskVault(owner, guardian);\n        _setting(T.Setting.DirectLimit, 0);\n        _setting(T.Setting.BalanceGas, balanceGas);\n        _setting(T.Setting.PayGas, payGas);\n        _setting(T.Setting.MaxAssets, count);\n        _setting(T.Setting.DirectLimit, directLimit);\n        bytes memory tokenCode = address(new BurningToken()).code;\n        bytes memory feedCode = address(new StaticFeed()).code;\n        address[] memory deposited = new address[](active);\n        uint256[] memory amounts = new uint256[](active);\n        for (uint256 i; i < count; ++i) {\n            address token = address(uint160(0x100000 + i));\n            address feed = address(uint160(0x200000 + i));\n            vm.etch(token, tokenCode);\n            vm.etch(feed, feedCode);\n            StaticFeed(feed).set(block.timestamp);\n            tokens.push(token);\n            feeds.push(feed);\n            vm.prank(owner);\n            vault.genesisList(token, feed, address(0), address(0), 0);\n            if (i < active) {\n                BurningToken(token).mint(alice, 1e18);\n                vm.prank(alice);\n                BurningToken(token).approve(address(vault), type(uint256).max);\n                deposited[i] = token;\n                amounts[i] = 1e18;\n            }\n        }\n        vm.prank(owner);\n        vault.finalizeGenesis();\n        vm.prank(alice);\n        vault.deposit(deposited, amounts, alice, 0, block.timestamp);\n        for (uint256 i; i < active; ++i) {\n            BurningToken(tokens[i]).setBurn(true);\n        }\n        vm.prank(guardian);\n        vault.pauseDeposits();\n    }\n\n    function _redeemWith28M() private returns (bool ok, uint256 gasUsed) {\n        for (uint256 i; i < tokens.length; ++i) {\n            vm.cool(tokens[i]);\n        }\n        vm.cool(address(vault));\n        uint256 shares = vault.balanceOf(alice);\n        bytes memory input = abi.encodeCall(vault.redeem, (shares / 2, alice, new uint256[](0), block.timestamp));\n        vm.prank(alice);\n        uint256 start = gasleft();\n        (ok,) = address(vault).call{gas: 28_000_000}(input);\n        gasUsed = start - gasleft();\n        emit log_named_uint(\"redeem gas\", gasUsed);\n    }\n\n    function testRedeemFitsIn28MillionAt350Assets49DirectLegalSettings() public {\n        _setup(350, 49, 20_000, 480_000, 49);\n        assertEq(vault.settings().maxAssets, 350);\n        assertEq(vault.settings().directLimit, 49);\n        (bool ok,) = _redeemWith28M();\n        assertTrue(ok, \"redeem must fit in 28,000,000 gas with maxAssets assets in any state\");\n        assertGt(vault.owed(alice, tokens[48]), 0, \"hostile legs are owed, not lost\");\n    }\n\n    function testRedeemFitsIn28MillionAt350Assets47DirectPayGas500k() public {\n        _setup(350, 47, 20_000, 500_000, 47);\n        (bool ok,) = _redeemWith28M();\n        assertTrue(ok, \"redeem must fit in 28,000,000 gas with maxAssets assets in any state\");\n    }\n}","reproduction":"1. Deploy BaskVault(owner, guardian). As owner, propose and (after 2 days each) execute Setting proposals: DirectLimit=0, BalanceGas=20_000, PayGas=480_000, MaxAssets=350, DirectLimit=49. Every one passes _changedSettings. 2. genesisList 350 tokens with fresh feeds (18-decimal tokens, 8-decimal $100 feeds, no pools); finalizeGenesis. 3. Alice deposits 1e18 of the first 49 tokens (one deposit call), so 49 assets have managed > 0 and 301 have managed == 0; count (49) <= directLimit (49) so redeem takes the direct path. 4. The 49 held tokens are upgraded to code whose balanceOf and transfer burn all gas they receive (paused/blocked/upgraded Stock Token scenario from the brief). 5. Alice calls vault.redeem(shares/2, alice, [], now) with exactly 28,000,000 gas. Expected (brief): the call succeeds, every hostile leg is recorded as owed. Actual: the call runs out of gas and reverts; measured consumption with a larger allowance is 28,607,662 gas. Same with 350/47/20,000/500,000 (28,444,975 gas). Proof: test/scratch/RedeemGasBound.t.sol, both tests fail on this tree with 'redeem must fit in 28,000,000 gas'.","severity":"high","snippet":"                || s.directLimit > 28_000_000 / (s.balanceGas + s.payGas + 70_000)","title":"Settings inequality admits configurations under which a worst-case redeem needs more than 28,000,000 gas"},{"citation":"resolved","description":"deposit (line 547) rejects receiver == address(this) but redeem (line 619) only rejects the zero address. When the receiver is the vault, pay() transfers token from the vault to the vault: the balance does not change, the exact-debit check at line 603 fails, the self-call reverts and redeem credits owed[address(vault)][token] and totalOwed[token] (lines 654-657). The vault can never call claim(), so these entries are permanent; Resync excludes them (available = bal - totalOwed) and removeRetired() requires totalOwed == 0 (line 448). Any shareholder can therefore, for a few wei of BASK, make every asset the vault currently holds un-removable forever after retirement, so its token can never be listed afresh and the slot stays in assetTokens (and in every redeem/deposit loop) permanently. The same permanent inflation of totalOwed is reachable without the vault address whenever count > directLimit (every leg is owed to whatever receiver the redeemer names, including an address nobody controls), so the asymmetry only closes the universally available path; the brief's guarantee 'anyone may remove a retired asset with managed and totalOwed 0' is weaker than it reads. Attacker cost is their own dust; no other user's funds are moved.","line":619,"path":"src/BaskVault.sol","reproduction":"Fixture: three 18-decimal tokens, $100 feeds, genesis finalized; Alice deposits 10e18 of each (supply 3000e18). 1. Alice calls redeem(1000, address(vault), [], now). Each leg is floor(10e18 * 1000 / 3000e18) = 3 wei; pay(token, vault, 3) reverts on the exact-debit check so owed[vault][token] = 3 and totalOwed[token] = 3 for all three tokens. 2. Alice redeems the rest to herself; owner closes token 0 and executes Retire; the leftover dust in managed is written off via flagDeficit/recognizeLoss after burning the vault balance. 3. managed[token0] == 0 but totalOwed[token0] == 3 forever. Expected: a retired asset with no holdings and no outstanding user claims can be removed and relisted. Actual: removeRetired(token0) reverts InvalidAsset permanently; nobody can ever make the vault call claim(). Test: test/scratch/Asymmetry.t.sol::testRedeemToVaultPermanentlyInflatesTotalOwedAndBlocksRemoveRetired passes on this tree.","severity":"low","snippet":"        if (receiver == address(0)) revert InvalidAddress();","title":"redeem accepts receiver == vault while deposit rejects it; the failed self-payment leaves totalOwed permanently nonzero and blocks removeRetired"},{"citation":"resolved","description":"minAmountsOut in redeem is matched to assets by position in assetTokens (line 644), and removeRetired (lines 446-459) is callable by anyone and moves the last asset into the removed slot. A redeemer who fetches the order and submits minima is exposed to anyone (including a bot that simply watches for removable assets) calling removeRetired first: the minimum they set for the last asset is then applied to nothing (its index is now beyond assetTokens.length, so the `i < minAmountsOut.length` guard skips it) and the slot formerly belonging to the retired asset, which necessarily carried a minimum of 0, now holds the last asset. The redeemer's slippage protection for that asset is silently lost, which matters exactly when a loss (recognizeLoss or a shrinking balance) lands between submission and execution. The reorder can only weaken minima, never make the redeem revert, because the retired slot's minimum must have been 0 for the redeem to be valid. The README documents the swap-and-pop but the user cannot control the ordering race; the asymmetry is that the view order a redeemer relies on can be changed by an unprivileged third party in the same block.","line":451,"path":"src/BaskVault.sol","reproduction":"Fixture: three tokens; Alice deposits 10e18 of tokens 1 and 2 only; owner closes and retires token 0 (managed 0, totalOwed 0). assetTokens = [t0, t1, t2]. 1. Alice prepares redeem(shares, alice, [0, 5e18, 5e18], now) so each held leg must be >= 5e18. 2. Bob front-runs with removeRetired(t0): assetTokens becomes [t2, t1]. 3. t2 loses 9e18 of its vault balance (confiscation) before Alice's transaction executes. 4. Alice's redeem runs: position 0 is now t2 with minimum 0 and position 2 is skipped, so the leg for t2 is about 1e18 and the call succeeds. Expected: the redeem reverts with Slippage because Alice demanded at least 5e18 of t2. Actual: it pays ~1e18 of t2 and 10e18 of t1. Test: test/scratch/Asymmetry.t.sol::testFrontRunRemoveRetiredReordersMinAmountsOut passes on this tree.","severity":"low","snippet":"        assetTokens[i] = last;","title":"Permissionless removeRetired swap-and-pops assetTokens, so a front-run reorders a pending redeem's positional minAmountsOut"}],"hash":"e1485e02a8ec4c4ae2b26dc7bd977664e92bc284a9c4e9c53098a07c72962d61","nodeId":"cf3f4790-095b-4a35-b15a-c676cd7244fb","outcome":"completed","summary":"The review is complete. The findings file is in place at the repository root, the tree's source files are untouched, and the only other writes are in the scratch test directory the assignment reserved for me. The harness ignores both paths through a global exclude, which is why they do not appear as tracked changes.\n\n## Outcome\n\nI audited the Basket vault against the Access Control, Trust Gap and Asymmetry guides, traced all 21 state-changing entry points, and found one high and two low defects. Each has a concrete reproduction, and the high one carries a Foundry proof that fails on the current code.\n\n**Finding 1, high: a legal settings combination pushes a worst-case redeem above 28,000,000 gas.** The brief's direct-payment inequality budgets only `directLimit * (balanceGas + payGas + 70,000)` and ignores the idle assets that redeem still iterates twice. With 350 listed assets and 49 held hostile tokens, the following configurations all pass `_changedSettings` yet exceed the mandated budget:\n\n| maxAssets | directLimit | balanceGas | payGas | redeem gas |\n|---|---|---|---|---|\n| 350 | 49 | 20,000 | 480,000 | 28,607,662 |\n| 350 | 56 | 20,000 | 410,000 | 28,556,844 |\n| 350 | 47 | 20,000 | 500,000 | 28,444,975 |\n| 350 | 76 | 20,000 | 278,000 | 28,183,209 |\n\nThe shipped gas tests never combine a large asset count with a large payment allowance, so this corner was unexercised. The proof is `test/scratch/RedeemGasBound.t.sol`. It gives redeem exactly 28,000,000 gas and fails on this tree with an out-of-gas revert.\n\n**Finding 2, low: redeem accepts the vault itself as receiver, while deposit rejects it.** The self-transfer fails the exact-debit check, so every leg is credited as owed to the vault, which can never claim. That leaves `totalOwed` permanently nonzero, which blocks `removeRetired` for that token forever. The cost to an attacker is a few wei of BASK.\n\n**Finding 3, low: permissionless `removeRetired` reorders `assetTokens` under an in-flight redeem.** A front-run swaps the last asset into the retired slot, so the redeemer's positional `minAmountsOut` protection for that asset is silently dropped. It can only weaken minima, never cause a revert.\n\n## What held\n\nRole separation is sound: owner and guardian can never coincide across any ordering of ownership transfer and guardian replacement, the guardian cannot block its own replacement by any route, `pay` is reachable only through the vault's own redeem and claim, and no role or setting can make redeem or claim revert apart from the gas bound above. Deposit and redeem fee math, first-deposit locking, resync bounds, and loss recognition are symmetric where they should be, and the asymmetries between them match the brief. I did not find any way to mint outside deposit, move assets, or change the fee rate.\n\n## Coverage\n\nAll 21 entry points have a coverage row, plus two invariant rows. Three rows point to findings and the rest hold. I did not reach pool-oracle arithmetic in depth, which belongs to a different specialist's area.","treeHash":null,"usage":{"cachedInputTokens":2469293,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":62943,"runtime":"claude","turns":40,"wallClockMs":1111253}}],"verification":[{"checks":[{"durationMs":24055,"exitCode":0,"name":"build","output":"Compiling 30 files with Solc 0.8.26\nSolc 0.8.26 finished in 23.74s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:116:26\n    │\n116 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:138:19\n    │\n138 │         ) return (false, 0);\n    │                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:145:30\n    │\n145 │         if (dl == 0) return (false, 0);\n    │                              ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:148:54\n    │\n148 │         if (mean < -887272 || mean > 887272) return (false, 0);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:150:82\n    │\n150 │         if (liquidity > type(uint128).max || liquidity < a.minLiquidity) return (false, 0);\n    │                                                                                  ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:165:26\n    │\n165 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:37:16\n   │\n37 │         return uint8(d);\n   │                ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:35\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:67\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:64:40\n   │\n64 │         if (signedAnswer > 0) answer = uint256(signedAnswer);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:464:16\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:99:17\n   │\n99 │             if (block.timestamp - updatedAt > s.noPoolAge) reason = T.Reason.Feed;\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:113:26\n    │\n113 │         secondsAgos[0] = uint32(s.poolWindow);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:136:87\n    │\n136 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || int256(int56(t0)) != t0\n    │                                                                                       ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:137:27\n    │\n137 │                 || int256(int56(t1)) != t1 || l0 > type(uint160).max || l1 > type(uint160).max\n    │                           ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:18\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                  ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:30\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                              ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:18\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                  ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:32\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:146:28\n    │\n146 │         int256 mean = dt / int256(s.poolWindow);\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:147:28\n    │\n147 │         if (dt < 0 && dt % int256(s.poolWindow) != 0) --mean;\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:151:52\n    │\n151 │         uint160 sqrt = TickMath.getSqrtRatioAtTick(int24(mean));\n    │                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:175:9\n    │\n175 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:379:13\n    │\n379 │             guardian = abi.decode(p.data, (address));\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:166:70\n    │\n166 │     function transferOwnership(address nextOwner) external onlyOwner nonReentrant {\n    │                                                                      ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:180:48\n    │\n180 │     function pauseDeposits() external onlyRole nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:185:51\n    │\n185 │     function unpauseDeposits() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:190:53\n    │\n190 │     function close(address token) external onlyRole nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:197:58\n    │\n197 │     function lowerNavCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:207:9\n    │\n207 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:213:51\n    │\n213 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:254:46\n    │\n254 │         a.quoteDecimals = O.decimals(address(uint160(a.tokenIs0 ? t1 : t0)), config.feedGas);\n    │                                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:280:9\n    │\n280 │         emit AssetListed(token, feed, pool);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:287:9\n    │\n287 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:294:9\n    │\n294 │         emit Proposed(id, action, token, data, block.timestamp + 2 days);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:329:45\n    │\n329 │         return p.readyAt != 0 && !p.done && block.timestamp <= p.readyAt + 7 days && p.epoch == epoch[p.token]\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:334:51\n    │\n334 │     function cancel(uint256 id) external onlyRole nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:342:53\n    │\n342 │     function execute(uint256 id) external onlyOwner nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:345:13\n    │\n345 │         if (block.timestamp < p.readyAt) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:377:13\n    │\n377 │             emit Resynced(token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:380:13\n    │\n380 │             emit GuardianChanged(guardian);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:383:13\n    │\n383 │             emit NavCapChanged(NAV_CAP);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:386:13\n    │\n386 │             emit FeeRecipientChanged(feeRecipient);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:390:13\n    │\n390 │             emit SettingChanged(key, value);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:392:42\n    │\n392 │         if (p.action <= T.Action.Resync) emit AssetChanged(token, p.action);\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:393:9\n    │\n393 │         emit ProposalExecuted(id);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:415:25\n    │\n415 │             s.hoursTo = uint32(value);\n    │                         ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:16\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:58\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:86\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:500:83\n    │\n500 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                                                                                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:500:21\n    │\n500 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:518:34\n    │\n518 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:546:13\n    │\n546 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:571:17\n    │\n571 │                 emit DeficitFlagged(token, 0, 0);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:577:9\n    │\n577 │         emit Deposit(msg.sender, receiver, v, received, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:555:22\n    │\n555 │             if (!ok) revert TransferFailed();\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:591:63\n    │\n591 │         if (!ok || (size != 0 && (size < 32 || result != 1))) revert TransferFailed();\n    │                                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:563:17\n    │\n563 │                 revert TransferFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:644:45\n    │\n644 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:654:18\n    │\n654 │             if (!paid) {\n    │                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:631:49\n    │\n631 │             if (managed[assetTokens[i]] != 0) ++count;\n    │                                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:618:13\n    │\n618 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:659:9\n    │\n659 │         emit Redeem(msg.sender, receiver, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:644:69\n    │\n644 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:680:13\n    │\n680 │             emit Claimed(msg.sender, to, token, ok ? amount : 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:697:9\n    │\n697 │         emit DeficitFlagged(token, deficits[token].amount, deficits[token].since);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:703:30\n    │\n703 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert TooEarly();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:711:9\n    │\n711 │         emit LossRecognized(token, loss);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:741:37\n    │\n741 │             if (proposalValid(i)) ++count;\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   ‡\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:168:75\n    │\n168 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:214:21\n    │\n214 │         f.set(20e8, block.timestamp);\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:230:29\n    │\n230 │         feeds[0].set(200e8, block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:62:83\n    │\n 62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n    │                                                                                   ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/GovernanceAndLoss.t.sol:324:9\n    │\n324 │         vm.warp(since + 7 days - 1);\n    │         ─────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:74:29\n   │\n74 │         feeds[2].set(100e8, block.timestamp - 4 hours - 1);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:76:29\n   │\n76 │         feeds[2].set(100e8, block.timestamp - 4 hours);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:88:9\n   │\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:86:27\n   │\n86 │         uint256 monday = (block.timestamp / 1 days + 7) / 7 * 7 * 1 days + 4 days;\n   │                           ━━━━━━━━━━━━━━━\n87 │         // Unix epoch Thursday; day 4 modulo 7 is Monday.\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:91:9\n   │\n91 │         vm.warp(monday + 17 hours);\n   │         ────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:94:9\n   │\n94 │         vm.warp(monday + 5 days + 10 hours);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:24:30\n   │\n24 │         quoteFeed.set(100e8, block.timestamp);\n   │                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/RedemptionGas.t.sol:22:17\n   │\n22 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":1223,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/GovernanceAndLoss.t.sol:LossTest\n[PASS] testDepositAndHealthyFlagClearUnretiredRecords() (gas: 947558)\n[PASS] testLossDoesNotAutoReduceAndWaitsSevenDays() (gas: 766294)\n[PASS] testOnlyLargerLossRestartsClockAndRecoveredPartNotWrittenOff() (gas: 753751)\n[PASS] testRedeemWithBalanceBelowOwedLeavesManagedAndPaysZero() (gas: 1182571)\n[PASS] testRetiredRemovedOnlyAfterManagedAndClaimsEmpty() (gas: 1819785)\n[PASS] testUnreadableNeverFabricatesLossOrClearsRecord() (gas: 611695)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 18.64ms (5.01ms CPU time)\n\nRan 12 tests for test/Prices.t.sol:PriceTest\n[PASS] testBandBoundariesAndOraclePause() (gas: 940453)\n[PASS] testEveryManagedAssetCheckedEvenClosedAndNotDeposited() (gas: 775211)\n[PASS] testFractionalQuoteWithZeroDecimalsIsNotRoundedToWholeQuote() (gas: 6690661)\n[PASS] testFreshCountIncludesIdleClosedUnretiredAssets() (gas: 1527645)\n[PASS] testHoursWeekdayEndpointsAndAlwaysOpen() (gas: 1740367)\n[PASS] testMixedDecimalsAndExactValueRounding() (gas: 4789419)\n[PASS] testNegativeFractionalMeanRoundsDownAndCumulativesWrap() (gas: 2635522)\n[PASS] testOptionalPauseAbsentAtListing() (gas: 1533625)\n[PASS] testPoolDeviationQuoteStaleAndObserveFailures() (gas: 3668686)\n[PASS] testPoolTickZeroPriceLiquidityAndMaxAge() (gas: 3110369)\n[PASS] testPriceAgeFutureSignAndReadFailures() (gas: 1233965)\n[PASS] testRemovePoolReturnsToNoPoolAgeAndWrongPoolRejected() (gas: 3187939)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 18.73ms (12.31ms CPU time)\n\nRan 17 tests for test/GovernanceAndLoss.t.sol:GovernanceTest\n[PASS] testCloseCancelsAllOlderReopenProposals() (gas: 805281)\n[PASS] testExecutionAtLastSecondAndPendingEnumeration() (gas: 295975)\n[PASS] testFeeRecipientCannotBeUnsetOrVault() (gas: 74111)\n[PASS] testGenesisThresholdAndFinalizationOnce() (gas: 911740)\n[PASS] testGuardianCannotCancelReplacementButOwnerCan() (gas: 933572)\n[PASS] testGuardianProposalRechecksNewOwnerAtExecution() (gas: 331816)\n[PASS] testListingAndNewFeedRecheckDecimalsUniquenessFreshness() (gas: 3390549)\n[PASS] testNavCapLoweringVoidsRaisesAndCapApplies() (gas: 803893)\n[PASS] testOnlyOwnerCanUnpauseAndUnprivilegedCannotConfigure() (gas: 342949)\n[PASS] testOnlyOwnerExecutionTimelockAndExpiry() (gas: 594926)\n[PASS] testRecentreUsesExecutionAnswerAndRejectsStale() (gas: 662901)\n[PASS] testRemoveRetiredAndRelistAndReuseFeed() (gas: 1249058)\n[PASS] testRetireClosedAtBothTimesInvalidatesPendingForever() (gas: 1498656)\n[PASS] testRetiredHoldingsIgnoredByDepositAndSharedWithLaterDepositor() (gas: 1905568)\n[PASS] testSettingBoundsRecheckedAtExecution() (gas: 786821)\n[PASS] testSettingsBoundsAndCoupledGasConstraints() (gas: 2310917)\n[PASS] testTwoStepOwnerNeverGuardianEvenAcrossRoleChanges() (gas: 691331)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 18.76ms (9.84ms CPU time)\n\nRan 18 tests for test/BaskVault.t.sol:BasketAccountingTest\n[PASS] testConstructorRejectsMissingAndEqualRoles() (gas: 6561)\n[PASS] testDeploymentAndMinimumLock() (gas: 422563)\n[PASS] testDepositChecksIdleUnreadableButSkipsRetired() (gas: 935261)\n[PASS] testDirectLimitZeroAlwaysCreditsAndOwedExcluded() (gas: 1081288)\n[PASS] testDonationDoesNotAffectSharesUntilResync() (gas: 1230743)\n[PASS] testDuplicateInvalidAmountReceiverAndDeadline() (gas: 309026)\n[PASS] testFeeDepositAndRedeemRounding() (gas: 918155)\n[PASS] testFeeOnTransferPullRejectedAndNoReturnSupported() (gas: 786436)\n[PASS] testFirstDepositTinyAndSlippageFailAtomically() (gas: 412631)\n[PASS] testFuzzConservation(uint128,uint16) (runs: 256, μ: 530617, ~: 530715)\nLogs:\n  Bound result 999999900000000930531\n  Bound result 5534\n\n[PASS] testNoRoleOrGasSettingLimitsClaimWork() (gas: 2235211)\n[PASS] testPausedBlockedFailedPaymentsAndPartialClaims() (gas: 783940)\n[PASS] testPaymentFailureRollsBackAllTokenEffects() (gas: 1168763)\n[PASS] testPreviewMatchesAndNoPriceOnRedeem() (gas: 1007538)\n[PASS] testRedeemMinimaFailureRestoresBurnAndTransfers() (gas: 444723)\n[PASS] testReentrancyOnPullPayAndClaimFails() (gas: 1410548)\n[PASS] testShareTransferEventsUseStandardTopics() (gas: 777994)\n[PASS] testTransferAndAllowance() (gas: 576112)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 24.93ms (37.32ms CPU time)\n\nRan 4 tests for test/MathAndDeployment.t.sol:MathAndDeploymentTest\n[PASS] testFullMathOverflowAndZeroDenominator() (gas: 153622)\n[PASS] testFuzzFullWidthDivisionIdentity(uint256) (runs: 256, μ: 3441, ~: 3442)\n[PASS] testRuntimeHasNoEscapeInstructions() (gas: 10003186)\n[PASS] testTickExtremesAndSubUnitValue() (gas: 6767)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 27.98ms (46.26ms CPU time)\n\nRan 9 tests for test/RedemptionGas.t.sol:RedemptionGasTest\n[PASS] testGas250AllPausedOrBlocked() (gas: 214494294)\nLogs:\n  250 paused or blocked assets gas: 15949261\n\n[PASS] testGas250AtBalanceCeilingWithHugeAccountingAndFees() (gas: 276064106)\nLogs:\n  250 assets at exact gas bound, 512-bit math and fee gas: 27236615\n\n[PASS] testGas250UnreadableFullGasBurningAssets() (gas: 219861783)\nLogs:\n  250 unreadable assets gas: 26647011\n\n[PASS] testGasDirect50TokensConsumeEntirePaymentAllowance() (gas: 177382873)\nLogs:\n  50 unreadable assets plus full payment failures gas: 18785323\n\n[PASS] testGasMaximumAssetSetting350Unreadable() (gas: 297558547)\nLogs:\n  350 unreadable assets at legal settings gas: 26784485\n\n[PASS] testGasMaximumBalance50Assets() (gas: 80397871)\nLogs:\n  50 deferred assets with 500k balance, 512-bit math and fee gas: 27910114\n\n[PASS] testGasMaximumBalanceAndPaymentAllowance() (gas: 63994835)\nLogs:\n  26 direct attempts with 500k call allowances gas: 27454112\n\n[PASS] testGasMaximumDirectLimit254() (gas: 280117667)\nLogs:\n  254 direct attempts at legal settings gas: 25108190\n\n[PASS] testGasReturnBombsAndMalformedBalanceReads() (gas: 178624656)\nLogs:\n  bounded returndata gas: 5426618\n  malformed returndata gas: 4335490\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.13s (5.59s CPU time)\n\nRan 6 test suites in 1.13s (1.24s CPU time): 66 tests passed, 0 failed, 0 skipped (66 total tests)\n","passed":true},{"durationMs":53,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancel(uint256)\",\"BaskVault.claim(address[],address)\",\"BaskVault.close(address)\",\"BaskVault.deposit(address[],uint256[],address,uint256,uint256)\",\"BaskVault.execute(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNavCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose(uint8,address,bytes)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeRetired(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":145,\"SECURITY.md\":67,\"THIRD_PARTY.md\":14,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskTypes.sol\":110,\"src/BaskVault.sol\":795,\"src/libraries/BaskOracle.sol\":168,\"src/libraries/FULLMATH-LICENSE\":22,\"src/libraries/FullMath.sol\":122,\"src/libraries/TickMath.sol\":56,\"src/libraries/UNISWAP-LICENSE\":339,\"test/BaskVault.t.sol\":341,\"test/GovernanceAndLoss.t.sol\":420,\"test/MathAndDeployment.t.sol\":53,\"test/Mocks.sol\":245,\"test/Prices.t.sol\":209,\"test/RedemptionGas.t.sol\":188},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"01561caf813d7f56714771750232230198d5aba866e60c258429714eb8f39cc1","verifiedTreeHash":"1cd9bc3a0418a6f7b9e13c9736d0dcd40138abff","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":21086,"exitCode":0,"name":"build","output":"Compiling 30 files with Solc 0.8.26\nSolc 0.8.26 finished in 20.82s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:116:26\n    │\n116 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:138:19\n    │\n138 │         ) return (false, 0);\n    │                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:145:30\n    │\n145 │         if (dl == 0) return (false, 0);\n    │                              ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:148:54\n    │\n148 │         if (mean < -887272 || mean > 887272) return (false, 0);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:150:82\n    │\n150 │         if (liquidity > type(uint128).max || liquidity < a.minLiquidity) return (false, 0);\n    │                                                                                  ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:165:26\n    │\n165 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:37:16\n   │\n37 │         return uint8(d);\n   │                ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:35\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:67\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:64:40\n   │\n64 │         if (signedAnswer > 0) answer = uint256(signedAnswer);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:99:17\n   │\n99 │             if (block.timestamp - updatedAt > s.noPoolAge) reason = T.Reason.Feed;\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:113:26\n    │\n113 │         secondsAgos[0] = uint32(s.poolWindow);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:136:87\n    │\n136 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || int256(int56(t0)) != t0\n    │                                                                                       ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:137:27\n    │\n137 │                 || int256(int56(t1)) != t1 || l0 > type(uint160).max || l1 > type(uint160).max\n    │                           ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:18\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                  ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:30\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                              ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:18\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                  ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:32\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:146:28\n    │\n146 │         int256 mean = dt / int256(s.poolWindow);\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:147:28\n    │\n147 │         if (dt < 0 && dt % int256(s.poolWindow) != 0) --mean;\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:151:52\n    │\n151 │         uint160 sqrt = TickMath.getSqrtRatioAtTick(int24(mean));\n    │                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:464:16\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:175:9\n    │\n175 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:379:13\n    │\n379 │             guardian = abi.decode(p.data, (address));\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:166:70\n    │\n166 │     function transferOwnership(address nextOwner) external onlyOwner nonReentrant {\n    │                                                                      ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:180:48\n    │\n180 │     function pauseDeposits() external onlyRole nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:185:51\n    │\n185 │     function unpauseDeposits() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:190:53\n    │\n190 │     function close(address token) external onlyRole nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:197:58\n    │\n197 │     function lowerNavCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:207:9\n    │\n207 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:213:51\n    │\n213 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:254:46\n    │\n254 │         a.quoteDecimals = O.decimals(address(uint160(a.tokenIs0 ? t1 : t0)), config.feedGas);\n    │                                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:280:9\n    │\n280 │         emit AssetListed(token, feed, pool);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:287:9\n    │\n287 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:294:9\n    │\n294 │         emit Proposed(id, action, token, data, block.timestamp + 2 days);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:329:45\n    │\n329 │         return p.readyAt != 0 && !p.done && block.timestamp <= p.readyAt + 7 days && p.epoch == epoch[p.token]\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:334:51\n    │\n334 │     function cancel(uint256 id) external onlyRole nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:342:53\n    │\n342 │     function execute(uint256 id) external onlyOwner nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:345:13\n    │\n345 │         if (block.timestamp < p.readyAt) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:377:13\n    │\n377 │             emit Resynced(token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:380:13\n    │\n380 │             emit GuardianChanged(guardian);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:383:13\n    │\n383 │             emit NavCapChanged(NAV_CAP);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:386:13\n    │\n386 │             emit FeeRecipientChanged(feeRecipient);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:390:13\n    │\n390 │             emit SettingChanged(key, value);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:392:42\n    │\n392 │         if (p.action <= T.Action.Resync) emit AssetChanged(token, p.action);\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:393:9\n    │\n393 │         emit ProposalExecuted(id);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:415:25\n    │\n415 │             s.hoursTo = uint32(value);\n    │                         ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:16\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:58\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:86\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:500:83\n    │\n500 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                                                                                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:500:21\n    │\n500 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:518:34\n    │\n518 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:546:13\n    │\n546 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:571:17\n    │\n571 │                 emit DeficitFlagged(token, 0, 0);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:577:9\n    │\n577 │         emit Deposit(msg.sender, receiver, v, received, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:555:22\n    │\n555 │             if (!ok) revert TransferFailed();\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:591:63\n    │\n591 │         if (!ok || (size != 0 && (size < 32 || result != 1))) revert TransferFailed();\n    │                                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:563:17\n    │\n563 │                 revert TransferFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:644:45\n    │\n644 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:654:18\n    │\n654 │             if (!paid) {\n    │                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:631:49\n    │\n631 │             if (managed[assetTokens[i]] != 0) ++count;\n    │                                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:618:13\n    │\n618 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:659:9\n    │\n659 │         emit Redeem(msg.sender, receiver, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:644:69\n    │\n644 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:680:13\n    │\n680 │             emit Claimed(msg.sender, to, token, ok ? amount : 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:697:9\n    │\n697 │         emit DeficitFlagged(token, deficits[token].amount, deficits[token].since);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:703:30\n    │\n703 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert TooEarly();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:711:9\n    │\n711 │         emit LossRecognized(token, loss);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:741:37\n    │\n741 │             if (proposalValid(i)) ++count;\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   ‡\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:168:75\n    │\n168 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:214:21\n    │\n214 │         f.set(20e8, block.timestamp);\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:230:29\n    │\n230 │         feeds[0].set(200e8, block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:62:83\n    │\n 62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n    │                                                                                   ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/GovernanceAndLoss.t.sol:324:9\n    │\n324 │         vm.warp(since + 7 days - 1);\n    │         ─────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:74:29\n   │\n74 │         feeds[2].set(100e8, block.timestamp - 4 hours - 1);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:76:29\n   │\n76 │         feeds[2].set(100e8, block.timestamp - 4 hours);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:88:9\n   │\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:86:27\n   │\n86 │         uint256 monday = (block.timestamp / 1 days + 7) / 7 * 7 * 1 days + 4 days;\n   │                           ━━━━━━━━━━━━━━━\n87 │         // Unix epoch Thursday; day 4 modulo 7 is Monday.\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:91:9\n   │\n91 │         vm.warp(monday + 17 hours);\n   │         ────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:94:9\n   │\n94 │         vm.warp(monday + 5 days + 10 hours);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:24:30\n   │\n24 │         quoteFeed.set(100e8, block.timestamp);\n   │                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/RedemptionGas.t.sol:22:17\n   │\n22 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":704,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 17 tests for test/GovernanceAndLoss.t.sol:GovernanceTest\n[PASS] testCloseCancelsAllOlderReopenProposals() (gas: 805281)\n[PASS] testExecutionAtLastSecondAndPendingEnumeration() (gas: 295975)\n[PASS] testFeeRecipientCannotBeUnsetOrVault() (gas: 74111)\n[PASS] testGenesisThresholdAndFinalizationOnce() (gas: 911740)\n[PASS] testGuardianCannotCancelReplacementButOwnerCan() (gas: 933572)\n[PASS] testGuardianProposalRechecksNewOwnerAtExecution() (gas: 331816)\n[PASS] testListingAndNewFeedRecheckDecimalsUniquenessFreshness() (gas: 3390549)\n[PASS] testNavCapLoweringVoidsRaisesAndCapApplies() (gas: 803893)\n[PASS] testOnlyOwnerCanUnpauseAndUnprivilegedCannotConfigure() (gas: 342949)\n[PASS] testOnlyOwnerExecutionTimelockAndExpiry() (gas: 594926)\n[PASS] testRecentreUsesExecutionAnswerAndRejectsStale() (gas: 662901)\n[PASS] testRemoveRetiredAndRelistAndReuseFeed() (gas: 1249058)\n[PASS] testRetireClosedAtBothTimesInvalidatesPendingForever() (gas: 1498656)\n[PASS] testRetiredHoldingsIgnoredByDepositAndSharedWithLaterDepositor() (gas: 1905568)\n[PASS] testSettingBoundsRecheckedAtExecution() (gas: 786821)\n[PASS] testSettingsBoundsAndCoupledGasConstraints() (gas: 2310917)\n[PASS] testTwoStepOwnerNeverGuardianEvenAcrossRoleChanges() (gas: 691331)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 3.47ms (8.19ms CPU time)\n\nRan 6 tests for test/GovernanceAndLoss.t.sol:LossTest\n[PASS] testDepositAndHealthyFlagClearUnretiredRecords() (gas: 947558)\n[PASS] testLossDoesNotAutoReduceAndWaitsSevenDays() (gas: 766294)\n[PASS] testOnlyLargerLossRestartsClockAndRecoveredPartNotWrittenOff() (gas: 753751)\n[PASS] testRedeemWithBalanceBelowOwedLeavesManagedAndPaysZero() (gas: 1182571)\n[PASS] testRetiredRemovedOnlyAfterManagedAndClaimsEmpty() (gas: 1819785)\n[PASS] testUnreadableNeverFabricatesLossOrClearsRecord() (gas: 611695)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 3.46ms (4.19ms CPU time)\n\nRan 12 tests for test/Prices.t.sol:PriceTest\n[PASS] testBandBoundariesAndOraclePause() (gas: 940453)\n[PASS] testEveryManagedAssetCheckedEvenClosedAndNotDeposited() (gas: 775211)\n[PASS] testFractionalQuoteWithZeroDecimalsIsNotRoundedToWholeQuote() (gas: 6690661)\n[PASS] testFreshCountIncludesIdleClosedUnretiredAssets() (gas: 1527645)\n[PASS] testHoursWeekdayEndpointsAndAlwaysOpen() (gas: 1740367)\n[PASS] testMixedDecimalsAndExactValueRounding() (gas: 4789419)\n[PASS] testNegativeFractionalMeanRoundsDownAndCumulativesWrap() (gas: 2635522)\n[PASS] testOptionalPauseAbsentAtListing() (gas: 1533625)\n[PASS] testPoolDeviationQuoteStaleAndObserveFailures() (gas: 3668686)\n[PASS] testPoolTickZeroPriceLiquidityAndMaxAge() (gas: 3110369)\n[PASS] testPriceAgeFutureSignAndReadFailures() (gas: 1233965)\n[PASS] testRemovePoolReturnsToNoPoolAgeAndWrongPoolRejected() (gas: 3187939)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 16.86ms (12.65ms CPU time)\n\nRan 4 tests for test/MathAndDeployment.t.sol:MathAndDeploymentTest\n[PASS] testFullMathOverflowAndZeroDenominator() (gas: 153622)\n[PASS] testFuzzFullWidthDivisionIdentity(uint256) (runs: 256, μ: 3441, ~: 3442)\n[PASS] testRuntimeHasNoEscapeInstructions() (gas: 10003186)\n[PASS] testTickExtremesAndSubUnitValue() (gas: 6767)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 18.00ms (20.76ms CPU time)\n\nRan 18 tests for test/BaskVault.t.sol:BasketAccountingTest\n[PASS] testConstructorRejectsMissingAndEqualRoles() (gas: 6561)\n[PASS] testDeploymentAndMinimumLock() (gas: 422563)\n[PASS] testDepositChecksIdleUnreadableButSkipsRetired() (gas: 935261)\n[PASS] testDirectLimitZeroAlwaysCreditsAndOwedExcluded() (gas: 1081288)\n[PASS] testDonationDoesNotAffectSharesUntilResync() (gas: 1230743)\n[PASS] testDuplicateInvalidAmountReceiverAndDeadline() (gas: 309026)\n[PASS] testFeeDepositAndRedeemRounding() (gas: 918155)\n[PASS] testFeeOnTransferPullRejectedAndNoReturnSupported() (gas: 786436)\n[PASS] testFirstDepositTinyAndSlippageFailAtomically() (gas: 412631)\n[PASS] testFuzzConservation(uint128,uint16) (runs: 256, μ: 530678, ~: 530715)\nLogs:\n  Bound result 999999900000000004097\n  Bound result 7005\n\n[PASS] testNoRoleOrGasSettingLimitsClaimWork() (gas: 2235211)\n[PASS] testPausedBlockedFailedPaymentsAndPartialClaims() (gas: 783940)\n[PASS] testPaymentFailureRollsBackAllTokenEffects() (gas: 1168763)\n[PASS] testPreviewMatchesAndNoPriceOnRedeem() (gas: 1007538)\n[PASS] testRedeemMinimaFailureRestoresBurnAndTransfers() (gas: 444723)\n[PASS] testReentrancyOnPullPayAndClaimFails() (gas: 1410548)\n[PASS] testShareTransferEventsUseStandardTopics() (gas: 777994)\n[PASS] testTransferAndAllowance() (gas: 576112)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 18.71ms (29.51ms CPU time)\n\nRan 9 tests for test/RedemptionGas.t.sol:RedemptionGasTest\n[PASS] testGas250AllPausedOrBlocked() (gas: 214494294)\nLogs:\n  250 paused or blocked assets gas: 15949261\n\n[PASS] testGas250AtBalanceCeilingWithHugeAccountingAndFees() (gas: 276064106)\nLogs:\n  250 assets at exact gas bound, 512-bit math and fee gas: 27236615\n\n[PASS] testGas250UnreadableFullGasBurningAssets() (gas: 219861783)\nLogs:\n  250 unreadable assets gas: 26647011\n\n[PASS] testGasDirect50TokensConsumeEntirePaymentAllowance() (gas: 177382873)\nLogs:\n  50 unreadable assets plus full payment failures gas: 18785323\n\n[PASS] testGasMaximumAssetSetting350Unreadable() (gas: 297558547)\nLogs:\n  350 unreadable assets at legal settings gas: 26784485\n\n[PASS] testGasMaximumBalance50Assets() (gas: 80397871)\nLogs:\n  50 deferred assets with 500k balance, 512-bit math and fee gas: 27910114\n\n[PASS] testGasMaximumBalanceAndPaymentAllowance() (gas: 63994835)\nLogs:\n  26 direct attempts with 500k call allowances gas: 27454112\n\n[PASS] testGasMaximumDirectLimit254() (gas: 280117667)\nLogs:\n  254 direct attempts at legal settings gas: 25108190\n\n[PASS] testGasReturnBombsAndMalformedBalanceReads() (gas: 178624656)\nLogs:\n  bounded returndata gas: 5426618\n  malformed returndata gas: 4335490\n\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 613.84ms (3.09s CPU time)\n\nRan 6 test suites in 614.89ms (674.35ms CPU time): 66 tests passed, 0 failed, 0 skipped (66 total tests)\n","passed":true},{"durationMs":34,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancel(uint256)\",\"BaskVault.claim(address[],address)\",\"BaskVault.close(address)\",\"BaskVault.deposit(address[],uint256[],address,uint256,uint256)\",\"BaskVault.execute(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNavCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose(uint8,address,bytes)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeRetired(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":145,\"SECURITY.md\":67,\"THIRD_PARTY.md\":14,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskTypes.sol\":110,\"src/BaskVault.sol\":795,\"src/libraries/BaskOracle.sol\":168,\"src/libraries/FULLMATH-LICENSE\":22,\"src/libraries/FullMath.sol\":122,\"src/libraries/TickMath.sol\":56,\"src/libraries/UNISWAP-LICENSE\":339,\"test/BaskVault.t.sol\":341,\"test/GovernanceAndLoss.t.sol\":420,\"test/MathAndDeployment.t.sol\":53,\"test/Mocks.sol\":245,\"test/Prices.t.sol\":209,\"test/RedemptionGas.t.sol\":188},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4228,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/BaskVault.sol:461: BaskVault._insideHours() (src/BaskVault.sol#461-465) uses a weak PRNG: \"time = block.timestamp % 86400 (src/BaskVault.sol#463)\"\n[high/medium] weak-prng at src/BaskVault.sol:461: BaskVault._insideHours() (src/BaskVault.sol#461-465) uses a weak PRNG: \"(block.timestamp / 86400 + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo (src/BaskVault.sol#464)\"\n[medium/medium] uninitialized-local at src/BaskVault.sol:784: BaskVault.allAssets().v (src/BaskVault.sol#784) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:739: BaskVault.pendingProposals(uint256,uint256).count (src/BaskVault.sol#739) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:485: BaskVault._snapshot(address[]).fresh (src/BaskVault.sol#485) is a local variable never initialized\n[medium/medium] unused-return at src/BaskVault.sol:342: BaskVault.execute(uint256) (src/BaskVault.sol#342-394) ignores return value by (ok,answer,None) = BaskOracle.feed(a.feed,config.feedGas,config.maxAge) (src/BaskVault.sol#359)\n[medium/medium] unused-return at src/BaskVault.sol:467: BaskVault._snapshot(address[]) (src/BaskVault.sol#467-507) ignores return value by (reason,answers[i_scope_0],updatedAt,None) = BaskOracle.price(a,config) (src/BaskVault.sol#497)\n[medium/medium] unused-return at src/BaskVault.sol:467: BaskVault._snapshot(address[]) (src/BaskVault.sol#467-507) ignores return value by (ok,None,None) = BaskOracle.feed(a.feed,config.feedGas,config.freshHours * 3600) (src/BaskVault.sol#502)\n[medium/medium] unused-return at src/BaskVault.sol:223: BaskVault._checkFeed(address,address) (src/BaskVault.sol#223-230) ignores return value by (ok,answer,None) = BaskOracle.feed(feed,config.feedGas,config.maxAge) (src/BaskVault.sol#228)\n[low/medium] timestamp at src/BaskVault.sol:467: BaskVault._snapshot(address[]) (src/BaskVault.sol#467-507) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:327: BaskVault.proposalValid(uint256) (src/BaskVault.sol#327-332) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:613: BaskVault.redeem(uint256,address,uint256[],uint256) (src/BaskVault.sol#613-660) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:342: BaskVault.execute(uint256) (src/BaskVault.sol#342-394) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:461: BaskVault._insideHours() (src/BaskVault.sol#461-465) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:539: BaskVault.deposit(address[],uint256[],address,uint256,uint256) (src/BaskVault.sol#539-578) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:700: BaskVault.recognizeLoss(address) (src/BaskVault.sol#700-712) uses timestamp for comparisons","passed":true},{"durationMs":375,"exitCode":0,"name":"aderyn","output":"[high] incorrect-caret-operator at src/libraries/FullMath.sol:86: Incorrect use of caret operator\n[high] incorrect-shift-order at src/libraries/BaskOracle.sol:44: Incorrect Assembly Shift Parameter Order\n[high] reentrancy-state-change at src/BaskVault.sol:651: Reentrancy: State change after external call (2 places)\n[high] storage-array-memory-edit at src/BaskVault.sol:311: Storage Array Edited with Memory (2 places)\n[high] weak-randomness at src/BaskVault.sol:463: Weak Randomness\n[low] centralization-risk at src/BaskVault.sol:166: Centralization Risk (10 places)\n[low] costly-loop at src/BaskVault.sol:552: Costly operations inside loop (4 places)\n[low] internal-function-used-once at src/libraries/BaskOracle.sol:68: Internal Function Used Only Once (3 places)\n[low] large-numeric-literal at src/BaskVault.sol:110: Large Numeric Literal (12 places)\n[low] literal-instead-of-constant at src/BaskVault.sol:110: Literal Instead of Constant (64 places)\n[low] non-reentrant-not-first at src/BaskVault.sol:166: `nonReentrant` is Not the First Modifier (10 places)\n[low] require-revert-in-loop at src/BaskVault.sol:486: Loop Contains `require`/`revert` (6 places)\n[low] state-change-without-event at src/BaskVault.sol:122: State Change Without Event\n[low] storage-array-length-not-cached at src/BaskVault.sol:486: Storage Array Length not Cached (4 places)\n[low] unchecked-return at src/BaskVault.sol:304: Unchecked Return (4 places)\n[low] uninitialized-local-variable at src/BaskVault.sol:477: Uninitialized Local Variable (8 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"1efaa88c53aaf45144531d4b7dee093fdb2ccbceccfca0007d2a3cab2903648b","verifiedTreeHash":"496ad7cd89b7e843ed9fa218a57d69590fd7748e","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":26817,"exitCode":0,"name":"build","output":"Compiling 32 files with Solc 0.8.26\nSolc 0.8.26 finished in 26.56s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:116:26\n    │\n116 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:138:19\n    │\n138 │         ) return (false, 0);\n    │                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:145:30\n    │\n145 │         if (dl == 0) return (false, 0);\n    │                              ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:148:54\n    │\n148 │         if (mean < -887272 || mean > 887272) return (false, 0);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:150:82\n    │\n150 │         if (liquidity > type(uint128).max || liquidity < a.minLiquidity) return (false, 0);\n    │                                                                                  ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:165:26\n    │\n165 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:472:16\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:37:16\n   │\n37 │         return uint8(d);\n   │                ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:35\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:67\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:64:40\n   │\n64 │         if (signedAnswer > 0) answer = uint256(signedAnswer);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:99:17\n   │\n99 │             if (block.timestamp - updatedAt > s.noPoolAge) reason = T.Reason.Feed;\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:113:26\n    │\n113 │         secondsAgos[0] = uint32(s.poolWindow);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:136:87\n    │\n136 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || int256(int56(t0)) != t0\n    │                                                                                       ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:137:27\n    │\n137 │                 || int256(int56(t1)) != t1 || l0 > type(uint160).max || l1 > type(uint160).max\n    │                           ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:18\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                  ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:30\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                              ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:18\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                  ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:32\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:146:28\n    │\n146 │         int256 mean = dt / int256(s.poolWindow);\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:147:28\n    │\n147 │         if (dt < 0 && dt % int256(s.poolWindow) != 0) --mean;\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:151:52\n    │\n151 │         uint160 sqrt = TickMath.getSqrtRatioAtTick(int24(mean));\n    │                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:178:9\n    │\n178 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:382:13\n    │\n382 │             guardian = abi.decode(p.data, (address));\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:169:70\n    │\n169 │     function transferOwnership(address nextOwner) external onlyOwner nonReentrant {\n    │                                                                      ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:183:48\n    │\n183 │     function pauseDeposits() external onlyRole nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:188:51\n    │\n188 │     function unpauseDeposits() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:193:53\n    │\n193 │     function close(address token) external onlyRole nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:200:58\n    │\n200 │     function lowerNavCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:210:9\n    │\n210 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:216:51\n    │\n216 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:257:46\n    │\n257 │         a.quoteDecimals = O.decimals(address(uint160(a.tokenIs0 ? t1 : t0)), config.feedGas);\n    │                                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:283:9\n    │\n283 │         emit AssetListed(token, feed, pool);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:290:9\n    │\n290 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:297:9\n    │\n297 │         emit Proposed(id, action, token, data, block.timestamp + 2 days);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:332:45\n    │\n332 │         return p.readyAt != 0 && !p.done && block.timestamp <= p.readyAt + 7 days && p.epoch == epoch[p.token]\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:337:51\n    │\n337 │     function cancel(uint256 id) external onlyRole nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:345:53\n    │\n345 │     function execute(uint256 id) external onlyOwner nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:348:13\n    │\n348 │         if (block.timestamp < p.readyAt) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:380:13\n    │\n380 │             emit Resynced(token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:383:13\n    │\n383 │             emit GuardianChanged(guardian);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:386:13\n    │\n386 │             emit NavCapChanged(NAV_CAP);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:389:13\n    │\n389 │             emit FeeRecipientChanged(feeRecipient);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:393:13\n    │\n393 │             emit SettingChanged(key, value);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:395:42\n    │\n395 │         if (p.action <= T.Action.Resync) emit AssetChanged(token, p.action);\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:396:9\n    │\n396 │         emit ProposalExecuted(id);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:418:25\n    │\n418 │             s.hoursTo = uint32(value);\n    │                         ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:16\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:58\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:86\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:509:83\n    │\n509 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                                                                                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:509:21\n    │\n509 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:527:34\n    │\n527 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:555:13\n    │\n555 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:580:17\n    │\n580 │                 emit DeficitFlagged(token, 0, 0);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:586:9\n    │\n586 │         emit Deposit(msg.sender, receiver, v, received, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:564:22\n    │\n564 │             if (!ok) revert TransferFailed();\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:600:63\n    │\n600 │         if (!ok || (size != 0 && (size < 32 || result != 1))) revert TransferFailed();\n    │                                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:572:17\n    │\n572 │                 revert TransferFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:682:18\n    │\n682 │             if (!paid) {\n    │                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:672:45\n    │\n672 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:661:17\n    │\n661 │             if (bits & (uint256(1) << (i & 255)) == 0) {\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:644:13\n    │\n644 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:687:9\n    │\n687 │         emit Redeem(msg.sender, receiver, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:662:72\n    │\n662 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:672:69\n    │\n672 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:708:13\n    │\n708 │             emit Claimed(msg.sender, to, token, ok ? amount : 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:725:9\n    │\n725 │         emit DeficitFlagged(token, deficits[token].amount, deficits[token].since);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:731:30\n    │\n731 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert TooEarly();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:739:9\n    │\n739 │         emit LossRecognized(token, loss);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:769:37\n    │\n769 │             if (proposalValid(i)) ++count;\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   ‡\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/DepositDebt.t.sol:13:75\n   │\n13 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n   │                                                                           ━━━━━━━━━━━━━━━\n   ‡\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/DepositDebt.t.sol:17:17\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:168:75\n    │\n168 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:214:21\n    │\n214 │         f.set(20e8, block.timestamp);\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:230:29\n    │\n230 │         feeds[0].set(200e8, block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:62:83\n    │\n 62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n    │                                                                                   ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/GovernanceAndLoss.t.sol:324:9\n    │\n324 │         vm.warp(since + 7 days - 1);\n    │         ─────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:18:60\n   │\n18 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n   │                                                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/HeldAccounting.t.sol:23:9\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/HeldAccounting.t.sol:23:9\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:12:76\n   │\n12 │         vault.deposit(_one(address(tokens[i])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                            ━━━━━━━━━━━━━━━\n   ‡\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:23:17\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:18:60\n   │\n18 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n   │                                                            ━━━━━━━━━━━━━━━\n   ‡\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:12:76\n   │\n12 │         vault.deposit(_one(address(tokens[i])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:183:75\n    │\n183 │         vault.deposit(_one(address(tokens[i])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:189:60\n    │\n189 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:46:45\n    │\n 46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n    │                                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HeldAccounting.t.sol:225:9\n    │\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:183:75\n    │\n183 │         vault.deposit(_one(address(tokens[i])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    ‡\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:189:60\n    │\n189 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n    │                                                            ━━━━━━━━━━━━━━━\n    ‡\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:225:17\n    │\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:74:29\n   │\n74 │         feeds[2].set(100e8, block.timestamp - 4 hours - 1);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:76:29\n   │\n76 │         feeds[2].set(100e8, block.timestamp - 4 hours);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:88:9\n   │\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:86:27\n   │\n86 │         uint256 monday = (block.timestamp / 1 days + 7) / 7 * 7 * 1 days + 4 days;\n   │                           ━━━━━━━━━━━━━━━\n87 │         // Unix epoch Thursday; day 4 modulo 7 is Monday.\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:91:9\n   │\n91 │         vm.warp(monday + 17 hours);\n   │         ────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:94:9\n   │\n94 │         vm.warp(monday + 5 days + 10 hours);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:24:30\n   │\n24 │         quoteFeed.set(100e8, block.timestamp);\n   │                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/RedemptionGas.t.sol:22:17\n   │\n22 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":696,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/DepositDebt.t.sol:DepositDebtTest\n[PASS] testUncoveredClaimsOnZeroManagedNonInputDoNotBlockDeposit() (gas: 2346884)\n[PASS] testUncoveredClaimsStillBlockDepositingThatToken() (gas: 1925509)\n[PASS] testZeroManagedNonInputMustStillHaveReadableBalance() (gas: 1966449)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.12ms (3.99ms CPU time)\n\nRan 6 tests for test/HeldAccounting.t.sol:HeldAccountingTest\n[PASS] testMinimumForIdleAssetRevertsAndRollsBackOtherLegs() (gas: 593021)\n[PASS] testPartialLossKeepsHoldingAndFullLossRestoresDirectPayments() (gas: 2689358)\n[PASS] testRemovingIdleSlotMovesHeldLastAssetWithinBitmapWord() (gas: 1078286)\n[PASS] testRepeatedDepositsCountOneHoldingAndNewAssetDefersPayments() (gas: 1874984)\n[PASS] testResyncActivatesOnlyNewPositiveHoldings() (gas: 2496132)\n[PASS] testRetiredHoldingsRemainInDirectLimitAndRedemption() (gas: 1853892)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 4.20ms (6.09ms CPU time)\n\nRan 12 tests for test/Prices.t.sol:PriceTest\n[PASS] testBandBoundariesAndOraclePause() (gas: 941393)\n[PASS] testEveryManagedAssetCheckedEvenClosedAndNotDeposited() (gas: 820841)\n[PASS] testFractionalQuoteWithZeroDecimalsIsNotRoundedToWholeQuote() (gas: 6690923)\n[PASS] testFreshCountIncludesIdleClosedUnretiredAssets() (gas: 1528352)\n[PASS] testHoursWeekdayEndpointsAndAlwaysOpen() (gas: 1740891)\n[PASS] testMixedDecimalsAndExactValueRounding() (gas: 4845597)\n[PASS] testNegativeFractionalMeanRoundsDownAndCumulativesWrap() (gas: 2635784)\n[PASS] testOptionalPauseAbsentAtListing() (gas: 1578868)\n[PASS] testPoolDeviationQuoteStaleAndObserveFailures() (gas: 3669834)\n[PASS] testPoolTickZeroPriceLiquidityAndMaxAge() (gas: 3111101)\n[PASS] testPriceAgeFutureSignAndReadFailures() (gas: 1234955)\n[PASS] testRemovePoolReturnsToNoPoolAgeAndWrongPoolRejected() (gas: 3188043)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 4.39ms (11.60ms CPU time)\n\nRan 6 tests for test/GovernanceAndLoss.t.sol:LossTest\n[PASS] testDepositAndHealthyFlagClearUnretiredRecords() (gas: 993336)\n[PASS] testLossDoesNotAutoReduceAndWaitsSevenDays() (gas: 805445)\n[PASS] testOnlyLargerLossRestartsClockAndRecoveredPartNotWrittenOff() (gas: 799115)\n[PASS] testRedeemWithBalanceBelowOwedLeavesManagedAndPaysZero() (gas: 1214745)\n[PASS] testRetiredRemovedOnlyAfterManagedAndClaimsEmpty() (gas: 1868805)\n[PASS] testUnreadableNeverFabricatesLossOrClearsRecord() (gas: 656859)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 4.36ms (3.38ms CPU time)\n\nRan 17 tests for test/GovernanceAndLoss.t.sol:GovernanceTest\n[PASS] testCloseCancelsAllOlderReopenProposals() (gas: 805281)\n[PASS] testExecutionAtLastSecondAndPendingEnumeration() (gas: 295975)\n[PASS] testFeeRecipientCannotBeUnsetOrVault() (gas: 74111)\n[PASS] testGenesisThresholdAndFinalizationOnce() (gas: 911740)\n[PASS] testGuardianCannotCancelReplacementButOwnerCan() (gas: 933572)\n[PASS] testGuardianProposalRechecksNewOwnerAtExecution() (gas: 331816)\n[PASS] testListingAndNewFeedRecheckDecimalsUniquenessFreshness() (gas: 3390549)\n[PASS] testNavCapLoweringVoidsRaisesAndCapApplies() (gas: 849316)\n[PASS] testOnlyOwnerCanUnpauseAndUnprivilegedCannotConfigure() (gas: 343211)\n[PASS] testOnlyOwnerExecutionTimelockAndExpiry() (gas: 594926)\n[PASS] testRecentreUsesExecutionAnswerAndRejectsStale() (gas: 662901)\n[PASS] testRemoveRetiredAndRelistAndReuseFeed() (gas: 1249198)\n[PASS] testRetireClosedAtBothTimesInvalidatesPendingForever() (gas: 1543561)\n[PASS] testRetiredHoldingsIgnoredByDepositAndSharedWithLaterDepositor() (gas: 1960738)\n[PASS] testSettingBoundsRecheckedAtExecution() (gas: 786821)\n[PASS] testSettingsBoundsAndCoupledGasConstraints() (gas: 2310917)\n[PASS] testTwoStepOwnerNeverGuardianEvenAcrossRoleChanges() (gas: 691331)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 4.96ms (8.72ms CPU time)\n\nRan 18 tests for test/BaskVault.t.sol:BasketAccountingTest\n[PASS] testConstructorRejectsMissingAndEqualRoles() (gas: 6561)\n[PASS] testDeploymentAndMinimumLock() (gas: 467727)\n[PASS] testDepositChecksIdleUnreadableButSkipsRetired() (gas: 980450)\n[PASS] testDirectLimitZeroAlwaysCreditsAndOwedExcluded() (gas: 1113706)\n[PASS] testDonationDoesNotAffectSharesUntilResync() (gas: 1277440)\n[PASS] testDuplicateInvalidAmountReceiverAndDeadline() (gas: 309276)\n[PASS] testFeeDepositAndRedeemRounding() (gas: 956952)\n[PASS] testFeeOnTransferPullRejectedAndNoReturnSupported() (gas: 825489)\n[PASS] testFirstDepositTinyAndSlippageFailAtomically() (gas: 413149)\n[PASS] testFuzzConservation(uint128,uint16) (runs: 256, μ: 569393, ~: 569512)\nLogs:\n  Bound result 999999900000000000051\n  Bound result 1536\n\n[PASS] testNoRoleOrGasSettingLimitsClaimWork() (gas: 2274002)\n[PASS] testPausedBlockedFailedPaymentsAndPartialClaims() (gas: 822728)\n[PASS] testPaymentFailureRollsBackAllTokenEffects() (gas: 1188459)\n[PASS] testPreviewMatchesAndNoPriceOnRedeem() (gas: 1046594)\n[PASS] testRedeemMinimaFailureRestoresBurnAndTransfers() (gas: 484451)\n[PASS] testReentrancyOnPullPayAndClaimFails() (gas: 1442972)\n[PASS] testShareTransferEventsUseStandardTopics() (gas: 823158)\n[PASS] testTransferAndAllowance() (gas: 621276)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 18.03ms (27.14ms CPU time)\n\nRan 4 tests for test/MathAndDeployment.t.sol:MathAndDeploymentTest\n[PASS] testFullMathOverflowAndZeroDenominator() (gas: 153622)\n[PASS] testFuzzFullWidthDivisionIdentity(uint256) (runs: 256, μ: 3441, ~: 3442)\n[PASS] testRuntimeHasNoEscapeInstructions() (gas: 10144052)\n[PASS] testTickExtremesAndSubUnitValue() (gas: 6767)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 28.05ms (32.20ms CPU time)\n\nRan 1 test for test/HeldAccounting.t.sol:HeldAccountingBoundaryTest\n[PASS] testMoveAcrossBitmapWordsRelistOldSlotAndClearMovedHolding() (gas: 41420429)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 136.72ms (82.38ms CPU time)\n\nRan 11 tests for test/RedemptionGas.t.sol:RedemptionGasTest\n[PASS] testGas250AllPausedOrBlocked() (gas: 214760453)\nLogs:\n  250 paused or blocked assets gas: 15869791\n\n[PASS] testGas250AtBalanceCeilingWithHugeAccountingAndFees() (gas: 276387728)\nLogs:\n  250 assets at exact gas bound, 512-bit math and fee gas: 27157145\n\n[PASS] testGas250UnreadableFullGasBurningAssets() (gas: 220127968)\nLogs:\n  250 unreadable assets gas: 26567541\n\n[PASS] testGas254Assets45DirectWithMaximumPaymentAllowance() (gas: 198823335)\nLogs:\n  254 listed / 45 held assets with 500k payment allowance gas: 27149129\n\n[PASS] testGas350Assets47DirectWithMaximumPaymentAllowance() (gas: 256877677)\nLogs:\n  350 listed / 47 held assets with 500k payment allowance gas: 26985824\n\n[PASS] testGasDirect50TokensConsumeEntirePaymentAllowance() (gas: 176459151)\nLogs:\n  50 unreadable assets plus full payment failures gas: 17741953\n\n[PASS] testGasMaximumAssetSetting350Unreadable() (gas: 297935900)\nLogs:\n  350 unreadable assets at legal settings gas: 26673712\n\n[PASS] testGasMaximumBalance50Assets() (gas: 80501272)\nLogs:\n  50 deferred assets with 500k balance, 512-bit math and fee gas: 27897644\n\n[PASS] testGasMaximumBalanceAndPaymentAllowance() (gas: 63949203)\nLogs:\n  26 direct attempts with 500k call allowances gas: 27331250\n\n[PASS] testGasMaximumDirectLimit254() (gas: 279903348)\nLogs:\n  254 direct attempts at legal settings gas: 24536125\n\n[PASS] testGasReturnBombsAndMalformedBalanceReads() (gas: 176657035)\nLogs:\n  bounded returndata gas: 4383248\n  malformed returndata gas: 3292120\n\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 617.89ms (3.92s CPU time)\n\nRan 9 test suites in 619.25ms (821.71ms CPU time): 78 tests passed, 0 failed, 0 skipped (78 total tests)\n","passed":true},{"durationMs":44,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancel(uint256)\",\"BaskVault.claim(address[],address)\",\"BaskVault.close(address)\",\"BaskVault.deposit(address[],uint256[],address,uint256,uint256)\",\"BaskVault.execute(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNavCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose(uint8,address,bytes)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeRetired(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":151,\"SECURITY.md\":75,\"THIRD_PARTY.md\":14,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskTypes.sol\":110,\"src/BaskVault.sol\":823,\"src/libraries/BaskOracle.sol\":168,\"src/libraries/FULLMATH-LICENSE\":22,\"src/libraries/FullMath.sol\":122,\"src/libraries/TickMath.sol\":56,\"src/libraries/UNISWAP-LICENSE\":339,\"test/BaskVault.t.sol\":341,\"test/DepositDebt.t.sol\":60,\"test/GovernanceAndLoss.t.sol\":420,\"test/HeldAccounting.t.sol\":234,\"test/MathAndDeployment.t.sol\":53,\"test/Mocks.sol\":245,\"test/Prices.t.sol\":209,\"test/RedemptionGas.t.sol\":216},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"7f69bf5074d9956aeff0b25ac237258be6117d31290993276400139d3079177b","verifiedTreeHash":"edc6c11942bb6db755e5d103ef212a459b9237bb","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":24451,"exitCode":0,"name":"build","output":"Compiling 32 files with Solc 0.8.26\nSolc 0.8.26 finished in 24.21s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:116:26\n    │\n116 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:138:19\n    │\n138 │         ) return (false, 0);\n    │                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:145:30\n    │\n145 │         if (dl == 0) return (false, 0);\n    │                              ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:148:54\n    │\n148 │         if (mean < -887272 || mean > 887272) return (false, 0);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:150:82\n    │\n150 │         if (liquidity > type(uint128).max || liquidity < a.minLiquidity) return (false, 0);\n    │                                                                                  ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:165:26\n    │\n165 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:472:16\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:37:16\n   │\n37 │         return uint8(d);\n   │                ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:35\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:67\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:64:40\n   │\n64 │         if (signedAnswer > 0) answer = uint256(signedAnswer);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:99:17\n   │\n99 │             if (block.timestamp - updatedAt > s.noPoolAge) reason = T.Reason.Feed;\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:113:26\n    │\n113 │         secondsAgos[0] = uint32(s.poolWindow);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:136:87\n    │\n136 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || int256(int56(t0)) != t0\n    │                                                                                       ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:137:27\n    │\n137 │                 || int256(int56(t1)) != t1 || l0 > type(uint160).max || l1 > type(uint160).max\n    │                           ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:18\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                  ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:30\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                              ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:18\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                  ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:32\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:146:28\n    │\n146 │         int256 mean = dt / int256(s.poolWindow);\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:147:28\n    │\n147 │         if (dt < 0 && dt % int256(s.poolWindow) != 0) --mean;\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:151:52\n    │\n151 │         uint160 sqrt = TickMath.getSqrtRatioAtTick(int24(mean));\n    │                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:178:9\n    │\n178 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:382:13\n    │\n382 │             guardian = abi.decode(p.data, (address));\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:169:70\n    │\n169 │     function transferOwnership(address nextOwner) external onlyOwner nonReentrant {\n    │                                                                      ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:183:48\n    │\n183 │     function pauseDeposits() external onlyRole nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:188:51\n    │\n188 │     function unpauseDeposits() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:193:53\n    │\n193 │     function close(address token) external onlyRole nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:200:58\n    │\n200 │     function lowerNavCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:210:9\n    │\n210 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:216:51\n    │\n216 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:257:46\n    │\n257 │         a.quoteDecimals = O.decimals(address(uint160(a.tokenIs0 ? t1 : t0)), config.feedGas);\n    │                                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:283:9\n    │\n283 │         emit AssetListed(token, feed, pool);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:290:9\n    │\n290 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:297:9\n    │\n297 │         emit Proposed(id, action, token, data, block.timestamp + 2 days);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:332:45\n    │\n332 │         return p.readyAt != 0 && !p.done && block.timestamp <= p.readyAt + 7 days && p.epoch == epoch[p.token]\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:337:51\n    │\n337 │     function cancel(uint256 id) external onlyRole nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:345:53\n    │\n345 │     function execute(uint256 id) external onlyOwner nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:348:13\n    │\n348 │         if (block.timestamp < p.readyAt) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:380:13\n    │\n380 │             emit Resynced(token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:383:13\n    │\n383 │             emit GuardianChanged(guardian);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:386:13\n    │\n386 │             emit NavCapChanged(NAV_CAP);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:389:13\n    │\n389 │             emit FeeRecipientChanged(feeRecipient);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:393:13\n    │\n393 │             emit SettingChanged(key, value);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:395:42\n    │\n395 │         if (p.action <= T.Action.Resync) emit AssetChanged(token, p.action);\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:396:9\n    │\n396 │         emit ProposalExecuted(id);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:418:25\n    │\n418 │             s.hoursTo = uint32(value);\n    │                         ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:16\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:58\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:86\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:509:83\n    │\n509 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                                                                                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:509:21\n    │\n509 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:527:34\n    │\n527 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:555:13\n    │\n555 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:580:17\n    │\n580 │                 emit DeficitFlagged(token, 0, 0);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:586:9\n    │\n586 │         emit Deposit(msg.sender, receiver, v, received, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:564:22\n    │\n564 │             if (!ok) revert TransferFailed();\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:600:63\n    │\n600 │         if (!ok || (size != 0 && (size < 32 || result != 1))) revert TransferFailed();\n    │                                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:572:17\n    │\n572 │                 revert TransferFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:672:45\n    │\n672 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:682:18\n    │\n682 │             if (!paid) {\n    │                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:661:17\n    │\n661 │             if (bits & (uint256(1) << (i & 255)) == 0) {\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:644:13\n    │\n644 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:687:9\n    │\n687 │         emit Redeem(msg.sender, receiver, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:662:72\n    │\n662 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:672:69\n    │\n672 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:708:13\n    │\n708 │             emit Claimed(msg.sender, to, token, ok ? amount : 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:725:9\n    │\n725 │         emit DeficitFlagged(token, deficits[token].amount, deficits[token].since);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:731:30\n    │\n731 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert TooEarly();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:739:9\n    │\n739 │         emit LossRecognized(token, loss);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:769:37\n    │\n769 │             if (proposalValid(i)) ++count;\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   ‡\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/DepositDebt.t.sol:13:75\n   │\n13 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n   │                                                                           ━━━━━━━━━━━━━━━\n   ‡\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/DepositDebt.t.sol:17:17\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:168:75\n    │\n168 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:214:21\n    │\n214 │         f.set(20e8, block.timestamp);\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:230:29\n    │\n230 │         feeds[0].set(200e8, block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:62:83\n    │\n 62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n    │                                                                                   ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/GovernanceAndLoss.t.sol:324:9\n    │\n324 │         vm.warp(since + 7 days - 1);\n    │         ─────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:18:60\n   │\n18 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n   │                                                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/HeldAccounting.t.sol:23:9\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/HeldAccounting.t.sol:23:9\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:12:76\n   │\n12 │         vault.deposit(_one(address(tokens[i])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                            ━━━━━━━━━━━━━━━\n   ‡\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:23:17\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:18:60\n   │\n18 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n   │                                                            ━━━━━━━━━━━━━━━\n   ‡\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:12:76\n   │\n12 │         vault.deposit(_one(address(tokens[i])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:183:75\n    │\n183 │         vault.deposit(_one(address(tokens[i])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:189:60\n    │\n189 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:46:45\n    │\n 46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n    │                                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HeldAccounting.t.sol:225:9\n    │\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:183:75\n    │\n183 │         vault.deposit(_one(address(tokens[i])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    ‡\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:189:60\n    │\n189 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n    │                                                            ━━━━━━━━━━━━━━━\n    ‡\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:225:17\n    │\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:74:29\n   │\n74 │         feeds[2].set(100e8, block.timestamp - 4 hours - 1);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:76:29\n   │\n76 │         feeds[2].set(100e8, block.timestamp - 4 hours);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:88:9\n   │\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:86:27\n   │\n86 │         uint256 monday = (block.timestamp / 1 days + 7) / 7 * 7 * 1 days + 4 days;\n   │                           ━━━━━━━━━━━━━━━\n87 │         // Unix epoch Thursday; day 4 modulo 7 is Monday.\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:91:9\n   │\n91 │         vm.warp(monday + 17 hours);\n   │         ────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:94:9\n   │\n94 │         vm.warp(monday + 5 days + 10 hours);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:24:30\n   │\n24 │         quoteFeed.set(100e8, block.timestamp);\n   │                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/RedemptionGas.t.sol:22:17\n   │\n22 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":660,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 17 tests for test/GovernanceAndLoss.t.sol:GovernanceTest\n[PASS] testCloseCancelsAllOlderReopenProposals() (gas: 805281)\n[PASS] testExecutionAtLastSecondAndPendingEnumeration() (gas: 295975)\n[PASS] testFeeRecipientCannotBeUnsetOrVault() (gas: 74111)\n[PASS] testGenesisThresholdAndFinalizationOnce() (gas: 911740)\n[PASS] testGuardianCannotCancelReplacementButOwnerCan() (gas: 933572)\n[PASS] testGuardianProposalRechecksNewOwnerAtExecution() (gas: 331816)\n[PASS] testListingAndNewFeedRecheckDecimalsUniquenessFreshness() (gas: 3390549)\n[PASS] testNavCapLoweringVoidsRaisesAndCapApplies() (gas: 849316)\n[PASS] testOnlyOwnerCanUnpauseAndUnprivilegedCannotConfigure() (gas: 343211)\n[PASS] testOnlyOwnerExecutionTimelockAndExpiry() (gas: 594926)\n[PASS] testRecentreUsesExecutionAnswerAndRejectsStale() (gas: 662901)\n[PASS] testRemoveRetiredAndRelistAndReuseFeed() (gas: 1249198)\n[PASS] testRetireClosedAtBothTimesInvalidatesPendingForever() (gas: 1543561)\n[PASS] testRetiredHoldingsIgnoredByDepositAndSharedWithLaterDepositor() (gas: 1960738)\n[PASS] testSettingBoundsRecheckedAtExecution() (gas: 786821)\n[PASS] testSettingsBoundsAndCoupledGasConstraints() (gas: 2310917)\n[PASS] testTwoStepOwnerNeverGuardianEvenAcrossRoleChanges() (gas: 691331)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 3.49ms (6.72ms CPU time)\n\nRan 6 tests for test/GovernanceAndLoss.t.sol:LossTest\n[PASS] testDepositAndHealthyFlagClearUnretiredRecords() (gas: 993336)\n[PASS] testLossDoesNotAutoReduceAndWaitsSevenDays() (gas: 805445)\n[PASS] testOnlyLargerLossRestartsClockAndRecoveredPartNotWrittenOff() (gas: 799115)\n[PASS] testRedeemWithBalanceBelowOwedLeavesManagedAndPaysZero() (gas: 1214745)\n[PASS] testRetiredRemovedOnlyAfterManagedAndClaimsEmpty() (gas: 1868805)\n[PASS] testUnreadableNeverFabricatesLossOrClearsRecord() (gas: 656859)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 3.82ms (3.39ms CPU time)\n\nRan 3 tests for test/DepositDebt.t.sol:DepositDebtTest\n[PASS] testUncoveredClaimsOnZeroManagedNonInputDoNotBlockDeposit() (gas: 2346884)\n[PASS] testUncoveredClaimsStillBlockDepositingThatToken() (gas: 1925509)\n[PASS] testZeroManagedNonInputMustStillHaveReadableBalance() (gas: 1966449)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 16.89ms (2.73ms CPU time)\n\nRan 4 tests for test/MathAndDeployment.t.sol:MathAndDeploymentTest\n[PASS] testFullMathOverflowAndZeroDenominator() (gas: 153622)\n[PASS] testFuzzFullWidthDivisionIdentity(uint256) (runs: 256, μ: 3441, ~: 3442)\n[PASS] testRuntimeHasNoEscapeInstructions() (gas: 10144052)\n[PASS] testTickExtremesAndSubUnitValue() (gas: 6767)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 17.16ms (18.79ms CPU time)\n\nRan 12 tests for test/Prices.t.sol:PriceTest\n[PASS] testBandBoundariesAndOraclePause() (gas: 941393)\n[PASS] testEveryManagedAssetCheckedEvenClosedAndNotDeposited() (gas: 820841)\n[PASS] testFractionalQuoteWithZeroDecimalsIsNotRoundedToWholeQuote() (gas: 6690923)\n[PASS] testFreshCountIncludesIdleClosedUnretiredAssets() (gas: 1528352)\n[PASS] testHoursWeekdayEndpointsAndAlwaysOpen() (gas: 1740891)\n[PASS] testMixedDecimalsAndExactValueRounding() (gas: 4845597)\n[PASS] testNegativeFractionalMeanRoundsDownAndCumulativesWrap() (gas: 2635784)\n[PASS] testOptionalPauseAbsentAtListing() (gas: 1578868)\n[PASS] testPoolDeviationQuoteStaleAndObserveFailures() (gas: 3669834)\n[PASS] testPoolTickZeroPriceLiquidityAndMaxAge() (gas: 3111101)\n[PASS] testPriceAgeFutureSignAndReadFailures() (gas: 1234955)\n[PASS] testRemovePoolReturnsToNoPoolAgeAndWrongPoolRejected() (gas: 3188043)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 17.88ms (9.47ms CPU time)\n\nRan 6 tests for test/HeldAccounting.t.sol:HeldAccountingTest\n[PASS] testMinimumForIdleAssetRevertsAndRollsBackOtherLegs() (gas: 593021)\n[PASS] testPartialLossKeepsHoldingAndFullLossRestoresDirectPayments() (gas: 2689358)\n[PASS] testRemovingIdleSlotMovesHeldLastAssetWithinBitmapWord() (gas: 1078286)\n[PASS] testRepeatedDepositsCountOneHoldingAndNewAssetDefersPayments() (gas: 1874984)\n[PASS] testResyncActivatesOnlyNewPositiveHoldings() (gas: 2496132)\n[PASS] testRetiredHoldingsRemainInDirectLimitAndRedemption() (gas: 1853892)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 17.92ms (5.15ms CPU time)\n\nRan 18 tests for test/BaskVault.t.sol:BasketAccountingTest\n[PASS] testConstructorRejectsMissingAndEqualRoles() (gas: 6561)\n[PASS] testDeploymentAndMinimumLock() (gas: 467727)\n[PASS] testDepositChecksIdleUnreadableButSkipsRetired() (gas: 980450)\n[PASS] testDirectLimitZeroAlwaysCreditsAndOwedExcluded() (gas: 1113706)\n[PASS] testDonationDoesNotAffectSharesUntilResync() (gas: 1277440)\n[PASS] testDuplicateInvalidAmountReceiverAndDeadline() (gas: 309276)\n[PASS] testFeeDepositAndRedeemRounding() (gas: 956952)\n[PASS] testFeeOnTransferPullRejectedAndNoReturnSupported() (gas: 825489)\n[PASS] testFirstDepositTinyAndSlippageFailAtomically() (gas: 413149)\n[PASS] testFuzzConservation(uint128,uint16) (runs: 256, μ: 569455, ~: 569512)\nLogs:\n  Bound result 568973659923949\n  Bound result 10\n\n[PASS] testNoRoleOrGasSettingLimitsClaimWork() (gas: 2274002)\n[PASS] testPausedBlockedFailedPaymentsAndPartialClaims() (gas: 822728)\n[PASS] testPaymentFailureRollsBackAllTokenEffects() (gas: 1188459)\n[PASS] testPreviewMatchesAndNoPriceOnRedeem() (gas: 1046594)\n[PASS] testRedeemMinimaFailureRestoresBurnAndTransfers() (gas: 484451)\n[PASS] testReentrancyOnPullPayAndClaimFails() (gas: 1442972)\n[PASS] testShareTransferEventsUseStandardTopics() (gas: 823158)\n[PASS] testTransferAndAllowance() (gas: 621276)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 17.94ms (24.51ms CPU time)\n\nRan 1 test for test/HeldAccounting.t.sol:HeldAccountingBoundaryTest\n[PASS] testMoveAcrossBitmapWordsRelistOldSlotAndClearMovedHolding() (gas: 41420429)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 132.59ms (80.71ms CPU time)\n\nRan 11 tests for test/RedemptionGas.t.sol:RedemptionGasTest\n[PASS] testGas250AllPausedOrBlocked() (gas: 214760453)\nLogs:\n  250 paused or blocked assets gas: 15869791\n\n[PASS] testGas250AtBalanceCeilingWithHugeAccountingAndFees() (gas: 276387728)\nLogs:\n  250 assets at exact gas bound, 512-bit math and fee gas: 27157145\n\n[PASS] testGas250UnreadableFullGasBurningAssets() (gas: 220127968)\nLogs:\n  250 unreadable assets gas: 26567541\n\n[PASS] testGas254Assets45DirectWithMaximumPaymentAllowance() (gas: 198823335)\nLogs:\n  254 listed / 45 held assets with 500k payment allowance gas: 27149129\n\n[PASS] testGas350Assets47DirectWithMaximumPaymentAllowance() (gas: 256877677)\nLogs:\n  350 listed / 47 held assets with 500k payment allowance gas: 26985824\n\n[PASS] testGasDirect50TokensConsumeEntirePaymentAllowance() (gas: 176459151)\nLogs:\n  50 unreadable assets plus full payment failures gas: 17741953\n\n[PASS] testGasMaximumAssetSetting350Unreadable() (gas: 297935900)\nLogs:\n  350 unreadable assets at legal settings gas: 26673712\n\n[PASS] testGasMaximumBalance50Assets() (gas: 80501272)\nLogs:\n  50 deferred assets with 500k balance, 512-bit math and fee gas: 27897644\n\n[PASS] testGasMaximumBalanceAndPaymentAllowance() (gas: 63949203)\nLogs:\n  26 direct attempts with 500k call allowances gas: 27331250\n\n[PASS] testGasMaximumDirectLimit254() (gas: 279903348)\nLogs:\n  254 direct attempts at legal settings gas: 24536125\n\n[PASS] testGasReturnBombsAndMalformedBalanceReads() (gas: 176657035)\nLogs:\n  bounded returndata gas: 4383248\n  malformed returndata gas: 3292120\n\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 591.07ms (3.77s CPU time)\n\nRan 9 test suites in 592.06ms (818.76ms CPU time): 78 tests passed, 0 failed, 0 skipped (78 total tests)\n","passed":true},{"durationMs":45,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancel(uint256)\",\"BaskVault.claim(address[],address)\",\"BaskVault.close(address)\",\"BaskVault.deposit(address[],uint256[],address,uint256,uint256)\",\"BaskVault.execute(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNavCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose(uint8,address,bytes)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeRetired(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":151,\"SECURITY.md\":75,\"THIRD_PARTY.md\":14,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskTypes.sol\":110,\"src/BaskVault.sol\":823,\"src/libraries/BaskOracle.sol\":168,\"src/libraries/FULLMATH-LICENSE\":22,\"src/libraries/FullMath.sol\":122,\"src/libraries/TickMath.sol\":56,\"src/libraries/UNISWAP-LICENSE\":339,\"test/BaskVault.t.sol\":341,\"test/DepositDebt.t.sol\":60,\"test/GovernanceAndLoss.t.sol\":420,\"test/HeldAccounting.t.sol\":234,\"test/MathAndDeployment.t.sol\":53,\"test/Mocks.sol\":245,\"test/Prices.t.sol\":209,\"test/RedemptionGas.t.sol\":216},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":3719,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/BaskVault.sol:469: BaskVault._insideHours() (src/BaskVault.sol#469-473) uses a weak PRNG: \"(block.timestamp / 86400 + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo (src/BaskVault.sol#472)\"\n[high/medium] weak-prng at src/BaskVault.sol:469: BaskVault._insideHours() (src/BaskVault.sol#469-473) uses a weak PRNG: \"time = block.timestamp % 86400 (src/BaskVault.sol#471)\"\n[medium/medium] uninitialized-local at src/BaskVault.sol:812: BaskVault.allAssets().v (src/BaskVault.sol#812) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:767: BaskVault.pendingProposals(uint256,uint256).count (src/BaskVault.sol#767) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:493: BaskVault._snapshot(address[]).fresh (src/BaskVault.sol#493) is a local variable never initialized\n[medium/medium] unused-return at src/BaskVault.sol:226: BaskVault._checkFeed(address,address) (src/BaskVault.sol#226-233) ignores return value by (ok,answer,None) = BaskOracle.feed(feed,config.feedGas,config.maxAge) (src/BaskVault.sol#231)\n[medium/medium] unused-return at src/BaskVault.sol:345: BaskVault.execute(uint256) (src/BaskVault.sol#345-397) ignores return value by (ok,answer,None) = BaskOracle.feed(a.feed,config.feedGas,config.maxAge) (src/BaskVault.sol#362)\n[medium/medium] unused-return at src/BaskVault.sol:475: BaskVault._snapshot(address[]) (src/BaskVault.sol#475-516) ignores return value by (ok,None,None) = BaskOracle.feed(a.feed,config.feedGas,config.freshHours * 3600) (src/BaskVault.sol#511)\n[medium/medium] unused-return at src/BaskVault.sol:475: BaskVault._snapshot(address[]) (src/BaskVault.sol#475-516) ignores return value by (reason,answers[i_scope_0],updatedAt,None) = BaskOracle.price(a,config) (src/BaskVault.sol#506)\n[low/medium] timestamp at src/BaskVault.sol:728: BaskVault.recognizeLoss(address) (src/BaskVault.sol#728-740) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:639: BaskVault.redeem(uint256,address,uint256[],uint256) (src/BaskVault.sol#639-688) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:469: BaskVault._insideHours() (src/BaskVault.sol#469-473) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:548: BaskVault.deposit(address[],uint256[],address,uint256,uint256) (src/BaskVault.sol#548-587) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:345: BaskVault.execute(uint256) (src/BaskVault.sol#345-397) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:475: BaskVault._snapshot(address[]) (src/BaskVault.sol#475-516) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:330: BaskVault.proposalValid(uint256) (src/BaskVault.sol#330-335) uses timestamp for comparisons","passed":true},{"durationMs":418,"exitCode":0,"name":"aderyn","output":"[high] incorrect-caret-operator at src/libraries/FullMath.sol:86: Incorrect use of caret operator\n[high] incorrect-shift-order at src/libraries/BaskOracle.sol:44: Incorrect Assembly Shift Parameter Order\n[high] reentrancy-state-change at src/BaskVault.sol:679: Reentrancy: State change after external call (2 places)\n[high] storage-array-memory-edit at src/BaskVault.sol:314: Storage Array Edited with Memory (2 places)\n[high] weak-randomness at src/BaskVault.sol:471: Weak Randomness\n[low] centralization-risk at src/BaskVault.sol:169: Centralization Risk (10 places)\n[low] costly-loop at src/BaskVault.sol:561: Costly operations inside loop (4 places)\n[low] internal-function-used-once at src/libraries/BaskOracle.sol:68: Internal Function Used Only Once (3 places)\n[low] large-numeric-literal at src/BaskVault.sol:113: Large Numeric Literal (12 places)\n[low] literal-instead-of-constant at src/BaskVault.sol:113: Literal Instead of Constant (74 places)\n[low] non-reentrant-not-first at src/BaskVault.sol:169: `nonReentrant` is Not the First Modifier (10 places)\n[low] require-revert-in-loop at src/BaskVault.sol:494: Loop Contains `require`/`revert` (6 places)\n[low] state-change-without-event at src/BaskVault.sol:125: State Change Without Event\n[low] storage-array-length-not-cached at src/BaskVault.sol:494: Storage Array Length not Cached (4 places)\n[low] unchecked-return at src/BaskVault.sol:307: Unchecked Return (4 places)\n[low] uninitialized-local-variable at src/BaskVault.sol:485: Uninitialized Local Variable (6 places)","passed":true},{"durationMs":5162,"exitCode":0,"name":"proof dd02fe479358","output":"Compiling 26 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.61s\nCompiler run successful!\n\nRan 2 tests for test/imd-proof-95734a27/Proof_dd02fe479358.t.sol:RedeemGasBoundTest\n[PASS] testRedeemFitsIn28M_254Assets_45Direct_PayGas500k() (gas: 134917613)\nLogs:\n  maxAssets: 254\n  directLimit: 45\n  balanceGas: 50000\n  payGas: 500000\n  redeem gas used under a 28,000,000 budget: 27055311\n\n[PASS] testRedeemFitsIn28M_350Assets_47Direct_PayGas500k() (gas: 172672939)\nLogs:\n  maxAssets: 350\n  directLimit: 47\n  balanceGas: 20000\n  payGas: 500000\n  redeem gas used under a 28,000,000 budget: 26869697\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 124.09ms (195.94ms CPU time)\n\nRan 1 test suite in 124.93ms (124.09ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"cb8af8ec1b982a6c66617baa086bbb44b314461e54e17f201addab49d5696564","verifiedTreeHash":"cf0af8992ee539afe1bd7317b370f96feff2dafd","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":32601,"exitCode":0,"name":"build","output":"Compiling 32 files with Solc 0.8.26\nSolc 0.8.26 finished in 32.34s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:116:26\n    │\n116 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:138:19\n    │\n138 │         ) return (false, 0);\n    │                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:145:30\n    │\n145 │         if (dl == 0) return (false, 0);\n    │                              ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:148:54\n    │\n148 │         if (mean < -887272 || mean > 887272) return (false, 0);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:150:82\n    │\n150 │         if (liquidity > type(uint128).max || liquidity < a.minLiquidity) return (false, 0);\n    │                                                                                  ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:165:26\n    │\n165 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:464:16\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:37:16\n   │\n37 │         return uint8(d);\n   │                ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:35\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:67\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:64:40\n   │\n64 │         if (signedAnswer > 0) answer = uint256(signedAnswer);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:99:17\n   │\n99 │             if (block.timestamp - updatedAt > s.noPoolAge) reason = T.Reason.Feed;\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:113:26\n    │\n113 │         secondsAgos[0] = uint32(s.poolWindow);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:136:87\n    │\n136 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || int256(int56(t0)) != t0\n    │                                                                                       ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:137:27\n    │\n137 │                 || int256(int56(t1)) != t1 || l0 > type(uint160).max || l1 > type(uint160).max\n    │                           ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:18\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                  ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:30\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                              ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:18\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                  ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:32\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:146:28\n    │\n146 │         int256 mean = dt / int256(s.poolWindow);\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:147:28\n    │\n147 │         if (dt < 0 && dt % int256(s.poolWindow) != 0) --mean;\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:151:52\n    │\n151 │         uint160 sqrt = TickMath.getSqrtRatioAtTick(int24(mean));\n    │                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:175:9\n    │\n175 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:379:13\n    │\n379 │             guardian = abi.decode(p.data, (address));\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:166:70\n    │\n166 │     function transferOwnership(address nextOwner) external onlyOwner nonReentrant {\n    │                                                                      ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:180:48\n    │\n180 │     function pauseDeposits() external onlyRole nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:185:51\n    │\n185 │     function unpauseDeposits() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:190:53\n    │\n190 │     function close(address token) external onlyRole nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:197:58\n    │\n197 │     function lowerNavCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:207:9\n    │\n207 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:213:51\n    │\n213 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:254:46\n    │\n254 │         a.quoteDecimals = O.decimals(address(uint160(a.tokenIs0 ? t1 : t0)), config.feedGas);\n    │                                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:280:9\n    │\n280 │         emit AssetListed(token, feed, pool);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:287:9\n    │\n287 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:294:9\n    │\n294 │         emit Proposed(id, action, token, data, block.timestamp + 2 days);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:329:45\n    │\n329 │         return p.readyAt != 0 && !p.done && block.timestamp <= p.readyAt + 7 days && p.epoch == epoch[p.token]\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:334:51\n    │\n334 │     function cancel(uint256 id) external onlyRole nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:342:53\n    │\n342 │     function execute(uint256 id) external onlyOwner nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:345:13\n    │\n345 │         if (block.timestamp < p.readyAt) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:377:13\n    │\n377 │             emit Resynced(token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:380:13\n    │\n380 │             emit GuardianChanged(guardian);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:383:13\n    │\n383 │             emit NavCapChanged(NAV_CAP);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:386:13\n    │\n386 │             emit FeeRecipientChanged(feeRecipient);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:390:13\n    │\n390 │             emit SettingChanged(key, value);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:392:42\n    │\n392 │         if (p.action <= T.Action.Resync) emit AssetChanged(token, p.action);\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:393:9\n    │\n393 │         emit ProposalExecuted(id);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:415:25\n    │\n415 │             s.hoursTo = uint32(value);\n    │                         ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:16\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:58\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:464:86\n    │\n464 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:500:83\n    │\n500 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                                                                                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:500:21\n    │\n500 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:518:34\n    │\n518 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:546:13\n    │\n546 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:571:17\n    │\n571 │                 emit DeficitFlagged(token, 0, 0);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:577:9\n    │\n577 │         emit Deposit(msg.sender, receiver, v, received, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:555:22\n    │\n555 │             if (!ok) revert TransferFailed();\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:591:63\n    │\n591 │         if (!ok || (size != 0 && (size < 32 || result != 1))) revert TransferFailed();\n    │                                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:563:17\n    │\n563 │                 revert TransferFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:631:49\n    │\n631 │             if (managed[assetTokens[i]] != 0) ++count;\n    │                                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:644:45\n    │\n644 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:654:18\n    │\n654 │             if (!paid) {\n    │                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:618:13\n    │\n618 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:659:9\n    │\n659 │         emit Redeem(msg.sender, receiver, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:644:69\n    │\n644 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:680:13\n    │\n680 │             emit Claimed(msg.sender, to, token, ok ? amount : 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:697:9\n    │\n697 │         emit DeficitFlagged(token, deficits[token].amount, deficits[token].since);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:703:30\n    │\n703 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert TooEarly();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:711:9\n    │\n711 │         emit LossRecognized(token, loss);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:741:37\n    │\n741 │             if (proposalValid(i)) ++count;\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   ‡\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/AdversarialFlows.t.sol:160:75\n    │\n160 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BasketInvariant.t.sol:69:17\n   │\n69 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:168:75\n    │\n168 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:214:21\n    │\n214 │         f.set(20e8, block.timestamp);\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:230:29\n    │\n230 │         feeds[0].set(200e8, block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:62:83\n    │\n 62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n    │                                                                                   ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/GovernanceAndLoss.t.sol:324:9\n    │\n324 │         vm.warp(since + 7 days - 1);\n    │         ─────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:74:29\n   │\n74 │         feeds[2].set(100e8, block.timestamp - 4 hours - 1);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:76:29\n   │\n76 │         feeds[2].set(100e8, block.timestamp - 4 hours);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:88:9\n   │\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:86:27\n   │\n86 │         uint256 monday = (block.timestamp / 1 days + 7) / 7 * 7 * 1 days + 4 days;\n   │                           ━━━━━━━━━━━━━━━\n87 │         // Unix epoch Thursday; day 4 modulo 7 is Monday.\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:91:9\n   │\n91 │         vm.warp(monday + 17 hours);\n   │         ────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:94:9\n   │\n94 │         vm.warp(monday + 5 days + 10 hours);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:24:30\n   │\n24 │         quoteFeed.set(100e8, block.timestamp);\n   │                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/RedemptionGas.t.sol:22:17\n   │\n22 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":5943,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/GovernanceAndLoss.t.sol:LossTest\n[PASS] testDepositAndHealthyFlagClearUnretiredRecords() (gas: 947558)\n[PASS] testLossDoesNotAutoReduceAndWaitsSevenDays() (gas: 766294)\n[PASS] testOnlyLargerLossRestartsClockAndRecoveredPartNotWrittenOff() (gas: 753751)\n[PASS] testRedeemWithBalanceBelowOwedLeavesManagedAndPaysZero() (gas: 1182571)\n[PASS] testRetiredRemovedOnlyAfterManagedAndClaimsEmpty() (gas: 1819785)\n[PASS] testUnreadableNeverFabricatesLossOrClearsRecord() (gas: 611695)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 222.08ms (4.35ms CPU time)\n\nRan 17 tests for test/GovernanceAndLoss.t.sol:GovernanceTest\n[PASS] testCloseCancelsAllOlderReopenProposals() (gas: 805281)\n[PASS] testExecutionAtLastSecondAndPendingEnumeration() (gas: 295975)\n[PASS] testFeeRecipientCannotBeUnsetOrVault() (gas: 74111)\n[PASS] testGenesisThresholdAndFinalizationOnce() (gas: 911740)\n[PASS] testGuardianCannotCancelReplacementButOwnerCan() (gas: 933572)\n[PASS] testGuardianProposalRechecksNewOwnerAtExecution() (gas: 331816)\n[PASS] testListingAndNewFeedRecheckDecimalsUniquenessFreshness() (gas: 3390549)\n[PASS] testNavCapLoweringVoidsRaisesAndCapApplies() (gas: 803893)\n[PASS] testOnlyOwnerCanUnpauseAndUnprivilegedCannotConfigure() (gas: 342949)\n[PASS] testOnlyOwnerExecutionTimelockAndExpiry() (gas: 594926)\n[PASS] testRecentreUsesExecutionAnswerAndRejectsStale() (gas: 662901)\n[PASS] testRemoveRetiredAndRelistAndReuseFeed() (gas: 1249058)\n[PASS] testRetireClosedAtBothTimesInvalidatesPendingForever() (gas: 1498656)\n[PASS] testRetiredHoldingsIgnoredByDepositAndSharedWithLaterDepositor() (gas: 1905568)\n[PASS] testSettingBoundsRecheckedAtExecution() (gas: 786821)\n[PASS] testSettingsBoundsAndCoupledGasConstraints() (gas: 2310917)\n[PASS] testTwoStepOwnerNeverGuardianEvenAcrossRoleChanges() (gas: 691331)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 222.13ms (9.49ms CPU time)\n\nRan 4 tests for test/MathAndDeployment.t.sol:MathAndDeploymentTest\n[PASS] testFullMathOverflowAndZeroDenominator() (gas: 153622)\n[PASS] testFuzzFullWidthDivisionIdentity(uint256) (runs: 256, μ: 3441, ~: 3442)\n[PASS] testRuntimeHasNoEscapeInstructions() (gas: 10003186)\n[PASS] testTickExtremesAndSubUnitValue() (gas: 6767)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 222.18ms (255.62ms CPU time)\n\nRan 18 tests for test/BaskVault.t.sol:BasketAccountingTest\n[PASS] testConstructorRejectsMissingAndEqualRoles() (gas: 6561)\n[PASS] testDeploymentAndMinimumLock() (gas: 422563)\n[PASS] testDepositChecksIdleUnreadableButSkipsRetired() (gas: 935261)\n[PASS] testDirectLimitZeroAlwaysCreditsAndOwedExcluded() (gas: 1081288)\n[PASS] testDonationDoesNotAffectSharesUntilResync() (gas: 1230743)\n[PASS] testDuplicateInvalidAmountReceiverAndDeadline() (gas: 309026)\n[PASS] testFeeDepositAndRedeemRounding() (gas: 918155)\n[PASS] testFeeOnTransferPullRejectedAndNoReturnSupported() (gas: 786436)\n[PASS] testFirstDepositTinyAndSlippageFailAtomically() (gas: 412631)\n[PASS] testFuzzConservation(uint128,uint16) (runs: 256, μ: 530651, ~: 530715)\nLogs:\n  Bound result 170802301332922741715\n  Bound result 12\n\n[PASS] testNoRoleOrGasSettingLimitsClaimWork() (gas: 2235211)\n[PASS] testPausedBlockedFailedPaymentsAndPartialClaims() (gas: 783940)\n[PASS] testPaymentFailureRollsBackAllTokenEffects() (gas: 1168763)\n[PASS] testPreviewMatchesAndNoPriceOnRedeem() (gas: 1007538)\n[PASS] testRedeemMinimaFailureRestoresBurnAndTransfers() (gas: 444723)\n[PASS] testReentrancyOnPullPayAndClaimFails() (gas: 1410548)\n[PASS] testShareTransferEventsUseStandardTopics() (gas: 777994)\n[PASS] testTransferAndAllowance() (gas: 576112)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 222.19ms (209.18ms CPU time)\n\nRan 15 tests for test/AdversarialFlows.t.sol:AdversarialFlowsTest\n[PASS] testFuzz_FirstDepositValueAcrossSupportedDecimals(uint8,uint8,uint96) (runs: 1000, μ: 4335970, ~: 4344724)\nLogs:\n  Bound result 3\n  Bound result 4\n  Bound result 9983\n\n[PASS] testFuzz_RepeatedDepositRedeemCyclesCannotCreateProfit(uint128,uint64,uint8,bool,bool) (runs: 1000, μ: 3280955, ~: 2938805)\nLogs:\n  Bound result 139156940390400\n  Bound result 999999900000000022811\n  Bound result 2\n\n[PASS] test_ClaimsBelongToReceiverAndCannotBeStolenOrPaidTwice() (gas: 1181847)\n[PASS] test_DirectLimitCountsManagedAssetsIncludingRetiredOnes() (gas: 1886134)\n[PASS] test_EmptyMismatchedAndZeroInputsRejectWithoutCustodyChanges() (gas: 216693)\n[PASS] test_ExternalTokenCodeDisappearsAndClaimsSurviveRestoration() (gas: 657487)\n[PASS] test_FailedClaimRollsBackTokenSideEffectsAndContinuesNextAsset() (gas: 1529453)\n[PASS] test_FeeRecipientCanRedeemOwnBalanceAndOneWeiFeeDoesNotUnderflow() (gas: 985304)\n[PASS] test_LateRedeemMinimumRevertsEarlierPaymentDebtFeeAndBurn() (gas: 1444818)\n[PASS] test_MinimumInitialSharesExactBoundaryAndNextTokenUnit() (gas: 545045)\n[PASS] test_RedeemExpiredZeroReceiverAndOverspendLeaveSharesUntouched() (gas: 470574)\n[PASS] test_ResyncAddsOnlySurplusAfterClaimsAndDoesNotRecognizeLoss() (gas: 1818469)\n[PASS] test_SecondPullFailureRevertsFirstPullAllowanceAndMint() (gas: 543796)\n[PASS] test_ShareAllowanceFailureRollsBackAndUnlimitedAllowancePersists() (gas: 610587)\n[PASS] test_ZeroNavRejectsDepositButRetiredStockTokensRemainRedeemable() (gas: 1112213)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 222.26ms (447.50ms CPU time)\n\nRan 12 tests for test/Prices.t.sol:PriceTest\n[PASS] testBandBoundariesAndOraclePause() (gas: 940453)\n[PASS] testEveryManagedAssetCheckedEvenClosedAndNotDeposited() (gas: 775211)\n[PASS] testFractionalQuoteWithZeroDecimalsIsNotRoundedToWholeQuote() (gas: 6690661)\n[PASS] testFreshCountIncludesIdleClosedUnretiredAssets() (gas: 1527645)\n[PASS] testHoursWeekdayEndpointsAndAlwaysOpen() (gas: 1740367)\n[PASS] testMixedDecimalsAndExactValueRounding() (gas: 4789419)\n[PASS] testNegativeFractionalMeanRoundsDownAndCumulativesWrap() (gas: 2635522)\n[PASS] testOptionalPauseAbsentAtListing() (gas: 1533625)\n[PASS] testPoolDeviationQuoteStaleAndObserveFailures() (gas: 3668686)\n[PASS] testPoolTickZeroPriceLiquidityAndMaxAge() (gas: 3110369)\n[PASS] testPriceAgeFutureSignAndReadFailures() (gas: 1233965)\n[PASS] testRemovePoolReturnsToNoPoolAgeAndWrongPoolRejected() (gas: 3187939)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 222.48ms (12.22ms CPU time)\n\nRan 10 tests for test/RedemptionGas.t.sol:RedemptionGasTest\n[PASS] testGas250AllPausedOrBlocked() (gas: 214504907)\nLogs:\n  250 paused or blocked assets gas: 15949261\n\n[PASS] testGas250AtBalanceCeilingWithHugeAccountingAndFees() (gas: 276075489)\nLogs:\n  250 assets at exact gas bound, 512-bit math and fee gas: 27236615\n\n[PASS] testGas250RetiredUnreadableAssetsStillRedeem() (gas: 297103128)\nLogs:\n  250 retired assets with unreadable balances gas: 26658619\n\n[PASS] testGas250UnreadableFullGasBurningAssets() (gas: 219872397)\nLogs:\n  250 unreadable assets gas: 26647011\n\n[PASS] testGasDirect50TokensConsumeEntirePaymentAllowance() (gas: 177385102)\nLogs:\n  50 unreadable assets plus full payment failures gas: 18785323\n\n[PASS] testGasMaximumAssetSetting350Unreadable() (gas: 297573354)\nLogs:\n  350 unreadable assets at legal settings gas: 26784485\n\n[PASS] testGasMaximumBalance50Assets() (gas: 80400230)\nLogs:\n  50 deferred assets with 500k balance, 512-bit math and fee gas: 27910114\n\n[PASS] testGasMaximumBalanceAndPaymentAllowance() (gas: 63995666)\nLogs:\n  26 direct attempts with 500k call allowances gas: 27454112\n\n[PASS] testGasMaximumDirectLimit254() (gas: 280124654)\nLogs:\n  254 direct attempts at legal settings gas: 25108190\n\n[PASS] testGasReturnBombsAndMalformedBalanceReads() (gas: 178626911)\nLogs:\n  bounded returndata gas: 5426618\n  malformed returndata gas: 4335490\n\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 708.73ms (4.30s CPU time)\n\nRan 2 tests for test/BasketInvariant.t.sol:BasketInvariantTest\n[PASS]\nBasketInvariantTest invariants:\n[PASS] invariant_CustodyManagedAndClaimsConserveStockTokens\n[PASS] invariant_ShareSupplyAndPermanentLock\n BasketInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | claim          | 1531  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 1511  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1474  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1454  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | governance     | 1502  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1470  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1510  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | resync         | 1479  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | slash          | 1513  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenState     | 1405  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1535  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10000000000000000000\n  Bound result 10000000\n  Bound result 10\n  Bound result 99000000000000023741\n  Bound result 100\n  Bound result 23133\n  Bound result 11122726381518264921\n  Bound result 2792918165460573370\n  Bound result 10000000000\n  Bound result 15519\n  Bound result 10\n  Bound result 300\n  Bound result 52380952380952380952\n  Bound result 17489\n  Bound result 39\n  Bound result 5111746\n  Bound result 194\n  Bound result 100\n  Bound result 97\n  Bound result 1\n  Bound result 2\n  Bound result 8\n  Bound result 244\n  Bound result 10928\n  Bound result 4829\n  Bound result 50000\n  Bound result 99000000000000020852\n  Bound result 298741217822411602\n  Bound result 17652\n  Bound result 100\n  Bound result 500000\n  Bound result 887272\n  Bound result 4663\n  Bound result 227940413087593442\n  Bound result 32\n  Bound result 1524156776253630000\n  Bound result 21495\n  Bound result 3622431747\n  Bound result 99000000000000345601\n\n[PASS] test_HandlerExercisesClaimsLossesAndRecovery() (gas: 3043159)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 10000000\n  Bound result 10\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 1000000000000000000\n  Bound result 2\n  Bound result 1\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.85s (5.84s CPU time)\n\nRan 8 test suites in 5.85s (7.89s CPU time): 84 tests passed, 0 failed, 0 skipped (84 total tests)\n","passed":true},{"durationMs":38,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancel(uint256)\",\"BaskVault.claim(address[],address)\",\"BaskVault.close(address)\",\"BaskVault.deposit(address[],uint256[],address,uint256,uint256)\",\"BaskVault.execute(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNavCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose(uint8,address,bytes)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeRetired(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":145,\"SECURITY.md\":67,\"THIRD_PARTY.md\":14,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskTypes.sol\":110,\"src/BaskVault.sol\":795,\"src/libraries/BaskOracle.sol\":168,\"src/libraries/FULLMATH-LICENSE\":22,\"src/libraries/FullMath.sol\":122,\"src/libraries/TickMath.sol\":56,\"src/libraries/UNISWAP-LICENSE\":339,\"test/ADVERSARIAL_TESTING.md\":50,\"test/AdversarialFlows.t.sol\":322,\"test/BaskVault.t.sol\":341,\"test/BasketInvariant.t.sol\":437,\"test/GovernanceAndLoss.t.sol\":420,\"test/MathAndDeployment.t.sol\":53,\"test/Mocks.sol\":245,\"test/Prices.t.sol\":209,\"test/RedemptionGas.t.sol\":212},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d79b7e6efb7f6dbd332c56871a34f59be05f9dd272470e5c0d36b8c26bde2eec","verifiedTreeHash":"331d88bbbd524dc106810539872323e328bad683","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":34291,"exitCode":0,"name":"build","output":"Compiling 34 files with Solc 0.8.26\nSolc 0.8.26 finished in 34.04s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:116:26\n    │\n116 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:138:19\n    │\n138 │         ) return (false, 0);\n    │                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:145:30\n    │\n145 │         if (dl == 0) return (false, 0);\n    │                              ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:148:54\n    │\n148 │         if (mean < -887272 || mean > 887272) return (false, 0);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:150:82\n    │\n150 │         if (liquidity > type(uint128).max || liquidity < a.minLiquidity) return (false, 0);\n    │                                                                                  ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/libraries/BaskOracle.sol:165:26\n    │\n165 │         if (!ok) return (false, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:472:16\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:37:16\n   │\n37 │         return uint8(d);\n   │                ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:35\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:65:67\n   │\n65 │         ok = ok && answer != 0 && updatedAt <= block.timestamp && block.timestamp - updatedAt <= maxAge;\n   │                                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/BaskOracle.sol:64:40\n   │\n64 │         if (signedAnswer > 0) answer = uint256(signedAnswer);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/libraries/BaskOracle.sol:99:17\n   │\n99 │             if (block.timestamp - updatedAt > s.noPoolAge) reason = T.Reason.Feed;\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:113:26\n    │\n113 │         secondsAgos[0] = uint32(s.poolWindow);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:136:87\n    │\n136 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || int256(int56(t0)) != t0\n    │                                                                                       ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:137:27\n    │\n137 │                 || int256(int56(t1)) != t1 || l0 > type(uint160).max || l1 > type(uint160).max\n    │                           ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:18\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                  ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:142:30\n    │\n142 │             dt = int56(t1) - int56(t0);\n    │                              ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int56' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:18\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                  ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:143:32\n    │\n143 │             dl = uint160(l1) - uint160(l0);\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:146:28\n    │\n146 │         int256 mean = dt / int256(s.poolWindow);\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:147:28\n    │\n147 │         if (dt < 0 && dt % int256(s.poolWindow) != 0) --mean;\n    │                            ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/libraries/BaskOracle.sol:151:52\n    │\n151 │         uint160 sqrt = TickMath.getSqrtRatioAtTick(int24(mean));\n    │                                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:178:9\n    │\n178 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:382:13\n    │\n382 │             guardian = abi.decode(p.data, (address));\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:169:70\n    │\n169 │     function transferOwnership(address nextOwner) external onlyOwner nonReentrant {\n    │                                                                      ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:183:48\n    │\n183 │     function pauseDeposits() external onlyRole nonReentrant {\n    │                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:188:51\n    │\n188 │     function unpauseDeposits() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:193:53\n    │\n193 │     function close(address token) external onlyRole nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:200:58\n    │\n200 │     function lowerNavCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:210:9\n    │\n210 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:216:51\n    │\n216 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:257:46\n    │\n257 │         a.quoteDecimals = O.decimals(address(uint160(a.tokenIs0 ? t1 : t0)), config.feedGas);\n    │                                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:283:9\n    │\n283 │         emit AssetListed(token, feed, pool);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:290:9\n    │\n290 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:297:9\n    │\n297 │         emit Proposed(id, action, token, data, block.timestamp + 2 days);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:332:45\n    │\n332 │         return p.readyAt != 0 && !p.done && block.timestamp <= p.readyAt + 7 days && p.epoch == epoch[p.token]\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:337:51\n    │\n337 │     function cancel(uint256 id) external onlyRole nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:345:53\n    │\n345 │     function execute(uint256 id) external onlyOwner nonReentrant {\n    │                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:348:13\n    │\n348 │         if (block.timestamp < p.readyAt) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:380:13\n    │\n380 │             emit Resynced(token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:383:13\n    │\n383 │             emit GuardianChanged(guardian);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:386:13\n    │\n386 │             emit NavCapChanged(NAV_CAP);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:389:13\n    │\n389 │             emit FeeRecipientChanged(feeRecipient);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:393:13\n    │\n393 │             emit SettingChanged(key, value);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:395:42\n    │\n395 │         if (p.action <= T.Action.Resync) emit AssetChanged(token, p.action);\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:396:9\n    │\n396 │         emit ProposalExecuted(id);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:418:25\n    │\n418 │             s.hoursTo = uint32(value);\n    │                         ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:16\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:58\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:472:86\n    │\n472 │         return (block.timestamp / 1 days + 3) % 7 < 5 && time >= config.hoursFrom && time < config.hoursTo;\n    │                                                                                      ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:509:83\n    │\n509 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                                                                                   ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:509:21\n    │\n509 │                 if (block.timestamp - updatedAt <= config.freshHours * 1 hours) ++fresh;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:527:34\n    │\n527 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:555:13\n    │\n555 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:580:17\n    │\n580 │                 emit DeficitFlagged(token, 0, 0);\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:586:9\n    │\n586 │         emit Deposit(msg.sender, receiver, v, received, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:564:22\n    │\n564 │             if (!ok) revert TransferFailed();\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:600:63\n    │\n600 │         if (!ok || (size != 0 && (size < 32 || result != 1))) revert TransferFailed();\n    │                                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:572:17\n    │\n572 │                 revert TransferFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:672:45\n    │\n672 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:661:17\n    │\n661 │             if (bits & (uint256(1) << (i & 255)) == 0) {\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:682:18\n    │\n682 │             if (!paid) {\n    │                  ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:644:13\n    │\n644 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:687:9\n    │\n687 │         emit Redeem(msg.sender, receiver, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:662:72\n    │\n662 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:672:69\n    │\n672 │             if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();\n    │                                                                     ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:708:13\n    │\n708 │             emit Claimed(msg.sender, to, token, ok ? amount : 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:725:9\n    │\n725 │         emit DeficitFlagged(token, deficits[token].amount, deficits[token].since);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:731:30\n    │\n731 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert TooEarly();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:739:9\n    │\n739 │         emit LossRecognized(token, loss);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:769:37\n    │\n769 │             if (proposalValid(i)) ++count;\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   ‡\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   ‡\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/AdversarialFlows.t.sol:160:75\n    │\n160 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BasketInvariant.t.sol:69:17\n   │\n69 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/DepositDebt.t.sol:13:75\n   │\n13 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n   │                                                                           ━━━━━━━━━━━━━━━\n   ‡\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:83:62\n   │\n83 │         return vault.redeem(shares, alice, new uint256[](0), block.timestamp);\n   │                                                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/DepositDebt.t.sol:17:9\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/DepositDebt.t.sol:17:17\n   │\n17 │         vm.warp(block.timestamp + 7 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:168:75\n    │\n168 │         vault.deposit(_one(address(tokens[1])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:214:21\n    │\n214 │         f.set(20e8, block.timestamp);\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GovernanceAndLoss.t.sol:230:29\n    │\n230 │         feeds[0].set(200e8, block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:62:83\n    │\n 62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n    │                                                                                   ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/GovernanceAndLoss.t.sol:324:9\n    │\n324 │         vm.warp(since + 7 days - 1);\n    │         ─────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:18:60\n   │\n18 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n   │                                                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/HeldAccounting.t.sol:23:9\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:62:83\n   │\n62 │         return vault.deposit(_one(address(tokens[0])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                                   ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/HeldAccounting.t.sol:23:9\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:12:76\n   │\n12 │         vault.deposit(_one(address(tokens[i])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                            ━━━━━━━━━━━━━━━\n   ‡\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:23:17\n   │\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:18:60\n   │\n18 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n   │                                                            ━━━━━━━━━━━━━━━\n   ‡\n23 │         vm.warp(block.timestamp + 7 days);\n   │         ───────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/HeldAccounting.t.sol:12:76\n   │\n12 │         vault.deposit(_one(address(tokens[i])), _amount(amount), alice, 0, block.timestamp);\n   │                                                                            ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:183:75\n    │\n183 │         vault.deposit(_one(address(tokens[i])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:189:60\n    │\n189 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n    │                                                            ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/BaskVault.t.sol:71:9\n    │\n 71 │         vm.warp(vault.proposal(id).readyAt);\n    │         ─────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/BaskVault.t.sol:46:45\n    │\n 46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n    │                                             ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/HeldAccounting.t.sol:225:9\n    │\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:183:75\n    │\n183 │         vault.deposit(_one(address(tokens[i])), _amount(10e18), alice, 0, block.timestamp);\n    │                                                                           ━━━━━━━━━━━━━━━\n    ‡\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:189:60\n    │\n189 │         return vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n    │                                                            ━━━━━━━━━━━━━━━\n    ‡\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ───────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/HeldAccounting.t.sol:225:17\n    │\n225 │         vm.warp(block.timestamp + 7 days);\n    │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:74:29\n   │\n74 │         feeds[2].set(100e8, block.timestamp - 4 hours - 1);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:76:29\n   │\n76 │         feeds[2].set(100e8, block.timestamp - 4 hours);\n   │                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:88:9\n   │\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:86:27\n   │\n86 │         uint256 monday = (block.timestamp / 1 days + 7) / 7 * 7 * 1 days + 4 days;\n   │                           ━━━━━━━━━━━━━━━\n87 │         // Unix epoch Thursday; day 4 modulo 7 is Monday.\n88 │         vm.warp(monday + 9 hours);\n   │         ───────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:91:9\n   │\n91 │         vm.warp(monday + 17 hours);\n   │         ────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/BaskVault.t.sol:46:45\n   │\n46 │             feeds[i].set(feeds[i].answer(), block.timestamp);\n   │                                             ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/Prices.t.sol:94:9\n   │\n94 │         vm.warp(monday + 5 days + 10 hours);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Prices.t.sol:24:30\n   │\n24 │         quoteFeed.set(100e8, block.timestamp);\n   │                              ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/BaskVault.t.sol:71:9\n   │\n71 │         vm.warp(vault.proposal(id).readyAt);\n   │         ─────────────────────────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/RedemptionGas.t.sol:22:17\n   │\n22 │         vm.warp(block.timestamp + 2 days);\n   │         ────────━━━━━━━━━━━━━━━────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":5369,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/HeldAccounting.t.sol:HeldAccountingTest\n[PASS] testMinimumForIdleAssetRevertsAndRollsBackOtherLegs() (gas: 593021)\n[PASS] testPartialLossKeepsHoldingAndFullLossRestoresDirectPayments() (gas: 2689358)\n[PASS] testRemovingIdleSlotMovesHeldLastAssetWithinBitmapWord() (gas: 1078286)\n[PASS] testRepeatedDepositsCountOneHoldingAndNewAssetDefersPayments() (gas: 1874984)\n[PASS] testResyncActivatesOnlyNewPositiveHoldings() (gas: 2496132)\n[PASS] testRetiredHoldingsRemainInDirectLimitAndRedemption() (gas: 1853892)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 4.13ms (5.95ms CPU time)\n\nRan 3 tests for test/DepositDebt.t.sol:DepositDebtTest\n[PASS] testUncoveredClaimsOnZeroManagedNonInputDoNotBlockDeposit() (gas: 2346884)\n[PASS] testUncoveredClaimsStillBlockDepositingThatToken() (gas: 1925509)\n[PASS] testZeroManagedNonInputMustStillHaveReadableBalance() (gas: 1966449)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 4.40ms (3.28ms CPU time)\n\nRan 17 tests for test/GovernanceAndLoss.t.sol:GovernanceTest\n[PASS] testCloseCancelsAllOlderReopenProposals() (gas: 805281)\n[PASS] testExecutionAtLastSecondAndPendingEnumeration() (gas: 295975)\n[PASS] testFeeRecipientCannotBeUnsetOrVault() (gas: 74111)\n[PASS] testGenesisThresholdAndFinalizationOnce() (gas: 911740)\n[PASS] testGuardianCannotCancelReplacementButOwnerCan() (gas: 933572)\n[PASS] testGuardianProposalRechecksNewOwnerAtExecution() (gas: 331816)\n[PASS] testListingAndNewFeedRecheckDecimalsUniquenessFreshness() (gas: 3390549)\n[PASS] testNavCapLoweringVoidsRaisesAndCapApplies() (gas: 849316)\n[PASS] testOnlyOwnerCanUnpauseAndUnprivilegedCannotConfigure() (gas: 343211)\n[PASS] testOnlyOwnerExecutionTimelockAndExpiry() (gas: 594926)\n[PASS] testRecentreUsesExecutionAnswerAndRejectsStale() (gas: 662901)\n[PASS] testRemoveRetiredAndRelistAndReuseFeed() (gas: 1249198)\n[PASS] testRetireClosedAtBothTimesInvalidatesPendingForever() (gas: 1543561)\n[PASS] testRetiredHoldingsIgnoredByDepositAndSharedWithLaterDepositor() (gas: 1960738)\n[PASS] testSettingBoundsRecheckedAtExecution() (gas: 786821)\n[PASS] testSettingsBoundsAndCoupledGasConstraints() (gas: 2310917)\n[PASS] testTwoStepOwnerNeverGuardianEvenAcrossRoleChanges() (gas: 691331)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 9.87ms (7.64ms CPU time)\n\nRan 1 test for test/HeldAccounting.t.sol:HeldAccountingBoundaryTest\n[PASS] testMoveAcrossBitmapWordsRelistOldSlotAndClearMovedHolding() (gas: 41420429)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 196.03ms (107.34ms CPU time)\n\nRan 4 tests for test/MathAndDeployment.t.sol:MathAndDeploymentTest\n[PASS] testFullMathOverflowAndZeroDenominator() (gas: 153622)\n[PASS] testFuzzFullWidthDivisionIdentity(uint256) (runs: 256, μ: 3441, ~: 3442)\n[PASS] testRuntimeHasNoEscapeInstructions() (gas: 10144052)\n[PASS] testTickExtremesAndSubUnitValue() (gas: 6767)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 298.39ms (336.76ms CPU time)\n\nRan 6 tests for test/GovernanceAndLoss.t.sol:LossTest\n[PASS] testDepositAndHealthyFlagClearUnretiredRecords() (gas: 993336)\n[PASS] testLossDoesNotAutoReduceAndWaitsSevenDays() (gas: 805445)\n[PASS] testOnlyLargerLossRestartsClockAndRecoveredPartNotWrittenOff() (gas: 799115)\n[PASS] testRedeemWithBalanceBelowOwedLeavesManagedAndPaysZero() (gas: 1214745)\n[PASS] testRetiredRemovedOnlyAfterManagedAndClaimsEmpty() (gas: 1868805)\n[PASS] testUnreadableNeverFabricatesLossOrClearsRecord() (gas: 656859)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 332.01ms (3.28ms CPU time)\n\nRan 12 tests for test/Prices.t.sol:PriceTest\n[PASS] testBandBoundariesAndOraclePause() (gas: 941393)\n[PASS] testEveryManagedAssetCheckedEvenClosedAndNotDeposited() (gas: 820841)\n[PASS] testFractionalQuoteWithZeroDecimalsIsNotRoundedToWholeQuote() (gas: 6690923)\n[PASS] testFreshCountIncludesIdleClosedUnretiredAssets() (gas: 1528352)\n[PASS] testHoursWeekdayEndpointsAndAlwaysOpen() (gas: 1740891)\n[PASS] testMixedDecimalsAndExactValueRounding() (gas: 4845597)\n[PASS] testNegativeFractionalMeanRoundsDownAndCumulativesWrap() (gas: 2635784)\n[PASS] testOptionalPauseAbsentAtListing() (gas: 1578868)\n[PASS] testPoolDeviationQuoteStaleAndObserveFailures() (gas: 3669834)\n[PASS] testPoolTickZeroPriceLiquidityAndMaxAge() (gas: 3111101)\n[PASS] testPriceAgeFutureSignAndReadFailures() (gas: 1234955)\n[PASS] testRemovePoolReturnsToNoPoolAgeAndWrongPoolRejected() (gas: 3188043)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 333.40ms (12.20ms CPU time)\n\nRan 18 tests for test/BaskVault.t.sol:BasketAccountingTest\n[PASS] testConstructorRejectsMissingAndEqualRoles() (gas: 6561)\n[PASS] testDeploymentAndMinimumLock() (gas: 467727)\n[PASS] testDepositChecksIdleUnreadableButSkipsRetired() (gas: 980450)\n[PASS] testDirectLimitZeroAlwaysCreditsAndOwedExcluded() (gas: 1113706)\n[PASS] testDonationDoesNotAffectSharesUntilResync() (gas: 1277440)\n[PASS] testDuplicateInvalidAmountReceiverAndDeadline() (gas: 309276)\n[PASS] testFeeDepositAndRedeemRounding() (gas: 956952)\n[PASS] testFeeOnTransferPullRejectedAndNoReturnSupported() (gas: 825489)\n[PASS] testFirstDepositTinyAndSlippageFailAtomically() (gas: 413149)\n[PASS] testFuzzConservation(uint128,uint16) (runs: 256, μ: 569460, ~: 569512)\nLogs:\n  Bound result 999999900000000014523\n  Bound result 9074\n\n[PASS] testNoRoleOrGasSettingLimitsClaimWork() (gas: 2274002)\n[PASS] testPausedBlockedFailedPaymentsAndPartialClaims() (gas: 822728)\n[PASS] testPaymentFailureRollsBackAllTokenEffects() (gas: 1188459)\n[PASS] testPreviewMatchesAndNoPriceOnRedeem() (gas: 1046594)\n[PASS] testRedeemMinimaFailureRestoresBurnAndTransfers() (gas: 484451)\n[PASS] testReentrancyOnPullPayAndClaimFails() (gas: 1442972)\n[PASS] testShareTransferEventsUseStandardTopics() (gas: 823158)\n[PASS] testTransferAndAllowance() (gas: 621276)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 333.58ms (91.27ms CPU time)\n\nRan 15 tests for test/AdversarialFlows.t.sol:AdversarialFlowsTest\n[PASS] testFuzz_FirstDepositValueAcrossSupportedDecimals(uint8,uint8,uint96) (runs: 1000, μ: 4379971, ~: 4389852)\nLogs:\n  Bound result 4\n  Bound result 2\n  Bound result 10002\n\n[PASS] testFuzz_RepeatedDepositRedeemCyclesCannotCreateProfit(uint128,uint64,uint8,bool,bool) (runs: 1000, μ: 3283732, ~: 2966984)\nLogs:\n  Bound result 320513194673510064\n  Bound result 136727512247809\n  Bound result 1\n\n[PASS] test_ClaimsBelongToReceiverAndCannotBeStolenOrPaidTwice() (gas: 1220629)\n[PASS] test_DirectLimitCountsManagedAssetsIncludingRetiredOnes() (gas: 1934393)\n[PASS] test_EmptyMismatchedAndZeroInputsRejectWithoutCustodyChanges() (gas: 216684)\n[PASS] test_ExternalTokenCodeDisappearsAndClaimsSurviveRestoration() (gas: 696278)\n[PASS] test_FailedClaimRollsBackTokenSideEffectsAndContinuesNextAsset() (gas: 1574189)\n[PASS] test_FeeRecipientCanRedeemOwnBalanceAndOneWeiFeeDoesNotUnderflow() (gas: 1017484)\n[PASS] test_LateRedeemMinimumRevertsEarlierPaymentDebtFeeAndBurn() (gas: 1495261)\n[PASS] test_MinimumInitialSharesExactBoundaryAndNextTokenUnit() (gas: 590468)\n[PASS] test_RedeemExpiredZeroReceiverAndOverspendLeaveSharesUntouched() (gas: 515738)\n[PASS] test_ResyncAddsOnlySurplusAfterClaimsAndDoesNotRecognizeLoss() (gas: 1858024)\n[PASS] test_SecondPullFailureRevertsFirstPullAllowanceAndMint() (gas: 588985)\n[PASS] test_ShareAllowanceFailureRollsBackAndUnlimitedAllowancePersists() (gas: 655751)\n[PASS] test_ZeroNavRejectsDepositButRetiredStockTokensRemainRedeemable() (gas: 1151190)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 333.66ms (670.65ms CPU time)\n\nRan 12 tests for test/RedemptionGas.t.sol:RedemptionGasTest\n[PASS] testGas250AllPausedOrBlocked() (gas: 214770983)\nLogs:\n  250 paused or blocked assets gas: 15869791\n\n[PASS] testGas250AtBalanceCeilingWithHugeAccountingAndFees() (gas: 276412280)\nLogs:\n  250 assets at exact gas bound, 512-bit math and fee gas: 27157145\n\n[PASS] testGas250RetiredUnreadableAssetsStillRedeem() (gas: 297372210)\nLogs:\n  250 retired assets with unreadable balances gas: 26579149\n\n[PASS] testGas250UnreadableFullGasBurningAssets() (gas: 220138520)\nLogs:\n  250 unreadable assets gas: 26567541\n\n[PASS] testGas254Assets45DirectWithMaximumPaymentAllowance() (gas: 198827122)\nLogs:\n  254 listed / 45 held assets with 500k payment allowance gas: 27149129\n\n[PASS] testGas350Assets47DirectWithMaximumPaymentAllowance() (gas: 256881630)\nLogs:\n  350 listed / 47 held assets with 500k payment allowance gas: 26985824\n\n[PASS] testGasDirect50TokensConsumeEntirePaymentAllowance() (gas: 176461303)\nLogs:\n  50 unreadable assets plus full payment failures gas: 17741953\n\n[PASS] testGasMaximumAssetSetting350Unreadable() (gas: 297950630)\nLogs:\n  350 unreadable assets at legal settings gas: 26673712\n\n[PASS] testGasMaximumBalance50Assets() (gas: 80506224)\nLogs:\n  50 deferred assets with 500k balance, 512-bit math and fee gas: 27897644\n\n[PASS] testGasMaximumBalanceAndPaymentAllowance() (gas: 63949957)\nLogs:\n  26 direct attempts with 500k call allowances gas: 27331250\n\n[PASS] testGasMaximumDirectLimit254() (gas: 279910258)\nLogs:\n  254 direct attempts at legal settings gas: 24536125\n\n[PASS] testGasReturnBombsAndMalformedBalanceReads() (gas: 176659187)\nLogs:\n  bounded returndata gas: 4383248\n  malformed returndata gas: 3292120\n\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 670.56ms (5.02s CPU time)\n\nRan 4 tests for test/BasketInvariant.t.sol:BasketInvariantTest\n[PASS]\nBasketInvariantTest invariants:\n[PASS] invariant_CustodyManagedAndClaimsConserveStockTokens\n[PASS] invariant_ShareSupplyAndPermanentLock\n BasketInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | claim          | 1509  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 1469  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1457  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1518  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | governance     | 1505  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1524  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1484  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | resync         | 1438  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | slash          | 1541  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenState     | 1484  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1455  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10000000000000000000\n  Bound result 10000000\n  Bound result 10\n  Bound result 264741657368839803891\n  Bound result 8182245\n  Bound result 9\n  Bound result 434\n  Bound result 9852909200542855612\n  Bound result 515\n  Bound result 741513\n  Bound result 0\n  Bound result 99000000002049484439\n  Bound result 499999999\n  Bound result 18106\n  Bound result 6211\n  Bound result 0\n  Bound result 1000000000000100\n  Bound result 7993\n  Bound result 99003722\n  Bound result 227\n  Bound result 10000\n  Bound result 14282\n  Bound result 14961378806\n  Bound result 641\n  Bound result 860\n  Bound result 99007942\n  Bound result 1069\n  Bound result 6\n  Bound result 216339619881426369174\n  Bound result 13982352284225800802\n  Bound result 495730264\n  Bound result 250000\n\n[PASS] testFuzz_HandlerUncoveredClaimRecovery(uint8,uint8,uint96) (runs: 1000, μ: 3083703, ~: 3097724)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 10000000\n  Bound result 10\n  Bound result 6000000000000013559\n  Bound result 6000000000000013559\n  Bound result 10\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 1\n\n[PASS] test_HandlerAllowsOtherAssetsAfterFullLossWithUncoveredClaims() (gas: 3014792)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 10000000\n  Bound result 10\n  Bound result 4000000000000000000\n  Bound result 10000000000000000000\n  Bound result 1000000\n  Bound result 1000000000000000000\n  Bound result 1326666666666666666\n  Bound result 1000000000000000000\n\n[PASS] test_HandlerExercisesClaimsLossesAndRecovery() (gas: 3057796)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 10000000\n  Bound result 10\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 2000000000000000000\n  Bound result 1000000000000000000\n  Bound result 2\n  Bound result 1\n\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 5.29s (5.62s CPU time)\n\nRan 11 test suites in 5.30s (7.81s CPU time): 98 tests passed, 0 failed, 0 skipped (98 total tests)\n","passed":true},{"durationMs":33,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancel(uint256)\",\"BaskVault.claim(address[],address)\",\"BaskVault.close(address)\",\"BaskVault.deposit(address[],uint256[],address,uint256,uint256)\",\"BaskVault.execute(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNavCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose(uint8,address,bytes)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeRetired(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":151,\"SECURITY.md\":75,\"THIRD_PARTY.md\":14,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskTypes.sol\":110,\"src/BaskVault.sol\":823,\"src/libraries/BaskOracle.sol\":168,\"src/libraries/FULLMATH-LICENSE\":22,\"src/libraries/FullMath.sol\":122,\"src/libraries/TickMath.sol\":56,\"src/libraries/UNISWAP-LICENSE\":339,\"test/ADVERSARIAL_TESTING.md\":56,\"test/AdversarialFlows.t.sol\":322,\"test/BaskVault.t.sol\":341,\"test/BasketInvariant.t.sol\":484,\"test/DepositDebt.t.sol\":60,\"test/GovernanceAndLoss.t.sol\":420,\"test/HeldAccounting.t.sol\":234,\"test/MathAndDeployment.t.sol\":53,\"test/Mocks.sol\":245,\"test/Prices.t.sol\":209,\"test/RedemptionGas.t.sol\":240},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d8ca9f6614dde638afe3bc970064203d364f18dce553dedbd81c3f03fb37cbd5","verifiedTreeHash":"b69850d19bdf672449b71524545de62f4080c62a","verifierVersion":"0.1.0+ad90ce4c"}]}