{"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":"9d7bffba-141b-4e33-be9c-1bfa450d9384","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"f4f5c279ba17bf2eacf548906cf073ef961cbc1b666ce3e61016dbaacb3cf220","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":"e350c30a3b91e6f76ff02332bcb1aeb8e4499608eee4e457dd0c70393ed41d1e","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":"6456a20344b08643e40bccf36d178f0aa1f241895fd60057913555f393042293","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":"cec4eecebaca23f1f1144595f33a0289eb9ccda6e7cbbafaa280c90a8d741a17","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":"d9e453aab7c24a46a23cd68fb637b3b2ac4fc01fd88d541a215a4d1fc87292e5","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":"87d54f8451701ab8aa50548fb452c14c33657e540eeaf4de59d8951642a19289","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"acb68d24e040a0b20746f730f2c2b1cdee8c2df932743adf21ae9aff774d42fc","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"2b474470146020e2d21184204db17529aab3e12f7b6b3d6185a91ce5123b68e8","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). Write \"Stock Tokens\", never \"tokenized\"; no Robinhood name, logo or ticker beyond the chain's name.\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, 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. Time is block.timestamp, never block.number.\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.\nSTOCK_FACTORY = 0x4783C67b63dE2B358Ac5951a7D41F47A38F3C046 is a source constant.\n\nOutside contracts (on chain 4663 only; tests mock exactly these functions under test/; no fork tests, no vm.env):\n- Stock Token: ERC-20, 18 decimals, uid() returns bytes32, oraclePaused() returns bool.\n- STOCK_FACTORY.tokenAddress(bytes32 uid) returns address.\n- Feed: Chainlink proxy: decimals() is 8, aggregator() returns address, latestRoundData(); answer = USD per whole token.\n\nASSETS: a list of (token, feed, open, retired, minAnswer, maxAnswer, listedAt), at most 64, empty at deployment, never removed. managed[token] is the accounting balance: value never uses balanceOf and tokens sent directly are ignored.\nListing checks, at proposal and again at execution: token not listed; token.decimals() == 18; STOCK_FACTORY.tokenAddress(token.uid()) == token; feed.decimals() == 8; feed.aggregator() != 0; feed not used by another asset; answer > 0. On listing open = true, minAnswer = answer / 4, maxAnswer = answer * 4.\nGenesis: until the owner calls finalizeGenesis() (once, needs 3 or more assets), proposeAsset(token, feed) and proposeAssets(tokens[], feeds[]) list at once and deposits are impossible. Deposits open 72 hours after finalizeGenesis().\nOwner proposals (genesis listing is direct): list an asset; replace an asset's feed (feed checks and new answer inside the band, both times); re-centre a band on the answer at execution, under 26 hours old; reopen an asset (cancelled by any later close); retire an asset (closed both times); replace the guardian; raise NAV_CAP. A proposal waits 7 days, then anyone may execute it; it lapses 7 days later; the owner may cancel it, as may the guardian unless it replaces the guardian. One listing or feed replacement executes per 24 hours. An asset listed after genesis is on probation for 30 days. A retired asset is closed for good, skipped by every deposit check, 0 in NAV.\n\nPRICE is valid only if the feed read succeeds, answer > 0, minAnswer <= answer <= maxAnswer, updatedAt <= now, now - updatedAt <= 26 hours, and token.oraclePaused() returns false. value(amount) = amount * answer / 1e8, rounded down (USD, 18 decimals). USD limits below are dollars times 1e18.\n\ndeposit(token, amount, receiver, minSharesOut, deadline) requires:\n- deposits open and not paused; token listed and open, vault balance >= totalOwed[token]; receiver not the vault;\n- market gate: (now / 86400 + 4) % 7 is 1 to 5 (0 = Sunday) and 55800 <= now % 86400 < 70200; and 3 or more listed assets have feed updatedAt within the last 4 hours;\n- a valid price for this token and every asset with managed > 0; no asset short or unreadable (see LOSSES).\nPull the tokens; the vault balance must rise by exactly amount. NAV = sum of value(managed) before the deposit; v = value(amount).\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, or not minted while that is unset. The receiver gets gross - fee; on the first deposit 1e15 of that goes to address(0xdEaD) instead. The receiver's amount must be > 0 and >= minSharesOut.\nCaps after the deposit, with NAV2 = NAV + v:\n- NAV2 <= NAV_CAP (starts 1,000,000; the owner lowers it at once, cancelling pending raises, raises it by proposal, never above 10,000,000,000);\n- value(managed[token]) <= max(NAV2 * 5 / 100, 25,000), or max(NAV2 / 100, 5,000) on probation;\n- bucket <= max(NAV2 * 25 / 100, 100,000): one bucket for all deposits, which first decays (bucket -= bucket * elapsed / 86400, floor 0), then adds v.\n\nredeem(shares, minAmountsOut[], deadline) reads no price, ignores every pause and gate, and never reverts because of an asset. fee = shares * 50 / 10000 rounded up: transferred to feeRecipient, or burned with the rest while unset. net = shares - fee is burned. Per asset: available = balanceOf(vault) - totalOwed[token], floor 0 (low-level static call, 50,000 gas, copying 32 bytes; any other outcome: unreadable, available = managed); leg = min(managed, available) * net / totalSupplyBeforeBurn, rounded down; require leg >= minAmountsOut[i] (missing entry = 0); managed -= leg. Each leg is paid to msg.sender by an external function only the vault itself may call, given 250,000 gas, which reverts unless the transfer succeeds, returns nothing or true, and the vault balance falls by exactly leg. If it fails, owed[msg.sender][token] and totalOwed[token] grow by leg. claim(token, to) pays 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. 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\nWho can call what:\n- Owner (two-step transfer, no renounce): the proposals; cancel; close an asset to deposits at once; pause and unpause deposits; lower NAV_CAP; setFeeRecipient(address) once, not zero or the vault, final. The vault never calls feeRecipient.\n- Guardian: pause deposits, close an asset, cancel proposals as stated.\n- Nobody can move assets, block redeem or claim, mint outside deposit, change a fee or upgrade.\nUpgrades and pausing: none except the deposit pause and per-asset close.\nNumbers the contracts enforce: all constants except NAV_CAP.\n\nVIEWS: all assets with feed, answer, updatedAt, band, open, retired, probation, managed, short, totalOwed; previewDeposit; previewRedeem; depositStatus(token): a reason code and the asset at fault, as in deposit's revert; pending proposals.\n\nREVIEW. Accepted design, note only, add no mechanism: (1) deposit-then-redeem profit when a feed lags more than the 1% round-trip fee; (2) the owner pairs each token with its true feed; (3) an untransferable asset keeps its feed value until deposits are paused; (4) a retired asset counts 0 in NAV. MUST ATTACK: redeem with paused, blocked or upgraded tokens (64 assets in any state: under 28,000,000 gas); any way a role blocks redeem.","parentJobId":null,"planHash":"f61395f8ffaa0ce27b0977b3a9280a0e47e6dbc29f509779fe37e2ec98c8d339","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"9d7bffba-141b-4e33-be9c-1bfa450d9384","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-877-basket"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52167","feedbackHash":"080a722fee3cb91c8c976ff547e7305d5ed5dd94a1950bd6b17f077b1f648db7","nodeKey":"audit_economics","submissionHash":"f4f5c279ba17bf2eacf548906cf073ef961cbc1b666ce3e61016dbaacb3cf220","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52157","feedbackHash":"426065c26ddf48e45d3f2f78cdfb84492a0777d752c93717e83cfcc8cc49b63a","nodeKey":"audit_flow","submissionHash":"e350c30a3b91e6f76ff02332bcb1aeb8e4499608eee4e457dd0c70393ed41d1e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52179","feedbackHash":"578d4fce77b47e35fba4dc8bdd5fcc4e56109c8d5cd74e8a5b7b6dec956d25cf","nodeKey":"audit_judge","submissionHash":"6456a20344b08643e40bccf36d178f0aa1f241895fd60057913555f393042293","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51291","feedbackHash":"b556215f1503fb945b98678eb71084b405fb10ec4a012013cce4273d75bd8f1b","nodeKey":"audit_judge","submissionHash":"035ddb566079ed864b7b48de8821b5a4841b956cf4748ceb7f497fb7be7e0d4b","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51428","feedbackHash":"c819df8d5adb22a0b0bf2d9d7c0cd4c31f6a3063dbdef0bc27d7915b47335b76","nodeKey":"audit_math","submissionHash":"cec4eecebaca23f1f1144595f33a0289eb9ccda6e7cbbafaa280c90a8d741a17","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52166","feedbackHash":"e00f4ac23c7d3584cef994c7e8e3b802c2f72604c1669bfc88f294c1ac8270cc","nodeKey":"audit_permissions","submissionHash":"d9e453aab7c24a46a23cd68fb637b3b2ac4fc01fd88d541a215a4d1fc87292e5","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52141","feedbackHash":"898882a61f6fef2b361d99a808f08e55894e121d5fc46de98f8d6fa47502e291","nodeKey":"build_contract_project","submissionHash":"f9ddf24e5b4461d5969acc22c1ae2d97b7937b33b9f1abb6efedae02085de744","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51149","feedbackHash":"0a1e216f9c76d618a7b5138e356ff27e574ac8a635cdfc3bcdfaa26e7f5fac67","nodeKey":"build_contract_project","submissionHash":"87d54f8451701ab8aa50548fb452c14c33657e540eeaf4de59d8951642a19289","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"50990","feedbackHash":"3c2071cbab6ffeb97048f48075db52c641d82f1332c30416e90df1df1c0d3340","nodeKey":"manifest","submissionHash":"acb68d24e040a0b20746f730f2c2b1cdee8c2df932743adf21ae9aff774d42fc","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51414","feedbackHash":"8f10738c495fb50334bcfa67019798ccbe7d8e856c6ffc890638a88cc532364c","nodeKey":"manifest","submissionHash":"a08532a01a378ca33c76ae484935c5e2b96b4a2b80a07a3756ac08880eef41a0","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51150","feedbackHash":"05093e6fe8ee72fb856f5800ec10bfd8f65771d17a222f39292744e4bdb417b4","nodeKey":"write_foundry_tests","submissionHash":"82b7e0eb0587004ad02caff84375067c1613855c2b7afd8cd0783a929e17cb72","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"50997","feedbackHash":"1b61273ac23fd5e753a0db21d22e0f2043a66fb893b61f47e17c5eb5dc928a7e","nodeKey":"write_foundry_tests","submissionHash":"2b474470146020e2d21184204db17529aab3e12f7b6b3d6185a91ce5123b68e8","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"6c4add4254d93910cda5c5fff75fca74202178a3946749b443de80521f52740a","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bd7adba3a8045853","findings":[{"citation":"resolved","description":"executeProposal(Kind.Band) (lines 415-421) and Kind.List (line 407 via _checkListing/_band) accept any positive answer under 26 hours old and set minAnswer = answer/4, maxAnswer = answer*4 with no relation to the band that was in force. Execution is open to anyone for 7 days. Feed replacement, by contrast, requires the new answer inside the current band both times (line 470). The band is the vault's only defence against a wrong feed print: one block before the execution a 1000x print is rejected as OutsideBand, one block later the same print is the new band centre. An unprivileged executor who sees an outlier round executes the pending Band proposal, deposits the mispriced token at the outlier (nominal value capped at max(5% NAV2, $25,000) per asset and max(25% NAV2, $100,000) per day, but the real cost is the honest price) and redeems pro rata of every real asset. Afterwards the honest price is outside the new band, so every deposit of any token reverts OutsideBand while managed[token] > 0, and the owner cannot repair it with proposeFeed (the honest answer is outside the band) - only another 7-day Band proposal or retirement. This merges the permissions finding (lockout) and the economics finding (extraction): same root cause. It follows the brief's wording ('re-centre a band on the answer at execution', 'anyone may execute'), so it is a design gap that needs a scope decision; a minimal fix that keeps the design is to require the re-centre answer inside the old band (as feed replacement already does) or to let only the owner execute Band/List proposals.","line":421,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract BandFactory {\n    mapping(bytes32 => address) public tokenAddress;\n\n    function register(bytes32 id, address token) external {\n        tokenAddress[id] = token;\n    }\n}\n\ncontract BandFeed {\n    uint8 public constant decimals = 8;\n    address public constant aggregator = address(1);\n    int256 public answer = 100e8;\n    uint256 public updatedAt;\n\n    constructor() {\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 answer_, uint256 time_) external {\n        answer = answer_;\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\ncontract BandStock {\n    bytes32 public uid;\n    uint8 public constant decimals = 18;\n    bool public constant oraclePaused = false;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    constructor(bytes32 id) {\n        uid = id;\n    }\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\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 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\n/// A Band proposal executed by anyone while the feed prints a 1000x outlier re-centres the band on\n/// the outlier. A deposit priced at that outlier then redeems a large slice of the other holders' assets.\ncontract BandRecentreProofTest is Test {\n    address internal constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address internal constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    address internal constant ALICE = address(0xA11CE);\n    address internal constant EVE = address(0xE0E);\n    uint256 internal constant MONDAY = 1_728_259_200; // 2024-10-07 00:00 UTC\n\n    BaskVault internal vault;\n    BandStock[] internal stocks;\n    BandFeed[] internal feeds;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(MONDAY + 55800);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        BandFactory template = new BandFactory();\n        vm.etch(vault.STOCK_FACTORY(), address(template).code);\n        BandFactory factory = BandFactory(vault.STOCK_FACTORY());\n        for (uint256 i; i < 4; ++i) {\n            BandStock stock = new BandStock(bytes32(i + 1));\n            BandFeed feed = new BandFeed();\n            factory.register(stock.uid(), address(stock));\n            stocks.push(stock);\n            feeds.push(feed);\n            stock.mint(ALICE, 1_000e18);\n            stock.mint(EVE, 1e18);\n            vm.prank(ALICE);\n            stock.approve(address(vault), type(uint256).max);\n            vm.prank(EVE);\n            stock.approve(address(vault), type(uint256).max);\n            vm.prank(OWNER);\n            vault.proposeAsset(address(stock), address(feed));\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n        vm.warp(block.timestamp + 72 hours); // Thursday 15:30 UTC\n        _refresh();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < feeds.length; ++i) {\n            feeds[i].set(100e8, block.timestamp);\n        }\n    }\n\n    function testExecutorCannotRecentreBandOnOutlierAndDrainHolders() public {\n        // Alice holds 240 of each of assets 1..3 (NAV $72,000); asset 0 is unheld.\n        for (uint256 i = 1; i < 4; ++i) {\n            vm.prank(ALICE);\n            vault.deposit(address(stocks[i]), 240e18, ALICE, 0, block.timestamp);\n        }\n        vm.prank(OWNER);\n        uint256 id = vault.proposeBand(address(stocks[0]));\n        vm.warp(block.timestamp + 7 days); // Thursday 15:30 UTC, market open\n        _refresh();\n        feeds[0].set(100_000e8, block.timestamp); // one 1000x outlier round, fresh\n\n        // The outlier is outside the band [25e8, 400e8] one block earlier.\n        (BaskVault.Reason before,) = vault.depositStatus(address(stocks[0]));\n        assertEq(uint256(before), uint256(BaskVault.Reason.OutsideBand));\n\n        vm.startPrank(EVE);\n        (bool executed,) = address(vault).call(abi.encodeCall(vault.executeProposal, (id)));\n        if (executed) {\n            (bool deposited, bytes memory ret) = address(vault).call(\n                abi.encodeCall(vault.deposit, (address(stocks[0]), 0.25e18, EVE, 0, block.timestamp))\n            );\n            if (deposited) {\n                uint256 shares = abi.decode(ret, (uint256));\n                vault.redeem(shares, new uint256[](0), block.timestamp);\n            }\n        }\n        vm.stopPrank();\n\n        // Eve paid 0.25 token0 (~$25 at the honest price). She must not walk away with other holders' assets.\n        assertLt(stocks[1].balanceOf(EVE), 1e18, \"band re-centred on an outlier let a depositor drain holders\");\n    }\n}","reproduction":"4 genesis assets at $100 (band [25e8, 400e8]); Alice deposits 240e18 of assets 1..3 (NAV $72,000), asset 0 unheld. OWNER: id = proposeBand(asset0). Thursday 15:30 UTC, 7 days later, feeds refreshed; feed0 publishes answer 100000e8 with updatedAt = now. depositStatus(asset0) == (OutsideBand, asset0). EVE (no role): executeProposal(id) succeeds; assets(0).minAnswer == 25000e8, maxAnswer == 400000e8. EVE: deposit(asset0, 0.25e18, EVE, 0, now) mints 24,647.6e18 shares against a pre-deposit supply of 71,341.8e18 (about 25.6% of the post-deposit supply for ~$25 of real value); redeem(all) pays legs of 61.3177e18 of each of assets 1, 2, 3 (~$18,395 at the honest price) plus 0.0639e18 of asset0. Expected: a print the band rejected one block earlier cannot become the band centre, so Eve's deposit is rejected and she extracts nothing; actual: Eve nets about $18,370 from Alice. Then feed0 returns to 100e8: depositStatus(asset1) == (OutsideBand, asset0) for every deposit, and proposeFeed(asset0, honestFeed@100e8) reverts InvalidFeed because 100e8 < minAnswer 25000e8. Scratch test test/scratch/Review.t.sol::testBandRecentreAtAnomalyExtractsAndLocksOut passes (behaviour present); the attached proof fails on this code with '62317677419354838709 >= 1000000000000000000'.","severity":"medium","snippet":"            _band(a, uint256(answer));","title":"Band re-centre and post-genesis listing set the band from whatever the feed prints at a permissionless execution; one outlier round lets the executor deposit at the outlier and drain other holders, th"},{"citation":"resolved","description":"NAV sums value(managed) over unretired assets only (line 579 skips retired), and _quote only falls back to gross = value when totalSupply == 0 (line 613). The first deposit mints LOCKED_SHARES = 1e15 to 0xdEaD (line 657) and nothing can burn them, so totalSupply never returns to 0. When every asset with managed > 0 has been retired (accepted design 4) or written to 0 by recognizeLoss, nav == 0 with totalSupply > 0 and _depositContext returns ZeroNAV for every token, including assets listed afterwards. Nothing raises managed except a deposit, nothing un-retires an asset, and pausing, NAV_CAP changes, reopening or relisting do not touch the check, so the vault never accepts another deposit; redeem and claim keep working. Merged from the math (medium), flow (low) and economics (low) specialists: one root cause. The implementation is literal to 'revert if NAV is 0', so the permanent consequence is a design decision for the requester; the author's own test testZeroNAVWithExistingSupplyReverts reaches the state without noting it is unrecoverable.","line":595,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract LockoutFactory {\n    mapping(bytes32 => address) public tokenAddress;\n\n    function register(bytes32 id, address token) external {\n        tokenAddress[id] = token;\n    }\n}\n\ncontract LockoutFeed {\n    uint8 public constant decimals = 8;\n    address public constant aggregator = address(1);\n    int256 public answer = 100e8;\n    uint256 public updatedAt;\n\n    constructor() {\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 answer_, uint256 time_) external {\n        answer = answer_;\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\ncontract LockoutStock {\n    bytes32 public uid;\n    uint8 public constant decimals = 18;\n    bool public constant oraclePaused = false;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    constructor(bytes32 id) {\n        uid = id;\n    }\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function confiscate(address from, uint256 amount) external {\n        balanceOf[from] -= amount;\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 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\n/// Once NAV is 0 while the 1e15 shares locked at 0xdEaD keep totalSupply > 0, deposits are impossible forever.\ncontract ZeroNavLockoutTest is Test {\n    address internal constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address internal constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    address internal constant ALICE = address(0xA11CE);\n    address internal constant BOB = address(0xB0B);\n    uint256 internal constant MONDAY = 1_728_259_200; // 2024-10-07 00:00 UTC\n\n    BaskVault internal vault;\n    LockoutFactory internal factory;\n    LockoutStock[] internal stocks;\n    LockoutFeed[] internal feeds;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(MONDAY + 55800);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        LockoutFactory template = new LockoutFactory();\n        vm.etch(vault.STOCK_FACTORY(), address(template).code);\n        factory = LockoutFactory(vault.STOCK_FACTORY());\n        for (uint256 i; i < 4; ++i) {\n            LockoutStock stock = new LockoutStock(bytes32(i + 1));\n            LockoutFeed feed = new LockoutFeed();\n            factory.register(stock.uid(), address(stock));\n            stocks.push(stock);\n            feeds.push(feed);\n            stock.mint(ALICE, 1_000e18);\n            stock.mint(BOB, 1_000e18);\n            vm.prank(ALICE);\n            stock.approve(address(vault), type(uint256).max);\n            vm.prank(BOB);\n            stock.approve(address(vault), type(uint256).max);\n            vm.prank(OWNER);\n            vault.proposeAsset(address(stock), address(feed));\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n        vm.warp(block.timestamp + 72 hours);\n        _refresh();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < feeds.length; ++i) {\n            feeds[i].set(100e8, block.timestamp);\n        }\n    }\n\n    function _nextMarketOpen(uint256 from) internal pure returns (uint256 t) {\n        t = from / 86400 * 86400 + 55800;\n        if (t <= from) t += 1 days;\n        while ((t / 86400 + 4) % 7 == 0 || (t / 86400 + 4) % 7 == 6) t += 1 days;\n    }\n\n    function testDepositsRecoverAfterOnlyHeldAssetIsRetiredAndRedeemed() public {\n        // 1. Alice makes the only deposit: 10 stock-0 at $100 -> NAV $1,000.\n        vm.prank(ALICE);\n        vault.deposit(address(stocks[0]), 10e18, ALICE, 0, block.timestamp);\n        assertEq(vault.balanceOf(address(0xdEaD)), 1e15);\n\n        // 2. Owner closes and retires stock-0 (the only held asset).\n        vm.startPrank(OWNER);\n        vault.closeAsset(address(stocks[0]));\n        uint256 id = vault.proposeRetire(address(stocks[0]));\n        vm.stopPrank();\n        vm.warp(block.timestamp + 7 days);\n        vault.executeProposal(id);\n\n        // 3. Alice redeems all of her shares; the retired token is still paid out to her.\n        uint256 aliceShares = vault.balanceOf(ALICE);\n        vm.prank(ALICE);\n        vault.redeem(aliceShares, new uint256[](0), block.timestamp);\n        assertEq(vault.totalSupply(), 1e15, \"only the dead shares remain\");\n        assertEq(vault.balanceOf(ALICE), 0);\n\n        // 4. Next market open, every feed fresh, nothing short: a new depositor must be able to deposit.\n        vm.warp(_nextMarketOpen(block.timestamp));\n        _refresh();\n        (BaskVault.Reason reason, address fault) = vault.depositStatus(address(stocks[1]));\n        assertEq(uint256(reason), uint256(BaskVault.Reason.OK), \"depositStatus must not report ZeroNAV\");\n        assertEq(fault, address(0));\n        vm.prank(BOB);\n        uint256 shares = vault.deposit(address(stocks[1]), 10e18, BOB, 0, block.timestamp);\n        assertGt(shares, 0, \"deposit must mint shares to the new depositor\");\n    }\n\n    function testDepositsRecoverAfterTotalLossIsRecognised() public {\n        vm.prank(ALICE);\n        vault.deposit(address(stocks[0]), 10e18, ALICE, 0, block.timestamp);\n        // The whole position is confiscated at the token and the loss is recognised by the spec'd process.\n        stocks[0].confiscate(address(vault), 10e18);\n        assertEq(stocks[0].balanceOf(address(vault)), 0);\n        vault.flagDeficit(address(stocks[0]));\n        vm.warp(block.timestamp + 7 days);\n        vault.recognizeLoss(address(stocks[0]));\n        assertEq(vault.managed(address(stocks[0])), 0);\n\n        vm.warp(_nextMarketOpen(block.timestamp));\n        _refresh();\n        (BaskVault.Reason reason,) = vault.depositStatus(address(stocks[1]));\n        assertEq(uint256(reason), uint256(BaskVault.Reason.OK), \"depositStatus must not report ZeroNAV\");\n        vm.prank(BOB);\n        uint256 shares = vault.deposit(address(stocks[1]), 10e18, BOB, 0, block.timestamp);\n        assertGt(shares, 0, \"deposit must mint shares to the new depositor\");\n    }\n}","reproduction":"4 genesis assets at $100, finalize, warp 72h to market open. Alice deposit(stock0, 10e18): totalSupply 995e18, dead holds 1e15. OWNER closeAsset(stock0), proposeRetire(stock0); +7 days; executeProposal. Alice redeem(all): totalSupply == 1e15 (only dead shares), managed[stock0] ~ 1e13. Next market open, all 4 feeds refreshed, nothing short. Expected: depositStatus(stock1) == OK and Bob's deposit(stock1, 10e18) mints shares; actual: depositStatus returns (ZeroNAV = 18, 0x0) and deposit reverts DepositUnavailable(ZeroNAV, 0x0), at any later time. Variant: deposit 10e18, confiscate the vault's 10e18 at the token, flagDeficit, +7 days, recognizeLoss -> managed 0 -> same permanent ZeroNAV. Variant with other live assets: 5 assets, deposits into 0 and 1 only, retire both -> deposits into open, priced, fresh assets 2..4 and into a newly listed asset 5 all revert ZeroNAV. The attached proof (from the math specialist, rerun here) fails on both paths with '18 != 0'.","severity":"medium","snippet":"        if (totalSupply > 0 && nav == 0) return (Reason.ZeroNAV, address(0), 0, 0);","title":"ZeroNAV is a terminal state: once every asset holding managed funds is retired or fully written off, the 1e15 dead shares keep totalSupply > 0 and no deposit can ever succeed again"},{"citation":"resolved","description":"_checkReplacement requires the replacement feed's answer inside the current band at proposal and execution, and the Band branch (lines 417-420) reads the asset's current feed and reverts InvalidFeed when it is 26 hours old or more. If a feed is deprecated and the true price has moved more than 4x from the band centre, both paths revert and the asset keeps every deposit blocked with StalePrice while managed > 0. The only exits are retiring the asset (its value leaves NAV, diluting holders per accepted design 4) or an interim feed that lies inside the old band followed by two more 7-day proposals. Spec-literal; reported so the requester can decide whether feed replacement should be allowed when the current feed is itself stale.","line":470,"path":"src/BaskVault.sol","reproduction":"4 genesis assets; Alice deposits 100e18 of asset0 (band [25e8, 400e8]). feed0 stops updating. New feed f2 answers 10e8, fresh. OWNER proposeFeed(asset0, f2) reverts InvalidFeed(f2). OWNER proposeBand(asset0); +7 days, feeds 1..3 refreshed, feed0 7 days old: executeProposal reverts InvalidFeed(feed0). depositStatus(asset1) == (StalePrice = 15, asset0): every deposit into any asset is blocked. Expected: the owner can repair a dead feed; actual: only retire. test/scratch/Review.t.sol::testDeadFeedOutOfBandDeadlock.","severity":"low","snippet":"        if (answer < a.minAnswer || answer > a.maxAnswer) revert InvalidFeed(feed);","title":"An asset whose feed went stale after the price left the band has no in-protocol recovery except retirement: feed replacement needs an in-band answer and band re-centre needs a fresh answer from the de"},{"citation":"resolved","description":"The quorum loop `continue`s on retired assets (line 579) before counting fresh feeds, and finalizeGenesis requires only 3 assets. With exactly 3 listed assets, retiring one caps `fresh` at 2, so _depositContext returns MarketNotFresh for every token no matter how fresh the remaining feeds are. Recovery needs a List proposal (7-day wait plus the 24-hour cooldown). The brief's '3 or more listed assets have feed updatedAt within the last 4 hours' can be read either way (a retired asset stays listed and its feed may still update; a retired asset is 'skipped by every deposit check'); the implementation picks the reading that produces the outage. Availability only; no loss.","line":594,"path":"src/BaskVault.sol","reproduction":"Genesis with exactly 3 assets, finalize, warp 72h, refresh. Alice deposit(stock0, 10e18). OWNER closeAsset(stock0), proposeRetire(stock0); +7 days (market open); refresh all three feeds to now; executeProposal. Expected: depositStatus(stock1) == OK; actual: depositStatus(stock1) == (MarketNotFresh = 7, 0x0) and deposit(stock1, 1e18, ...) reverts DepositUnavailable(MarketNotFresh, 0x0). test/scratch/Review.t.sol::ReviewRepro3::testRetireOneOfThreeBlocksDeposits.","severity":"low","snippet":"        if (fresh < 3) return (Reason.MarketNotFresh, address(0), 0, 0);","title":"Fresh-feed quorum skips retired assets and equals the genesis minimum: retiring one of three assets blocks every deposit until a new listing executes (7 days or more)"},{"citation":"resolved","description":"flagDeficit records any readable shortfall and recognizeLoss lowers managed 7 days later; the only clearing path is a successful deposit, which is impossible while the deficit exists (Reason.Deficit) and impossible for a retired asset. Neither owner nor guardian can cancel a flag, stop the clock (pauseDeposits does not affect flag/recognize) or re-credit managed once the balance returns, and the brief forbids rescue/sweep. Stock Tokens are issuer-controlled and upgradeable: a token that reports 0 for a frozen holder, or an upgrade that briefly mis-reads balances, produces a readable but false shortfall; if it lasts 7 days anyone zeroes managed[token], and when the balance returns the tokens are invisible to NAV, never paid by redeem (legs are capped at managed) and unclaimable. The same applies when a confiscated balance is later restored. Merged from the permissions (low) and math (info) specialists: one root cause (nothing ever raises managed except deposit). Spec-literal; recorded so the requester knows loss recognition is final even if the asset recovers.","line":768,"path":"src/BaskVault.sol","reproduction":"4 genesis assets; Alice deposits 100e18 of asset0 (managed = balance = 100e18). vm.mockCall asset0.balanceOf(vault) -> 0. Anyone: flagDeficit(asset0) records 100e18. GUARDIAN pauseDeposits (changes nothing). +7 days. Anyone: recognizeLoss(asset0) -> managed[asset0] == 0. Clear the mock: balanceOf(vault) == 100e18. Alice redeem(all): legs[0] == 0 and asset0.balanceOf(vault) is still 100e18 with no entry point that can pay it out. Expected: a temporary read anomaly does not become a permanent loss, or a role can halt the clock; actual: permanent strand. test/scratch/Review.t.sol::testTemporaryZeroBalanceReadStrandsTokens.","severity":"low","snippet":"        managed[token] -= amount;","title":"recognizeLoss is irreversible and permissionless: a balance that temporarily under-reports (frozen holder, upgrade glitch) or later recovers leaves the returned tokens stranded above managed forever"},{"citation":"resolved","description":"A proposal is executable from createdAt + 7 days until createdAt + 14 days (exclusive, line 385). List and Feed executions share nextAssetChangeAt (lines 403-404). A batch created at T can execute at T+7d, T+8d, ..., T+13d: seven slots. The eighth proposal of the batch, or any Feed proposal created around the same time, is Expired before its first legal execution time and costs another 7-day wait. Spec-literal (one listing or feed replacement per 24 hours), but proposeAssets(tokens[], feeds[]) invites exactly this batching after genesis.","line":404,"path":"src/BaskVault.sol","reproduction":"After genesis, OWNER proposeAssets with 8 valid token/feed pairs at T -> ids[0..7]. executeProposal(ids[i]) at T+7d+i days for i = 0..6 all succeed. At T+14d-1s executeProposal(ids[7]) reverts ChangeCooldown; at T+14d it reverts InvalidProposal(ids[7]) and proposalState(ids[7]) == Expired. Expected: a batch proposed together can all execute; actual: the eighth never can. test/scratch/Review.t.sol::testBatchedListingsLapse.","severity":"low","snippet":"            nextAssetChangeAt = block.timestamp + 24 hours;","title":"proposeAssets after genesis creates batches that cannot all execute: the shared 24-hour listing/feed cooldown gives a 7-day execution window only seven slots, so the eighth and later proposals lapse"},{"citation":"resolved","description":"The constructor rejects owner_ == guardian_ (line 196) and proposeGuardian/executeProposal reject a target equal to the current owner (lines 360, 431), but transferOwnership only rejects address(0), acceptOwnership performs no identity check, and the Guardian proposal is compared against owner, not pendingOwner. Two sequences make one key hold both roles. No fund-loss path follows: the guardian's powers are a subset of the owner's and cancelProposal's owner branch already short-circuits. Reported as an asymmetry between the construction-time invariant and later transitions, merged from the permissions (low), flow (info) and economics (low) specialists; the brief adds no requirement here and says to add no safeguard, so the requester decides whether a one-line `next == guardian` / `p.target == pendingOwner` check is wanted.","line":262,"path":"src/BaskVault.sol","reproduction":"(a) OWNER transferOwnership(0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68); GUARDIAN acceptOwnership(): owner() == guardian() == 0x5ed3...9B68. (b) OWNER id = proposeGuardian(BOB); transferOwnership(BOB); +7 days; anyone executeProposal(id) succeeds (BOB != owner at that moment); BOB acceptOwnership(): owner() == guardian() == BOB. Expected by analogy with the constructor: revert InvalidAddress; actual: accepted. The permissions specialist's proof (.imd/reads/proofs/Proof_56bf3a113dc6.t.sol) was rerun here and fails on this code with 'owner and guardian collapsed into one address' for both sequences.","severity":"info","snippet":"        if (next == address(0)) revert InvalidAddress();","title":"owner != guardian is enforced only in the constructor and proposeGuardian: transferOwnership to the guardian, or a Guardian proposal that races a pending owner, collapses both roles into one address"},{"citation":"resolved","description":"Note only, per the brief's REVIEW section; no mechanism is proposed. Deposit pricing skips retired assets (line 579) while redemption pays pro rata of every asset including retired ones (lines 671-675). Any depositor after a retirement mints at a NAV that excludes the retired asset and redeems a slice of it; the caps bound the nominal deposit (per-asset max(5% NAV2, $25,000), bucket max(25% NAV2, $100,000) per day), not the leak, and because retire execution is permissionless the extractor can execute and deposit in one transaction. The leak scales with retiredValue / liveNAV: when the unretired NAV is tiny the depositor takes almost the entire retired position for the price of a few dollars of live asset plus 1% fees. Merged from the permissions and economics specialists plus the reviewer's amplification case. Operator guidance: retire only assets whose real value is already ~0 or whose transfer is permanently broken, and never while they dominate NAV.","line":579,"path":"src/BaskVault.sol","reproduction":"(a) 4 genesis assets at $100; Alice deposits 125e18 of each (NAV $50,000). Owner closes and retires asset0 (+7 days). Eve deposits 125e18 of assets 1..3 ($37,500) and redeems: she receives ~62e18 of retired asset0 (~$5,900 net of fees) from Alice. (b) Amplified: Alice deposits 100e18 of asset0 ($10,000) and 1e16 of asset1 ($1); owner closes and retires asset0; +7 days execute; live NAV == 1e18. Eve deposits 1e18 of asset1 ($100) and redeems all: legs[0] == 98.51e18 of retired asset0 ($9,851) for $100 plus fees. Expected under accepted design (4): exactly this; recorded for magnitude. test/scratch/Review.t.sol::testRetiredLeakAmplifiedByTinyLiveNAV.","severity":"info","snippet":"            if (a.retired) continue;","title":"Accepted design (4) quantified: after a retirement, deposit-then-redeem buys the retired asset's holdings at zero, and the extraction approaches the whole retired position when the live NAV is small"}],"hash":"035ddb566079ed864b7b48de8821b5a4841b956cf4748ceb7f497fb7be7e0d4b","nodeId":"a3801330-780a-44ed-8a6d-ce588c60b87b","outcome":"completed","summary":"The review is complete. The findings file is at `.imd-findings.json` in the repository root, and the scratch directory has been removed so no source or test file in the tree is changed.\n\n**Outcome.** No critical or high defect. I kept 8 findings after reproducing all 15 specialist claims against the code and merging duplicates, and I answered all 27 entry points plus three invariants in the coverage record.\n\n**Findings kept, by severity**\n\n- **Medium, band re-centre on an outlier.** A Band or List proposal is executed by anyone and re-centres the band on whatever the feed prints at that moment, with no relation to the old band. An executor who sees a 1000x round executes, deposits at that price and redeems pro rata. In the reproduction Eve pays about $25 of real value and takes about 61 tokens of each of three real assets from Alice, and deposits are then locked out of band until another 7-day proposal. Permissions and economics findings merged. The attached proof fails on current code.\n- **Medium, permanent ZeroNAV.** Retiring every held asset, or writing it off through loss recognition, leaves NAV at 0 while the 1e15 dead shares keep supply above 0. Every deposit reverts ZeroNAV forever, including into newly listed assets. Three specialists merged. The math specialist's proof was rerun and fails on current code.\n- **Low, dead feed out of band.** Feed replacement needs an in-band answer and band re-centre needs a fresh answer from the dead feed, so the only exit is retirement.\n- **Low, fresh quorum excludes retired assets.** With exactly three assets, retiring one blocks all deposits until a new listing executes.\n- **Low, irreversible loss recognition.** A temporary under-reporting balance lets anyone zero managed after 7 days. Tokens that return are stranded above managed forever. Permissions and math findings merged.\n- **Low, batched listings lapse.** The shared 24-hour cooldown gives a 7-day window seven slots, so the eighth proposal of a batch expires unexecuted.\n- **Info, owner and guardian collapse.** Ownership transfer to the guardian, or a guardian proposal racing a pending owner, puts both roles on one key. Three specialists merged. No harm path found.\n- **Info, accepted design 4 quantified.** After a retirement, deposit-then-redeem buys the retired holdings at zero. My own amplification case shows $100 of live NAV buying about 98.5 of 100 retired tokens.\n\n**What I verified myself.** Build at the required settings gives 20,951 bytes of runtime with no forbidden opcodes. All 73 project tests pass, including the 64-asset hostile redemption tests under a 27.9M gas bound. The redeem and claim paths read no prices, make only gas-bounded self-calls, and no owner or guardian power enters them. The slither mulDiv lines are false positives on the standard 512-bit routine. The first two findings are spec-literal consequences of the brief, so I flagged both as scope decisions for the requester rather than implementation slips.","treeHash":null,"usage":{"cachedInputTokens":1198190,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":54190,"runtime":"claude","turns":26,"wallClockMs":746622}},{"artifacts":[],"attempt":1,"bundleHash":"9b4e5cc01b368b15fb10bee1e3cadf98cd49f91c1cc2a497fbcd7987030ac89e","device":"593a9c894818e368","findings":[],"hash":"2b474470146020e2d21184204db17529aab3e12f7b6b3d6185a91ce5123b68e8","nodeId":"32200ef7-7c6c-44fb-91df-a29fb49f0ede","outcome":"completed","summary":"Added 128-run randomized coverage across 64 assets, checking hostile-token redemption, prior claims, accounting, and the gas limit.\n\nOnly `test/` changed. Offline build succeeded; all 87 tests passed, including both invariant suites. No new defect was reproduced.","treeHash":"221eafd365f5a6c675db089778712b39273d0176","usage":{"cachedInputTokens":947072,"inputTokens":101861,"model":"gpt-6-astra","outputTokens":6237,"runtime":"codex","turns":5,"wallClockMs":283886}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"02f22d6f13810ca8","findings":[{"citation":"resolved","description":"Round-2 settlement of 6e714ebf9d08. The source is byte-for-byte unchanged since round 1 (git diff 5702ae1..HEAD touches only README.md, REVIEW.md, launch.json notes and tests), so the behaviour reproduces exactly as before: executeProposal(Kind.Band) (lines 415-421) and Kind.List (line 407 via _checkListing/_band, lines 481-486) accept any positive answer (under 26 hours old for Band) and set minAnswer = answer/4, maxAnswer = answer*4, while feed replacement (line 470) requires the new answer inside the current band. The author disputes the requested change rather than the reproduction, and on the brief's text the dispute is correct: the brief says 're-centre a band on the answer at execution, under 26 hours old', 'A proposal waits 7 days, then anyone may execute it', lists only 'answer > 0' among the listing checks with 'minAnswer = answer / 4, maxAnswer = answer * 4', and the build rules say 'add no feature, role, setting or safeguard'. Requiring the re-centre answer inside the old band, or restricting Band/List execution to the owner, both change those rules, and a new listing has no old band to compare against. The implementation is therefore spec-literal, not defective. The author also correctly identified a flaw in the proof I attached: its setUp mints EVE 1e18 of every stock (line 96) and the final check is assertLt(stocks[1].balanceOf(EVE), 1e18), so the proof fails even when the attack is prevented (test/RevisionFindings.t.sol::testCancelledBandShowsSuppliedProofBalanceBaselineError demonstrates this); the assertion should have been assertEq(..., 1e18). The residual risk is real and now documented in README.md ('A pending band proposal authorizes anyone to re-centre on a fresh execution-time answer, including an outlier...') and REVIEW.md. Impact if the requester regards it as a defect: loss of holder funds under a specific condition (an outlier feed round during an open Band/List execution window), which would be medium; as the brief is written it is mandated behaviour and only a scope decision by the requester can change it. Kept at low as a documented design risk; no code change is required of the author under the current brief.","line":421,"path":"src/BaskVault.sol","reproduction":"Unchanged code, re-run this round. 4 genesis assets at $100 (band [25e8, 400e8]); Alice deposits 240e18 of assets 1..3 (NAV $72,000), asset 0 unheld. OWNER: id = proposeBand(asset0). +7 days (Thursday 15:30 UTC), feeds refreshed; feed0 publishes answer 100000e8 with updatedAt = now. depositStatus(asset0) == (OutsideBand, asset0). BOB/EVE (no role): executeProposal(id) succeeds; assets(0).minAnswer == 25000e8, maxAnswer == 400000e8. deposit(asset0, 0.25e18, EVE, 0, now) then redeem(all) pays 61.317677419354838709e18 of each of assets 1, 2, 3 (~$18,395 at the honest price) for 0.25e18 of asset0 (~$25). Then feed0 back at 100e8: depositStatus(asset1) == (OutsideBand, asset0) and proposeFeed(asset0, honestFeed@100e8) reverts InvalidFeed. Verified: test/RevisionFindings.t.sol::testBandOutlierExtractionAndRecoveredPriceLockout and ::testPostGenesisListingOutlierExtractionDespiteProbationCap pass (behaviour present); test/scratch copy of .imd/reads/proofs/Proof_6e714ebf9d08.t.sol fails with '62317677419354838709 >= 1000000000000000000'. Expected under the brief: exactly this (re-centre on the execution answer, anyone executes). Expected if the requester wants the band to be a defence against outlier prints: a scope change to the brief (e.g. require the re-centre answer inside the old band, as feed replacement already does).","severity":"low","snippet":"            _band(a, uint256(answer));","title":"SETTLED (design risk, dispute upheld): band re-centre and post-genesis listing take the band from the execution-time answer with no relation to the old band; one outlier round in the 7-day permissionl"},{"citation":"resolved","description":"Round-2 settlement of 48206a61a1da (merged math/flow/economics). Source unchanged; the behaviour reproduces: NAV skips retired assets (line 579), _quote falls back to gross = value only when totalSupply == 0 (line 613), the first deposit mints LOCKED_SHARES to 0xdEaD (line 657) which nothing can burn, so after every asset with managed > 0 is retired (or written to 0 by recognizeLoss) every deposit, including into newly listed assets, returns ZeroNAV for good. Redeem and claim keep working; no funds are lost. The author's dispute is upheld on the brief's text: 'gross = v if totalSupply is 0, else v * totalSupply / NAV rounded down (revert if NAV is 0)', 'on the first deposit 1e15 of that goes to address(0xdEaD)', 'A retired asset ... 0 in NAV', and 'add no feature, role, setting or safeguard'. Any recovery path (reset, dead-share burn, managed recapitalisation, alternate mint formula) is behaviour the brief does not contain. The permanent consequence is now documented in README.md ('If every managed position is retired or fully written off, this zero-NAV rejection is permanent under the specified rules...'). Recorded at low: availability only, owner-triggered precondition (retire) or total loss of the only held positions, and the requester now has the information needed to decide whether the brief should change. No code change is required under the current brief.","line":595,"path":"src/BaskVault.sol","reproduction":"Unchanged code, re-run this round. 4 genesis assets at $100, finalize, +72h to market open. Alice deposit(stock0, 10e18): totalSupply 995e18, dead holds 1e15. OWNER closeAsset(stock0), proposeRetire(stock0); +7 days; executeProposal. Alice redeem(all): totalSupply == 1e15 (only dead shares). Next market open, all feeds refreshed: depositStatus(stock1) == (ZeroNAV = 18, 0x0) and deposit(stock1, 1e18, ...) reverts DepositUnavailable(ZeroNAV, 0x0); listing a new asset by proposal and executing it, and donating 10e18 of it to the vault, leave depositStatus(newAsset) == ZeroNAV. Variant: deposit 10e18, confiscate 10e18 at the token, flagDeficit, +7 days, recognizeLoss -> managed 0 -> ZeroNAV before and after Alice burns all her shares. Verified: test/RevisionFindings.t.sol::testZeroNAVPersistsAfterRetirementRedemptionNewListingAndDonation and ::testZeroNAVPersistsAfterFullLossAndAllUserSharesBurned pass; test/scratch copies of Proof_48206a61a1da.t.sol and Proof_fdcc42d3651a.t.sol fail on both paths with '18 != 0'. Expected under the brief: revert while NAV is 0 and supply > 0, which is what happens.","severity":"low","snippet":"        if (totalSupply > 0 && nav == 0) return (Reason.ZeroNAV, address(0), 0, 0);","title":"SETTLED (design risk, dispute upheld): ZeroNAV is a terminal state once every asset holding managed funds is retired or fully written off, because the 1e15 dead shares keep totalSupply > 0 forever"},{"citation":"resolved","description":"Round-2 settlement of 837d258ed4ac. Source unchanged; reproduces. _checkReplacement requires the replacement answer inside the current band at proposal and execution, and the Band branch (lines 417-420) reverts InvalidFeed when the asset's current feed is 26 hours old or more, so a dead feed whose last price is more than 4x from the band centre blocks every deposit (StalePrice while managed > 0) until the asset is retired or an interim in-band feed is used over two or three 7-day cycles. The brief requires both checks verbatim ('feed checks and new answer inside the band, both times'; 're-centre a band on the answer at execution, under 26 hours old'), so the author's dispute holds and the limitation is documented in README.md. Availability only, no loss. No code change required under the current brief.","line":470,"path":"src/BaskVault.sol","reproduction":"4 genesis assets; Alice deposits 100e18 of asset0 (band [25e8, 400e8]). feed0 stops updating. Replacement feed f2 answers 10e8, fresh: OWNER proposeFeed(asset0, f2) reverts InvalidFeed(f2). OWNER proposeBand(asset0); +7 days, feeds 1..3 refreshed, feed0 7 days old: executeProposal reverts InvalidFeed(feed0). depositStatus(asset1) == (StalePrice = 15, asset0) and deposit(asset1, 1e18, ...) reverts DepositUnavailable(StalePrice, asset0). Verified: test/RevisionFindings.t.sol::testStaleFeedAndOutOfBandReplacementCannotRepairHeldAsset passes on this code.","severity":"low","snippet":"        if (answer < a.minAnswer || answer > a.maxAnswer) revert InvalidFeed(feed);","title":"SETTLED (design limitation, dispute upheld): an asset whose feed went stale after the price left the band has no in-protocol repair except retirement"},{"citation":"resolved","description":"Round-2 settlement of 952288203837. Source unchanged; reproduces. The loop at line 579 'continue's on retired assets before counting fresh feeds, and finalizeGenesis requires only 3 assets, so with 3 listed assets retiring one caps fresh at 2 and every deposit returns MarketNotFresh regardless of feed freshness; recovery needs a List proposal (7 days plus the 24-hour cooldown). The author's reading ('a retired asset is ... skipped by every deposit check', so its feed cannot count toward the deposit quorum) is the more literal one and the brief says to add no safeguard, so the dispute holds; README.md now states that three fresh unretired feeds are needed and that replacement listings should precede retirement. Availability only. No code change required under the current brief.","line":594,"path":"src/BaskVault.sol","reproduction":"Genesis with exactly 3 assets, finalize, +72h, refresh. Alice deposit(stock0, 10e18) and deposit(stock1, 1e18). OWNER closeAsset(stock0), proposeRetire(stock0); +7 days (market open); refresh all three feeds to now; executeProposal. depositStatus(stock1) == (MarketNotFresh = 7, 0x0) although managed[stock1] > 0 and every feed is fresh; deposit(stock1, 1e18, ...) reverts DepositUnavailable(MarketNotFresh, 0x0). Verified: test/RevisionFindings.t.sol::RevisionQuorumTest::testRetiringOneOfThreeRemovesQuorumDespitePositiveLiveNAV passes on this code.","severity":"low","snippet":"        if (fresh < 3) return (Reason.MarketNotFresh, address(0), 0, 0);","title":"SETTLED (design limitation, dispute upheld): fresh-feed quorum skips retired assets and equals the genesis minimum, so retiring one of exactly three assets blocks every deposit until a new listing exe"},{"citation":"resolved","description":"Round-2 settlement of 1a92e4b7aee8 (merged permissions/math). Source unchanged; reproduces. flagDeficit records any readable shortfall, recognizeLoss lowers managed after 7 days, nothing raises managed except a deposit (impossible while Reason.Deficit holds or for a retired asset), and no role can cancel a flag or stop the clock; pauseDeposits has no effect on the loss path. The brief specifies exactly this ('flagDeficit(token), by anyone ... recognizeLoss(token), by anyone 7 days or more later ... Nothing lowers managed automatically', 'no ... rescue or sweep'), and the author's control test shows recovery before recognition preserves managed because the current shortfall is re-checked (line 766). The dispute holds; README.md now documents recognition finality and the before/after-recognition distinction. No code change required under the current brief.","line":768,"path":"src/BaskVault.sol","reproduction":"4 genesis assets; Alice deposits 100e18 of asset0. vm.mockCall asset0.balanceOf(vault) -> 0. Anyone: flagDeficit(asset0) records 100e18. GUARDIAN pauseDeposits (no effect). +7 days. Anyone: recognizeLoss(asset0) -> managed[asset0] == 0. Clear the mock: balanceOf(vault) == 100e18. Alice redeem(all): legs[0] == 0; claim(asset0, ALICE) returns 0; the vault still holds 100e18 of asset0 with no entry point that pays it. Control: clearing the mock before recognizeLoss leaves managed == 100e18 and the record cleared. Verified: test/RevisionFindings.t.sol::testTemporaryZeroReadRecognizedDuringPauseStrandsRecoveredTokens and ::testRecoveryBeforeRecognitionPreservesManagedBalance pass on this code.","severity":"low","snippet":"        managed[token] -= amount;","title":"SETTLED (design limitation, dispute upheld): recognizeLoss is irreversible and permissionless; a balance that temporarily under-reports for 7 days lets anyone zero managed, and tokens that return afte"},{"citation":"resolved","description":"Round-2 settlement of 95658eb9f8df. Source unchanged; reproduces. A proposal is executable from createdAt + 7 days until createdAt + 14 days exclusive (line 385); List and Feed executions share nextAssetChangeAt (lines 403-404); a batch created at T has seven execution slots, so the eighth proposal of the batch is Expired before its first legal execution time. The brief fixes both the 7/14-day window and 'One listing or feed replacement executes per 24 hours' and does not guarantee batch completion, so the dispute holds; README.md now explains staggering and re-proposal. Availability only. No code change required under the current brief.","line":404,"path":"src/BaskVault.sol","reproduction":"After genesis, OWNER proposeAssets with 8 valid token/feed pairs at T -> ids[0..7]. executeProposal(ids[i]) at T + 7d + i days for i = 0..6 all succeed. At T + 14d - 1s executeProposal(ids[7]) reverts ChangeCooldown; at T + 14d it reverts InvalidProposal(ids[7]) and proposalState(ids[7]) == Expired; assetCount() == 11. Verified: test/RevisionFindings.t.sol::testEighthSimultaneousListingExpiresBeforeCooldownEnds passes on this code.","severity":"low","snippet":"            nextAssetChangeAt = block.timestamp + 24 hours;","title":"SETTLED (design limitation, dispute upheld): proposeAssets after genesis creates batches of which at most seven can execute; the shared 24-hour listing/feed cooldown leaves the eighth and later propos"},{"citation":"resolved","description":"Round-2 settlement of dcbe805bab63 (merged permissions/flow/economics). Source unchanged; reproduces. The constructor rejects owner_ == guardian_ (line 196) and proposeGuardian/executeProposal reject a target equal to the current owner (lines 360, 431), but transferOwnership only rejects address(0), acceptOwnership makes no identity check, and the Guardian proposal is compared against owner, not pendingOwner. No authority is gained: the guardian's powers are a subset of the owner's and no fund-moving or redeem-blocking power exists for either role. The brief requires the constructor check only and says to add no safeguard, so the author's dispute holds and README.md now records separate-key maintenance as an operator responsibility. The permissions specialist's proof (Proof_56bf3a113dc6.t.sol) is present in this round's inputs and fails on this code for both sequences, which confirms the behaviour but changes nothing about the disposition. No code change required under the current brief.","line":262,"path":"src/BaskVault.sol","reproduction":"(a) OWNER transferOwnership(0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68); GUARDIAN acceptOwnership(): owner() == guardian(). (b) OWNER id = proposeGuardian(BOB); transferOwnership(BOB); +7 days; anyone executeProposal(id) succeeds (BOB != owner at that moment); BOB acceptOwnership(): owner() == guardian() == BOB. Verified: test/RevisionFindings.t.sol::testOwnershipCanBeTransferredToCurrentGuardian and ::testGuardianProposalCanExecuteBeforePendingOwnerAccepts pass; test/scratch copy of .imd/reads/proofs/Proof_56bf3a113dc6.t.sol fails with 'owner and guardian collapsed into one address' for both tests.","severity":"info","snippet":"        if (next == address(0)) revert InvalidAddress();","title":"SETTLED (asymmetry noted, dispute upheld): owner != guardian is enforced only in the constructor and proposeGuardian; transferOwnership to the guardian, or a Guardian proposal racing a pending owner, "},{"citation":"resolved","description":"Round-2 settlement of d3e5853ef3e9. Note only, per the brief's REVIEW section; the author answered 'fixed' by documentation and that is confirmed: README.md now carries the quantified example ('retiring a $10,000 position while leaving only $1 of live NAV lets a $100 deposit followed by redemption receive about 98.51 of the 100 retired Stock Tokens'), states that deposit caps do not cap the extraction, and advises retiring only positions of negligible value or permanently broken transfer. Contract behaviour is unchanged and is the accepted design. Nothing further is required.","line":579,"path":"src/BaskVault.sol","reproduction":"4 genesis assets at $100. Alice deposits 100e18 of asset0 ($10,000) and 1e16 of asset1 ($1). OWNER closeAsset(asset0), proposeRetire(asset0); +7 days. BOB executeProposal(id); previewDeposit(asset1, 1e18).nav == 1e18; deposit(asset1, 1e18, BOB, 0, now); redeem(all): legs[0] == 98.509950248756218905e18 of retired asset0 for $100 plus fees. Verified: test/RevisionFindings.t.sol::testRetiredPositionExtractionAmplifiesWhenLiveNAVIsSmall passes on this code.","severity":"info","snippet":"            if (a.retired) continue;","title":"SETTLED (accepted design 4 quantified; documentation added as asked): after a retirement, deposit-then-redeem buys the retired asset's holdings at zero, and the extraction approaches the whole retired"}],"hash":"6456a20344b08643e40bccf36d178f0aa1f241895fd60057913555f393042293","nodeId":"a3801330-780a-44ed-8a6d-ce588c60b87b","outcome":"completed","summary":"Review settled. The findings file is written at `.imd-findings.json` with 8 settled entries and 29 coverage rows, all snippets verified against the tree.\n\n**Outcome: no blocking findings remain.** The source is byte-for-byte unchanged since round 1, so every behaviour I reported still reproduces, and all four attached proofs still fail on this tree. The author did not dispute the reproductions. They disputed that the brief permits a fix, and on the brief's own text those disputes hold:\n\n- **Band re-centre on an outlier (was medium, now low design note).** The brief says \"re-centre a band on the answer at execution\", \"anyone may execute\", and \"add no safeguard\". Requiring the old band or owner-only execution changes those rules, and a new listing has no old band. The author also correctly found a flaw in my proof: its setUp mints the executor 1e18 of every stock and then asserts the final balance is below 1e18, so it fails even when the attack is prevented. The extraction risk is real and is now documented in README.md and REVIEW.md. Changing it needs a scope decision from the requester, not a code fix.\n- **ZeroNAV terminal state (was medium, now low design note).** \"Revert if NAV is 0\", the 1e15 dead shares, and retired assets counting 0 are all explicit. Any recovery path is unrequested behaviour. Availability only, no loss, and documented.\n- **The five advisories** (dead-feed deadlock, three-asset quorum, irreversible recognizeLoss, batch lapse, owner/guardian collapse) all reproduce unchanged and are spec-literal; each is now documented. Kept at low/info as settled notes.\n- **Accepted design 4 quantified** is confirmed addressed: README now carries the 98.51-of-100 retired-token example and the operator guidance.\n\n**Verification this round.** All 87 project tests pass, including the four 64-asset redemption attacks under the 27.9M gas ceiling. I re-read the full contract once more and found no new defect to report.\n\n**What's next for the requester.** Only one decision is outstanding and it is theirs, not the author's: whether the brief should be amended so the band cannot be re-centred on a print outside the previous band. As written, the contract does what the brief asks.","treeHash":null,"usage":{"cachedInputTokens":589631,"inputTokens":194,"model":"claude-fable-5-1","outputTokens":22331,"runtime":"claude","turns":13,"wallClockMs":320542}},{"artifacts":[],"attempt":1,"bundleHash":"bb37361e88c6a16e91941444c77aec334333320981b31693af993fedf1e6062b","device":"4a019e19ac096894","findings":[],"hash":"82b7e0eb0587004ad02caff84375067c1613855c2b7afd8cd0783a929e17cb72","nodeId":"32200ef7-7c6c-44fb-91df-a29fb49f0ede","outcome":"completed","summary":"Added 14 tests covering multi-actor accounting invariants, rounding, repeated round trips, claims, and failure rollback. Improved the 64-asset redemption gas check.\n\nAll 73 tests pass offline, including a second fuzz seed. Build and formatting checks pass. All changes are under `test/`.\n\nNo implementation defect was reproduced.","treeHash":"3a75844d74002f78b374c9e5cc1eeca38e344a59","usage":{"cachedInputTokens":1727616,"inputTokens":110048,"model":"gpt-6-astra","outputTokens":17560,"runtime":"codex","turns":6,"wallClockMs":580058}},{"artifacts":[],"attempt":1,"bundleHash":"5ddb92e23836fdbe95afa2e31e801d649b1423e7dfc655bc6b248441b32a1e0b","device":"985b73231a8fa1f8","findings":[],"hash":"87d54f8451701ab8aa50548fb452c14c33657e540eeaf4de59d8951642a19289","nodeId":"312a8e7b-fa6e-435e-bc65-afe7471c1144","outcome":"completed","summary":"Recorded all eight findings in [.imd-responses.json](/home/seat7/.identitymd/work/9d7bffba-141b-4e33-be9c-1bfa450d9384/312a8e7b-fa6e-435e-bc65-afe7471c1144/.imd-responses.json).\n\nContracts remain unchanged: seven requested behavior changes conflict with the explicit brief. Documented the retirement risk and added 13 reproduction tests. Supplied proof failures are explicitly disputed; the underlying risks remain.\n\nOffline build, formatting, and all 72 project tests pass, including a second fuzz seed with 1,024 runs.","treeHash":"914f5859b996759af131019e2ae0ca80ce1da0c3","usage":{"cachedInputTokens":1169664,"inputTokens":107138,"model":"gpt-6-astra","outputTokens":15601,"runtime":"codex","turns":5,"wallClockMs":545869}},{"artifacts":[],"attempt":1,"bundleHash":"576b7fd8e376e2cafa5a3ed985b1a70bc347e3db8ccd33f1057ed5cf993525ec","device":"9ef5559b56f3a7a2","findings":[],"hash":"a08532a01a378ca33c76ae484935c5e2b96b4a2b80a07a3756ac08880eef41a0","nodeId":"10dca6a3-687a-4c45-8f9f-10b82e796d27","outcome":"completed","summary":"Updated `launch.json` with the specified literal addresses and expanded implementation and risk notes. Only the manifest changed.\n\nValidation passed: schema and constructor ABI checks, offline build, and all 59 tests—including a second seed with 1,024 fuzz runs. Runtime is 20,951 bytes; no lens needed.","treeHash":"b7dabc60b07589bdedbf4c055ee46bbd6cac2d8d","usage":{"cachedInputTokens":263552,"inputTokens":44767,"model":"gpt-6-astra","outputTokens":2914,"runtime":"codex","turns":3,"wallClockMs":94753}},{"artifacts":[],"attempt":1,"bundleHash":"6b9abee764acea55feb0d1b2a225fe3d363317bcaee0d4ce9f0b525c3d9d8b0a","device":"1f805d33d69c340e","findings":[],"hash":"acb68d24e040a0b20746f730f2c2b1cdee8c2df932743adf21ae9aff774d42fc","nodeId":"10dca6a3-687a-4c45-8f9f-10b82e796d27","outcome":"completed","summary":"Updated [launch.json](/root/.identitymd/work/9d7bffba-141b-4e33-be9c-1bfa450d9384/10dca6a3-687a-4c45-8f9f-10b82e796d27/launch.json) to clarify the redemption balance-read gas limit. Preserved the contract and required address literals.\n\nSchema and ABI checks passed. `forge build` succeeded; all 72 tests passed. Worst tested 64-asset redemption used 22.79 million gas.\n\nOnly `launch.json` changed.","treeHash":"362435de6c54c0f6b4407ff3f2d1c9fd89887533","usage":{"cachedInputTokens":203776,"inputTokens":68781,"model":"gpt-6-astra","outputTokens":5074,"runtime":"codex","turns":3,"wallClockMs":154854}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bc1e515ca5c78ac4","findings":[{"citation":"resolved","description":"The first deposit mints 1e15 BASK to 0xdEaD, which no function can ever burn, so totalSupply can never return to 0 after the first deposit. _depositContext returns ZeroNAV whenever totalSupply > 0 and the managed-NAV is 0, and _quote (line 613) only falls back to gross = value when totalSupply == 0. NAV reaches 0 while shares still exist in two spec'd ways: (a) the owner retires the only asset with managed > 0 (retired assets count 0 in NAV, accepted design 4) and holders redeem; (b) a token confiscates the whole position and recognizeLoss lowers managed to 0. In both states every asset is healthy, all feeds fresh and nothing short, yet deposit() reverts with DepositUnavailable(ZeroNAV) for every token, for every caller, forever. No owner, guardian or user action can undo it: nothing raises managed, nothing burns the dead shares, and lowering/raising NAV_CAP, reopening, relisting or pausing does not touch the check. The vault's only working function from then on is redeem of the remaining dust. Boundary x invariant seam: the spec's 'revert if NAV is 0' was meant as a division guard for v*totalSupply/NAV, but combined with the irrevocable 1e15 lock it becomes a terminal state. The author's own test testZeroNAVWithExistingSupplyReverts reaches this state (totalSupply == 1e15, reason ZeroNAV) without noting that it is unrecoverable.","line":595,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract LockoutFactory {\n    mapping(bytes32 => address) public tokenAddress;\n\n    function register(bytes32 id, address token) external {\n        tokenAddress[id] = token;\n    }\n}\n\ncontract LockoutFeed {\n    uint8 public constant decimals = 8;\n    address public constant aggregator = address(1);\n    int256 public answer = 100e8;\n    uint256 public updatedAt;\n\n    constructor() {\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 answer_, uint256 time_) external {\n        answer = answer_;\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\ncontract LockoutStock {\n    bytes32 public uid;\n    uint8 public constant decimals = 18;\n    bool public constant oraclePaused = false;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    constructor(bytes32 id) {\n        uid = id;\n    }\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function confiscate(address from, uint256 amount) external {\n        balanceOf[from] -= amount;\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 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\n/// Once NAV is 0 while the 1e15 shares locked at 0xdEaD keep totalSupply > 0, deposits are impossible forever.\ncontract ZeroNavLockoutTest is Test {\n    address internal constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address internal constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    address internal constant ALICE = address(0xA11CE);\n    address internal constant BOB = address(0xB0B);\n    uint256 internal constant MONDAY = 1_728_259_200; // 2024-10-07 00:00 UTC\n\n    BaskVault internal vault;\n    LockoutFactory internal factory;\n    LockoutStock[] internal stocks;\n    LockoutFeed[] internal feeds;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(MONDAY + 55800);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        LockoutFactory template = new LockoutFactory();\n        vm.etch(vault.STOCK_FACTORY(), address(template).code);\n        factory = LockoutFactory(vault.STOCK_FACTORY());\n        for (uint256 i; i < 4; ++i) {\n            LockoutStock stock = new LockoutStock(bytes32(i + 1));\n            LockoutFeed feed = new LockoutFeed();\n            factory.register(stock.uid(), address(stock));\n            stocks.push(stock);\n            feeds.push(feed);\n            stock.mint(ALICE, 1_000e18);\n            stock.mint(BOB, 1_000e18);\n            vm.prank(ALICE);\n            stock.approve(address(vault), type(uint256).max);\n            vm.prank(BOB);\n            stock.approve(address(vault), type(uint256).max);\n            vm.prank(OWNER);\n            vault.proposeAsset(address(stock), address(feed));\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n        vm.warp(block.timestamp + 72 hours);\n        _refresh();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < feeds.length; ++i) {\n            feeds[i].set(100e8, block.timestamp);\n        }\n    }\n\n    function _nextMarketOpen(uint256 from) internal pure returns (uint256 t) {\n        t = from / 86400 * 86400 + 55800;\n        if (t <= from) t += 1 days;\n        while ((t / 86400 + 4) % 7 == 0 || (t / 86400 + 4) % 7 == 6) t += 1 days;\n    }\n\n    function testDepositsRecoverAfterOnlyHeldAssetIsRetiredAndRedeemed() public {\n        // 1. Alice makes the only deposit: 10 stock-0 at $100 -> NAV $1,000.\n        vm.prank(ALICE);\n        vault.deposit(address(stocks[0]), 10e18, ALICE, 0, block.timestamp);\n        assertEq(vault.balanceOf(address(0xdEaD)), 1e15);\n\n        // 2. Owner closes and retires stock-0 (the only held asset).\n        vm.startPrank(OWNER);\n        vault.closeAsset(address(stocks[0]));\n        uint256 id = vault.proposeRetire(address(stocks[0]));\n        vm.stopPrank();\n        vm.warp(block.timestamp + 7 days);\n        vault.executeProposal(id);\n\n        // 3. Alice redeems all of her shares; the retired token is still paid out to her.\n        uint256 aliceShares = vault.balanceOf(ALICE);\n        vm.prank(ALICE);\n        vault.redeem(aliceShares, new uint256[](0), block.timestamp);\n        assertEq(vault.totalSupply(), 1e15, \"only the dead shares remain\");\n        assertEq(vault.balanceOf(ALICE), 0);\n\n        // 4. Next market open, every feed fresh, nothing short: a new depositor must be able to deposit.\n        vm.warp(_nextMarketOpen(block.timestamp));\n        _refresh();\n        (BaskVault.Reason reason, address fault) = vault.depositStatus(address(stocks[1]));\n        assertEq(uint256(reason), uint256(BaskVault.Reason.OK), \"depositStatus must not report ZeroNAV\");\n        assertEq(fault, address(0));\n        vm.prank(BOB);\n        uint256 shares = vault.deposit(address(stocks[1]), 10e18, BOB, 0, block.timestamp);\n        assertGt(shares, 0, \"deposit must mint shares to the new depositor\");\n    }\n\n    function testDepositsRecoverAfterTotalLossIsRecognised() public {\n        vm.prank(ALICE);\n        vault.deposit(address(stocks[0]), 10e18, ALICE, 0, block.timestamp);\n        // The whole position is confiscated at the token and the loss is recognised by the spec'd process.\n        stocks[0].confiscate(address(vault), 10e18);\n        assertEq(stocks[0].balanceOf(address(vault)), 0);\n        vault.flagDeficit(address(stocks[0]));\n        vm.warp(block.timestamp + 7 days);\n        vault.recognizeLoss(address(stocks[0]));\n        assertEq(vault.managed(address(stocks[0])), 0);\n\n        vm.warp(_nextMarketOpen(block.timestamp));\n        _refresh();\n        (BaskVault.Reason reason,) = vault.depositStatus(address(stocks[1]));\n        assertEq(uint256(reason), uint256(BaskVault.Reason.OK), \"depositStatus must not report ZeroNAV\");\n        vm.prank(BOB);\n        uint256 shares = vault.deposit(address(stocks[1]), 10e18, BOB, 0, block.timestamp);\n        assertGt(shares, 0, \"deposit must mint shares to the new depositor\");\n    }\n}","reproduction":"Genesis with 4 assets at $100 each, finalize, warp 72h to Monday 15:30 UTC. Alice deposit(stock0, 10e18): NAV 1000e18, totalSupply 995e18, dead holds 1e15. Owner closeAsset(stock0), proposeRetire(stock0), warp 7 days, executeProposal. Alice redeem(all her shares): totalSupply == 1e15 (only dead shares), managed[stock0] ~ 1e13. Warp to next market open, refresh all 4 feeds (fresh quorum satisfied). Expected: depositStatus(stock1) == OK and Bob's deposit(stock1, 10e18) mints shares. Actual: depositStatus returns (ZeroNAV, 0x0) and deposit reverts DepositUnavailable(ZeroNAV, 0x0); the same after warping one year. Variant: deposit 10e18, confiscate the vault's 10e18 at the token, flagDeficit, warp 7 days, recognizeLoss -> managed 0 -> same permanent ZeroNAV. The attached test fails on both paths with '18 != 0' (Reason.ZeroNAV = 18).","severity":"medium","snippet":"        if (totalSupply > 0 && nav == 0) return (Reason.ZeroNAV, address(0), 0, 0);","title":"Zero NAV with permanently locked dead shares bricks deposits forever"},{"citation":"resolved","description":"The quorum loop skips retired assets (line 579 `if (a.retired) continue;`) before counting `fresh`, and finalizeGenesis only requires 3 assets. With exactly 3 listed assets, retiring any one of them makes `fresh` top out at 2, so _depositContext returns MarketNotFresh for every token regardless of how fresh the remaining feeds are. Recovery needs a List proposal (7-day wait, 24h cooldown) to execute, so deposits are impossible for a minimum of 7 days after the retirement, and if the owner has nothing to list, indefinitely. Boundary x invariant seam: the invariant 'deposits possible while every held asset is healthy' is broken by a threshold that exactly equals the launch minimum. The spec text '3 or more listed assets have feed updatedAt within the last 4 hours' can be read either way (a retired asset is still listed and its feed may still update); the implementation chose to exclude retired feeds, which produces this outage. Reported as low because it is an availability outage with a known (slow) recovery, not a loss.","line":594,"path":"src/BaskVault.sol","reproduction":"Genesis with exactly 3 assets, finalize, warp 72h to market open, refresh feeds. Alice deposit(stock0, 10e18). Owner closeAsset(stock0), proposeRetire(stock0), warp 7 days, executeProposal. Refresh all three feeds to block.timestamp (all fresh, all readable, nothing short). Expected: depositStatus(stock1) is OK (two healthy held/unheld assets, nothing wrong). Actual: depositStatus(stock1) returns (MarketNotFresh = 7, 0x0) and deposit(stock1, ...) reverts DepositUnavailable(MarketNotFresh, 0x0). Observed in test/scratch/Probe.t.sol run with 3 assets: 'reason: 7'. Deposits stay blocked until a fourth asset's List proposal executes (>= 7 days later).","severity":"low","snippet":"        if (fresh < 3) return (Reason.MarketNotFresh, address(0), 0, 0);","title":"Fresh-feed quorum equals the genesis minimum: retiring one of three assets blocks all deposits for at least 7 days"},{"citation":"resolved","description":"Redeem legs are capped at managed, and nothing ever raises managed except deposit. If an issuer freezes/confiscates the vault's balance, the spec'd flagDeficit -> 7 days -> recognizeLoss path lowers managed to the surviving balance. If the issuer later restores the balance (unfreeze, court order, reissue), the restored tokens are above managed, are invisible to NAV, are never paid by redeem, and there is no rescue/sweep by design. Holders who were diluted by the loss recognition do not get the recovery back. This is a direct consequence of the accepted rules 'nothing lowers managed automatically', 'tokens sent directly are ignored' and 'no rescue or sweep'; it is recorded here so the owner understands that recognizing a loss is irreversible even if the underlying asset recovers. No code change is proposed.","line":674,"path":"src/BaskVault.sol","reproduction":"deposit(stock0, 10e18); confiscate 10e18 at the token; flagDeficit(stock0); warp 7 days; recognizeLoss(stock0) -> managed[stock0] == 0. Token mints 10e18 back to the vault. Alice redeem(all shares): legs[0] == 0, vault balance of stock0 stays 10e18 and can never be redeemed or claimed by anyone (verified in test/scratch/Probe.t.sol testRecoveredTokensAfterLossAreStranded).","severity":"info","snippet":"            amounts[i] = M.mulDiv(M.min(managed[token], available), net, supply);","title":"Tokens that come back after recognizeLoss are stranded (accepted design, note only)"}],"hash":"cec4eecebaca23f1f1144595f33a0289eb9ccda6e7cbbafaa280c90a8d741a17","nodeId":"31385a89-48e5-40ea-b0bd-d3a87dc1446c","outcome":"completed","summary":"The review is complete. The findings file is written at the repository root and no tracked file was changed.\n\n**Outcome.** The vault's arithmetic is sound in my area. The hand-rolled 512-bit `mulDiv` matches the canonical algorithm step for step, so the static-analysis lines about the caret operator and divide-before-multiply are false positives. Fee rounding, share minting, the three caps, bucket decay, bands, time boundaries, and the redeem leg formula all match the brief, and the conservation invariant between managed, owed and real balance holds exactly. Redeem stayed under the 28,000,000 gas bound in every hostile 64-asset mix I ran, and no role can block redeem or claim.\n\n**Findings written to `.imd-findings.json`:**\n\n1. **Medium: zero NAV with locked dead shares bricks deposits forever.** The 1e15 shares at the dead address can never be burned, so totalSupply never returns to zero. Once NAV reaches zero, by retiring the only held asset or by recognizing a total loss, every deposit reverts with ZeroNAV permanently with no recovery path for any role. A self-contained proof test under `test/scratch/ZeroNavLockout.t.sol` fails on both paths today and is embedded in the finding.\n2. **Low: the fresh-feed quorum equals the genesis minimum.** With exactly three assets, retiring one blocks every deposit with MarketNotFresh until a new listing executes, so at least seven days.\n3. **Info, accepted design:** tokens restored by an issuer after recognizeLoss are stranded above managed and can never be redeemed. Recorded as a note only.\n\n**Coverage.** All 27 entry points have a row, 26 hold and deposit carries finding 1, plus four invariant rows for the math library, conservation, share-price inflation, and time boundaries. Leads I dropped after testing: a gas-bombing feed does not brick the views because the 63/64 gas rule leaves the loop enough gas to finish.","treeHash":null,"usage":{"cachedInputTokens":2217205,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":60964,"runtime":"claude","turns":32,"wallClockMs":859086}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7f1dec5ffcbde1d8","findings":[{"citation":"resolved","description":"The brief requires the constructor to revert when owner_ == guardian_, and proposeGuardian/executeProposal(Guardian) reject a target equal to the current owner (lines 360 and 431). The mirror check is missing on the ownership side: transferOwnership(next) only rejects address(0), acceptOwnership performs no identity check, and the Guardian proposal is compared against `owner` but not `pendingOwner`. Two sequences therefore make one key hold both roles: (a) owner calls transferOwnership(guardian) and the guardian accepts; (b) owner proposes guardian = X, then transferOwnership(X); the proposal executes (X != owner at that moment) and X accepts. Once collapsed, the separation the brief relies on is gone: the 'guardian cannot cancel its own replacement' rule is moot (msg.sender == owner passes cancelProposal), a single compromised key holds pause, close, cancel and every owner power, and there is no on-chain way to notice except reading both getters. This is an access-control asymmetry (constructor vs. later role setters), not a fund-loss path; a fix is a one-line `next == guardian` / `p.target == pendingOwner` check, which the requester must weigh against the 'add no safeguard' build rule.","line":262,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\n/// The constructor rejects owner == guardian, but the two-step ownership transfer and the\n/// guardian-replacement proposal can later make the same address hold both roles.\ncontract OwnerGuardianIdentityTest is Test {\n    address internal constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address internal constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    address internal constant BOB = address(0xB0B);\n    BaskVault internal vault;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(1_728_259_200);\n        vault = new BaskVault(OWNER, GUARDIAN);\n    }\n\n    function testOwnershipTransferCannotMakeOwnerTheGuardian() public {\n        vm.prank(OWNER);\n        (bool started,) = address(vault).call(abi.encodeCall(vault.transferOwnership, (GUARDIAN)));\n        if (started) {\n            vm.prank(GUARDIAN);\n            address(vault).call(abi.encodeCall(vault.acceptOwnership, ()));\n        }\n        assertTrue(vault.owner() != vault.guardian(), \"owner and guardian collapsed into one address\");\n    }\n\n    function testGuardianProposalCannotTargetIncomingOwner() public {\n        vm.startPrank(OWNER);\n        uint256 id = vault.proposeGuardian(BOB);\n        vault.transferOwnership(BOB);\n        vm.stopPrank();\n        vm.warp(block.timestamp + 7 days);\n        (bool executed,) = address(vault).call(abi.encodeCall(vault.executeProposal, (id)));\n        if (executed) {\n            vm.prank(BOB);\n            address(vault).call(abi.encodeCall(vault.acceptOwnership, ()));\n        }\n        assertTrue(vault.owner() != vault.guardian(), \"owner and guardian collapsed into one address\");\n    }\n}","reproduction":"Deploy BaskVault(OWNER, GUARDIAN). (a) prank OWNER: transferOwnership(GUARDIAN); prank GUARDIAN: acceptOwnership(). Expected (by the constructor's own invariant): revert or owner != guardian. Actual: owner() == guardian() == GUARDIAN, and GUARDIAN can now proposeGuardian(BOB) and cancelProposal(id) on it. (b) prank OWNER: id = proposeGuardian(BOB); transferOwnership(BOB); warp +7 days; anyone executeProposal(id) succeeds (BOB != owner); prank BOB: acceptOwnership(). Actual: owner() == guardian() == BOB. The attached test fails on current code with 'owner and guardian collapsed into one address' and passes if either step rejects the collision.","severity":"low","snippet":"        if (next == address(0)) revert InvalidAddress();","title":"owner != guardian is enforced only in the constructor; transferOwnership/acceptOwnership and a guardian proposal targeting the pending owner collapse both roles into one address"},{"citation":"resolved","description":"Trust gap (access x asymmetry): the owner authorises a band re-centre once, but the price it is centred on is chosen by whoever executes within the 7-day window, and executeProposal has no caller restriction. Unlike feed replacement (_checkReplacement requires the answer inside the current band both times), the Band branch and the List branch accept any positive answer under 26 hours old with no relation to the old band. An unprivileged executor who waits for (or observes) a transient outlier round sets minAnswer/maxAnswer around that outlier; when the feed returns to its normal level the asset is OutsideBand, so _depositContext rejects every deposit while managed[token] > 0 (and every deposit of that token regardless). The owner cannot repair quickly: proposeFeed with a correct feed is rejected because the true answer is outside the new band, lowering the band needs another 7-day Band proposal (which the same executor can again time), and retirement is a 7-day proposal that permanently zeroes the asset in NAV. closeAsset does not help because a closed asset with managed > 0 is still priced. Impact is deposit availability only; redeem is unaffected. This follows the brief's wording ('re-centre a band on the answer at execution'), so it is reported as a design risk with a concrete trigger rather than a spec violation.","line":417,"path":"src/BaskVault.sol","reproduction":"Genesis with 3 assets at answer 100e8, Alice deposits 10e18 of asset0 (managed > 0). OWNER: id = proposeBand(asset0). Warp +7 days. Feed0 publishes one round with answer 1000e8 (updatedAt = now). EVE (no role) calls executeProposal(id): band becomes [250e8, 4000e8]. Next round feed0 returns to 100e8. depositStatus(asset1) == (OutsideBand, asset0) and deposit(asset1, ...) reverts DepositUnavailable(13, asset0). OWNER: proposeFeed(asset0, correctFeed@100e8) reverts InvalidFeed because 100e8 < minAnswer 250e8. Expected: an authorised band change should not be able to move the band away from the price the owner approved it against; actual: deposits are blocked until a further 7-day proposal executes. Verified in test/scratch/BandGlitch.t.sol (passes, i.e. the behaviour is reproduced).","severity":"low","snippet":"            (bool ok, int256 answer, uint256 updatedAt) = _readFeed(a.feed);","title":"Permissionless Band (and List) execution re-centres on whatever the feed prints in the executor-chosen round; one outlier round locks the asset out of band and blocks every deposit for at least 7 days"},{"citation":"resolved","description":"Trust gap (access x economics x asymmetry): the loss path is fully permissionless and one-directional. flagDeficit records any readable shortfall, recognizeLoss lowers managed after 7 days, and the only clearing path is a successful deposit, which is impossible while the deficit exists (Reason.Deficit) and impossible for a retired asset at all. Neither owner nor guardian can cancel a flagged deficit, pause the loss clock, or re-credit managed after the balance returns, and the brief forbids rescue/sweep. Stock Tokens are issuer-controlled and upgradeable (the brief's MUST ATTACK list names 'paused, blocked or upgraded tokens'); a token that reports 0 for a frozen or paused holder, or an upgrade that briefly mis-reads balances, produces a readable but false shortfall. If that state lasts 7 days anyone can zero managed[token]; when the freeze lifts the tokens sit in the vault forever as an unmanaged surplus: redeem legs are min(managed, available) * net / supply = 0, previewRedeem shows 0, and value() ignores them. All current holders lose that asset. The 7-day wait is the only guard and is not operator-controllable (pausing deposits does not stop flag/recognize). This follows the brief's loss mechanism exactly, so it is reported as a design risk with a concrete trigger; it is not covered by accepted risks (1)-(4).","line":766,"path":"src/BaskVault.sol","reproduction":"Genesis with 3 assets; Alice deposits 100e18 of asset0 (managed = 100e18, balance = 100e18). Mock asset0.balanceOf(vault) to return 0 (vm.mockCall) to model a frozen-holder read. Anyone: flagDeficit(asset0) records 100e18. Warp +7 days (guardian pauseDeposits in between changes nothing). Anyone: recognizeLoss(asset0) -> managed[asset0] == 0. Clear the mock: real balanceOf(vault) == 100e18. Alice redeems all shares: legs[0] == 0 and asset0.balanceOf(vault) is still 100e18 with no entry point that can ever pay it out. Expected: a temporary read anomaly should not convert into a permanent loss, or a role should be able to halt the clock; actual: permanent strand. Verified in test/scratch/Probe.t.sol::testTemporaryZeroBalanceReportStrandsFunds (passes, i.e. behaviour reproduced).","severity":"low","snippet":"        uint256 shortfall = managed[token] > available ? managed[token] - available : 0;","title":"A balanceOf that temporarily under-reports (frozen-holder or upgraded token) lets anyone permanently strand the recovered tokens: recognizeLoss is irreversible, no role can clear a flag, and nothing e"},{"citation":"resolved","description":"Note only, per the brief's REVIEW section; no mechanism is proposed. The asymmetry is deposit pricing (NAV skips retired assets) versus redemption (pro-rata in kind across all assets including retired ones, lines 671-675). Any depositor after a retirement buys shares at a NAV that excludes the retired asset and then redeems a slice of it. The caps bound the per-day size (bucket max(NAV2/4, 100k), per-asset 5%/25k), not the existence of the leak, and the loss is borne by holders who held before the retirement. Because executeProposal(Retire) is permissionless, the extractor can also be the executor and deposit in the same block. Worth stating in operator guidance: retire only assets whose real value is already ~0 or whose transfer is permanently broken.","line":579,"path":"src/BaskVault.sol","reproduction":"4 genesis assets at $100; Alice deposits 125e18 of each (NAV $50,000). Owner closes asset0, proposeRetire(asset0), +7 days, executeProposal -> NAV $37,500. Eve deposits 125e18 of assets 1..3 ($37,500, within asset caps) and immediately redeems all her shares: she receives 61.99e18 of retired asset0 plus her assets 1..3 slices; net token delta +58.97e18 (= +$5,897 at $100) taken from Alice's holdings. Measured in test/scratch/Probe.t.sol::testRetiredAssetLeakWithRoom.","severity":"info","snippet":"            if (a.retired) continue;","title":"Accepted design (4), quantified: after retirement, deposit-then-redeem extracts the retired asset from existing holders (~15.7% round-trip gain in the example, net of both 0.5% fees)"}],"hash":"d9e453aab7c24a46a23cd68fb637b3b2ac4fc01fd88d541a215a4d1fc87292e5","nodeId":"a721f531-579f-4086-81a1-714165fe0d7e","outcome":"completed","summary":"Review complete. Only `.imd-findings.json` and `test/scratch/` (my probes, not kept) were added; no source, test, or config file was touched.\n\n## Summary\n\n**Area covered:** Access Control, Trust Gap and Asymmetry (Pashov guides), plus the MUST-ATTACK items. I mapped every role → entry point → guard, diffed the paired surfaces (deposit↔redeem, redeem↔claim, previewX↔X, propose↔execute, constructor↔later role setters), traced storage lifecycles for `managed`/`owed`/`totalOwed`/`losses`, and attacked redeem with 64 hostile assets under cold access. All 27 entry points have coverage rows (23 hold, 4 carry findings).\n\n**Headline result for the MUST-ATTACK:** no role can block `redeem` or `claim`. Redeem reads only `assets[]`, `managed`, `totalOwed` and `feeRecipient`; every external interaction is gas-bounded and the fee transfer cannot revert for a non-zero recipient. Worst combined case I constructed (balance read succeeds just under 50k, then payment bombs, fee recipient set, 64 cold assets) used 22.5M gas; the suite's own read-bomb case is the ceiling at 22.8M — under 28M.\n\n**Findings (none critical/high):**\n\n1. **Low — owner/guardian separation enforced only in the constructor.** `transferOwnership(guardian)` + `acceptOwnership`, or a guardian proposal targeting `pendingOwner`, collapse both roles into one key. Proof test attached; fails on current code.\n2. **Low — permissionless Band/List execution re-centres on an executor-chosen round.** One outlier print locks the asset `OutsideBand` and blocks all deposits; `proposeFeed` with the true price is then rejected, so the owner needs another 7-day proposal. Follows the brief's wording; reported as a concrete-trigger design risk.\n3. **Low — temporary `balanceOf` under-report → permanent strand.** `flagDeficit`/`recognizeLoss` are permissionless and irreversible, no role can clear a flag, and nothing raises `managed`; a 7-day frozen-holder read zeroes the asset and the returned tokens can never be paid out. Mechanism is as specified, but it's a trust gap not covered by accepted risks (1)–(4).\n4. **Info — accepted design (4) quantified:** post-retirement deposit-then-redeem extracted ~$5,900 on a $37,500 round trip (≈15.7%) from pre-existing holders in my example.\n\n**Not reached / limits:** no fork or live feed verification (none permitted); Slither/Aderyn leads (`weak-prng`, `incorrect-exp`, `divide-before-multiply`, `incorrect-equality`) were examined and are false positives for this code (calendar arithmetic, the standard `mulDiv` inverse seed, and intentional strict equalities).","treeHash":null,"usage":{"cachedInputTokens":2898130,"inputTokens":51,"model":"claude-fable-5-1","outputTokens":55062,"runtime":"claude","turns":27,"wallClockMs":766580}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"37eed9f56188ea8b","findings":[{"citation":"resolved","description":"Execution-trace note, not a code defect against the brief. NAV sums value(managed) only over non-retired assets (line 579 `if (a.retired) continue;`) and the brief mandates both that a retired asset counts 0 in NAV (accepted design 4) and that gross reverts when NAV is 0 with supply outstanding. Combined, once every asset with managed > 0 has been retired, NAV is 0 while totalSupply > 0 forever: the 1e15 shares at 0xdEaD can never be burned, and no deposit can ever succeed to put managed > 0 into a non-retired asset, so the vault can never leave ZeroNAV even after fresh assets are listed. Redeem and claim keep working, so no funds are lost; only new deposits are dead for good. Owner-only precondition (close + retire proposals, 7-day waits). Recorded so the author and operator know the state is unrecoverable; the brief says add no mechanism.","line":595,"path":"src/BaskVault.sol","reproduction":"Genesis with assets A,B,C; Alice deposits 10e18 of A (supply > 0, managed[A] = 10e18). Owner: closeAsset(A); proposeRetire(A); proposeAsset(D, feedD). Warp 7 days; executeProposal(list D); executeProposal(retire A). Refresh feeds. depositStatus(B) == ZeroNAV (18) and deposit(B, 1e18, ...) reverts DepositUnavailable(ZeroNAV, 0). The same holds for deposit(D, ...) and for any token at any later time: no call path can increase managed of a non-retired asset, and totalSupply >= 1e15 permanently, so the vault never accepts another deposit. Reproduced locally (scratch test testRetireAllHeldAssetsLeavesZeroNAV: reason 18; redeem(100e18) afterwards still pays A's leg).","severity":"low","snippet":"        if (totalSupply > 0 && nav == 0) return (Reason.ZeroNAV, address(0), 0, 0);","title":"Retiring every asset that holds value leaves deposits permanently at ZeroNAV (spec-conformant liveness trap, note only)"},{"citation":"resolved","description":"The constructor rejects owner_ == guardian_, and proposeGuardian/executeProposal reject the current owner, but transferOwnership(next) does not reject next == guardian, and a Guardian proposal is checked only against `owner`, not `pendingOwner`. So the two roles can collapse into one address. No concrete harm follows: the guardian's powers (pause, close, cancel non-guardian proposals) are a subset of the owner's, and the cancelProposal check `msg.sender != owner && (...)` short-circuits for the owner. Recorded as an asymmetry between the construction-time invariant and later transitions; the brief adds no requirement here, so no change is proposed.","line":262,"path":"src/BaskVault.sol","reproduction":"Owner calls transferOwnership(0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68) (the guardian). Guardian calls acceptOwnership(). owner() == guardian() == 0x5ed3...9B68; both succeed. Alternative: owner proposes guardian X, then transferOwnership(X) and X accepts before day 7; executeProposal reverts InvalidAddress only because X is now owner, but if X accepts after execution, owner == guardian again. Reproduced locally (scratch test testOwnerCanBecomeGuardian).","severity":"info","snippet":"        if (next == address(0)) revert InvalidAddress();","title":"Owner and guardian must differ at construction but may become the same address through transferOwnership/acceptOwnership or a Guardian proposal that races a pending owner"}],"hash":"e350c30a3b91e6f76ff02332bcb1aeb8e4499608eee4e457dd0c70393ed41d1e","nodeId":"348e3b51-d7df-41b6-852e-77cf24e61fb7","outcome":"completed","summary":"The review is complete and written to `.imd-findings.json`. No source files were changed, and the scratch tests I used for probing have been removed.\n\n**Outcome: no critical, high or medium defects in the assigned area.** I traced the Execution Trace, Periphery and First Principles checklists against every entry point of `src/BaskVault.sol` and `src/BaskMath.sol`, and the code matches the brief on each path I followed.\n\nWhat I verified in depth:\n\n- **Deposit flow.** Every gate, the freshness quorum, the per-asset balance and price checks, the exact balance-rise requirement, share math and rounding, the three caps, bucket decay and loss-record clearing all behave as specified. The reentrancy guard covers every state-changing entry, and the self-call `payLeg` rejects any caller but the vault.\n- **Redeem, payLeg and claim.** Legs are computed before any transfer, failures are isolated into owed debt, and the balance-conservation invariant held in every path. I added a worst-case mix the suite lacked, readable-but-expensive balance reads plus gas-bombing transfers across 64 assets, and it used about 22.5M gas, under the 28M requirement. No owner or guardian action can block redeem or claim.\n- **Proposal interleavings.** Feed reuse races, retire versus reopen, cap lowering during pending raises, and listing cooldown ordering are all re-validated at execution time.\n- **Periphery.** The 512-bit `mulDiv`, ceil fee, and the raw-return assembly helpers are correct. The slither and aderyn lines on the math library and the weekday arithmetic are false positives for this algorithm and for a market calendar, so I did not report them.\n\nTwo notes recorded, both with reproductions, neither a code defect against the brief:\n\n1. **Low, note only.** Once every asset holding value is retired, NAV is zero while supply is permanently positive, so the vault can never accept another deposit even after listing new assets. This follows directly from two rules in the brief, so no mechanism is proposed. Redeem and claim still work.\n2. **Info.** The owner can hand ownership to the guardian, collapsing the two roles that the constructor requires to differ. No harmful consequence exists.\n\nThe coverage record answers all 27 listed entry points plus four invariant and periphery rows. The only `finding` rows point at the info-level role note. Everything else is `holds`; nothing was left `unreached`.","treeHash":null,"usage":{"cachedInputTokens":944885,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":52763,"runtime":"claude","turns":25,"wallClockMs":720007}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1ca477e8d9b58040","findings":[{"citation":"resolved","description":"The min/max band is the vault's only defence against a wrong feed print (accepted design (1) bounds feed-lag profit to the 4x band). executeProposal(Kind.Band) is permissionless for 7 days and sets the band to whatever latestRoundData() returns at that moment with no relation to the old band (lines 417-421); Kind.List does the same through _checkListing/_band. If the feed prints an anomalous answer (> 4x or < 1/4 of the band centre) at any point in that window, an executor can execute the proposal in the same block, which re-centres the band on the anomaly, deposit at the anomalous price, and redeem the whole basket pro rata. The asset cap (max(5% NAV2, 25k)) and the bucket only limit the nominal value, not the real cost. Afterwards the legitimate price is outside the new band, so every deposit reverts OutsideBand until a further 7-day band proposal. The spec wording ('re-centre a band on the answer at execution', 'anyone may execute') mandates the mechanism, so this is a design gap rather than an implementation slip; the exposure above 4x exists only while a Band or List proposal is in its execution window.","line":417,"path":"src/BaskVault.sol","reproduction":"State: 4 genesis assets at $100, Alice holds 240 tokens each of assets 1..3 (NAV $72,000), asset 0 has managed 0; owner proposeBand(asset0) (id). Day 7, market open: feed0 prints 100000e8 (fresh). depositStatus(asset0) = OutsideBand. Eve: executeProposal(id) -> band becomes [25000e8, 400000e8]; deposit(asset0, 0.25e18, Eve, 0, now) succeeds (nominal $25,000 = 25.7% of supply, real cost ~$25); redeem(all) in the same transaction pays legs of 61.3 tokens of each of assets 1,2,3 (~$18,395 real) plus 0.064 token0. Eve's net cost is 0.186 token0 (~$18.6). Expected: a 1000x print should be rejected by the band as it was one block earlier; actual: band follows the print and existing holders lose ~$18.4k. Afterwards feed0 back at 100e8 gives depositStatus(asset1) = OutsideBand(asset0) for all deposits until another 7-day band proposal. Scratch test test/scratch/Econ.t.sol::testBandRecentreAtAnomalyThenDepositAndRedeem logs these numbers.","severity":"medium","snippet":"            (bool ok, int256 answer, uint256 updatedAt) = _readFeed(a.feed);\n            if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\n                revert InvalidFeed(a.feed);\n            }\n            _band(a, uint256(answer));","title":"Band re-centre (and post-genesis listing) is executed by anyone on the spot answer, so an executor can time it to a feed anomaly, defeat the band and extract basket value"},{"citation":"resolved","description":"NAV sums value(managed) over unretired assets only (line 579 skips retired). totalSupply never returns to 0 after the first deposit because LOCKED_SHARES sit at 0xdEaD. So after the owner retires every asset that has managed > 0 (or recognizeLoss zeroes them), nav == 0 with totalSupply > 0 and _depositContext returns ZeroNAV for every token, including assets listed afterwards. Nothing can raise managed except a deposit, and nothing can un-retire, so the vault is dead for deposits forever while redeem keeps paying the retired legs. The spec's 'revert if NAV is 0' is implemented literally; the permanent consequence is the defect to decide on.","line":595,"path":"src/BaskVault.sol","reproduction":"5 genesis assets; Alice deposits 100 tokens into assets 0 and 1; owner closeAsset(0), closeAsset(1), proposeRetire(0), proposeRetire(1); +7 days executeProposal both. Next market open with assets 2,3,4 open, fresh and priced: depositStatus(asset2) == ZeroNAV and deposit(asset2, 1e18, ...) reverts DepositUnavailable(ZeroNAV, 0). Owner lists a new asset 5 by proposal and executes it: depositStatus(asset5) == ZeroNAV too. Expected: a vault with three open, priced, fresh assets should accept deposits; actual: every deposit is blocked for good (totalSupply = 1.985e22 > 0, nav = 0). test/scratch/Econ.t.sol::testZeroNAVPermanentAfterRetire.","severity":"low","snippet":"        if (totalSupply > 0 && nav == 0) return (Reason.ZeroNAV, address(0), 0, 0);","title":"ZeroNAV is permanent: once every asset holding managed funds is retired (or fully written off), no deposit can ever succeed again, even for newly listed assets"},{"citation":"resolved","description":"_checkReplacement (line 470) requires the replacement feed's answer to be inside the current band at proposal and execution, and the Band proposal (lines 417-421) reads the asset's *current* feed and reverts when it is >= 26 hours old. If a feed is deprecated/stops updating and the true price has moved more than 4x from the band centre (a replacement feed therefore answers outside the band), both paths revert and the asset keeps blocking every deposit with StalePrice while managed > 0. The only exits are retiring the asset (its value leaves NAV, accepted design (4) then dilutes existing holders) or the owner deploying an interim feed that answers inside the old band, waiting 7 days, re-centring on that interim feed's later answer, then replacing again: 2-3 weeks of blocked deposits.","line":470,"path":"src/BaskVault.sol","reproduction":"Alice deposits 100 of asset0 (band [25e8, 400e8]). feed0 stops updating; a new feed f2 answers 10e8 (fresh). owner proposeFeed(asset0, f2) reverts InvalidFeed(f2) (10e8 < minAnswer). owner proposeBand(asset0); +7 days executeProposal reverts InvalidFeed(feed0) because feed0.updatedAt is 7 days old. At the next market open with feed0 27h old, depositStatus(asset1) = (StalePrice, asset0): every deposit into any asset is blocked. test/scratch/Econ.t.sol::testDeadFeedOutOfBandDeadlock.","severity":"low","snippet":"        if (answer < a.minAnswer || answer > a.maxAnswer) revert InvalidFeed(feed);","title":"An asset whose feed has gone stale while the price left the band has no in-protocol recovery except retirement: feed replacement needs an in-band answer and band re-centre needs a fresh answer from th"},{"citation":"resolved","description":"A proposal is executable from createdAt + 7 days up to createdAt + 14 days (exclusive, line 385). List and Feed executions share nextAssetChangeAt = now + 24 hours (lines 403-404). A batch created at T can execute at T+7d, T+8d, ..., T+13d: seven slots. The 8th and later proposals of the batch (or any Feed proposal created around the same time) are Expired before their first legal execution time. proposeAssets(tokens[], feeds[]) invites exactly this batching after genesis, and each lapsed listing costs another 7-day wait. Spec-literal, but the function's post-genesis purpose is partly unreachable.","line":403,"path":"src/BaskVault.sol","reproduction":"After genesis, owner proposeAssets with 8 valid token/feed pairs at T -> ids[0..7]. Execute ids[0] at T+7d, ids[1] at T+8d, ... ids[6] at T+13d (each succeeds). At T+14d-1s executeProposal(ids[7]) reverts ChangeCooldown; at T+14d it reverts InvalidProposal and proposalState(ids[7]) == Expired. Expected: a batch of 8 listings proposed together can all be executed; actual: the 8th can never execute. test/scratch/Econ.t.sol::testBatchedListingsLapse.","severity":"low","snippet":"            if (block.timestamp < nextAssetChangeAt) revert ChangeCooldown();\n            nextAssetChangeAt = block.timestamp + 24 hours;","title":"proposeAssets after genesis creates proposals that cannot all execute: the shared 24-hour cooldown lets at most 7 listing/feed proposals from one batch execute before the rest lapse"},{"citation":"resolved","description":"The constructor reverts when owner_ == guardian_ and proposeGuardian/executeProposal reject next == owner, but transferOwnership only rejects address(0). After the guardian accepts, one key holds both roles: it can cancel guardian-replacement proposals (as owner) that the guardian role was meant not to be able to block, and the two-party check on pauses/closes/cancellations is gone.","line":262,"path":"src/BaskVault.sol","reproduction":"owner.transferOwnership(0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68); guardian.acceptOwnership(). owner() == guardian() == 0x5ed3.... Expected (by analogy with the constructor and proposeGuardian): revert InvalidAddress; actual: accepted. test/scratch/Econ.t.sol::testOwnerCanBecomeGuardian.","severity":"low","snippet":"        if (next == address(0)) revert InvalidAddress();","title":"transferOwnership can hand ownership to the current guardian, collapsing the owner/guardian separation the constructor and proposeGuardian enforce"},{"citation":"resolved","description":"Note only, per the brief. Retire execution is permissionless at day 7; immediately after it the retired asset is 0 in NAV (line 579 skips it) but still pays redemption legs. A depositor who executes the retire and deposits in the same transaction mints at the reduced NAV and redeems pro rata of the retired asset too. With NAV $1,000,000 of which the retired asset is $50,000, a deposit of $316,000 across six or more assets (bucket cap 25% of NAV2, asset cap 5%) yields ~25% of supply; redeeming returns ~$12,500 of the retired asset for a 1% round-trip fee of ~$3,160, i.e. ~$9,300 taken from existing holders. Same mechanism also applies to the window between any NAV-lowering event and the next deposit; recorded here so the author sees the magnitude.","line":579,"path":"src/BaskVault.sol","reproduction":"Owner closeAsset(A), proposeRetire(A); +7 days, attacker contract: executeProposal(id); deposit(B..G, ...) up to the caps; redeem(all) — legs include A. No test written: accepted design.","severity":"info","snippet":"            if (a.retired) continue;","title":"Accepted design (4) quantified: executing a retire proposal and depositing in the same transaction buys the retired asset's holdings at zero"}],"hash":"f4f5c279ba17bf2eacf548906cf073ef961cbc1b666ce3e61016dbaacb3cf220","nodeId":"410a2227-40c3-44bf-9b0b-308c4d96b8ea","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds 6 findings and a 31-row coverage record (all 27 entry points answered, none unreached, plus 4 invariant rows). No tracked file was modified; scratch tests live only under `test/scratch/`.\n\n## Summary\n\n**Scope covered (Economic Security, Invariant, Flow Gap guides):** every entry point traced; `managed + totalOwed == balance`, `totalOwed == Σ owed`, rounding direction, short-asset payout ratio, first-deposit/inflation, view↔write parity, and the \"must attack\" redeem path (64 hostile assets: gas-bomb reads, expensive reads + bomb transfers, large-return reads/transfers, fee recipient set, 64 mins — worst case 22.83M gas, always completes; no role can block `redeem`/`claim`).\n\n**Findings**\n\n| # | Sev | Finding |\n|---|---|---|\n| 1 | medium | `executeProposal(Band)` (and post-genesis `List`) is permissionless and seeds the band from the spot answer with no bound. An executor can time it to a feed anomaly (>4×, i.e. outside what accepted design (1) already allows), re-centre the band on the anomaly, deposit, and redeem the basket. Reproduced: Eve spends ~$18.6 real of token0 and takes ~$18.4k of assets 1–3; legit price is then out-of-band for ≥7 days. Spec-mandated mechanism, flagged as a design gap. |\n| 2 | low | ZeroNAV is permanent: once every asset with `managed > 0` is retired (or written off), `nav == 0` with `totalSupply > 0` (dead shares) and no deposit — including into newly listed assets — can ever succeed. |\n| 3 | low | Dead feed + price outside band: `proposeFeed` needs an in-band answer, `Band` execution needs a fresh answer from the dead feed → every deposit blocked (`StalePrice`) until retirement or a multi-week interim-feed workaround. |\n| 4 | low | Post-genesis `proposeAssets` batches of >7 cannot fully execute: the shared 24h cooldown vs the 7-day execution window lapses the 8th+. |\n| 5 | low | `transferOwnership` accepts the guardian, collapsing the role separation the constructor and `proposeGuardian` enforce. |\n| 6 | info | Accepted design (4) quantified: execute-retire-then-deposit in one tx buys the retired asset's holdings at zero (~$9.3k on a $1M/$50k example). |\n\n**Not found (checked and holding):** inflation attack (NAV is `managed`-based, dead shares lock), fee rounding/extraction, cap bypass paths, deficit/loss timer manipulation, claim seniority games, reentrancy via token hooks, feed-decimals/split discontinuity (Chainlink's Robinhood feeds price the token × `uiMultiplier`, so `amount·answer/1e8` stays continuous across splits — source: [Chainlink Robinhood Tokenized Equity feeds](https://docs.chain.link/data-feeds/tokenized-equity-feeds/robinhood), [ERC-8056 overview](https://sqd.dev/learn/erc-8056-tokenized-stock-splits/)).\n\nNo critical/high findings, so no proof files were attached.","treeHash":null,"usage":{"cachedInputTokens":3491528,"inputTokens":62,"model":"claude-fable-5-1","outputTokens":75457,"runtime":"claude","turns":30,"wallClockMs":1119225}},{"artifacts":[],"attempt":1,"bundleHash":"200620c0a9777bc7fd0447ff8df80b160b4fb295eb1b5b7be2a49c842eb943a2","device":"265d2bb313654afc","findings":[],"hash":"f9ddf24e5b4461d5969acc22c1ae2d97b7937b33b9f1abb6efedae02085de744","nodeId":"312a8e7b-fa6e-435e-bc65-afe7471c1144","outcome":"completed","summary":"Implemented the vault, deployment manifest, vendored dependencies, tests and [operational documentation](/home/seat/.identitymd/work/9d7bffba-141b-4e33-be9c-1bfa450d9384/312a8e7b-fa6e-435e-bc65-afe7471c1144/README.md).\n\n- `forge build`, `forge test`, and `forge fmt --check` pass.\n- 59 tests pass, including fuzzing and hostile-token attacks.\n- Runtime: **20,951 bytes**.\n- Worst tested 64-asset redemption: **22.79 million gas**, below 28 million.\n\nNo deployment transactions were sent.","treeHash":"4fb7f2cf3953f90dcbda76573d9ce7872e7954cc","usage":{"cachedInputTokens":1155712,"inputTokens":95876,"model":"gpt-6-astra","outputTokens":42288,"runtime":"codex","turns":7,"wallClockMs":846908}}],"verification":[{"checks":[{"durationMs":4351,"exitCode":0,"name":"build","output":"Compiling 29 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.95s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:26\n    │\n523 │         if (!ok) return (false, 0, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:544:32\n    │\n544 │         if (!readable) return (false, managed[token]);\n    │                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:546:17\n    │\n546 │         return (true, actual > debt ? actual - debt : 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:571:23\n    │\n571 │         uint256 day = (block.timestamp / 86400 + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\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:485:9\n    │\n485 │         emit BandChanged(a.token, a.minAnswer, a.maxAnswer);\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:478:9\n    │\n478 │         emit AssetListed(token, feed, !genesisFinalized);\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:375:9\n    │\n375 │         emit ProposalCreated(id, kind, token, target, value);\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:443:60\n    │\n443 │         if (assetIndex[token] != 0 || token == address(0)) revert InvalidAsset(token);\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:444:42\n    │\n444 │         if (assets.length >= MAX_ASSETS) revert AssetLimit();\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:446:33\n    │\n446 │         if (!ok || value != 18) revert InvalidAsset(token);\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:448:18\n    │\n448 │         if (!ok) revert InvalidAsset(token);\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:450:54\n    │\n450 │         if (!ok || value != uint256(uint160(token))) revert InvalidAsset(token);\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:457:72\n    │\n457 │         if (feedAsset[feed] != address(0) && feedAsset[feed] != token) revert InvalidFeed(feed);\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:459:31\n    │\n459 │         if (!ok || word != 8) revert InvalidFeed(feed);\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:461:59\n    │\n461 │         if (!ok || word == 0 || word > type(uint160).max) revert InvalidFeed(feed);\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:463:35\n    │\n463 │         if (!read || answer <= 0) revert InvalidFeed(feed);\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:452:45\n    │\n452 │         if (answer > type(uint256).max / 4) revert InvalidFeed(feed);\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:482:45\n    │\n482 │         if (answer > type(uint256).max / 4) revert InvalidFeed(a.feed);\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:385:13\n    │\n385 │         if (block.timestamp >= p.createdAt + 14 days) return State.Expired;\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:400:13\n    │\n400 │         if (block.timestamp < p.createdAt + 7 days) revert ProposalNotReady(id);\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:403:17\n    │\n403 │             if (block.timestamp < nextAssetChangeAt) revert ChangeCooldown();\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:418:39\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:418:70\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:414:13\n    │\n414 │             emit FeedChanged(p.token, p.target);\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:439:9\n    │\n439 │         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:421:22\n    │\n421 │             _band(a, uint256(answer));\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/BaskVault.sol:464:16\n    │\n464 │         return uint256(answer);\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/BaskVault.sol:500:35\n    │\n500 │         return !a.genesisAsset && block.timestamp < a.listedAt + 30 days;\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:553:13\n    │\n553 │         if (updatedAt > block.timestamp) return Reason.FuturePrice;\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:554:13\n    │\n554 │         if (block.timestamp - updatedAt > 26 hours) return Reason.StalePrice;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:552:13\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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/BaskVault.sol:552:46\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:586:97\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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:567:13\n    │\n567 │         if (block.timestamp < depositsOpenAt) return (Reason.OpeningDelay, address(0), 0, 0);\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:573:13\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:25\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:37\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:61\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:586:23\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 hours) ++fresh;\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:586:55\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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/BaskMath.sol:17:36\n   │\n17 │             if (d == 0 || hi >= d) revert MathOverflow();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:590:51\n    │\n590 │                 nav += M.mulDiv(managed[a.token], uint256(answer), 1e8);\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/BaskVault.sol:591:47\n    │\n591 │                 if (a.token == token) price = uint256(answer);\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/BaskVault.sol:605:16\n    │\n605 │         return elapsed >= 86400 ? 0 : bucket - M.mulDiv(bucket, elapsed, 86400);\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:636:13\n    │\n636 │         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:654:17\n    │\n654 │                 emit DeficitCleared(t);\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:251:9\n    │\n251 │         emit Transfer(address(0), to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:661:9\n    │\n661 │         emit Deposit(msg.sender, receiver, token, amount, shares, q.fee);\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:683:13\n    │\n683 │         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:258:9\n    │\n258 │         emit Transfer(from, address(0), amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:245:9\n    │\n245 │         emit Transfer(from, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:707:17\n    │\n707 │                 emit LegOwed(msg.sender, token, leg);\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:710:9\n    │\n710 │         emit Redeem(msg.sender, shares, net, 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:695:69\n    │\n695 │             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:725:9\n    │\n725 │         emit LegPaid(token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/BaskVault.sol:747:26\n    │\n747 │         if (amount != 0) this.payLeg(token, to, amount);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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:748:9\n    │\n748 │         emit Claimed(msg.sender, token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:758:9\n    │\n758 │         emit DeficitFlagged(token, shortfall, block.timestamp);\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:763:33\n    │\n763 │         if (loss.amount == 0 || block.timestamp < loss.flaggedAt + 7 days) revert LossNotReady();\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:770:9\n    │\n770 │         emit LossRecognized(token, amount);\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:817:21\n    │\n817 │                 ids[n] = id;\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:33:17\n   │\n33 │         vm.warp(block.timestamp + 72 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:169:28\n    │\n169 │         uint256 dayStart = block.timestamp / 86400 * 86400;\n    │                            ━━━━━━━━━━━━━━━\n170 │         vm.warp(dayStart + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n172 │         vm.warp(dayStart + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n174 │         vm.warp(dayStart + 70199);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n176 │         vm.warp(dayStart + 70200);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n178 │         vm.warp(MONDAY + 5 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n180 │         vm.warp(MONDAY + 6 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n182 │         vm.warp(MONDAY + 7 days + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n234 │         vm.warp(block.timestamp + 1 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:234:17\n    │\n234 │         vm.warp(block.timestamp + 1 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n257 │         vm.warp(MONDAY + 6 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n371 │         vm.warp(block.timestamp + 6 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:371:17\n    │\n371 │         vm.warp(block.timestamp + 6 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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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:69:55\n   │\n69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n   │                                                       ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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/AccountingEdges.t.sol:82:17\n   │\n82 │         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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:93:9\n   │\n93 │         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/AccountingEdges.t.sol:93:17\n   │\n93 │         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/AccountingEdges.t.sol:105:17\n    │\n105 │         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/BasketInvariant.t.sol:46:25\n   │\n46 │         uint256 today = block.timestamp / 1 days * 1 days;\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n50 │         vm.warp(next);\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:230:40\n    │\n230 │         if (mature && recorded != 0 && block.timestamp < time + 7 days) vm.warp(time + 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/Governance.t.sol:64:21\n   │\n64 │         feed.set(0, block.timestamp);\n   │                     ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:68:25\n   │\n68 │         feed.set(100e8, block.timestamp);\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:71:17\n   │\n71 │         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/Governance.t.sol:105:24\n    │\n105 │         uint256 time = block.timestamp;\n    │                        ━━━━━━━━━━━━━━━\n106 │         vm.warp(time + 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/Governance.t.sol:129:17\n    │\n129 │         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/Governance.t.sol:133:17\n    │\n133 │         vm.warp(block.timestamp + 24 hours - 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/Governance.t.sol:144:25\n    │\n144 │         feed.set(401e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:148:25\n    │\n148 │         feed.set(100e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:151:17\n    │\n151 │         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/Governance.t.sol:169:17\n    │\n169 │         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/Governance.t.sol:193:17\n    │\n193 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:237:9\n    │\n237 │         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/Governance.t.sol:237:17\n    │\n237 │         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/Governance.t.sol:258:17\n    │\n258 │         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/Governance.t.sol:260:28\n    │\n260 │         uint256 listedAt = block.timestamp;\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RedemptionAttack.t.sol:215:9\n    │\n215 │         vm.warp(block.timestamp + 1 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/RedemptionAttack.t.sol:215:17\n    │\n215 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:101:17\n    │\n101 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:115:9\n    │\n115 │         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/RevisionFindings.t.sol:115:17\n    │\n115 │         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:69:55\n    │\n 69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n    │                                                       ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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/RevisionFindings.t.sol:127:17\n    │\n127 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:140:9\n    │\n140 │         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/RevisionFindings.t.sol:140:17\n    │\n140 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:159:9\n    │\n159 │         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/RevisionFindings.t.sol:153:31\n    │\n153 │         replacement.set(10e8, block.timestamp);\n    │                               ━━━━━━━━━━━━━━━\n    ‡\n159 │         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/RevisionFindings.t.sol:159:17\n    │\n159 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:176:9\n    │\n176 │         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/RevisionFindings.t.sol:176:17\n    │\n176 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:194:9\n    │\n194 │         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/RevisionFindings.t.sol:194:17\n    │\n194 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:257:9\n    │\n257 │         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/RevisionFindings.t.sol:257:17\n    │\n257 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:279:9\n    │\n279 │         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/RevisionFindings.t.sol:279:17\n    │\n279 │         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\n","passed":true},{"durationMs":5334,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RevisionFindings.t.sol:RevisionQuorumTest\n[PASS] testRetiringOneOfThreeRemovesQuorumDespitePositiveLiveNAV() (gas: 1132783)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.87ms (693.18µs CPU time)\n\nRan 17 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testBandUsesFreshExecutionAnswerOutsideOldBand() (gas: 539896)\n[PASS] testDuplicateTokenFeedAndArrayMismatch() (gas: 1692818)\n[PASS] testFeedReplacementBandAndMetadataRechecked() (gas: 1135044)\n[PASS] testGenesisBatchAndDelay() (gas: 977092)\n[PASS] testGuardianCanCancelExceptItsOwnReplacement() (gas: 490356)\n[PASS] testLaterCloseCancelsEveryEarlierReopen() (gas: 790241)\n[PASS] testListingAndFeedReplacementShareCooldown() (gas: 2683978)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 3102585)\n[PASS] testLoweringNAVCapCancelsAllRaisesAndMaximumIsEnforced() (gas: 621134)\n[PASS] testOwnerCanCancelGuardianReplacement() (gas: 197240)\n[PASS] testOwnershipTwoStepsNoRenounceAndGuardianCannotUnpause() (gas: 308906)\n[PASS] testPendingProposalPaginationExcludesCancelledAndExpired() (gas: 549631)\n[PASS] testProbationCapAndThirtyDayBoundary() (gas: 3361208)\n[PASS] testProposalSevenDayWaitAndSevenDayExecutionWindow() (gas: 478841)\n[PASS] testRetiredAssetSkippedByEveryDepositCheckButStillRedeemed() (gas: 3725485)\n[PASS] testRetirementRequiresClosedAtBothTimesAndIsPermanent() (gas: 859873)\n[PASS] testUnauthorizedAdministrativeCalls() (gas: 525174)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 572.71ms (8.82ms CPU time)\n\nRan 13 tests for test/AccountingEdges.t.sol:AccountingEdgesTest\n[PASS] testFeeRecipientCanRedeemItsOwnShares() (gas: 521739)\n[PASS] testFeeRoundsUpOnBothPathsAndTinyDepositsCannotMint() (gas: 667748)\n[PASS] testFirstDepositMustCoverLockedSharesAndReceiverGetsPositiveAmount() (gas: 749896)\n[PASS] testFullPrecisionArithmeticAndOverflowErrors() (gas: 197220)\n[PASS] testFuzzFullPrecisionAgainstQuotientRemainder(uint256,uint128,uint128) (runs: 256, μ: 4391, ~: 4339)\n[PASS] testFuzzMixedActionAccounting(uint256) (runs: 256, μ: 6396655, ~: 6389316)\n[PASS] testOracleMalformedReturnIsUnavailableButCannotBlockRedeem() (gas: 590805)\n[PASS] testOwedUncoveredStopsTargetDepositEvenWithZeroManaged() (gas: 904993)\n[PASS] testPriceExactlyTwentySixHoursOldAndSeparateMarketQuorum() (gas: 2841862)\n[PASS] testRuntimeHasNoForbiddenEscapeOpcodes() (gas: 9122322)\n[PASS] testStatusCodesForPauseCloseAndUnlisted() (gas: 276732)\n[PASS] testTwoClaimantsReserveDebtBeforeLaterRedemption() (gas: 1121973)\n[PASS] testZeroNAVWithExistingSupplyReverts() (gas: 954567)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 573.36ms (889.51ms CPU time)\n\nRan 12 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testBandOutlierExtractionAndRecoveredPriceLockout() (gas: 2827749)\nLogs:\n  live asset leg after outlier re-centre: 61317677419354838709\n\n[PASS] testCancelledBandShowsSuppliedProofBalanceBaselineError() (gas: 454753)\n[PASS] testEighthSimultaneousListingExpiresBeforeCooldownEnds() (gas: 17883695)\n[PASS] testGuardianProposalCanExecuteBeforePendingOwnerAccepts() (gas: 307502)\n[PASS] testOwnershipCanBeTransferredToCurrentGuardian() (gas: 113955)\n[PASS] testPostGenesisListingOutlierExtractionDespiteProbationCap() (gas: 4210330)\nLogs:\n  live asset leg after outlier listing: 15433972068853523871\n\n[PASS] testRecoveryBeforeRecognitionPreservesManagedBalance() (gas: 665795)\n[PASS] testRetiredPositionExtractionAmplifiesWhenLiveNAVIsSmall() (gas: 1653656)\nLogs:\n  retired asset paid on a $100 deposit: 98509950248756218905\n\n[PASS] testStaleFeedAndOutOfBandReplacementCannotRepairHeldAsset() (gas: 1198791)\n[PASS] testTemporaryZeroReadRecognizedDuringPauseStrandsRecoveredTokens() (gas: 733221)\n[PASS] testZeroNAVPersistsAfterFullLossAndAllUserSharesBurned() (gas: 1425169)\n[PASS] testZeroNAVPersistsAfterRetirementRedemptionNewListingAndDonation() (gas: 4041151)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 2.35s (16.80ms CPU time)\n\nRan 6 tests for test/RedemptionAttack.t.sol:RedemptionAttackTest\n[PASS] test64GasExhaustingBalanceReadsStayUnderGasLimit() (gas: 27129244)\n[PASS] test64GasExhaustingTransfersStayUnderGasLimit() (gas: 24258035)\n[PASS] test64PausedBlockedUpgradedAndMalformedTokens() (gas: 18005173)\n[PASS] test64RetiredUnreadableTokensCannotBlockRedemption() (gas: 19674608)\n[PASS] testAssetLimitAndGlobalBucket() (gas: 19207068)\n[PASS] testFuzz64MixedFailuresPreserveOtherClaimantsAndAccounting(uint256,bool) (runs: 128, μ: 40317020, ~: 40230147)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 2.35s (2.36s CPU time)\n\nRan 10 tests for test/BasketProperties.t.sol:BasketPropertiesTest\n[PASS] testClaimIsCallerSpecificAndCannotBeRepeated() (gas: 754780)\n[PASS] testFuzzDonationCannotChangeNAVQuotesOrManaged(uint256) (runs: 1000, μ: 950523, ~: 950378)\nLogs:\n  Bound result 5184000\n\n[PASS] testFuzzFeeCeilingAtFullUint256Range(uint256) (runs: 1000, μ: 5302, ~: 5317)\n[PASS] testFuzzFirstDepositRoundingAndDistinctReceiver(uint256,uint256,bool) (runs: 1000, μ: 720811, ~: 690790)\nLogs:\n  Bound result 100000000000000\n  Bound result 10213444813\n\n[PASS] testFuzzRepeatedRoundTripsCannotCreateValue(uint256,bool) (runs: 1000, μ: 8436394, ~: 8588670)\nLogs:\n  Bound result 351021500497034823\n\n[PASS] testInfiniteAllowanceSelfTransfersAndFailedTransferAtomicity() (gas: 605847)\n[PASS] testLateRedeemSlippageRollsBackEarlierPaymentsDebtsAndFees() (gas: 1719093)\n[PASS] testPaymentAndDebtEventsIdentifyActualBeneficiary() (gas: 706544)\n[PASS] testRejectedDepositRollsBackPullAllowanceBucketAndShares() (gas: 704322)\n[PASS] testZeroAndOneWeiRedeemsDoNotPayFreeTokens() (gas: 573321)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 2.35s (5.83s CPU time)\n\nRan 24 tests for test/BaskVault.t.sol:BaskVaultTest\n[PASS] testBlockedRecipientDebtAndAlternateClaim() (gas: 977995)\n[PASS] testBucketDecayIsLinearAndFloorsAtZero() (gas: 718871)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesWholeBalance() (gas: 774459)\n[PASS] testDeficitsNeedSevenDaysAndNeverReduceManagedAutomatically() (gas: 721492)\n[PASS] testDeploymentAndConstructorValidation() (gas: 58753)\n[PASS] testDepositSlippageDeadlineReceiverAndExactTransfer() (gas: 1106466)\n[PASS] testDonationsAreExcludedAndShareMathUsesManagedNAV() (gas: 807328)\n[PASS] testERC20TransfersAllowancesAndNoRoleSeizure() (gas: 530167)\n[PASS] testExpensiveTokenCanClaimWithoutPaymentGasLimit() (gas: 1191502)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 712521)\n[PASS] testFirstDepositAndUnsetFee() (gas: 504332)\n[PASS] testFreshnessAndEveryHeldAssetPrice() (gas: 2912661)\n[PASS] testFuzzDepositRedeemConservation(uint96,uint16) (runs: 256, μ: 553272, ~: 553148)\nLogs:\n  Bound result 249000000000000000878\n  Bound result 46\n\n[PASS] testLargerDeficitResetsClockButSameDeficitCannot() (gas: 635326)\n[PASS] testMarketGateBoundaries() (gas: 588240)\n[PASS] testNAVCapAssetCapAndGlobalBucket() (gas: 686310)\n[PASS] testPaymentFailureRollsBackMaliciousTransferEffects() (gas: 601377)\n[PASS] testRecoveredDeficitClearedByDeposit() (gas: 731985)\n[PASS] testRedeemMinimumsAndDeadlineAreUserControls() (gas: 470441)\n[PASS] testRedeemReadsNoFeedAndIgnoresAllAdministrativeGates() (gas: 1192495)\n[PASS] testReentrancyFromDepositAndRedeemAndClaim() (gas: 1131968)\n[PASS] testShortRedemptionUsesAvailableLessExistingDebt() (gas: 702697)\n[PASS] testUnreadableBalanceUsesManagedAndCreatesDebt() (gas: 701699)\n[PASS] testUnreadableUnheldAssetBlocksDeposits() (gas: 273451)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 2.35s (80.53ms CPU time)\n\nRan 2 tests for test/BasketInvariant.t.sol:BasketFeesUnsetInvariantTest\n[PASS] invariant_CustodyDebtLossAndShareConservation() (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | advance        | 1356  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | claim          | 1299  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | confiscate     | 1369  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 2772  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1315  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1376  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | operator       | 1352  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1369  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1382  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenFailure   | 1380  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1414  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 4000000000000000000\n  Bound result 97249307130827280786\n  Bound result 999900000000000353\n  Bound result 4830359493117652626\n  Bound result 405757\n  Bound result 7410\n  Bound result 999900000000093745\n  Bound result 679615524038120910\n  Bound result 29253544093264438541\n  Bound result 100000000000000\n  Bound result 999900000005184001\n  Bound result 1000000000000000001\n  Bound result 823928789637976797\n  Bound result 34037476427863070\n  Bound result 2764800\n  Bound result 123128804486410584\n  Bound result 999900000000001084\n  Bound result 436160000888570857\n  Bound result 100000000000315\n  Bound result 41150970652309465860\n  Bound result 5420\n  Bound result 20741\n  Bound result 470\n  Bound result 2000000000000000000\n  Bound result 52507064612565396183\n  Bound result 9839\n  Bound result 999900000000019960\n  Bound result 999900000000000200\n  Bound result 50000000000000000\n  Bound result 484235632915950212\n  Bound result 8817\n  Bound result 19999999999999800\n  Bound result 448964801421143847\n  Bound result 259200\n  Bound result 999900000000000384\n\n[PASS] testHandlerReachesDebtPartialClaimLossRecoveryAndFullExit() (gas: 2973652)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 40000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 10000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.01s (5.01s CPU time)\n\nRan 2 tests for test/BasketInvariant.t.sol:BasketFeesSetInvariantTest\n[PASS] invariant_CustodyDebtLossAndShareConservation() (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | advance        | 1356  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | claim          | 1299  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | confiscate     | 1369  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 2772  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1315  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1376  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | operator       | 1352  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1369  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1382  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenFailure   | 1380  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1414  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 4000000000000000000\n  Bound result 97249307130827280786\n  Bound result 999900000000000316\n  Bound result 4830359493117652626\n  Bound result 405757\n  Bound result 7125\n  Bound result 999900000000093745\n  Bound result 679615524038120910\n  Bound result 62586044069919730692\n  Bound result 100000000000000\n  Bound result 999900000005184001\n  Bound result 1000000000000000001\n  Bound result 823928789637976797\n  Bound result 97434341657111162\n  Bound result 2764800\n  Bound result 31924722048100127\n  Bound result 999900000000001311\n  Bound result 526511943941530029\n  Bound result 321257784913011079\n  Bound result 499950000000000158\n  Bound result 5247\n  Bound result 19968\n  Bound result 804\n  Bound result 2000000000000000000\n  Bound result 7468\n  Bound result 10086\n  Bound result 950786877730033361\n  Bound result 999900000000000200\n  Bound result 50000000000000000\n  Bound result 484235632915950212\n  Bound result 132085522054998360673\n  Bound result 19999999999999800\n  Bound result 651682169845663387\n  Bound result 259200\n  Bound result 999900000000008536\n\n[PASS] testHandlerReachesDebtPartialClaimLossRecoveryAndFullExit() (gas: 3004340)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 40000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 10000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.23s (5.24s CPU time)\n\nRan 9 test suites in 5.24s (20.78s CPU time): 87 tests passed, 0 failed, 0 skipped (87 total tests)\n","passed":true},{"durationMs":48,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancelProposal(uint256)\",\"BaskVault.claim(address,address)\",\"BaskVault.closeAsset(address)\",\"BaskVault.deposit(address,uint256,address,uint256,uint256)\",\"BaskVault.executeProposal(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.payLeg(address,address,uint256)\",\"BaskVault.proposeAsset(address,address)\",\"BaskVault.proposeAssets(address[],address[])\",\"BaskVault.proposeBand(address)\",\"BaskVault.proposeFeed(address,address)\",\"BaskVault.proposeGuardian(address)\",\"BaskVault.proposeNAVCap(uint256)\",\"BaskVault.proposeReopen(address)\",\"BaskVault.proposeRetire(address)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,uint256[],uint256)\",\"BaskVault.setFeeRecipient(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":148,\"REVIEW.md\":63,\"foundry.toml\":12,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskMath.sol\":54,\"src/BaskVault.sol\":826,\"test/AccountingEdges.t.sol\":211,\"test/BaskVault.t.sol\":449,\"test/BasketInvariant.t.sol\":382,\"test/BasketProperties.t.sol\":215,\"test/Governance.t.sol\":394,\"test/RedemptionAttack.t.sol\":219,\"test/RevisionFindings.t.sol\":291,\"test/TESTING.md\":71,\"test/mocks/Mocks.sol\":208},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"2b474470146020e2d21184204db17529aab3e12f7b6b3d6185a91ce5123b68e8","verifiedTreeHash":"221eafd365f5a6c675db089778712b39273d0176","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":3145,"exitCode":0,"name":"build","output":"Compiling 28 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.83s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:26\n    │\n523 │         if (!ok) return (false, 0, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:544:32\n    │\n544 │         if (!readable) return (false, managed[token]);\n    │                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:546:17\n    │\n546 │         return (true, actual > debt ? actual - debt : 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:571:23\n    │\n571 │         uint256 day = (block.timestamp / 86400 + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\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:485:9\n    │\n485 │         emit BandChanged(a.token, a.minAnswer, a.maxAnswer);\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:478:9\n    │\n478 │         emit AssetListed(token, feed, !genesisFinalized);\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:375:9\n    │\n375 │         emit ProposalCreated(id, kind, token, target, value);\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:443:60\n    │\n443 │         if (assetIndex[token] != 0 || token == address(0)) revert InvalidAsset(token);\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:444:42\n    │\n444 │         if (assets.length >= MAX_ASSETS) revert AssetLimit();\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:446:33\n    │\n446 │         if (!ok || value != 18) revert InvalidAsset(token);\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:448:18\n    │\n448 │         if (!ok) revert InvalidAsset(token);\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:450:54\n    │\n450 │         if (!ok || value != uint256(uint160(token))) revert InvalidAsset(token);\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:457:72\n    │\n457 │         if (feedAsset[feed] != address(0) && feedAsset[feed] != token) revert InvalidFeed(feed);\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:459:31\n    │\n459 │         if (!ok || word != 8) revert InvalidFeed(feed);\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:461:59\n    │\n461 │         if (!ok || word == 0 || word > type(uint160).max) revert InvalidFeed(feed);\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:463:35\n    │\n463 │         if (!read || answer <= 0) revert InvalidFeed(feed);\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:452:45\n    │\n452 │         if (answer > type(uint256).max / 4) revert InvalidFeed(feed);\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:482:45\n    │\n482 │         if (answer > type(uint256).max / 4) revert InvalidFeed(a.feed);\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:385:13\n    │\n385 │         if (block.timestamp >= p.createdAt + 14 days) return State.Expired;\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:400:13\n    │\n400 │         if (block.timestamp < p.createdAt + 7 days) revert ProposalNotReady(id);\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:403:17\n    │\n403 │             if (block.timestamp < nextAssetChangeAt) revert ChangeCooldown();\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:418:39\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:418:70\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:414:13\n    │\n414 │             emit FeedChanged(p.token, p.target);\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:439:9\n    │\n439 │         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:421:22\n    │\n421 │             _band(a, uint256(answer));\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/BaskVault.sol:464:16\n    │\n464 │         return uint256(answer);\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/BaskVault.sol:500:35\n    │\n500 │         return !a.genesisAsset && block.timestamp < a.listedAt + 30 days;\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:553:13\n    │\n553 │         if (updatedAt > block.timestamp) return Reason.FuturePrice;\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:554:13\n    │\n554 │         if (block.timestamp - updatedAt > 26 hours) return Reason.StalePrice;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:552:13\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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/BaskVault.sol:552:46\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:586:97\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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:567:13\n    │\n567 │         if (block.timestamp < depositsOpenAt) return (Reason.OpeningDelay, address(0), 0, 0);\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:573:13\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:25\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:37\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:61\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:586:23\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 hours) ++fresh;\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:586:55\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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/BaskMath.sol:17:36\n   │\n17 │             if (d == 0 || hi >= d) revert MathOverflow();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:590:51\n    │\n590 │                 nav += M.mulDiv(managed[a.token], uint256(answer), 1e8);\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/BaskVault.sol:591:47\n    │\n591 │                 if (a.token == token) price = uint256(answer);\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/BaskVault.sol:605:16\n    │\n605 │         return elapsed >= 86400 ? 0 : bucket - M.mulDiv(bucket, elapsed, 86400);\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:636:13\n    │\n636 │         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:654:17\n    │\n654 │                 emit DeficitCleared(t);\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:251:9\n    │\n251 │         emit Transfer(address(0), to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:661:9\n    │\n661 │         emit Deposit(msg.sender, receiver, token, amount, shares, q.fee);\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:683:13\n    │\n683 │         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:258:9\n    │\n258 │         emit Transfer(from, address(0), amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:245:9\n    │\n245 │         emit Transfer(from, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:707:17\n    │\n707 │                 emit LegOwed(msg.sender, token, leg);\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:710:9\n    │\n710 │         emit Redeem(msg.sender, shares, net, 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:695:69\n    │\n695 │             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:725:9\n    │\n725 │         emit LegPaid(token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/BaskVault.sol:747:26\n    │\n747 │         if (amount != 0) this.payLeg(token, to, amount);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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:748:9\n    │\n748 │         emit Claimed(msg.sender, token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:758:9\n    │\n758 │         emit DeficitFlagged(token, shortfall, block.timestamp);\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:763:33\n    │\n763 │         if (loss.amount == 0 || block.timestamp < loss.flaggedAt + 7 days) revert LossNotReady();\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:770:9\n    │\n770 │         emit LossRecognized(token, amount);\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:817:21\n    │\n817 │                 ids[n] = id;\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:33:17\n   │\n33 │         vm.warp(block.timestamp + 72 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:169:28\n    │\n169 │         uint256 dayStart = block.timestamp / 86400 * 86400;\n    │                            ━━━━━━━━━━━━━━━\n170 │         vm.warp(dayStart + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n172 │         vm.warp(dayStart + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n174 │         vm.warp(dayStart + 70199);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n176 │         vm.warp(dayStart + 70200);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n178 │         vm.warp(MONDAY + 5 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n180 │         vm.warp(MONDAY + 6 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n182 │         vm.warp(MONDAY + 7 days + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n234 │         vm.warp(block.timestamp + 1 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:234:17\n    │\n234 │         vm.warp(block.timestamp + 1 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n257 │         vm.warp(MONDAY + 6 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n371 │         vm.warp(block.timestamp + 6 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:371:17\n    │\n371 │         vm.warp(block.timestamp + 6 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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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:69:55\n   │\n69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n   │                                                       ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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/AccountingEdges.t.sol:82:17\n   │\n82 │         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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:93:9\n   │\n93 │         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/AccountingEdges.t.sol:93:17\n   │\n93 │         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/AccountingEdges.t.sol:105:17\n    │\n105 │         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/BasketInvariant.t.sol:46:25\n   │\n46 │         uint256 today = block.timestamp / 1 days * 1 days;\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n50 │         vm.warp(next);\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:230:40\n    │\n230 │         if (mature && recorded != 0 && block.timestamp < time + 7 days) vm.warp(time + 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/Governance.t.sol:64:21\n   │\n64 │         feed.set(0, block.timestamp);\n   │                     ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:68:25\n   │\n68 │         feed.set(100e8, block.timestamp);\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:71:17\n   │\n71 │         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/Governance.t.sol:105:24\n    │\n105 │         uint256 time = block.timestamp;\n    │                        ━━━━━━━━━━━━━━━\n106 │         vm.warp(time + 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/Governance.t.sol:129:17\n    │\n129 │         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/Governance.t.sol:133:17\n    │\n133 │         vm.warp(block.timestamp + 24 hours - 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/Governance.t.sol:144:25\n    │\n144 │         feed.set(401e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:148:25\n    │\n148 │         feed.set(100e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:151:17\n    │\n151 │         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/Governance.t.sol:169:17\n    │\n169 │         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/Governance.t.sol:193:17\n    │\n193 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:237:9\n    │\n237 │         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/Governance.t.sol:237:17\n    │\n237 │         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/Governance.t.sol:258:17\n    │\n258 │         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/Governance.t.sol:260:28\n    │\n260 │         uint256 listedAt = block.timestamp;\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RedemptionAttack.t.sol:122:9\n    │\n122 │         vm.warp(block.timestamp + 1 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/RedemptionAttack.t.sol:122:17\n    │\n122 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":4531,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 5 tests for test/RedemptionAttack.t.sol:RedemptionAttackTest\n[PASS] test64GasExhaustingBalanceReadsStayUnderGasLimit() (gas: 27129202)\n[PASS] test64GasExhaustingTransfersStayUnderGasLimit() (gas: 24257993)\n[PASS] test64PausedBlockedUpgradedAndMalformedTokens() (gas: 18005123)\n[PASS] test64RetiredUnreadableTokensCannotBlockRedemption() (gas: 19674566)\n[PASS] testAssetLimitAndGlobalBucket() (gas: 19207068)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 123.79ms (79.24ms CPU time)\n\nRan 13 tests for test/AccountingEdges.t.sol:AccountingEdgesTest\n[PASS] testFeeRecipientCanRedeemItsOwnShares() (gas: 521739)\n[PASS] testFeeRoundsUpOnBothPathsAndTinyDepositsCannotMint() (gas: 667748)\n[PASS] testFirstDepositMustCoverLockedSharesAndReceiverGetsPositiveAmount() (gas: 749896)\n[PASS] testFullPrecisionArithmeticAndOverflowErrors() (gas: 197220)\n[PASS] testFuzzFullPrecisionAgainstQuotientRemainder(uint256,uint128,uint128) (runs: 256, μ: 4392, ~: 4339)\n[PASS] testFuzzMixedActionAccounting(uint256) (runs: 256, μ: 6383701, ~: 6401091)\n[PASS] testOracleMalformedReturnIsUnavailableButCannotBlockRedeem() (gas: 590805)\n[PASS] testOwedUncoveredStopsTargetDepositEvenWithZeroManaged() (gas: 904993)\n[PASS] testPriceExactlyTwentySixHoursOldAndSeparateMarketQuorum() (gas: 2841862)\n[PASS] testRuntimeHasNoForbiddenEscapeOpcodes() (gas: 9122322)\n[PASS] testStatusCodesForPauseCloseAndUnlisted() (gas: 276732)\n[PASS] testTwoClaimantsReserveDebtBeforeLaterRedemption() (gas: 1121973)\n[PASS] testZeroNAVWithExistingSupplyReverts() (gas: 954567)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 260.02ms (309.67ms CPU time)\n\nRan 24 tests for test/BaskVault.t.sol:BaskVaultTest\n[PASS] testBlockedRecipientDebtAndAlternateClaim() (gas: 977995)\n[PASS] testBucketDecayIsLinearAndFloorsAtZero() (gas: 718871)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesWholeBalance() (gas: 774459)\n[PASS] testDeficitsNeedSevenDaysAndNeverReduceManagedAutomatically() (gas: 721492)\n[PASS] testDeploymentAndConstructorValidation() (gas: 58753)\n[PASS] testDepositSlippageDeadlineReceiverAndExactTransfer() (gas: 1106466)\n[PASS] testDonationsAreExcludedAndShareMathUsesManagedNAV() (gas: 807328)\n[PASS] testERC20TransfersAllowancesAndNoRoleSeizure() (gas: 530167)\n[PASS] testExpensiveTokenCanClaimWithoutPaymentGasLimit() (gas: 1191502)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 712521)\n[PASS] testFirstDepositAndUnsetFee() (gas: 504332)\n[PASS] testFreshnessAndEveryHeldAssetPrice() (gas: 2912661)\n[PASS] testFuzzDepositRedeemConservation(uint96,uint16) (runs: 256, μ: 553203, ~: 553148)\nLogs:\n  Bound result 249000000000000017250\n  Bound result 1558\n\n[PASS] testLargerDeficitResetsClockButSameDeficitCannot() (gas: 635326)\n[PASS] testMarketGateBoundaries() (gas: 588240)\n[PASS] testNAVCapAssetCapAndGlobalBucket() (gas: 686310)\n[PASS] testPaymentFailureRollsBackMaliciousTransferEffects() (gas: 601377)\n[PASS] testRecoveredDeficitClearedByDeposit() (gas: 731985)\n[PASS] testRedeemMinimumsAndDeadlineAreUserControls() (gas: 470441)\n[PASS] testRedeemReadsNoFeedAndIgnoresAllAdministrativeGates() (gas: 1192495)\n[PASS] testReentrancyFromDepositAndRedeemAndClaim() (gas: 1131968)\n[PASS] testShortRedemptionUsesAvailableLessExistingDebt() (gas: 702697)\n[PASS] testUnreadableBalanceUsesManagedAndCreatesDebt() (gas: 701699)\n[PASS] testUnreadableUnheldAssetBlocksDeposits() (gas: 273451)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 508.07ms (516.14ms CPU time)\n\nRan 17 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testBandUsesFreshExecutionAnswerOutsideOldBand() (gas: 539896)\n[PASS] testDuplicateTokenFeedAndArrayMismatch() (gas: 1692818)\n[PASS] testFeedReplacementBandAndMetadataRechecked() (gas: 1135044)\n[PASS] testGenesisBatchAndDelay() (gas: 977092)\n[PASS] testGuardianCanCancelExceptItsOwnReplacement() (gas: 490356)\n[PASS] testLaterCloseCancelsEveryEarlierReopen() (gas: 790241)\n[PASS] testListingAndFeedReplacementShareCooldown() (gas: 2683978)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 3102585)\n[PASS] testLoweringNAVCapCancelsAllRaisesAndMaximumIsEnforced() (gas: 621134)\n[PASS] testOwnerCanCancelGuardianReplacement() (gas: 197240)\n[PASS] testOwnershipTwoStepsNoRenounceAndGuardianCannotUnpause() (gas: 308906)\n[PASS] testPendingProposalPaginationExcludesCancelledAndExpired() (gas: 549631)\n[PASS] testProbationCapAndThirtyDayBoundary() (gas: 3361208)\n[PASS] testProposalSevenDayWaitAndSevenDayExecutionWindow() (gas: 478841)\n[PASS] testRetiredAssetSkippedByEveryDepositCheckButStillRedeemed() (gas: 3725485)\n[PASS] testRetirementRequiresClosedAtBothTimesAndIsPermanent() (gas: 859873)\n[PASS] testUnauthorizedAdministrativeCalls() (gas: 525174)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 520.35ms (9.50ms CPU time)\n\nRan 10 tests for test/BasketProperties.t.sol:BasketPropertiesTest\n[PASS] testClaimIsCallerSpecificAndCannotBeRepeated() (gas: 754780)\n[PASS] testFuzzDonationCannotChangeNAVQuotesOrManaged(uint256) (runs: 1000, μ: 950494, ~: 950354)\nLogs:\n  Bound result 8811964124124203162540\n\n[PASS] testFuzzFeeCeilingAtFullUint256Range(uint256) (runs: 1000, μ: 5299, ~: 5317)\n[PASS] testFuzzFirstDepositRoundingAndDistinctReceiver(uint256,uint256,bool) (runs: 1000, μ: 720327, ~: 690790)\nLogs:\n  Bound result 49999900000000014401\n  Bound result 14333333334\n\n[PASS] testFuzzRepeatedRoundTripsCannotCreateValue(uint256,bool) (runs: 1000, μ: 8430338, ~: 8271614)\nLogs:\n  Bound result 999999999999999997\n\n[PASS] testInfiniteAllowanceSelfTransfersAndFailedTransferAtomicity() (gas: 605847)\n[PASS] testLateRedeemSlippageRollsBackEarlierPaymentsDebtsAndFees() (gas: 1719093)\n[PASS] testPaymentAndDebtEventsIdentifyActualBeneficiary() (gas: 706544)\n[PASS] testRejectedDepositRollsBackPullAllowanceBucketAndShares() (gas: 704322)\n[PASS] testZeroAndOneWeiRedeemsDoNotPayFreeTokens() (gas: 573321)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 520.41ms (1.67s CPU time)\n\nRan 2 tests for test/BasketInvariant.t.sol:BasketFeesUnsetInvariantTest\n[PASS] invariant_CustodyDebtLossAndShareConservation() (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | advance        | 1314  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | claim          | 1336  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | confiscate     | 1378  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 2746  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1386  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1268  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | operator       | 1365  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1366  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1443  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenFailure   | 1404  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1378  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 33429326380456062855\n  Bound result 396260\n  Bound result 4050\n  Bound result 395133\n  Bound result 9000000000000000000\n  Bound result 1172\n  Bound result 999900000000000014\n  Bound result 999900000000017077\n  Bound result 646515824029774822\n  Bound result 4176\n  Bound result 699999999999993\n  Bound result 874112374\n  Bound result 100\n  Bound result 999900002293517446\n  Bound result 1977\n  Bound result 999900000000057006\n  Bound result 99065\n  Bound result 0\n  Bound result 999900000000001475\n  Bound result 668127\n  Bound result 0\n  Bound result 10000\n  Bound result 212918\n  Bound result 19195\n  Bound result 563239\n  Bound result 33468\n  Bound result 2827\n  Bound result 177257\n  Bound result 999900000000057006\n\n[PASS] testHandlerReachesDebtPartialClaimLossRecoveryAndFullExit() (gas: 2973652)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 40000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 10000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 4.43s (4.42s CPU time)\n\nRan 2 tests for test/BasketInvariant.t.sol:BasketFeesSetInvariantTest\n[PASS] invariant_CustodyDebtLossAndShareConservation() (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | advance        | 1314  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | claim          | 1336  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | confiscate     | 1378  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 2746  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1386  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1268  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | operator       | 1365  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1366  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1443  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenFailure   | 1404  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1378  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 98104326380501625244\n  Bound result 396260\n  Bound result 4048\n  Bound result 395133\n  Bound result 9000000000000000000\n  Bound result 1172\n  Bound result 999900000000000014\n  Bound result 999900000000017935\n  Bound result 646515824029774822\n  Bound result 4175\n  Bound result 699999999999993\n  Bound result 874112374\n  Bound result 100\n  Bound result 999900000000010489\n  Bound result 3145075316\n  Bound result 999900000000057006\n  Bound result 99065\n  Bound result 0\n  Bound result 999900000000001476\n  Bound result 668127\n  Bound result 0\n  Bound result 10000\n  Bound result 212918\n  Bound result 19407\n  Bound result 563239\n  Bound result 33468\n  Bound result 2827\n  Bound result 177257\n  Bound result 999900000000057006\n\n[PASS] testHandlerReachesDebtPartialClaimLossRecoveryAndFullExit() (gas: 3004340)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 40000000000000000000\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 10000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 4.45s (4.45s CPU time)\n\nRan 7 test suites in 4.45s (10.81s CPU time): 73 tests passed, 0 failed, 0 skipped (73 total tests)\n","passed":true},{"durationMs":35,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancelProposal(uint256)\",\"BaskVault.claim(address,address)\",\"BaskVault.closeAsset(address)\",\"BaskVault.deposit(address,uint256,address,uint256,uint256)\",\"BaskVault.executeProposal(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.payLeg(address,address,uint256)\",\"BaskVault.proposeAsset(address,address)\",\"BaskVault.proposeAssets(address[],address[])\",\"BaskVault.proposeBand(address)\",\"BaskVault.proposeFeed(address,address)\",\"BaskVault.proposeGuardian(address)\",\"BaskVault.proposeNAVCap(uint256)\",\"BaskVault.proposeReopen(address)\",\"BaskVault.proposeRetire(address)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,uint256[],uint256)\",\"BaskVault.setFeeRecipient(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":134,\"REVIEW.md\":26,\"foundry.toml\":12,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskMath.sol\":54,\"src/BaskVault.sol\":826,\"test/AccountingEdges.t.sol\":211,\"test/BaskVault.t.sol\":449,\"test/BasketInvariant.t.sol\":382,\"test/BasketProperties.t.sol\":215,\"test/Governance.t.sol\":394,\"test/RedemptionAttack.t.sol\":126,\"test/TESTING.md\":63,\"test/mocks/Mocks.sol\":208},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"82b7e0eb0587004ad02caff84375067c1613855c2b7afd8cd0783a929e17cb72","verifiedTreeHash":"3a75844d74002f78b374c9e5cc1eeca38e344a59","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":2847,"exitCode":0,"name":"build","output":"Compiling 27 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.49s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:26\n    │\n523 │         if (!ok) return (false, 0, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:544:32\n    │\n544 │         if (!readable) return (false, managed[token]);\n    │                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:546:17\n    │\n546 │         return (true, actual > debt ? actual - debt : 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:571:23\n    │\n571 │         uint256 day = (block.timestamp / 86400 + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\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:485:9\n    │\n485 │         emit BandChanged(a.token, a.minAnswer, a.maxAnswer);\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:478:9\n    │\n478 │         emit AssetListed(token, feed, !genesisFinalized);\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:375:9\n    │\n375 │         emit ProposalCreated(id, kind, token, target, value);\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:443:60\n    │\n443 │         if (assetIndex[token] != 0 || token == address(0)) revert InvalidAsset(token);\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:444:42\n    │\n444 │         if (assets.length >= MAX_ASSETS) revert AssetLimit();\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:446:33\n    │\n446 │         if (!ok || value != 18) revert InvalidAsset(token);\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:448:18\n    │\n448 │         if (!ok) revert InvalidAsset(token);\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:450:54\n    │\n450 │         if (!ok || value != uint256(uint160(token))) revert InvalidAsset(token);\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:457:72\n    │\n457 │         if (feedAsset[feed] != address(0) && feedAsset[feed] != token) revert InvalidFeed(feed);\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:459:31\n    │\n459 │         if (!ok || word != 8) revert InvalidFeed(feed);\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:461:59\n    │\n461 │         if (!ok || word == 0 || word > type(uint160).max) revert InvalidFeed(feed);\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:463:35\n    │\n463 │         if (!read || answer <= 0) revert InvalidFeed(feed);\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:452:45\n    │\n452 │         if (answer > type(uint256).max / 4) revert InvalidFeed(feed);\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:482:45\n    │\n482 │         if (answer > type(uint256).max / 4) revert InvalidFeed(a.feed);\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:385:13\n    │\n385 │         if (block.timestamp >= p.createdAt + 14 days) return State.Expired;\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:400:13\n    │\n400 │         if (block.timestamp < p.createdAt + 7 days) revert ProposalNotReady(id);\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:403:17\n    │\n403 │             if (block.timestamp < nextAssetChangeAt) revert ChangeCooldown();\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:418:39\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:418:70\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:414:13\n    │\n414 │             emit FeedChanged(p.token, p.target);\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:439:9\n    │\n439 │         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:421:22\n    │\n421 │             _band(a, uint256(answer));\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/BaskVault.sol:464:16\n    │\n464 │         return uint256(answer);\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/BaskVault.sol:500:35\n    │\n500 │         return !a.genesisAsset && block.timestamp < a.listedAt + 30 days;\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:553:13\n    │\n553 │         if (updatedAt > block.timestamp) return Reason.FuturePrice;\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:554:13\n    │\n554 │         if (block.timestamp - updatedAt > 26 hours) return Reason.StalePrice;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:552:13\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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/BaskVault.sol:552:46\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:586:97\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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:567:13\n    │\n567 │         if (block.timestamp < depositsOpenAt) return (Reason.OpeningDelay, address(0), 0, 0);\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:573:13\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:25\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:37\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:61\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:586:23\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 hours) ++fresh;\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:586:55\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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/BaskMath.sol:17:36\n   │\n17 │             if (d == 0 || hi >= d) revert MathOverflow();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:590:51\n    │\n590 │                 nav += M.mulDiv(managed[a.token], uint256(answer), 1e8);\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/BaskVault.sol:591:47\n    │\n591 │                 if (a.token == token) price = uint256(answer);\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/BaskVault.sol:605:16\n    │\n605 │         return elapsed >= 86400 ? 0 : bucket - M.mulDiv(bucket, elapsed, 86400);\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:636:13\n    │\n636 │         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:654:17\n    │\n654 │                 emit DeficitCleared(t);\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:251:9\n    │\n251 │         emit Transfer(address(0), to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:661:9\n    │\n661 │         emit Deposit(msg.sender, receiver, token, amount, shares, q.fee);\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:683:13\n    │\n683 │         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:258:9\n    │\n258 │         emit Transfer(from, address(0), amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:245:9\n    │\n245 │         emit Transfer(from, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:707:17\n    │\n707 │                 emit LegOwed(msg.sender, token, leg);\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:710:9\n    │\n710 │         emit Redeem(msg.sender, shares, net, 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:695:69\n    │\n695 │             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:725:9\n    │\n725 │         emit LegPaid(token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/BaskVault.sol:747:26\n    │\n747 │         if (amount != 0) this.payLeg(token, to, amount);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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:748:9\n    │\n748 │         emit Claimed(msg.sender, token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:758:9\n    │\n758 │         emit DeficitFlagged(token, shortfall, block.timestamp);\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:763:33\n    │\n763 │         if (loss.amount == 0 || block.timestamp < loss.flaggedAt + 7 days) revert LossNotReady();\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:770:9\n    │\n770 │         emit LossRecognized(token, amount);\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:817:21\n    │\n817 │                 ids[n] = id;\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:33:17\n   │\n33 │         vm.warp(block.timestamp + 72 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:169:28\n    │\n169 │         uint256 dayStart = block.timestamp / 86400 * 86400;\n    │                            ━━━━━━━━━━━━━━━\n170 │         vm.warp(dayStart + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n172 │         vm.warp(dayStart + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n174 │         vm.warp(dayStart + 70199);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n176 │         vm.warp(dayStart + 70200);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n178 │         vm.warp(MONDAY + 5 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n180 │         vm.warp(MONDAY + 6 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n182 │         vm.warp(MONDAY + 7 days + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n234 │         vm.warp(block.timestamp + 1 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:234:17\n    │\n234 │         vm.warp(block.timestamp + 1 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n257 │         vm.warp(MONDAY + 6 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n371 │         vm.warp(block.timestamp + 6 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:371:17\n    │\n371 │         vm.warp(block.timestamp + 6 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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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:69:55\n   │\n69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n   │                                                       ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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/AccountingEdges.t.sol:82:17\n   │\n82 │         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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:93:9\n   │\n93 │         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/AccountingEdges.t.sol:93:17\n   │\n93 │         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/AccountingEdges.t.sol:105:17\n    │\n105 │         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/Governance.t.sol:64:21\n   │\n64 │         feed.set(0, block.timestamp);\n   │                     ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:68:25\n   │\n68 │         feed.set(100e8, block.timestamp);\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:71:17\n   │\n71 │         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/Governance.t.sol:105:24\n    │\n105 │         uint256 time = block.timestamp;\n    │                        ━━━━━━━━━━━━━━━\n106 │         vm.warp(time + 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/Governance.t.sol:129:17\n    │\n129 │         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/Governance.t.sol:133:17\n    │\n133 │         vm.warp(block.timestamp + 24 hours - 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/Governance.t.sol:144:25\n    │\n144 │         feed.set(401e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:148:25\n    │\n148 │         feed.set(100e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:151:17\n    │\n151 │         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/Governance.t.sol:169:17\n    │\n169 │         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/Governance.t.sol:193:17\n    │\n193 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:237:9\n    │\n237 │         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/Governance.t.sol:237:17\n    │\n237 │         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/Governance.t.sol:258:17\n    │\n258 │         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/Governance.t.sol:260:28\n    │\n260 │         uint256 listedAt = block.timestamp;\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RedemptionAttack.t.sol:124:9\n    │\n124 │         vm.warp(block.timestamp + 1 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/RedemptionAttack.t.sol:124:17\n    │\n124 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:101:17\n    │\n101 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:115:9\n    │\n115 │         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/RevisionFindings.t.sol:115:17\n    │\n115 │         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:69:55\n    │\n 69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n    │                                                       ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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/RevisionFindings.t.sol:127:17\n    │\n127 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:140:9\n    │\n140 │         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/RevisionFindings.t.sol:140:17\n    │\n140 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:159:9\n    │\n159 │         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/RevisionFindings.t.sol:153:31\n    │\n153 │         replacement.set(10e8, block.timestamp);\n    │                               ━━━━━━━━━━━━━━━\n    ‡\n159 │         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/RevisionFindings.t.sol:159:17\n    │\n159 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:176:9\n    │\n176 │         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/RevisionFindings.t.sol:176:17\n    │\n176 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:194:9\n    │\n194 │         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/RevisionFindings.t.sol:194:17\n    │\n194 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:257:9\n    │\n257 │         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/RevisionFindings.t.sol:257:17\n    │\n257 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:279:9\n    │\n279 │         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/RevisionFindings.t.sol:279:17\n    │\n279 │         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\n","passed":true},{"durationMs":288,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RevisionFindings.t.sol:RevisionQuorumTest\n[PASS] testRetiringOneOfThreeRemovesQuorumDespitePositiveLiveNAV() (gas: 1132783)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.90ms (826.37µs CPU time)\n\nRan 24 tests for test/BaskVault.t.sol:BaskVaultTest\n[PASS] testBlockedRecipientDebtAndAlternateClaim() (gas: 977995)\n[PASS] testBucketDecayIsLinearAndFloorsAtZero() (gas: 718871)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesWholeBalance() (gas: 774459)\n[PASS] testDeficitsNeedSevenDaysAndNeverReduceManagedAutomatically() (gas: 721492)\n[PASS] testDeploymentAndConstructorValidation() (gas: 58753)\n[PASS] testDepositSlippageDeadlineReceiverAndExactTransfer() (gas: 1106466)\n[PASS] testDonationsAreExcludedAndShareMathUsesManagedNAV() (gas: 807328)\n[PASS] testERC20TransfersAllowancesAndNoRoleSeizure() (gas: 530167)\n[PASS] testExpensiveTokenCanClaimWithoutPaymentGasLimit() (gas: 1191502)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 712521)\n[PASS] testFirstDepositAndUnsetFee() (gas: 504332)\n[PASS] testFreshnessAndEveryHeldAssetPrice() (gas: 2912661)\n[PASS] testFuzzDepositRedeemConservation(uint96,uint16) (runs: 256, μ: 553244, ~: 553148)\nLogs:\n  Bound result 6164819101343489488\n  Bound result 1\n\n[PASS] testLargerDeficitResetsClockButSameDeficitCannot() (gas: 635326)\n[PASS] testMarketGateBoundaries() (gas: 588240)\n[PASS] testNAVCapAssetCapAndGlobalBucket() (gas: 686310)\n[PASS] testPaymentFailureRollsBackMaliciousTransferEffects() (gas: 601377)\n[PASS] testRecoveredDeficitClearedByDeposit() (gas: 731985)\n[PASS] testRedeemMinimumsAndDeadlineAreUserControls() (gas: 470441)\n[PASS] testRedeemReadsNoFeedAndIgnoresAllAdministrativeGates() (gas: 1192495)\n[PASS] testReentrancyFromDepositAndRedeemAndClaim() (gas: 1131968)\n[PASS] testShortRedemptionUsesAvailableLessExistingDebt() (gas: 702697)\n[PASS] testUnreadableBalanceUsesManagedAndCreatesDebt() (gas: 701699)\n[PASS] testUnreadableUnheldAssetBlocksDeposits() (gas: 273451)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 42.50ms (68.96ms CPU time)\n\nRan 5 tests for test/RedemptionAttack.t.sol:RedemptionAttackTest\n[PASS] test64GasExhaustingBalanceReadsStayUnderGasLimit() (gas: 27131630)\nLogs:\n  64-asset redemption gas: 22789402\n\n[PASS] test64GasExhaustingTransfersStayUnderGasLimit() (gas: 24260421)\nLogs:\n  64-asset redemption gas: 19916698\n\n[PASS] test64PausedBlockedUpgradedAndMalformedTokens() (gas: 18007551)\nLogs:\n  64-asset redemption gas: 4668338\n\n[PASS] test64RetiredUnreadableTokensCannotBlockRedemption() (gas: 19676994)\nLogs:\n  64-asset redemption gas: 3891515\n\n[PASS] testAssetLimitAndGlobalBucket() (gas: 19207068)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 138.46ms (87.26ms CPU time)\n\nRan 12 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testBandOutlierExtractionAndRecoveredPriceLockout() (gas: 2827749)\nLogs:\n  live asset leg after outlier re-centre: 61317677419354838709\n\n[PASS] testCancelledBandShowsSuppliedProofBalanceBaselineError() (gas: 454753)\n[PASS] testEighthSimultaneousListingExpiresBeforeCooldownEnds() (gas: 17883695)\n[PASS] testGuardianProposalCanExecuteBeforePendingOwnerAccepts() (gas: 307502)\n[PASS] testOwnershipCanBeTransferredToCurrentGuardian() (gas: 113955)\n[PASS] testPostGenesisListingOutlierExtractionDespiteProbationCap() (gas: 4210330)\nLogs:\n  live asset leg after outlier listing: 15433972068853523871\n\n[PASS] testRecoveryBeforeRecognitionPreservesManagedBalance() (gas: 665795)\n[PASS] testRetiredPositionExtractionAmplifiesWhenLiveNAVIsSmall() (gas: 1653656)\nLogs:\n  retired asset paid on a $100 deposit: 98509950248756218905\n\n[PASS] testStaleFeedAndOutOfBandReplacementCannotRepairHeldAsset() (gas: 1198791)\n[PASS] testTemporaryZeroReadRecognizedDuringPauseStrandsRecoveredTokens() (gas: 733221)\n[PASS] testZeroNAVPersistsAfterFullLossAndAllUserSharesBurned() (gas: 1425169)\n[PASS] testZeroNAVPersistsAfterRetirementRedemptionNewListingAndDonation() (gas: 4041151)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 201.71ms (17.91ms CPU time)\n\nRan 13 tests for test/AccountingEdges.t.sol:AccountingEdgesTest\n[PASS] testFeeRecipientCanRedeemItsOwnShares() (gas: 521739)\n[PASS] testFeeRoundsUpOnBothPathsAndTinyDepositsCannotMint() (gas: 667748)\n[PASS] testFirstDepositMustCoverLockedSharesAndReceiverGetsPositiveAmount() (gas: 749896)\n[PASS] testFullPrecisionArithmeticAndOverflowErrors() (gas: 197220)\n[PASS] testFuzzFullPrecisionAgainstQuotientRemainder(uint256,uint128,uint128) (runs: 256, μ: 4371, ~: 4334)\n[PASS] testFuzzMixedActionAccounting(uint256) (runs: 256, μ: 6387355, ~: 6386773)\n[PASS] testOracleMalformedReturnIsUnavailableButCannotBlockRedeem() (gas: 590805)\n[PASS] testOwedUncoveredStopsTargetDepositEvenWithZeroManaged() (gas: 904993)\n[PASS] testPriceExactlyTwentySixHoursOldAndSeparateMarketQuorum() (gas: 2841862)\n[PASS] testRuntimeHasNoForbiddenEscapeOpcodes() (gas: 9122322)\n[PASS] testStatusCodesForPauseCloseAndUnlisted() (gas: 276732)\n[PASS] testTwoClaimantsReserveDebtBeforeLaterRedemption() (gas: 1121973)\n[PASS] testZeroNAVWithExistingSupplyReverts() (gas: 954567)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 201.70ms (268.56ms CPU time)\n\nRan 17 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testBandUsesFreshExecutionAnswerOutsideOldBand() (gas: 539896)\n[PASS] testDuplicateTokenFeedAndArrayMismatch() (gas: 1692818)\n[PASS] testFeedReplacementBandAndMetadataRechecked() (gas: 1135044)\n[PASS] testGenesisBatchAndDelay() (gas: 977092)\n[PASS] testGuardianCanCancelExceptItsOwnReplacement() (gas: 490356)\n[PASS] testLaterCloseCancelsEveryEarlierReopen() (gas: 790241)\n[PASS] testListingAndFeedReplacementShareCooldown() (gas: 2683978)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 3102585)\n[PASS] testLoweringNAVCapCancelsAllRaisesAndMaximumIsEnforced() (gas: 621134)\n[PASS] testOwnerCanCancelGuardianReplacement() (gas: 197240)\n[PASS] testOwnershipTwoStepsNoRenounceAndGuardianCannotUnpause() (gas: 308906)\n[PASS] testPendingProposalPaginationExcludesCancelledAndExpired() (gas: 549631)\n[PASS] testProbationCapAndThirtyDayBoundary() (gas: 3361208)\n[PASS] testProposalSevenDayWaitAndSevenDayExecutionWindow() (gas: 478841)\n[PASS] testRetiredAssetSkippedByEveryDepositCheckButStillRedeemed() (gas: 3725485)\n[PASS] testRetirementRequiresClosedAtBothTimesAndIsPermanent() (gas: 859873)\n[PASS] testUnauthorizedAdministrativeCalls() (gas: 525174)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 201.72ms (17.66ms CPU time)\n\nRan 6 test suites in 202.60ms (787.99ms CPU time): 72 tests passed, 0 failed, 0 skipped (72 total tests)\n","passed":true},{"durationMs":29,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancelProposal(uint256)\",\"BaskVault.claim(address,address)\",\"BaskVault.closeAsset(address)\",\"BaskVault.deposit(address,uint256,address,uint256,uint256)\",\"BaskVault.executeProposal(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.payLeg(address,address,uint256)\",\"BaskVault.proposeAsset(address,address)\",\"BaskVault.proposeAssets(address[],address[])\",\"BaskVault.proposeBand(address)\",\"BaskVault.proposeFeed(address,address)\",\"BaskVault.proposeGuardian(address)\",\"BaskVault.proposeNAVCap(uint256)\",\"BaskVault.proposeReopen(address)\",\"BaskVault.proposeRetire(address)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,uint256[],uint256)\",\"BaskVault.setFeeRecipient(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":148,\"REVIEW.md\":63,\"foundry.toml\":12,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskMath.sol\":54,\"src/BaskVault.sol\":826,\"test/AccountingEdges.t.sol\":211,\"test/BaskVault.t.sol\":449,\"test/Governance.t.sol\":394,\"test/RedemptionAttack.t.sol\":128,\"test/RevisionFindings.t.sol\":291,\"test/mocks/Mocks.sol\":208},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"87d54f8451701ab8aa50548fb452c14c33657e540eeaf4de59d8951642a19289","verifiedTreeHash":"914f5859b996759af131019e2ae0ca80ce1da0c3","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":2523,"exitCode":0,"name":"build","output":"Compiling 26 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.12s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:26\n    │\n523 │         if (!ok) return (false, 0, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:544:32\n    │\n544 │         if (!readable) return (false, managed[token]);\n    │                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:546:17\n    │\n546 │         return (true, actual > debt ? actual - debt : 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:571:23\n    │\n571 │         uint256 day = (block.timestamp / 86400 + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\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:485:9\n    │\n485 │         emit BandChanged(a.token, a.minAnswer, a.maxAnswer);\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:478:9\n    │\n478 │         emit AssetListed(token, feed, !genesisFinalized);\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:375:9\n    │\n375 │         emit ProposalCreated(id, kind, token, target, value);\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:443:60\n    │\n443 │         if (assetIndex[token] != 0 || token == address(0)) revert InvalidAsset(token);\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:444:42\n    │\n444 │         if (assets.length >= MAX_ASSETS) revert AssetLimit();\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:446:33\n    │\n446 │         if (!ok || value != 18) revert InvalidAsset(token);\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:448:18\n    │\n448 │         if (!ok) revert InvalidAsset(token);\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:450:54\n    │\n450 │         if (!ok || value != uint256(uint160(token))) revert InvalidAsset(token);\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:457:72\n    │\n457 │         if (feedAsset[feed] != address(0) && feedAsset[feed] != token) revert InvalidFeed(feed);\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:459:31\n    │\n459 │         if (!ok || word != 8) revert InvalidFeed(feed);\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:461:59\n    │\n461 │         if (!ok || word == 0 || word > type(uint160).max) revert InvalidFeed(feed);\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:463:35\n    │\n463 │         if (!read || answer <= 0) revert InvalidFeed(feed);\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:452:45\n    │\n452 │         if (answer > type(uint256).max / 4) revert InvalidFeed(feed);\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:482:45\n    │\n482 │         if (answer > type(uint256).max / 4) revert InvalidFeed(a.feed);\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:385:13\n    │\n385 │         if (block.timestamp >= p.createdAt + 14 days) return State.Expired;\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:400:13\n    │\n400 │         if (block.timestamp < p.createdAt + 7 days) revert ProposalNotReady(id);\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:403:17\n    │\n403 │             if (block.timestamp < nextAssetChangeAt) revert ChangeCooldown();\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:418:39\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:418:70\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:414:13\n    │\n414 │             emit FeedChanged(p.token, p.target);\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:439:9\n    │\n439 │         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:421:22\n    │\n421 │             _band(a, uint256(answer));\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/BaskVault.sol:464:16\n    │\n464 │         return uint256(answer);\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/BaskVault.sol:500:35\n    │\n500 │         return !a.genesisAsset && block.timestamp < a.listedAt + 30 days;\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:553:13\n    │\n553 │         if (updatedAt > block.timestamp) return Reason.FuturePrice;\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:554:13\n    │\n554 │         if (block.timestamp - updatedAt > 26 hours) return Reason.StalePrice;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:552:13\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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/BaskVault.sol:552:46\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:586:97\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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:567:13\n    │\n567 │         if (block.timestamp < depositsOpenAt) return (Reason.OpeningDelay, address(0), 0, 0);\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:573:13\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:25\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:37\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:61\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:586:23\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 hours) ++fresh;\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:586:55\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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/BaskMath.sol:17:36\n   │\n17 │             if (d == 0 || hi >= d) revert MathOverflow();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:590:51\n    │\n590 │                 nav += M.mulDiv(managed[a.token], uint256(answer), 1e8);\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/BaskVault.sol:591:47\n    │\n591 │                 if (a.token == token) price = uint256(answer);\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/BaskVault.sol:605:16\n    │\n605 │         return elapsed >= 86400 ? 0 : bucket - M.mulDiv(bucket, elapsed, 86400);\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:636:13\n    │\n636 │         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:654:17\n    │\n654 │                 emit DeficitCleared(t);\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:251:9\n    │\n251 │         emit Transfer(address(0), to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:661:9\n    │\n661 │         emit Deposit(msg.sender, receiver, token, amount, shares, q.fee);\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:683:13\n    │\n683 │         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:258:9\n    │\n258 │         emit Transfer(from, address(0), amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:245:9\n    │\n245 │         emit Transfer(from, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:707:17\n    │\n707 │                 emit LegOwed(msg.sender, token, leg);\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:710:9\n    │\n710 │         emit Redeem(msg.sender, shares, net, 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:695:69\n    │\n695 │             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:725:9\n    │\n725 │         emit LegPaid(token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/BaskVault.sol:747:26\n    │\n747 │         if (amount != 0) this.payLeg(token, to, amount);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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:748:9\n    │\n748 │         emit Claimed(msg.sender, token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:758:9\n    │\n758 │         emit DeficitFlagged(token, shortfall, block.timestamp);\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:763:33\n    │\n763 │         if (loss.amount == 0 || block.timestamp < loss.flaggedAt + 7 days) revert LossNotReady();\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:770:9\n    │\n770 │         emit LossRecognized(token, amount);\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:817:21\n    │\n817 │                 ids[n] = id;\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:33:17\n   │\n33 │         vm.warp(block.timestamp + 72 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:169:28\n    │\n169 │         uint256 dayStart = block.timestamp / 86400 * 86400;\n    │                            ━━━━━━━━━━━━━━━\n170 │         vm.warp(dayStart + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n172 │         vm.warp(dayStart + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n174 │         vm.warp(dayStart + 70199);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n176 │         vm.warp(dayStart + 70200);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n178 │         vm.warp(MONDAY + 5 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n180 │         vm.warp(MONDAY + 6 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n182 │         vm.warp(MONDAY + 7 days + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n234 │         vm.warp(block.timestamp + 1 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:234:17\n    │\n234 │         vm.warp(block.timestamp + 1 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n257 │         vm.warp(MONDAY + 6 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n371 │         vm.warp(block.timestamp + 6 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:371:17\n    │\n371 │         vm.warp(block.timestamp + 6 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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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:69:55\n   │\n69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n   │                                                       ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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/AccountingEdges.t.sol:82:17\n   │\n82 │         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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:93:9\n   │\n93 │         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/AccountingEdges.t.sol:93:17\n   │\n93 │         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/AccountingEdges.t.sol:105:17\n    │\n105 │         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/Governance.t.sol:64:21\n   │\n64 │         feed.set(0, block.timestamp);\n   │                     ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:68:25\n   │\n68 │         feed.set(100e8, block.timestamp);\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:71:17\n   │\n71 │         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/Governance.t.sol:105:24\n    │\n105 │         uint256 time = block.timestamp;\n    │                        ━━━━━━━━━━━━━━━\n106 │         vm.warp(time + 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/Governance.t.sol:129:17\n    │\n129 │         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/Governance.t.sol:133:17\n    │\n133 │         vm.warp(block.timestamp + 24 hours - 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/Governance.t.sol:144:25\n    │\n144 │         feed.set(401e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:148:25\n    │\n148 │         feed.set(100e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:151:17\n    │\n151 │         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/Governance.t.sol:169:17\n    │\n169 │         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/Governance.t.sol:193:17\n    │\n193 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:237:9\n    │\n237 │         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/Governance.t.sol:237:17\n    │\n237 │         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/Governance.t.sol:258:17\n    │\n258 │         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/Governance.t.sol:260:28\n    │\n260 │         uint256 listedAt = block.timestamp;\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RedemptionAttack.t.sol:124:9\n    │\n124 │         vm.warp(block.timestamp + 1 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/RedemptionAttack.t.sol:124:17\n    │\n124 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":286,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 5 tests for test/RedemptionAttack.t.sol:RedemptionAttackTest\n[PASS] test64GasExhaustingBalanceReadsStayUnderGasLimit() (gas: 27131630)\nLogs:\n  64-asset redemption gas: 22789402\n\n[PASS] test64GasExhaustingTransfersStayUnderGasLimit() (gas: 24260421)\nLogs:\n  64-asset redemption gas: 19916698\n\n[PASS] test64PausedBlockedUpgradedAndMalformedTokens() (gas: 18007551)\nLogs:\n  64-asset redemption gas: 4668338\n\n[PASS] test64RetiredUnreadableTokensCannotBlockRedemption() (gas: 19676994)\nLogs:\n  64-asset redemption gas: 3891515\n\n[PASS] testAssetLimitAndGlobalBucket() (gas: 19207068)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 111.65ms (83.68ms CPU time)\n\nRan 17 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testBandUsesFreshExecutionAnswerOutsideOldBand() (gas: 539896)\n[PASS] testDuplicateTokenFeedAndArrayMismatch() (gas: 1692818)\n[PASS] testFeedReplacementBandAndMetadataRechecked() (gas: 1135044)\n[PASS] testGenesisBatchAndDelay() (gas: 977092)\n[PASS] testGuardianCanCancelExceptItsOwnReplacement() (gas: 490356)\n[PASS] testLaterCloseCancelsEveryEarlierReopen() (gas: 790241)\n[PASS] testListingAndFeedReplacementShareCooldown() (gas: 2683978)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 3102585)\n[PASS] testLoweringNAVCapCancelsAllRaisesAndMaximumIsEnforced() (gas: 621134)\n[PASS] testOwnerCanCancelGuardianReplacement() (gas: 197240)\n[PASS] testOwnershipTwoStepsNoRenounceAndGuardianCannotUnpause() (gas: 308906)\n[PASS] testPendingProposalPaginationExcludesCancelledAndExpired() (gas: 549631)\n[PASS] testProbationCapAndThirtyDayBoundary() (gas: 3361208)\n[PASS] testProposalSevenDayWaitAndSevenDayExecutionWindow() (gas: 478841)\n[PASS] testRetiredAssetSkippedByEveryDepositCheckButStillRedeemed() (gas: 3725485)\n[PASS] testRetirementRequiresClosedAtBothTimesAndIsPermanent() (gas: 859873)\n[PASS] testUnauthorizedAdministrativeCalls() (gas: 525174)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 200.44ms (13.85ms CPU time)\n\nRan 24 tests for test/BaskVault.t.sol:BaskVaultTest\n[PASS] testBlockedRecipientDebtAndAlternateClaim() (gas: 977995)\n[PASS] testBucketDecayIsLinearAndFloorsAtZero() (gas: 718871)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesWholeBalance() (gas: 774459)\n[PASS] testDeficitsNeedSevenDaysAndNeverReduceManagedAutomatically() (gas: 721492)\n[PASS] testDeploymentAndConstructorValidation() (gas: 58753)\n[PASS] testDepositSlippageDeadlineReceiverAndExactTransfer() (gas: 1106466)\n[PASS] testDonationsAreExcludedAndShareMathUsesManagedNAV() (gas: 807328)\n[PASS] testERC20TransfersAllowancesAndNoRoleSeizure() (gas: 530167)\n[PASS] testExpensiveTokenCanClaimWithoutPaymentGasLimit() (gas: 1191502)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 712521)\n[PASS] testFirstDepositAndUnsetFee() (gas: 504332)\n[PASS] testFreshnessAndEveryHeldAssetPrice() (gas: 2912661)\n[PASS] testFuzzDepositRedeemConservation(uint96,uint16) (runs: 256, μ: 553206, ~: 553148)\nLogs:\n  Bound result 1910157928026349015\n  Bound result 35\n\n[PASS] testLargerDeficitResetsClockButSameDeficitCannot() (gas: 635326)\n[PASS] testMarketGateBoundaries() (gas: 588240)\n[PASS] testNAVCapAssetCapAndGlobalBucket() (gas: 686310)\n[PASS] testPaymentFailureRollsBackMaliciousTransferEffects() (gas: 601377)\n[PASS] testRecoveredDeficitClearedByDeposit() (gas: 731985)\n[PASS] testRedeemMinimumsAndDeadlineAreUserControls() (gas: 470441)\n[PASS] testRedeemReadsNoFeedAndIgnoresAllAdministrativeGates() (gas: 1192495)\n[PASS] testReentrancyFromDepositAndRedeemAndClaim() (gas: 1131968)\n[PASS] testShortRedemptionUsesAvailableLessExistingDebt() (gas: 702697)\n[PASS] testUnreadableBalanceUsesManagedAndCreatesDebt() (gas: 701699)\n[PASS] testUnreadableUnheldAssetBlocksDeposits() (gas: 273451)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 200.53ms (41.20ms CPU time)\n\nRan 13 tests for test/AccountingEdges.t.sol:AccountingEdgesTest\n[PASS] testFeeRecipientCanRedeemItsOwnShares() (gas: 521739)\n[PASS] testFeeRoundsUpOnBothPathsAndTinyDepositsCannotMint() (gas: 667748)\n[PASS] testFirstDepositMustCoverLockedSharesAndReceiverGetsPositiveAmount() (gas: 749896)\n[PASS] testFullPrecisionArithmeticAndOverflowErrors() (gas: 197220)\n[PASS] testFuzzFullPrecisionAgainstQuotientRemainder(uint256,uint128,uint128) (runs: 256, μ: 4390, ~: 4339)\n[PASS] testFuzzMixedActionAccounting(uint256) (runs: 256, μ: 6336142, ~: 6324272)\n[PASS] testOracleMalformedReturnIsUnavailableButCannotBlockRedeem() (gas: 590805)\n[PASS] testOwedUncoveredStopsTargetDepositEvenWithZeroManaged() (gas: 904993)\n[PASS] testPriceExactlyTwentySixHoursOldAndSeparateMarketQuorum() (gas: 2841862)\n[PASS] testRuntimeHasNoForbiddenEscapeOpcodes() (gas: 9122322)\n[PASS] testStatusCodesForPauseCloseAndUnlisted() (gas: 276732)\n[PASS] testTwoClaimantsReserveDebtBeforeLaterRedemption() (gas: 1121973)\n[PASS] testZeroNAVWithExistingSupplyReverts() (gas: 954567)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 200.55ms (228.92ms CPU time)\n\nRan 4 test suites in 201.21ms (713.17ms CPU time): 59 tests passed, 0 failed, 0 skipped (59 total tests)\n","passed":true},{"durationMs":37,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancelProposal(uint256)\",\"BaskVault.claim(address,address)\",\"BaskVault.closeAsset(address)\",\"BaskVault.deposit(address,uint256,address,uint256,uint256)\",\"BaskVault.executeProposal(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.payLeg(address,address,uint256)\",\"BaskVault.proposeAsset(address,address)\",\"BaskVault.proposeAssets(address[],address[])\",\"BaskVault.proposeBand(address)\",\"BaskVault.proposeFeed(address,address)\",\"BaskVault.proposeGuardian(address)\",\"BaskVault.proposeNAVCap(uint256)\",\"BaskVault.proposeReopen(address)\",\"BaskVault.proposeRetire(address)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,uint256[],uint256)\",\"BaskVault.setFeeRecipient(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":134,\"REVIEW.md\":26,\"foundry.toml\":12,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskMath.sol\":54,\"src/BaskVault.sol\":826,\"test/AccountingEdges.t.sol\":211,\"test/BaskVault.t.sol\":449,\"test/Governance.t.sol\":394,\"test/RedemptionAttack.t.sol\":128,\"test/mocks/Mocks.sol\":208},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a08532a01a378ca33c76ae484935c5e2b96b4a2b80a07a3756ac08880eef41a0","verifiedTreeHash":"b7dabc60b07589bdedbf4c055ee46bbd6cac2d8d","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":2800,"exitCode":0,"name":"build","output":"Compiling 27 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.48s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:26\n    │\n523 │         if (!ok) return (false, 0, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:544:32\n    │\n544 │         if (!readable) return (false, managed[token]);\n    │                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:546:17\n    │\n546 │         return (true, actual > debt ? actual - debt : 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:571:23\n    │\n571 │         uint256 day = (block.timestamp / 86400 + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\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:485:9\n    │\n485 │         emit BandChanged(a.token, a.minAnswer, a.maxAnswer);\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:478:9\n    │\n478 │         emit AssetListed(token, feed, !genesisFinalized);\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:375:9\n    │\n375 │         emit ProposalCreated(id, kind, token, target, value);\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:443:60\n    │\n443 │         if (assetIndex[token] != 0 || token == address(0)) revert InvalidAsset(token);\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:444:42\n    │\n444 │         if (assets.length >= MAX_ASSETS) revert AssetLimit();\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:446:33\n    │\n446 │         if (!ok || value != 18) revert InvalidAsset(token);\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:448:18\n    │\n448 │         if (!ok) revert InvalidAsset(token);\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:450:54\n    │\n450 │         if (!ok || value != uint256(uint160(token))) revert InvalidAsset(token);\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:457:72\n    │\n457 │         if (feedAsset[feed] != address(0) && feedAsset[feed] != token) revert InvalidFeed(feed);\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:459:31\n    │\n459 │         if (!ok || word != 8) revert InvalidFeed(feed);\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:461:59\n    │\n461 │         if (!ok || word == 0 || word > type(uint160).max) revert InvalidFeed(feed);\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:463:35\n    │\n463 │         if (!read || answer <= 0) revert InvalidFeed(feed);\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:452:45\n    │\n452 │         if (answer > type(uint256).max / 4) revert InvalidFeed(feed);\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:482:45\n    │\n482 │         if (answer > type(uint256).max / 4) revert InvalidFeed(a.feed);\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:385:13\n    │\n385 │         if (block.timestamp >= p.createdAt + 14 days) return State.Expired;\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:400:13\n    │\n400 │         if (block.timestamp < p.createdAt + 7 days) revert ProposalNotReady(id);\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:403:17\n    │\n403 │             if (block.timestamp < nextAssetChangeAt) revert ChangeCooldown();\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:418:39\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:418:70\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:414:13\n    │\n414 │             emit FeedChanged(p.token, p.target);\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:439:9\n    │\n439 │         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:421:22\n    │\n421 │             _band(a, uint256(answer));\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/BaskVault.sol:464:16\n    │\n464 │         return uint256(answer);\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/BaskVault.sol:500:35\n    │\n500 │         return !a.genesisAsset && block.timestamp < a.listedAt + 30 days;\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:553:13\n    │\n553 │         if (updatedAt > block.timestamp) return Reason.FuturePrice;\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:554:13\n    │\n554 │         if (block.timestamp - updatedAt > 26 hours) return Reason.StalePrice;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:552:13\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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/BaskVault.sol:552:46\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:586:97\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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:567:13\n    │\n567 │         if (block.timestamp < depositsOpenAt) return (Reason.OpeningDelay, address(0), 0, 0);\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:573:13\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:25\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:37\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:61\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:586:23\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 hours) ++fresh;\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:586:55\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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/BaskMath.sol:17:36\n   │\n17 │             if (d == 0 || hi >= d) revert MathOverflow();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:590:51\n    │\n590 │                 nav += M.mulDiv(managed[a.token], uint256(answer), 1e8);\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/BaskVault.sol:591:47\n    │\n591 │                 if (a.token == token) price = uint256(answer);\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/BaskVault.sol:605:16\n    │\n605 │         return elapsed >= 86400 ? 0 : bucket - M.mulDiv(bucket, elapsed, 86400);\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:636:13\n    │\n636 │         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:654:17\n    │\n654 │                 emit DeficitCleared(t);\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:251:9\n    │\n251 │         emit Transfer(address(0), to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:661:9\n    │\n661 │         emit Deposit(msg.sender, receiver, token, amount, shares, q.fee);\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:683:13\n    │\n683 │         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:258:9\n    │\n258 │         emit Transfer(from, address(0), amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:245:9\n    │\n245 │         emit Transfer(from, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:707:17\n    │\n707 │                 emit LegOwed(msg.sender, token, leg);\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:710:9\n    │\n710 │         emit Redeem(msg.sender, shares, net, 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:695:69\n    │\n695 │             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:725:9\n    │\n725 │         emit LegPaid(token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/BaskVault.sol:747:26\n    │\n747 │         if (amount != 0) this.payLeg(token, to, amount);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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:748:9\n    │\n748 │         emit Claimed(msg.sender, token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:758:9\n    │\n758 │         emit DeficitFlagged(token, shortfall, block.timestamp);\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:763:33\n    │\n763 │         if (loss.amount == 0 || block.timestamp < loss.flaggedAt + 7 days) revert LossNotReady();\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:770:9\n    │\n770 │         emit LossRecognized(token, amount);\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:817:21\n    │\n817 │                 ids[n] = id;\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:33:17\n   │\n33 │         vm.warp(block.timestamp + 72 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:169:28\n    │\n169 │         uint256 dayStart = block.timestamp / 86400 * 86400;\n    │                            ━━━━━━━━━━━━━━━\n170 │         vm.warp(dayStart + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n172 │         vm.warp(dayStart + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n174 │         vm.warp(dayStart + 70199);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n176 │         vm.warp(dayStart + 70200);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n178 │         vm.warp(MONDAY + 5 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n180 │         vm.warp(MONDAY + 6 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n182 │         vm.warp(MONDAY + 7 days + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n234 │         vm.warp(block.timestamp + 1 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:234:17\n    │\n234 │         vm.warp(block.timestamp + 1 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n257 │         vm.warp(MONDAY + 6 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n371 │         vm.warp(block.timestamp + 6 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:371:17\n    │\n371 │         vm.warp(block.timestamp + 6 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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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:69:55\n   │\n69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n   │                                                       ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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/AccountingEdges.t.sol:82:17\n   │\n82 │         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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:93:9\n   │\n93 │         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/AccountingEdges.t.sol:93:17\n   │\n93 │         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/AccountingEdges.t.sol:105:17\n    │\n105 │         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/Governance.t.sol:64:21\n   │\n64 │         feed.set(0, block.timestamp);\n   │                     ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:68:25\n   │\n68 │         feed.set(100e8, block.timestamp);\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:71:17\n   │\n71 │         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/Governance.t.sol:105:24\n    │\n105 │         uint256 time = block.timestamp;\n    │                        ━━━━━━━━━━━━━━━\n106 │         vm.warp(time + 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/Governance.t.sol:129:17\n    │\n129 │         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/Governance.t.sol:133:17\n    │\n133 │         vm.warp(block.timestamp + 24 hours - 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/Governance.t.sol:144:25\n    │\n144 │         feed.set(401e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:148:25\n    │\n148 │         feed.set(100e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:151:17\n    │\n151 │         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/Governance.t.sol:169:17\n    │\n169 │         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/Governance.t.sol:193:17\n    │\n193 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:237:9\n    │\n237 │         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/Governance.t.sol:237:17\n    │\n237 │         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/Governance.t.sol:258:17\n    │\n258 │         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/Governance.t.sol:260:28\n    │\n260 │         uint256 listedAt = block.timestamp;\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RedemptionAttack.t.sol:124:9\n    │\n124 │         vm.warp(block.timestamp + 1 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/RedemptionAttack.t.sol:124:17\n    │\n124 │         vm.warp(block.timestamp + 1 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/RevisionFindings.t.sol:101:17\n    │\n101 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:115:9\n    │\n115 │         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/RevisionFindings.t.sol:115:17\n    │\n115 │         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:69:55\n    │\n 69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n    │                                                       ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:127:9\n    │\n127 │         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/RevisionFindings.t.sol:127:17\n    │\n127 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:140:9\n    │\n140 │         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/RevisionFindings.t.sol:140:17\n    │\n140 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:159:9\n    │\n159 │         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/RevisionFindings.t.sol:153:31\n    │\n153 │         replacement.set(10e8, block.timestamp);\n    │                               ━━━━━━━━━━━━━━━\n    ‡\n159 │         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/RevisionFindings.t.sol:159:17\n    │\n159 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:176:9\n    │\n176 │         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/RevisionFindings.t.sol:176:17\n    │\n176 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:194:9\n    │\n194 │         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/RevisionFindings.t.sol:194:17\n    │\n194 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:257:9\n    │\n257 │         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/RevisionFindings.t.sol:257:17\n    │\n257 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RevisionFindings.t.sol:279:9\n    │\n279 │         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/RevisionFindings.t.sol:279:17\n    │\n279 │         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\n","passed":true},{"durationMs":294,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RevisionFindings.t.sol:RevisionQuorumTest\n[PASS] testRetiringOneOfThreeRemovesQuorumDespitePositiveLiveNAV() (gas: 1132783)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.75ms (754.91µs CPU time)\n\nRan 12 tests for test/RevisionFindings.t.sol:RevisionFindingsTest\n[PASS] testBandOutlierExtractionAndRecoveredPriceLockout() (gas: 2827749)\nLogs:\n  live asset leg after outlier re-centre: 61317677419354838709\n\n[PASS] testCancelledBandShowsSuppliedProofBalanceBaselineError() (gas: 454753)\n[PASS] testEighthSimultaneousListingExpiresBeforeCooldownEnds() (gas: 17883695)\n[PASS] testGuardianProposalCanExecuteBeforePendingOwnerAccepts() (gas: 307502)\n[PASS] testOwnershipCanBeTransferredToCurrentGuardian() (gas: 113955)\n[PASS] testPostGenesisListingOutlierExtractionDespiteProbationCap() (gas: 4210330)\nLogs:\n  live asset leg after outlier listing: 15433972068853523871\n\n[PASS] testRecoveryBeforeRecognitionPreservesManagedBalance() (gas: 665795)\n[PASS] testRetiredPositionExtractionAmplifiesWhenLiveNAVIsSmall() (gas: 1653656)\nLogs:\n  retired asset paid on a $100 deposit: 98509950248756218905\n\n[PASS] testStaleFeedAndOutOfBandReplacementCannotRepairHeldAsset() (gas: 1198791)\n[PASS] testTemporaryZeroReadRecognizedDuringPauseStrandsRecoveredTokens() (gas: 733221)\n[PASS] testZeroNAVPersistsAfterFullLossAndAllUserSharesBurned() (gas: 1425169)\n[PASS] testZeroNAVPersistsAfterRetirementRedemptionNewListingAndDonation() (gas: 4041151)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 20.57ms (14.26ms CPU time)\n\nRan 24 tests for test/BaskVault.t.sol:BaskVaultTest\n[PASS] testBlockedRecipientDebtAndAlternateClaim() (gas: 977995)\n[PASS] testBucketDecayIsLinearAndFloorsAtZero() (gas: 718871)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesWholeBalance() (gas: 774459)\n[PASS] testDeficitsNeedSevenDaysAndNeverReduceManagedAutomatically() (gas: 721492)\n[PASS] testDeploymentAndConstructorValidation() (gas: 58753)\n[PASS] testDepositSlippageDeadlineReceiverAndExactTransfer() (gas: 1106466)\n[PASS] testDonationsAreExcludedAndShareMathUsesManagedNAV() (gas: 807328)\n[PASS] testERC20TransfersAllowancesAndNoRoleSeizure() (gas: 530167)\n[PASS] testExpensiveTokenCanClaimWithoutPaymentGasLimit() (gas: 1191502)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 712521)\n[PASS] testFirstDepositAndUnsetFee() (gas: 504332)\n[PASS] testFreshnessAndEveryHeldAssetPrice() (gas: 2912661)\n[PASS] testFuzzDepositRedeemConservation(uint96,uint16) (runs: 256, μ: 553232, ~: 553148)\nLogs:\n  Bound result 249000000000000000345\n  Bound result 928\n\n[PASS] testLargerDeficitResetsClockButSameDeficitCannot() (gas: 635326)\n[PASS] testMarketGateBoundaries() (gas: 588240)\n[PASS] testNAVCapAssetCapAndGlobalBucket() (gas: 686310)\n[PASS] testPaymentFailureRollsBackMaliciousTransferEffects() (gas: 601377)\n[PASS] testRecoveredDeficitClearedByDeposit() (gas: 731985)\n[PASS] testRedeemMinimumsAndDeadlineAreUserControls() (gas: 470441)\n[PASS] testRedeemReadsNoFeedAndIgnoresAllAdministrativeGates() (gas: 1192495)\n[PASS] testReentrancyFromDepositAndRedeemAndClaim() (gas: 1131968)\n[PASS] testShortRedemptionUsesAvailableLessExistingDebt() (gas: 702697)\n[PASS] testUnreadableBalanceUsesManagedAndCreatesDebt() (gas: 701699)\n[PASS] testUnreadableUnheldAssetBlocksDeposits() (gas: 273451)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 33.84ms (51.87ms CPU time)\n\nRan 5 tests for test/RedemptionAttack.t.sol:RedemptionAttackTest\n[PASS] test64GasExhaustingBalanceReadsStayUnderGasLimit() (gas: 27131630)\nLogs:\n  64-asset redemption gas: 22789402\n\n[PASS] test64GasExhaustingTransfersStayUnderGasLimit() (gas: 24260421)\nLogs:\n  64-asset redemption gas: 19916698\n\n[PASS] test64PausedBlockedUpgradedAndMalformedTokens() (gas: 18007551)\nLogs:\n  64-asset redemption gas: 4668338\n\n[PASS] test64RetiredUnreadableTokensCannotBlockRedemption() (gas: 19676994)\nLogs:\n  64-asset redemption gas: 3891515\n\n[PASS] testAssetLimitAndGlobalBucket() (gas: 19207068)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 103.97ms (81.09ms CPU time)\n\nRan 17 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testBandUsesFreshExecutionAnswerOutsideOldBand() (gas: 539896)\n[PASS] testDuplicateTokenFeedAndArrayMismatch() (gas: 1692818)\n[PASS] testFeedReplacementBandAndMetadataRechecked() (gas: 1135044)\n[PASS] testGenesisBatchAndDelay() (gas: 977092)\n[PASS] testGuardianCanCancelExceptItsOwnReplacement() (gas: 490356)\n[PASS] testLaterCloseCancelsEveryEarlierReopen() (gas: 790241)\n[PASS] testListingAndFeedReplacementShareCooldown() (gas: 2683978)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 3102585)\n[PASS] testLoweringNAVCapCancelsAllRaisesAndMaximumIsEnforced() (gas: 621134)\n[PASS] testOwnerCanCancelGuardianReplacement() (gas: 197240)\n[PASS] testOwnershipTwoStepsNoRenounceAndGuardianCannotUnpause() (gas: 308906)\n[PASS] testPendingProposalPaginationExcludesCancelledAndExpired() (gas: 549631)\n[PASS] testProbationCapAndThirtyDayBoundary() (gas: 3361208)\n[PASS] testProposalSevenDayWaitAndSevenDayExecutionWindow() (gas: 478841)\n[PASS] testRetiredAssetSkippedByEveryDepositCheckButStillRedeemed() (gas: 3725485)\n[PASS] testRetirementRequiresClosedAtBothTimesAndIsPermanent() (gas: 859873)\n[PASS] testUnauthorizedAdministrativeCalls() (gas: 525174)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 208.27ms (24.31ms CPU time)\n\nRan 13 tests for test/AccountingEdges.t.sol:AccountingEdgesTest\n[PASS] testFeeRecipientCanRedeemItsOwnShares() (gas: 521739)\n[PASS] testFeeRoundsUpOnBothPathsAndTinyDepositsCannotMint() (gas: 667748)\n[PASS] testFirstDepositMustCoverLockedSharesAndReceiverGetsPositiveAmount() (gas: 749896)\n[PASS] testFullPrecisionArithmeticAndOverflowErrors() (gas: 197220)\n[PASS] testFuzzFullPrecisionAgainstQuotientRemainder(uint256,uint128,uint128) (runs: 256, μ: 4381, ~: 4339)\n[PASS] testFuzzMixedActionAccounting(uint256) (runs: 256, μ: 6368086, ~: 6384246)\n[PASS] testOracleMalformedReturnIsUnavailableButCannotBlockRedeem() (gas: 590805)\n[PASS] testOwedUncoveredStopsTargetDepositEvenWithZeroManaged() (gas: 904993)\n[PASS] testPriceExactlyTwentySixHoursOldAndSeparateMarketQuorum() (gas: 2841862)\n[PASS] testRuntimeHasNoForbiddenEscapeOpcodes() (gas: 9122322)\n[PASS] testStatusCodesForPauseCloseAndUnlisted() (gas: 276732)\n[PASS] testTwoClaimantsReserveDebtBeforeLaterRedemption() (gas: 1121973)\n[PASS] testZeroNAVWithExistingSupplyReverts() (gas: 954567)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 211.27ms (233.50ms CPU time)\n\nRan 6 test suites in 211.79ms (579.67ms CPU time): 72 tests passed, 0 failed, 0 skipped (72 total tests)\n","passed":true},{"durationMs":35,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancelProposal(uint256)\",\"BaskVault.claim(address,address)\",\"BaskVault.closeAsset(address)\",\"BaskVault.deposit(address,uint256,address,uint256,uint256)\",\"BaskVault.executeProposal(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.payLeg(address,address,uint256)\",\"BaskVault.proposeAsset(address,address)\",\"BaskVault.proposeAssets(address[],address[])\",\"BaskVault.proposeBand(address)\",\"BaskVault.proposeFeed(address,address)\",\"BaskVault.proposeGuardian(address)\",\"BaskVault.proposeNAVCap(uint256)\",\"BaskVault.proposeReopen(address)\",\"BaskVault.proposeRetire(address)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,uint256[],uint256)\",\"BaskVault.setFeeRecipient(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":148,\"REVIEW.md\":63,\"foundry.toml\":12,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskMath.sol\":54,\"src/BaskVault.sol\":826,\"test/AccountingEdges.t.sol\":211,\"test/BaskVault.t.sol\":449,\"test/Governance.t.sol\":394,\"test/RedemptionAttack.t.sol\":128,\"test/RevisionFindings.t.sol\":291,\"test/mocks/Mocks.sol\":208},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"acb68d24e040a0b20746f730f2c2b1cdee8c2df932743adf21ae9aff774d42fc","verifiedTreeHash":"362435de6c54c0f6b4407ff3f2d1c9fd89887533","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":2417,"exitCode":0,"name":"build","output":"Compiling 26 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.10s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:26\n    │\n523 │         if (!ok) return (false, 0, 0);\n    │                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:544:32\n    │\n544 │         if (!readable) return (false, managed[token]);\n    │                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:546:17\n    │\n546 │         return (true, actual > debt ? actual - debt : 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:571:23\n    │\n571 │         uint256 day = (block.timestamp / 86400 + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\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:485:9\n    │\n485 │         emit BandChanged(a.token, a.minAnswer, a.maxAnswer);\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:478:9\n    │\n478 │         emit AssetListed(token, feed, !genesisFinalized);\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:375:9\n    │\n375 │         emit ProposalCreated(id, kind, token, target, value);\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:443:60\n    │\n443 │         if (assetIndex[token] != 0 || token == address(0)) revert InvalidAsset(token);\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:444:42\n    │\n444 │         if (assets.length >= MAX_ASSETS) revert AssetLimit();\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:446:33\n    │\n446 │         if (!ok || value != 18) revert InvalidAsset(token);\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:448:18\n    │\n448 │         if (!ok) revert InvalidAsset(token);\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:450:54\n    │\n450 │         if (!ok || value != uint256(uint160(token))) revert InvalidAsset(token);\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:457:72\n    │\n457 │         if (feedAsset[feed] != address(0) && feedAsset[feed] != token) revert InvalidFeed(feed);\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:459:31\n    │\n459 │         if (!ok || word != 8) revert InvalidFeed(feed);\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:461:59\n    │\n461 │         if (!ok || word == 0 || word > type(uint160).max) revert InvalidFeed(feed);\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:463:35\n    │\n463 │         if (!read || answer <= 0) revert InvalidFeed(feed);\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:452:45\n    │\n452 │         if (answer > type(uint256).max / 4) revert InvalidFeed(feed);\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:482:45\n    │\n482 │         if (answer > type(uint256).max / 4) revert InvalidFeed(a.feed);\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:385:13\n    │\n385 │         if (block.timestamp >= p.createdAt + 14 days) return State.Expired;\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:400:13\n    │\n400 │         if (block.timestamp < p.createdAt + 7 days) revert ProposalNotReady(id);\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:403:17\n    │\n403 │             if (block.timestamp < nextAssetChangeAt) revert ChangeCooldown();\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:418:39\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:418:70\n    │\n418 │             if (!ok || answer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt >= 26 hours) {\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:414:13\n    │\n414 │             emit FeedChanged(p.token, p.target);\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:439:9\n    │\n439 │         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:421:22\n    │\n421 │             _band(a, uint256(answer));\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/BaskVault.sol:464:16\n    │\n464 │         return uint256(answer);\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/BaskVault.sol:500:35\n    │\n500 │         return !a.genesisAsset && block.timestamp < a.listedAt + 30 days;\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:553:13\n    │\n553 │         if (updatedAt > block.timestamp) return Reason.FuturePrice;\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:554:13\n    │\n554 │         if (block.timestamp - updatedAt > 26 hours) return Reason.StalePrice;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:552:13\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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/BaskVault.sol:552:46\n    │\n552 │         if (uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer) return Reason.OutsideBand;\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[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:586:97\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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:567:13\n    │\n567 │         if (block.timestamp < depositsOpenAt) return (Reason.OpeningDelay, address(0), 0, 0);\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:573:13\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:25\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:37\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:573:61\n    │\n573 │         if (day == 0 || day == 6 || secondsToday < 55800 || secondsToday >= 70200) {\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:586:23\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 hours) ++fresh;\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:586:55\n    │\n586 │             if (ok && updatedAt <= block.timestamp && block.timestamp - updatedAt <= 4 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/BaskMath.sol:17:36\n   │\n17 │             if (d == 0 || hi >= d) revert MathOverflow();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:590:51\n    │\n590 │                 nav += M.mulDiv(managed[a.token], uint256(answer), 1e8);\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/BaskVault.sol:591:47\n    │\n591 │                 if (a.token == token) price = uint256(answer);\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/BaskVault.sol:605:16\n    │\n605 │         return elapsed >= 86400 ? 0 : bucket - M.mulDiv(bucket, elapsed, 86400);\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:636:13\n    │\n636 │         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:654:17\n    │\n654 │                 emit DeficitCleared(t);\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:251:9\n    │\n251 │         emit Transfer(address(0), to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:661:9\n    │\n661 │         emit Deposit(msg.sender, receiver, token, amount, shares, q.fee);\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:683:13\n    │\n683 │         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:258:9\n    │\n258 │         emit Transfer(from, address(0), amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:245:9\n    │\n245 │         emit Transfer(from, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:707:17\n    │\n707 │                 emit LegOwed(msg.sender, token, leg);\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:710:9\n    │\n710 │         emit Redeem(msg.sender, shares, net, 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:695:69\n    │\n695 │             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:725:9\n    │\n725 │         emit LegPaid(token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `entered` is updated\n    ╭▸ src/BaskVault.sol:747:26\n    │\n747 │         if (amount != 0) this.payLeg(token, to, amount);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\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:748:9\n    │\n748 │         emit Claimed(msg.sender, token, to, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:758:9\n    │\n758 │         emit DeficitFlagged(token, shortfall, block.timestamp);\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:763:33\n    │\n763 │         if (loss.amount == 0 || block.timestamp < loss.flaggedAt + 7 days) revert LossNotReady();\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:770:9\n    │\n770 │         emit LossRecognized(token, amount);\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:817:21\n    │\n817 │                 ids[n] = id;\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:33:17\n   │\n33 │         vm.warp(block.timestamp + 72 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:169:28\n    │\n169 │         uint256 dayStart = block.timestamp / 86400 * 86400;\n    │                            ━━━━━━━━━━━━━━━\n170 │         vm.warp(dayStart + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n172 │         vm.warp(dayStart + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n174 │         vm.warp(dayStart + 70199);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n176 │         vm.warp(dayStart + 70200);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n178 │         vm.warp(MONDAY + 5 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n180 │         vm.warp(MONDAY + 6 days + 55800);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n182 │         vm.warp(MONDAY + 7 days + 55799);\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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n234 │         vm.warp(block.timestamp + 1 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:234:17\n    │\n234 │         vm.warp(block.timestamp + 1 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n257 │         vm.warp(MONDAY + 6 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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    ‡\n371 │         vm.warp(block.timestamp + 6 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:371:17\n    │\n371 │         vm.warp(block.timestamp + 6 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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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:69:55\n   │\n69 │         return vault.redeem(shares, new uint256[](0), block.timestamp);\n   │                                                       ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:82:9\n   │\n82 │         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/AccountingEdges.t.sol:82:17\n   │\n82 │         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:64:68\n   │\n64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n   │                                                                    ━━━━━━━━━━━━━━━\n   │\n   ⸬  test/AccountingEdges.t.sol:93:9\n   │\n93 │         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/AccountingEdges.t.sol:93:17\n   │\n93 │         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/AccountingEdges.t.sol:105:17\n    │\n105 │         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/Governance.t.sol:64:21\n   │\n64 │         feed.set(0, block.timestamp);\n   │                     ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:68:25\n   │\n68 │         feed.set(100e8, block.timestamp);\n   │                         ━━━━━━━━━━━━━━━\n   ‡\n71 │         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/Governance.t.sol:71:17\n   │\n71 │         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/Governance.t.sol:105:24\n    │\n105 │         uint256 time = block.timestamp;\n    │                        ━━━━━━━━━━━━━━━\n106 │         vm.warp(time + 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/Governance.t.sol:129:17\n    │\n129 │         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/Governance.t.sol:133:17\n    │\n133 │         vm.warp(block.timestamp + 24 hours - 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/Governance.t.sol:144:25\n    │\n144 │         feed.set(401e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:148:25\n    │\n148 │         feed.set(100e8, block.timestamp);\n    │                         ━━━━━━━━━━━━━━━\n    ‡\n151 │         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/Governance.t.sol:151:17\n    │\n151 │         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/Governance.t.sol:169:17\n    │\n169 │         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/Governance.t.sol:193:17\n    │\n193 │         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:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:237:9\n    │\n237 │         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/Governance.t.sol:237:17\n    │\n237 │         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/Governance.t.sol:258:17\n    │\n258 │         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/Governance.t.sol:260:28\n    │\n260 │         uint256 listedAt = block.timestamp;\n    │                            ━━━━━━━━━━━━━━━\n    ‡\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:58:33\n    │\n 58 │             feeds[i].set(100e8, block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Governance.t.sol:267:9\n    │\n267 │         vm.warp(listedAt + 30 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/BaskVault.t.sol:64:68\n    │\n 64 │         return vault.deposit(address(stocks[i]), amount, ALICE, 0, block.timestamp);\n    │                                                                    ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/RedemptionAttack.t.sol:124:9\n    │\n124 │         vm.warp(block.timestamp + 1 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/RedemptionAttack.t.sol:124:17\n    │\n124 │         vm.warp(block.timestamp + 1 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\n","passed":true},{"durationMs":269,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 17 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testBandUsesFreshExecutionAnswerOutsideOldBand() (gas: 539896)\n[PASS] testDuplicateTokenFeedAndArrayMismatch() (gas: 1692818)\n[PASS] testFeedReplacementBandAndMetadataRechecked() (gas: 1135044)\n[PASS] testGenesisBatchAndDelay() (gas: 977092)\n[PASS] testGuardianCanCancelExceptItsOwnReplacement() (gas: 490356)\n[PASS] testLaterCloseCancelsEveryEarlierReopen() (gas: 790241)\n[PASS] testListingAndFeedReplacementShareCooldown() (gas: 2683978)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 3102585)\n[PASS] testLoweringNAVCapCancelsAllRaisesAndMaximumIsEnforced() (gas: 621134)\n[PASS] testOwnerCanCancelGuardianReplacement() (gas: 197240)\n[PASS] testOwnershipTwoStepsNoRenounceAndGuardianCannotUnpause() (gas: 308906)\n[PASS] testPendingProposalPaginationExcludesCancelledAndExpired() (gas: 549631)\n[PASS] testProbationCapAndThirtyDayBoundary() (gas: 3361208)\n[PASS] testProposalSevenDayWaitAndSevenDayExecutionWindow() (gas: 478841)\n[PASS] testRetiredAssetSkippedByEveryDepositCheckButStillRedeemed() (gas: 3725485)\n[PASS] testRetirementRequiresClosedAtBothTimesAndIsPermanent() (gas: 859873)\n[PASS] testUnauthorizedAdministrativeCalls() (gas: 525174)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 4.12ms (10.11ms CPU time)\n\nRan 5 tests for test/RedemptionAttack.t.sol:RedemptionAttackTest\n[PASS] test64GasExhaustingBalanceReadsStayUnderGasLimit() (gas: 27131630)\nLogs:\n  64-asset redemption gas: 22789402\n\n[PASS] test64GasExhaustingTransfersStayUnderGasLimit() (gas: 24260421)\nLogs:\n  64-asset redemption gas: 19916698\n\n[PASS] test64PausedBlockedUpgradedAndMalformedTokens() (gas: 18007551)\nLogs:\n  64-asset redemption gas: 4668338\n\n[PASS] test64RetiredUnreadableTokensCannotBlockRedemption() (gas: 19676994)\nLogs:\n  64-asset redemption gas: 3891515\n\n[PASS] testAssetLimitAndGlobalBucket() (gas: 19207068)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 102.13ms (85.91ms CPU time)\n\nRan 24 tests for test/BaskVault.t.sol:BaskVaultTest\n[PASS] testBlockedRecipientDebtAndAlternateClaim() (gas: 977995)\n[PASS] testBucketDecayIsLinearAndFloorsAtZero() (gas: 718871)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesWholeBalance() (gas: 774459)\n[PASS] testDeficitsNeedSevenDaysAndNeverReduceManagedAutomatically() (gas: 721492)\n[PASS] testDeploymentAndConstructorValidation() (gas: 58753)\n[PASS] testDepositSlippageDeadlineReceiverAndExactTransfer() (gas: 1106466)\n[PASS] testDonationsAreExcludedAndShareMathUsesManagedNAV() (gas: 807328)\n[PASS] testERC20TransfersAllowancesAndNoRoleSeizure() (gas: 530167)\n[PASS] testExpensiveTokenCanClaimWithoutPaymentGasLimit() (gas: 1191502)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 712521)\n[PASS] testFirstDepositAndUnsetFee() (gas: 504332)\n[PASS] testFreshnessAndEveryHeldAssetPrice() (gas: 2912661)\n[PASS] testFuzzDepositRedeemConservation(uint96,uint16) (runs: 256, μ: 553247, ~: 553148)\nLogs:\n  Bound result 249000000000000021837\n  Bound result 7\n\n[PASS] testLargerDeficitResetsClockButSameDeficitCannot() (gas: 635326)\n[PASS] testMarketGateBoundaries() (gas: 588240)\n[PASS] testNAVCapAssetCapAndGlobalBucket() (gas: 686310)\n[PASS] testPaymentFailureRollsBackMaliciousTransferEffects() (gas: 601377)\n[PASS] testRecoveredDeficitClearedByDeposit() (gas: 731985)\n[PASS] testRedeemMinimumsAndDeadlineAreUserControls() (gas: 470441)\n[PASS] testRedeemReadsNoFeedAndIgnoresAllAdministrativeGates() (gas: 1192495)\n[PASS] testReentrancyFromDepositAndRedeemAndClaim() (gas: 1131968)\n[PASS] testShortRedemptionUsesAvailableLessExistingDebt() (gas: 702697)\n[PASS] testUnreadableBalanceUsesManagedAndCreatesDebt() (gas: 701699)\n[PASS] testUnreadableUnheldAssetBlocksDeposits() (gas: 273451)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 189.36ms (42.90ms CPU time)\n\nRan 13 tests for test/AccountingEdges.t.sol:AccountingEdgesTest\n[PASS] testFeeRecipientCanRedeemItsOwnShares() (gas: 521739)\n[PASS] testFeeRoundsUpOnBothPathsAndTinyDepositsCannotMint() (gas: 667748)\n[PASS] testFirstDepositMustCoverLockedSharesAndReceiverGetsPositiveAmount() (gas: 749896)\n[PASS] testFullPrecisionArithmeticAndOverflowErrors() (gas: 197220)\n[PASS] testFuzzFullPrecisionAgainstQuotientRemainder(uint256,uint128,uint128) (runs: 256, μ: 4383, ~: 4339)\n[PASS] testFuzzMixedActionAccounting(uint256) (runs: 256, μ: 6364340, ~: 6357647)\n[PASS] testOracleMalformedReturnIsUnavailableButCannotBlockRedeem() (gas: 590805)\n[PASS] testOwedUncoveredStopsTargetDepositEvenWithZeroManaged() (gas: 904993)\n[PASS] testPriceExactlyTwentySixHoursOldAndSeparateMarketQuorum() (gas: 2841862)\n[PASS] testRuntimeHasNoForbiddenEscapeOpcodes() (gas: 9122322)\n[PASS] testStatusCodesForPauseCloseAndUnlisted() (gas: 276732)\n[PASS] testTwoClaimantsReserveDebtBeforeLaterRedemption() (gas: 1121973)\n[PASS] testZeroNAVWithExistingSupplyReverts() (gas: 954567)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 189.42ms (213.65ms CPU time)\n\nRan 4 test suites in 190.14ms (485.03ms CPU time): 59 tests passed, 0 failed, 0 skipped (59 total tests)\n","passed":true},{"durationMs":24,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancelProposal(uint256)\",\"BaskVault.claim(address,address)\",\"BaskVault.closeAsset(address)\",\"BaskVault.deposit(address,uint256,address,uint256,uint256)\",\"BaskVault.executeProposal(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pauseDeposits()\",\"BaskVault.payLeg(address,address,uint256)\",\"BaskVault.proposeAsset(address,address)\",\"BaskVault.proposeAssets(address[],address[])\",\"BaskVault.proposeBand(address)\",\"BaskVault.proposeFeed(address,address)\",\"BaskVault.proposeGuardian(address)\",\"BaskVault.proposeNAVCap(uint256)\",\"BaskVault.proposeReopen(address)\",\"BaskVault.proposeRetire(address)\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,uint256[],uint256)\",\"BaskVault.setFeeRecipient(address)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\",\"BaskVault.unpauseDeposits()\"],\"files\":{\".gitignore\":2,\"README.md\":134,\"REVIEW.md\":26,\"foundry.toml\":12,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskMath.sol\":54,\"src/BaskVault.sol\":826,\"test/AccountingEdges.t.sol\":211,\"test/BaskVault.t.sol\":449,\"test/Governance.t.sol\":394,\"test/RedemptionAttack.t.sol\":128,\"test/mocks/Mocks.sol\":208},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1239,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/BaskVault.sol:561: BaskVault._depositContext(address) (src/BaskVault.sol#561-597) uses a weak PRNG: \"day = (block.timestamp / 86400 + 4) % 7 (src/BaskVault.sol#571)\"\n[high/medium] weak-prng at src/BaskVault.sol:561: BaskVault._depositContext(address) (src/BaskVault.sol#561-597) uses a weak PRNG: \"secondsToday = block.timestamp % 86400 (src/BaskVault.sol#572)\"\n[high/medium] incorrect-exp at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/BaskMath.sol:8: BaskMath.mulDiv(uint256,uint256,uint256) (src/BaskMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/BaskVault.sol:678: BaskVault.redeem(uint256,uint256[],uint256) (src/BaskVault.sol#678-712) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:488: BaskVault._asset(address) (src/BaskVault.sol#488-492) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:561: BaskVault._depositContext(address) (src/BaskVault.sol#561-597) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:561: BaskVault._depositContext(address) (src/BaskVault.sol#561-597) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:664: BaskVault.previewRedeem(uint256) (src/BaskVault.sol#664-676) uses a dangerous strict equality:\n[medium/medium] uninitialized-local at src/BaskVault.sol:576: BaskVault._depositContext(address).fresh (src/BaskVault.sol#576) is a local variable never initialized\n[low/medium] timestamp at src/BaskVault.sol:240: BaskVault._transfer(address,address,uint256) (src/BaskVault.sol#240-246) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:603: BaskVault.decayedBucket() (src/BaskVault.sol#603-606) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:678: BaskVault.redeem(uint256,uint256[],uint256) (src/BaskVault.sol#678-712) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:664: BaskVault.previewRedeem(uint256) (src/BaskVault.sol#664-676) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:488: BaskVault._asset(address) (src/BaskVault.sol#488-492) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:549: BaskVault._priceReason(BaskVault.Asset,bool,int256,uint256) (src/BaskVault.sol#549-559) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:608: BaskVault._quote(address,uint256) (src/BaskVault.sol#608-625) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:561: BaskVault._depositContext(address) (src/BaskVault.sol#561-597) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:631: BaskVault.deposit(address,uint256,address,uint256,uint256) (src/BaskVault.sol#631-662) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:397: BaskVault.executeProposal(uint256) (src/BaskVault.sol#397-440) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:254: BaskVault._burn(address,uint256) (src/BaskVault.sol#254-259) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:378: BaskVault.proposalState(uint256) (src/BaskVault.sol#378-387) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:499: BaskVault._probation(BaskVault.Asset) (src/BaskVault.sol#499-501) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:442: BaskVault._checkListing(address,address) (src/BaskVault.sol#442-454) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:761: BaskVault.recognizeLoss(address) (src/BaskVault.sol#761-771) uses timestamp for comparisons","passed":true},{"durationMs":247,"exitCode":0,"name":"aderyn","output":"[high] incorrect-caret-operator at src/BaskMath.sol:32: Incorrect use of caret operator\n[high] reentrancy-state-change at src/BaskVault.sol:699: Reentrancy: State change after external call\n[high] weak-randomness at src/BaskVault.sol:572: Weak Randomness\n[low] centralization-risk at src/BaskVault.sol:261: Centralization Risk (13 places)\n[low] costly-loop at src/BaskVault.sol:325: Costly operations inside loop (3 places)\n[low] large-numeric-literal at src/BaskVault.sol:527: Large Numeric Literal\n[low] literal-instead-of-constant at src/BaskMath.sol:52: Literal Instead of Constant (25 places)\n[low] local-variable-shadowing at src/BaskVault.sol:95: Local Variable Shadows State Variable (2 places)\n[low] require-revert-in-loop at src/BaskVault.sol:325: Loop Contains `require`/`revert` (4 places)\n[low] storage-array-length-not-cached at src/BaskVault.sol:577: Storage Array Length not Cached (5 places)\n[low] unchecked-return at src/BaskVault.sol:345: Unchecked Return (3 places)\n[low] uninitialized-local-variable at src/BaskVault.sol:576: Uninitialized Local Variable (5 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"f9ddf24e5b4461d5969acc22c1ae2d97b7937b33b9f1abb6efedae02085de744","verifiedTreeHash":"4fb7f2cf3953f90dcbda76573d9ce7872e7954cc","verifierVersion":"0.1.0+be003835"}]}