{"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":"75b59a69-3f1b-40be-a42a-1343aa91d720","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"85f6204cb2dfae4f584dd9e43f409f56cfacc98aba0eb395182e6d6f1b5101e2","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":"b9bf480f1c94636d253a4e20e7c0108baa5f332d5a366c378a9fa7f0757cbe68","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":"d9be98411a52a6cf19ea0b53d52ceaef2e2ee7ad68c0aea5b509ec1a48777da2","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":"1423e26e8aa55a90bf63e7019b6dada8394194a4fdbc452677b068be62f5c232","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":"163498d6b1f362ef5df7de86feb9664b64184806d6bdae549cc838dbb7c4b1f4","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":"18073358d04c3bbcf5d261b1ff5ed56f37cccd653f168ea7d886f31ba1f54fc2","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":"1a584bf7fca59ddd71f4c07f888e52cd4b59a161f1391f8ce5b46ed352214ab7","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"3328f25322f629ad2136c964c911d5c04c51e510943aab6986e2cd12da2da204","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 (only on chain 4663: tests use mocks under test/ with exactly these functions; no fork tests, no vm.env):\n- Stock Token: ERC-20, 18 decimals, uid() returns bytes32, oraclePaused() returns bool. Its issuer can pause it, block or burn any holder and upgrade it.\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, 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().\nExcept listing in genesis, these owner actions are always proposals: 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); 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.\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 (Mon-Fri 15:30-19:30 UTC all year); 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, 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 every record.\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, probation, managed, short, totalOwed; previewDeposit; previewRedeem; navPerShare; 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 is trusted to pair each token with its true feed; (3) an untransferable asset keeps its feed value until deposits are paused. MUST ATTACK: a paused, blocked or upgraded token during redeem (with 64 assets in any state it stays under 28,000,000 gas); role abuse; any way a role blocks redeem.","parentJobId":null,"planHash":"309c852c3107ab0541106e274f1a1e58e21ebbd5d19ec5ab6d9e38fa5257c923","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"75b59a69-3f1b-40be-a42a-1343aa91d720","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-865-basket"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52114","feedbackHash":"acd2f17cab543de96c785275a50b047f4693f558b820f23e08993efd5e367c6d","nodeKey":"audit_economics","submissionHash":"85f6204cb2dfae4f584dd9e43f409f56cfacc98aba0eb395182e6d6f1b5101e2","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51004","feedbackHash":"016287f54f0d3086c646e1150c1c3ef586f4e6ee1b49405fdb54b8f5d1c67ee1","nodeKey":"audit_flow","submissionHash":"b9bf480f1c94636d253a4e20e7c0108baa5f332d5a366c378a9fa7f0757cbe68","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52124","feedbackHash":"84948c2597c7f7d7ade9187ea1b5cfc4df90bb6cf07ca84d954927d3ec27538c","nodeKey":"audit_judge","submissionHash":"d9be98411a52a6cf19ea0b53d52ceaef2e2ee7ad68c0aea5b509ec1a48777da2","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51451","feedbackHash":"78e199c4e59929f244f01de72a48ee69c8830de5cf086657738a139e52199eaa","nodeKey":"audit_math","submissionHash":"1423e26e8aa55a90bf63e7019b6dada8394194a4fdbc452677b068be62f5c232","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51450","feedbackHash":"07d0ad18b51b440387c0a662c846a820a9930bfb1b5cb83936c3a327307dc622","nodeKey":"audit_permissions","submissionHash":"163498d6b1f362ef5df7de86feb9664b64184806d6bdae549cc838dbb7c4b1f4","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52148","feedbackHash":"c19b3fec28e5b61486b982b5b58bddcf85c0977934319db49a45076ce0d9d546","nodeKey":"build_contract_project","submissionHash":"18073358d04c3bbcf5d261b1ff5ed56f37cccd653f168ea7d886f31ba1f54fc2","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51058","feedbackHash":"f60a68c9a4df26128eb6fa84e05b2b3425870d0621475389d87435f52f2b18de","nodeKey":"manifest","submissionHash":"1a584bf7fca59ddd71f4c07f888e52cd4b59a161f1391f8ce5b46ed352214ab7","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52208","feedbackHash":"2e55f55b022e3f75c1992576e4d50b26ab4d81e049651867b983d57bb513bdb2","nodeKey":"write_foundry_tests","submissionHash":"3328f25322f629ad2136c964c911d5c04c51e510943aab6986e2cd12da2da204","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"9ca685d603f76a35ba23c68903448cef2eb7c426760713779881e38ecb9f560a","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"79373c79d1351eba","findings":[{"citation":"resolved","description":"redeem() burns the full share amount before the asset loop (lines 709/712) and then reduces managed[token] one asset at a time (line 723) immediately before each payLeg self-call (line 728). While payLeg is executing the Stock Token's transfer, totalSupply is already fully reduced but managed for every asset after the current index is still at its pre-redeem value. The views navPerShare() and previewRedeem() have no reentrancy guard and read that mixed state, so a Stock Token whose transfer runs a hook (the brief says issuers can upgrade tokens) can make any contract that prices BASK through those views observe a share value well above the true one. The state-changing paths are protected by nonReentrant, so vault funds are not at risk directly; the exposure is to any external consumer of navPerShare/previewRedeem (collateral valuation, pricing) and the trigger requires issuer-level control of a listed token, which is why this is low. Precision/invariant seam: the invariant NAV/supply is only restored after the loop, and the views do not check `entered`.","line":728,"path":"src/BaskVault.sol","reproduction":"Three assets listed at $100, 10e18 of each deposited (NAV $3,000, supply 2,985e18 after the 0.5% fee is not minted). Asset 0 is a Stock Token whose transfer() calls an observer before moving tokens. User redeems half their shares. Inside the asset-0 leg the observer calls vault.navPerShare() and vault.previewRedeem(1e18). Observed with test/scratch/Probe.t.sol::testReadOnlyReentrancyMidRedeem: navPerShare before = 1.009226e18, mid-redeem = 1.683725e18 (67% inflated), after = 1.014272e18; previewRedeem(1e18)[1] before = 3.347e15, mid = 6.694e15 (exactly doubled), after = 3.364e15. Expected: a view read during a redeem should return a value consistent with either the pre- or post-redeem state (or revert while `entered != 0`). Actual: supply is fully burned while assets 1 and 2 still carry their full managed amounts, so NAV/supply is overstated.","severity":"low","snippet":"            assembly (\"memory-safe\") { paid := call(250000, address(), 0, add(data, 32), mload(data), 0, 0) }","title":"Read-only reentrancy during redeem: navPerShare and previewRedeem report inflated values from inside a leg payment"}],"hash":"1423e26e8aa55a90bf63e7019b6dada8394194a4fdbc452677b068be62f5c232","nodeId":"b2c3c41d-dbac-4a50-baf2-5fefef908f51","outcome":"completed","summary":"The review is complete. The findings file is in place and validated against the source.\n\n**Outcome.** The vault's arithmetic matches the brief. I found one low-severity defect and no loss-of-funds issues in the math, boundary, or numerical-gap areas.\n\n**Finding (low), `src/BaskVault.sol:728`.** Read-only reentrancy during redeem. The function burns the full share amount before the asset loop, then reduces each asset's managed balance just before paying its leg. A Stock Token whose transfer runs a hook can call the unguarded views mid-leg and see supply fully reduced while later assets still hold their pre-redeem managed amounts. Measured with a scratch test: NAV per share read 1.68 mid-redeem against 1.01 before and after, and the preview leg for the next asset read exactly double. Vault funds are safe because every state-changing path is guarded. The exposure is to any external consumer pricing BASK through those views, and the trigger needs issuer-level control of a listed token, so it stays low.\n\n**What held, with concrete checks.**\n- Share issuance, fee ceiling, first-deposit lock, NAV, asset and bucket caps, bucket decay, and redeem legs all round in the vault's favour and match the brief's formulas.\n- A 256-run fuzz confirmed a deposit never lowers NAV per share for existing holders.\n- FullMath is the Uniswap v3 implementation. The slither exponent and divide-before-multiply lines are false positives.\n- The 64-asset redeem worst case measured 22.7M gas with gas-burning transfers and costly readable balances, under the 28M bound.\n- Time boundaries (26h inclusive, band recentre strictly under 26h, 4h freshness inclusive, 72h open, 7-day and 14-day proposal edges, market window) all behave as specified.\n\n**Noted but not reported as defects.** A loss leaving dust managed at a sub-dollar price produces a permanent ZeroNAV deposit lock with supply outstanding. I reproduced it, but it is the brief's mandated behaviour and the README documents it, and it needs an issuer burn.\n\n**Coverage.** All 26 verifier-listed entry points have a row, plus five invariant rows. Only `redeem` carries a finding reference. The scratch probe lives in `test/scratch/Probe.t.sol` and is not part of the deliverable.","treeHash":null,"usage":{"cachedInputTokens":1552552,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":49724,"runtime":"claude","turns":29,"wallClockMs":719259}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f2101c240e0b52a9","findings":[{"citation":"resolved","description":"The brief lists the issuer powers as pause, block, burn and upgrade, and the vault's accounting only ever raises managed[token] inside deposit() (line 644) and lowers it in redeem() (line 723) and recognizeLoss() (line 769). Nothing can raise managed to match a balance that the issuer increased. If a Stock Token implements a stock split as a balance rebase (balances x10, feed answer /10), every redemption leg is still min(managed, available) * net / supply, so holders are paid 1/10 of their true entitlement and the other 9/10 stays in the vault with no path out (no sweep, no removal, no deposit-free managed increase). Until the band is re-centred, the post-split answer is outside [answer/4, answer*4], so _priceOK fails for the held asset and every deposit of any token reverts with InvalidPrice. After an owner band proposal executes (7 days), NAV = managed * newAnswer is 1/10 of the real backing, so navPerShare and deposit pricing undervalue the vault ten-fold while the surplus remains unreachable. This is the mirror image of the LOSSES mechanism, which only handles balances falling below managed; nothing handles balances rising above it. It is an accepted-design-style trust assumption that the brief does not state, so it is reported at low severity for the requester to either document (Stock Tokens never rebase upward) or decide on a scope change.","line":718,"path":"src/BaskVault.sol","reproduction":"Fresh vault, 3 genesis assets, deposits open, feeds at 100e8. (1) USER deposits 100e18 of stocks[0]: managed = 100e18, USER shares = 9_950e18 - 1e15. (2) Issuer rebases: stocks[0].mint(vault, 900e18) (balance 1000e18) and feeds[0].set(10e8, now). (3) depositStatus(stocks[1]) == (InvalidPrice, stocks[0]); every deposit reverts. (4) OWNER proposeBand(stocks[0]); warp +7 days; refresh feeds; executeProposal(id) succeeds; band becomes [2.5e8, 40e8]. (5) navPerShare() == 100_502_512_562_814_070 (about $0.1005 per share) although the vault holds 1000e18 tokens worth $1.005 per share. (6) USER redeems all shares: paid 99_499_990_000_000_000_000 (99.49999e18) of stocks[0]; managed = 0; vault still holds 900.5e18 that no function can ever pay out. Expected (if upward rebases are possible on this chain): redemption pays the holder's pro-rata share of the real balance, or the brief documents that Stock Tokens never rebase upward. Scratch test: test/scratch/Probe.t.sol testSplitRebaseStrandsBalanceAndUndervaluesNAV.","severity":"low","snippet":"            uint256 amount = managed[token];\n            if (available < amount) amount = available;","title":"Trust gap: a positive balance rebase by a Stock Token issuer (e.g. a split) is never reflected in managed, stranding the surplus and undervaluing NAV"},{"citation":"resolved","description":"deposit() requires every listed asset, including closed assets and assets with managed == 0, to have a readable balance. The only mechanisms that react to a damaged asset are flagDeficit/recognizeLoss, and both revert with TransferFailed when the balance is unreadable (lines 754, 766). Assets are never removed and closeAsset does not exclude an asset from the readability scan. So a single issuer upgrading its token to code that reverts on balanceOf, or to no code at all, turns the vault redeem-only forever, even if the vault never held that token. This matches the brief ('no asset short or unreadable', 'never removed') and redeem/claim stay available, so it is reported as a trust-boundary note rather than a defect: the deposit guarantee depends on all up-to-64 third-party issuers indefinitely.","line":554,"path":"src/BaskVault.sol","reproduction":"Fresh vault with 4 genesis assets, deposits open. (1) USER deposits 10e18 of stocks[0]. (2) Issuer of stocks[3] (managed == 0, never deposited) upgrades it: vm.etch(stocks[3], hex''). (3) depositStatus(stocks[0]) == (Unreadable, stocks[3]); deposit of any token reverts DepositUnavailable(Unreadable, stocks[3]). (4) flagDeficit(stocks[3]) reverts TransferFailed(stocks[3]); recognizeLoss is therefore never reachable. (5) GUARDIAN closeAsset(stocks[3]) changes nothing: depositStatus is still Unreadable. (6) USER redeem(all shares) still pays out[0] > 0. Scratch test: test/scratch/Probe2.t.sol testOneUnreadableAssetFreezesAllDepositsForever.","severity":"info","snippet":"            if (!ok) return (Reason.Unreadable, a.token, 0, 0);","title":"Trust note: one Stock Token issuer making its token's balanceOf unreadable permanently freezes deposits of every asset (no loss path, no removal)"},{"citation":"resolved","description":"executeProposal for Kind.Band validates only read success, answer > 0 and age < 26 hours, whereas _priceOK (lines 503-518) additionally requires the answer inside the current band and token.oraclePaused() == false. Execution is permissionless over a 7-day window, so the party that picks the snapshot is whoever calls first, not the owner. A transient answer that deposit pricing rejects (issuer-paused oracle during a corporate action, or a 5x glitch outside the old band) can be locked in as the new band centre. Once the true price returns, it falls outside the new band and deposits into that asset (and, if it has managed > 0, every deposit) revert with InvalidPrice until a further 7-day band proposal executes. This matches the brief's wording ('re-centre a band on the answer at execution, under 26 hours old'), so it is a note on the asymmetry between the two validity rules, not a defect; impact is bounded to deposit availability and a wider accepted price range.","line":386,"path":"src/BaskVault.sol","reproduction":"Fresh vault, 4 genesis assets with band [25e8, 400e8]. (1) OWNER proposeBand(stocks[0]) -> id. (2) warp +7 days; refresh feeds. (3) stocks[0].configure(18, true, false) so oraclePaused() == true; feeds[0].set(500e8, now). depositStatus(stocks[0]) == InvalidPrice. (4) Anyone calls executeProposal(id): succeeds; allAssets()[0].minAnswer == 125e8, maxAnswer == 2000e8. (5) Oracle unpaused, feeds[0].set(100e8, now): depositStatus(stocks[0]) == InvalidPrice (100e8 < 125e8) until another band proposal passes 7 days later. Expected under deposit's own validity rule: execution would reject a paused-oracle answer. Scratch test: test/scratch/Probe2.t.sol testBandRecentreIgnoresOraclePauseAndOldBand.","severity":"info","snippet":"            if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 26 hours) {","title":"Asymmetry note: band re-centre executes on an answer that deposit pricing would reject (oracle paused, outside old band), at a moment chosen by any executor"}],"hash":"163498d6b1f362ef5df7de86feb9664b64184806d6bdae549cc838dbb7c4b1f4","nodeId":"0c7d84a7-d2e4-4e59-b089-ed332ac64238","outcome":"completed","summary":"Review complete. No tracked file was modified; the deliverable is `.imd-findings.json` at the repository root, and my probes live under `test/scratch/` (yours to discard).\n\n**Outcome.** The access-control, trust-gap and asymmetry surface of `BaskVault` holds against the brief. All 26 state-changing entry points are traced and recorded as `holds` except three that carry notes, and four invariant rows are added (owner never equals guardian under any handover ordering, no role can make redeem or claim revert, no external call target is attacker-chosen, runtime is 23,601 bytes). The full suite plus my six probes pass (59 tests).\n\n**What I verified in depth**\n- Every role check matches the manifest: two-step ownership with guardian exclusion on both sides, guardian limited to pause, close and non-guardian cancels, fee recipient set once and never called, self-only `payLeg` reachable only from guarded `redeem` and `claim`.\n- Proposal lifecycle: rechecks at execution for listing, feed, band, guardian and cap, the shared 24-hour cooldown, the 7-day window, and reopen invalidation by any later close.\n- Redeem and claim cannot be blocked by any role or by a paused, blocked, gas-bombing or codeless token; share-price economics are symmetric with and without a fee recipient.\n\n**Findings written (none critical or high, so no proof files)**\n1. **Low, trust gap.** If a Stock Token issuer rebases balances upward (a split), `managed` never follows: redemptions pay the stale accounting amount, the surplus is stranded forever, and after a band re-centre NAV is undervalued. Reproduced with concrete numbers. This issuer power is outside the four the brief lists, so it is flagged for the requester to document or decide.\n2. **Info, trust note.** One issuer making its token's balance unreadable freezes deposits of every asset permanently, since loss recognition also needs a readable balance and assets are never removed. Spec-consistent; redeem still works.\n3. **Info, asymmetry note.** Band re-centre executes on an answer that deposit pricing would reject (oracle paused, outside the old band), and any executor picks the moment within the 7-day window. Spec-consistent; impact is deposit availability only.\n\n**Not reached.** Nothing within my area was left untraced. I did not independently re-derive the 64-asset gas bound beyond running the project's own gas tests, and the live factory and feed pairings on chain 4663 are outside what local mocks can verify.","treeHash":null,"usage":{"cachedInputTokens":1729324,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":57018,"runtime":"claude","turns":33,"wallClockMs":922259}},{"artifacts":[],"attempt":1,"bundleHash":"875ddf98a2b40c166a13a7015521db374779e2c3ab7d4cf38ea1dbe1b2829f3b","device":"94220c4a6ab72976","findings":[],"hash":"18073358d04c3bbcf5d261b1ff5ed56f37cccd653f168ea7d886f31ba1f54fc2","nodeId":"d9c11432-6736-4982-b981-b22966a71ea3","outcome":"completed","summary":"Implemented [BaskVault](src/BaskVault.sol), deployment manifest, offline test dependencies, and [operational documentation](README.md).\n\nVerified:\n\n- `forge build` passes.\n- `forge test`: 53 tests pass.\n- `forge fmt --check` passes.\n- Runtime: 23,601 bytes; protected opcode scan passes.\n- Highest measured 64-asset redemption: 22,663,996 gas, below 28 million.","treeHash":"e5bff5da9fb0b7521605edf24d7f43fd0a63331f","usage":{"cachedInputTokens":3421952,"inputTokens":112391,"model":"gpt-6-astra","outputTokens":48086,"runtime":"codex","turns":9,"wallClockMs":1281994}},{"artifacts":[],"attempt":1,"bundleHash":"72491b18e795fe64b6f18d28f6a5242d0210ea842440c66452fd2e5bcd710580","device":"99fdbd4812d28337","findings":[],"hash":"1a584bf7fca59ddd71f4c07f888e52cd4b59a161f1391f8ce5b46ed352214ab7","nodeId":"e4907966-d1a4-4646-9b01-cc4febd2a274","outcome":"completed","summary":"Updated only [launch.json](/root/.identitymd/work/75b59a69-3f1b-40be-a42a-1343aa91d720/e4907966-d1a4-4646-9b01-cc4febd2a274/launch.json), preserving the required constructor literals and documenting supply behavior and accepted risks.\n\nValidation passed: manifest constraints, constructor ABI, `forge build`, and all 53 tests. Runtime is 23,601 bytes; tested 64-asset redemptions stayed below 28 million gas.","treeHash":"f0938dfa16eff473d631c6b8dfdd2dc7fd426724","usage":{"cachedInputTokens":338432,"inputTokens":34529,"model":"gpt-6-astra","outputTokens":3425,"runtime":"codex","turns":4,"wallClockMs":118169}},{"artifacts":[],"attempt":1,"bundleHash":"e00784244def153151e5183893e1b2121908ed54b5c5352d7d11c28fb870ce07","device":"9676188abd3783f2","findings":[],"hash":"3328f25322f629ad2136c964c911d5c04c51e510943aab6986e2cd12da2da204","nodeId":"c5623807-2a39-47bc-8505-ee31112bb1eb","outcome":"completed","summary":"Added multi-actor invariants, repeated round-trip fuzzing, and adversarial permission, claim, proposal, and event tests.\n\nValidation passed: `forge build` and all **63 tests**, including **65,536 random handler calls** with zero unexpected reverts.\n\nOnly `test/**` changed. No reproducible contract defects found.","treeHash":"58fc606781f805ef64054ada47b07a08c5ecef34","usage":{"cachedInputTokens":4049920,"inputTokens":122469,"model":"gpt-6-astra","outputTokens":22335,"runtime":"codex","turns":10,"wallClockMs":847937}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"918f8261a6fd589c","findings":[{"citation":"resolved","description":"redeem distributes min(managed, available) only, nothing ever raises managed[token], and the brief forbids rescue/sweep. So any balance the issuer credits to the vault's address without a deposit is unreachable forever. Two ordinary events produce it: (a) a Stock Token corporate action settled on-chain as a balance change (a 2:1 split that doubles holder balances while the feed halves; a dividend reinvested as extra tokens); (b) an issuer freeze/burn that is flagged and recognized via recognizeLoss (managed drops to available) and is later reversed by the issuer re-crediting the vault. In both cases NAV (managed x price) also undercounts the vault's holdings, so new depositors buy in below true value while the surplus itself is never distributable. Accepted-design items (1)-(3) do not cover this; the LOSSES section only lowers managed. Economics for case (a): vault holds 100 tokens at $100 (NAV $10,000, one holder); split credits +100 and price becomes $50; the holder's full redemption returns 99.5 tokens worth $4,975 and 100.5 tokens ($5,025) stay in the vault forever. Case (b): a 100-token custody balance burned then restored yields a redemption of 0 tokens while the vault holds 100. Fixing this needs a scope decision (e.g. a symmetrical, anyone-callable recognition of available above managed, bounded by balance - totalOwed), which the build rules currently forbid; reporting so the requester can decide rather than discover it after the first split.","line":718,"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 ProofStock {\n    bytes32 public uid;\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    constructor(bytes32 id) { uid = id; }\n    function oraclePaused() external pure returns (bool) { return false; }\n    function mint(address to, uint256 amount) external { balanceOf[to] += amount; }\n    function burn(address from, uint256 amount) external { balanceOf[from] -= amount; }\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        return true;\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    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n}\n\ncontract ProofFactory {\n    mapping(bytes32 => address) public tokenAddress;\n    function set(bytes32 id, address token) external { tokenAddress[id] = token; }\n}\n\ncontract ProofFeed {\n    uint8 public constant decimals = 8;\n    address public constant aggregator = address(1);\n    int256 public answer = 100e8;\n    uint256 public updatedAt;\n    function set(int256 a, uint256 t) external { answer = a; updatedAt = t; }\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// Tokens credited to the vault by the issuer (a stock split, an in-kind dividend, or a custody\n/// balance restored after recognizeLoss) can never reach shareholders: nothing raises managed and\n/// there is no other path out. The vault ends holding tokens that no redemption can distribute.\ncontract StrandedBalanceProof is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    address constant USER = address(0xBEEF);\n    uint256 constant MONDAY = 1_767_628_800; // Monday 2026-01-05 16:00 UTC\n    BaskVault vault;\n    ProofStock[] stocks;\n    ProofFeed[] feeds;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(MONDAY - 4 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        ProofFactory impl = new ProofFactory();\n        vm.etch(vault.STOCK_FACTORY(), address(impl).code);\n        ProofFactory factory = ProofFactory(vault.STOCK_FACTORY());\n        for (uint256 i; i < 3; ++i) {\n            ProofStock s = new ProofStock(bytes32(i + 1));\n            ProofFeed f = new ProofFeed();\n            f.set(100e8, block.timestamp);\n            factory.set(s.uid(), address(s));\n            s.mint(USER, 1_000_000e18);\n            vm.prank(USER);\n            s.approve(address(vault), type(uint256).max);\n            stocks.push(s);\n            feeds.push(f);\n            vm.prank(OWNER);\n            vault.proposeAsset(address(s), address(f));\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n        vm.warp(MONDAY);\n        for (uint256 i; i < 3; ++i) feeds[i].set(100e8, block.timestamp);\n    }\n\n    function testSplitCreditReachesShareholders() public {\n        vm.prank(USER);\n        vault.deposit(address(stocks[0]), 100e18, USER, 0, block.timestamp); // managed 100\n        // Issuer processes a 2:1 split: every holder's balance doubles, the feed halves.\n        stocks[0].mint(address(vault), 100e18);\n        feeds[0].set(50e8, block.timestamp);\n        assertEq(stocks[0].balanceOf(address(vault)), 200e18);\n\n        // USER holds every share except the 1e15 locked ones; redeeming them all should return\n        // (almost) the vault's whole balance of stock 0.\n        uint256 shares = vault.balanceOf(USER);\n        vm.prank(USER);\n        uint256[] memory out = vault.redeem(shares, new uint256[](0), block.timestamp);\n        assertGt(out[0], 150e18, \"split credit never reaches shareholders: only managed is distributed\");\n        assertLt(stocks[0].balanceOf(address(vault)), 50e18, \"tokens stranded in the vault\");\n    }\n\n    function testRestoredCustodyReachesShareholders() public {\n        vm.prank(USER);\n        vault.deposit(address(stocks[0]), 100e18, USER, 0, block.timestamp);\n        stocks[0].burn(address(vault), 100e18); // issuer freezes and burns the custody balance\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        stocks[0].mint(address(vault), 100e18); // issuer restores the balance\n        uint256 shares = vault.balanceOf(USER);\n        vm.prank(USER);\n        uint256[] memory out = vault.redeem(shares, new uint256[](0), block.timestamp);\n        assertGt(out[0], 90e18, \"restored custody never reaches shareholders\");\n    }\n}","reproduction":"State: genesis with 3 assets, deposits open, USER deposits 100e18 of stock0 at answer 100e8 (managed[stock0]=100e18, totalSupply=9_950e18+... USER holds all but 1e15). Step 1: issuer mints 100e18 of stock0 to the vault (split) and feed answer becomes 50e8. Step 2: USER calls redeem(balanceOf(USER), [], now). Expected (per the vault's purpose of returning holders' pro-rata assets): ~199e18 stock0 returned, vault near empty. Actual: amounts[0] = 99_499_990_000_000_000_000 (99.5e18) and stock0.balanceOf(vault) = 100.5e18 remains unreachable; navPerShare before redeem reported $5,000 for $10,000 of tokens. Variant: deposit 100e18, issuer burns the vault's 100e18, flagDeficit, +7 days, recognizeLoss (managed=0), issuer mints 100e18 back; redeem all shares returns amounts[0]=0 while the vault holds 100e18. Run: forge test --match-path test/scratch/StrandedProof.t.sol (both tests fail on current code).","severity":"medium","snippet":"            uint256 amount = managed[token];\n            if (available < amount) amount = available;","title":"Tokens credited to the vault above managed (stock split, in-kind dividend, custody restored after recognizeLoss) are permanently stranded and lost to shareholders"},{"citation":"resolved","description":"navPerShare applies the deposit-time price validity rule (updatedAt within 26 hours, in band, oraclePaused false) and reverts on the first managed asset that fails it. Chainlink equity feeds stop updating outside market sessions, so from roughly Saturday 22:00 UTC until the first Monday round every call reverts with DepositUnavailable(InvalidPrice, token), and a single halted or out-of-band asset makes it revert all week. The brief lists navPerShare as a required view; the sibling view allAssets tolerates failed reads (zero answer) and previewRedeem never reads prices, so this view is strictly less available than the rest. Integrators and the fee recipient cannot read NAV during the periods when it matters most (losses, halts). Impact is informational/availability only; no funds move.","line":810,"path":"src/BaskVault.sol","reproduction":"Monday 16:00 UTC, USER deposits 10e18 of stock0 (feed updatedAt = now). Call navPerShare(): returns 1_005_025_125_628_140_703 (> 0). Warp +26 hours + 1 second with feeds untouched. Call navPerShare(): expected a NAV figure (or a stale indicator); actual revert DepositUnavailable(10 /*InvalidPrice*/, stock0). Same result with stock0.oraclePaused() == true or the answer outside [minAnswer, maxAnswer].","severity":"low","snippet":"            if (!_priceOK(a, ok, answer, updated)) revert DepositUnavailable(Reason.InvalidPrice, a.token);","title":"navPerShare reverts whenever any managed asset's price is invalid (every weekend and Monday pre-update, trading halts), so the only NAV view is unavailable most of the week"},{"citation":"resolved","description":"claim pays min(owed, balance) without regard to managed. A redeem during an issuer pause converts the caller's pro-rata share into an owed amount (managed falls, totalOwed rises) that later takes priority over everything still managed. If the issuer afterwards burns or freezes part of the vault's custody balance, owed creditors collect 100% first and the shareholders who did not redeem bear all of the loss, beyond their pro-rata part. This is written in the brief ('pays min(caller's owed, vault balance)') and is reported as an economic property for the requester to confirm: during any pause of a Stock Token the dominant strategy for every holder is to redeem immediately to become senior, i.e. the design rewards a run on the vault exactly when the token is distressed. Concrete numbers: two equal holders (100 tokens each deposited); issuer pauses transfers; holder A redeems all and is owed 99.749 tokens; issuer burns 100 of the vault's 200 tokens; A claims 99.749 in full; holder B's full redemption yields 0.249 tokens (vault left with 0.00125). B lost ~$9,975 of $10,000, A lost ~$25 (fees) although the haircut was 50% of custody.","line":744,"path":"src/BaskVault.sol","reproduction":"USER deposits 100e18 stock0, OTHER deposits 100e18 stock0 (managed 200e18). stocks[0].modes(1,0) (transfers revert). USER redeem(balanceOf(USER)): amounts[0]=99_749_363_408_521_303_258 deferred, owed[USER][stock0]=that, managed=100.25e18. stocks[0].modes(0,0); stocks[0].burn(vault, 100e18) (balance 100e18). USER claim(stock0, USER) pays 99_749_363_408_521_303_258 (full). OTHER redeem(balanceOf(OTHER)): amounts[0]=249_383_383_331_698_618 (0.249e18). Expected under pro-rata loss sharing: both receive ~49.9e18. See test/scratch/Econ.t.sol testOwedSeniorityShiftsLossToRemainingHolders.","severity":"low","snippet":"        if (balance < amount) amount = balance;","title":"Owed claims are paid from the whole vault balance, so a holder who redeems during a transfer freeze is made whole and remaining holders absorb the entire issuer haircut"},{"citation":"resolved","description":"The OwedUnderfunded gate requires balance >= totalOwed[token] for the incoming token. claim pays min(owed, balance) and decrements totalOwed by exactly what it pays, so the gap totalOwed - balance never shrinks through any protocol action; recognizeLoss only touches managed. After an issuer burn of the vault's custody while deferred legs are outstanding, the asset can never again receive deposits unless a third party donates at least the gap directly to the vault (the one case where a direct transfer is not stranded). Since assets can never be removed and the vault is capped at 64, the slot is dead for deposits forever. Redeem and claim are unaffected. Reported as a permanent-state consequence of the brief's rule for the requester's awareness; the fix is a design decision.","line":539,"path":"src/BaskVault.sol","reproduction":"Deposit 1e18 stock1 and 1e18 stock0. stocks[0].modes(1,0); redeem(50e18): owed[USER][stock0]=250_626_566_416_040_100, totalOwed same. stocks[0].modes(0,0); stocks[0].burn(vault, 1e18): balance 0. claim(stock0, USER) returns 0 (pays nothing, totalOwed unchanged). depositStatus(stock0) = (OwedUnderfunded, stock0). flagDeficit(stock0), warp +7 days, recognizeLoss(stock0): managed[stock0]=0, depositStatus(stock1)=OK but depositStatus(stock0) is still (OwedUnderfunded, stock0) and stays so after any number of claims. See test/scratch/Owed.t.sol.","severity":"low","snippet":"        if (balance < totalOwed[token]) return (Reason.OwedUnderfunded, token, 0, 0);","title":"Once an issuer burn drives a token's vault balance below totalOwed, deposits of that token are blocked permanently because claims reduce balance and totalOwed by the same amount"}],"hash":"85f6204cb2dfae4f584dd9e43f409f56cfacc98aba0eb395182e6d6f1b5101e2","nodeId":"ad479f7c-7eac-4a32-b1fc-f091f5f7452f","outcome":"completed","summary":"Review complete. The findings file is written at `.imd-findings.json` with 4 findings and 34 coverage rows. Only untracked scratch tests and the findings file were created. No tracked file changed.\n\n**Verdict.** The economics of BaskVault hold up well against the Economic Security, Invariant and Flow Gap checklists. NAV uses `managed` only, so donation and first-deposit inflation attacks fail. Every rounding favors the vault. Redeem reads no prices and no role or hostile token can revert it. The 64-asset hostile redemption measured 22.7M gas, under the 28M limit. The caps, proposal lifecycle, feed uniqueness and conservation invariants all trace cleanly. All slither and aderyn leads are false positives.\n\n**Findings reported:**\n\n1. **Medium, with failing proof.** Tokens credited to the vault above `managed` are stranded forever. A 2:1 split that doubles balances, an in-kind dividend, or custody restored after `recognizeLoss` cannot reach shareholders because nothing raises `managed` and there is no sweep. The proof under test/scratch/StrandedProof.t.sol fails on current code in both scenarios. A full redemption after a split returns 99.5 of 200 tokens held, and after a restore returns 0 of 100. Fixing this is a scope decision for the requester, since the build rules forbid adding mechanisms.\n\n2. **Low.** The NAV view reverts whenever any managed asset's price is older than 26 hours or halted, so it is unavailable every weekend and during trading halts.\n\n3. **Low.** Owed claims are paid from the entire balance, so a holder who redeems during a token pause becomes senior. After a 50% issuer haircut, that holder collected in full and an equal holder received 0.25 of 100 tokens. This follows the brief's rule but rewards a run during distress.\n\n4. **Low.** After an issuer burn drives a token's balance below `totalOwed`, deposits of that token stay blocked forever because claims reduce balance and `totalOwed` equally.\n\n**Coverage.** All 26 entry points have rows. Redeem and claim carry findings 1 and 3. Everything else holds. Nothing in the assigned area was left unreached. I did not examine read-only reentrancy beyond a quick probe that showed no inconsistency in the ordering tested, and no live-chain Stock Token behavior was verified, so finding 1's likelihood depends on how issuers settle corporate actions on-chain.","treeHash":null,"usage":{"cachedInputTokens":2094327,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":67545,"runtime":"claude","turns":34,"wallClockMs":1017397}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"560d41abbfbbcbfe","findings":[{"citation":"resolved","description":"The two owner tools for fixing a price source depend on each other. proposeFeed/executeProposal(Feed) run _checkReplacement, which requires the NEW feed's answer to lie inside the CURRENT band (src/BaskVault.sol:454). executeProposal(Band) re-centres the band but reads the CURRENT feed and reverts unless that read is fresh: `if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 26 hours) revert InvalidFeed(a.feed);` (src/BaskVault.sol:386). If the current feed stops updating (Chainlink deprecates a proxy, a delisted or acquired stock) and the true price is outside the old answer/4..answer*4 band, the band cannot be re-centred (stale read) and the feed cannot be replaced (new answer outside band). Because _depositState requires a valid price for every asset with managed > 0 (src/BaskVault.sol:557-558), and nothing can bring managed[token] to zero (no delisting; redeem only reduces managed proportionally; recognizeLoss needs an actual balance shortfall), every deposit into every asset is blocked permanently. closeAsset and pause do not help. Redeem and claim keep working, so no funds are lost. The behaviour follows the brief literally ('new answer inside the band, both times'; 're-centre ... under 26 hours old'), so this is a liveness gap in the agreed design that needs a scope decision rather than a silent code change. It is also untested: no test exercises a Feed or Band proposal against a stale current feed.","line":454,"path":"src/BaskVault.sol","reproduction":"Genesis with 3 assets at answer 100e8 (band 25e8..400e8), deposit 10e18 of stock0 so managed[stock0] > 0. feed0 stops updating (last updatedAt = T0). True price moves to 500e8 and a fresh replacement feed `fresh` reports 500e8. (1) owner.proposeFeed(stock0, fresh) -> reverts InvalidFeed(fresh) because 500e8 > maxAnswer 400e8. (2) owner.proposeBand(stock0); warp +7 days; executeProposal(id) -> reverts InvalidFeed(feed0) because block.timestamp - updatedAt >= 26 hours. (3) depositStatus(stock1) during market hours with 3 other fresh feeds -> (InvalidPrice, stock0); redeeming every share leaves managed[stock0] > 0 (0xdEaD's 1e15 locked shares keep ~5e16 managed), so the InvalidPrice block never clears. Expected: some owner path (proposal + delay) exists to re-price the asset; actual: none, deposits are frozen for the vault's lifetime. Verified in a scratch Foundry test (test/scratch/Probe.t.sol::testFeedBandDeadlock, not kept).","severity":"low","snippet":"        if (answer < a.minAnswer || answer > a.maxAnswer) revert InvalidFeed(feed);","title":"Feed replacement and band re-centre can deadlock: an asset whose current feed goes stale while its true price sits outside the stored band can never be re-priced, which freezes all deposits"},{"citation":"resolved","description":"_depositState requires _priceOK for every asset with managed > 0 (src/BaskVault.sol:557-558), and _priceOK requires token.oraclePaused() to return exactly false (src/BaskVault.sol:508-517). The issuer of any listed Stock Token can set oraclePaused() permanently (a delisted or halted stock) or upgrade the token so oraclePaused() reverts. Once managed[token] > 0 there is no path back to managed == 0: assets are never removed, closeAsset only stops new deposits into it, recognizeLoss lowers managed only by a real balance shortfall (none exists when the balance is intact), and redeem scales managed down proportionally to supply so the 1e15 shares locked at 0xdEaD keep a residual managed balance forever. The result is that one issuer action freezes deposits for the entire vault, not just for that asset; the owner's only remaining tool is to pause, which changes nothing. Redeem and claim are unaffected, so there is no loss of funds. This is literal to the brief ('a valid price for this token and every asset with managed > 0') and overlaps the accepted note about untransferable assets, so it is reported as a design liveness note for a scope decision, not as an implementation bug. The suite tests a paused oracle only as a transient InvalidPrice status, never the no-recovery property.","line":557,"path":"src/BaskVault.sol","reproduction":"Genesis with 3 assets, deposit 10e18 into stock0 and 10e18 into stock1. stock0.configure(18, true, false) (oraclePaused() == true). depositStatus(stock1) -> (InvalidPrice, stock0); deposit(stock1, ...) reverts DepositUnavailable(InvalidPrice, stock0). owner.closeAsset(stock0) -> still (InvalidPrice, stock0). USER redeems their whole balance -> managed[stock0] == 50005012531328321 (> 0) because 1e15 shares remain at 0xdEaD; depositStatus(stock1) still (InvalidPrice, stock0). flagDeficit(stock0) reverts InvalidInput (nothing is short), so recognizeLoss cannot zero managed. Expected: a role can restore deposit liveness for the other assets; actual: deposits into every asset are blocked for as long as the issuer keeps the oracle paused, with no vault-side remedy. Verified in a scratch Foundry test (test/scratch/Probe.t.sol::testPermanentOraclePauseFreezesDeposits, not kept).","severity":"low","snippet":"            if (amount != 0 || a.token == token) {\n                if (!_priceOK(a, reads[i], answers[i], times[i])) return (Reason.InvalidPrice, a.token, 0, 0);","title":"A single Stock Token whose oraclePaused() stays true (or reverts) blocks every deposit forever because managed[token] can never reach zero and no role can remove or re-price the asset"}],"hash":"b9bf480f1c94636d253a4e20e7c0108baa5f332d5a366c378a9fa7f0757cbe68","nodeId":"5c6d370e-46d0-4f69-8360-5ed711bfe9de","outcome":"completed","summary":"The findings file is in place at the repository root and the scratch directory is removed. The tree is otherwise unchanged.\n\n## Review result\n\n**Verdict: no fund-loss or role-abuse defect found.** The two findings are low-severity liveness gaps in the agreed design, not implementation bugs.\n\n**What I covered**\n\n- Traced every one of the 26 state-changing entry points from guard to final state, plus `FullMath`, the four assembly helpers, and the static-analysis leads. All rows are recorded in the coverage block of `.imd-findings.json`.\n- Ran the existing 53 tests. All pass, runtime is 23,601 bytes, and the worst hostile 64-asset redeem measured 22.66M gas.\n- Probed the \"must attack\" items with scratch tests: paused, blocked, upgraded and gas-bombing tokens all defer to `owed` without reverting redeem. No owner or guardian state can make redeem or claim revert. A deposit-then-redeem round trip at constant price never profits over 256 fuzz runs. Two feed-replacement proposals sharing one new feed correctly fail at the second execution.\n- Slither and Aderyn lines are false positives here: the weekday modulo is not randomness, the `FullMath` xor seed is the standard inverse, and the state write after the self-call sits inside the reentrancy guard.\n\n**Findings, both low**\n\n1. **Feed and band tools can deadlock.** Replacing a feed requires the new answer inside the current band, while re-centring the band requires a fresh read of the current feed. If a Chainlink proxy stops updating while the true price has drifted outside the band, neither proposal can execute. Since every managed asset needs a valid price, deposits into every asset freeze permanently.\n2. **One paused oracle freezes all deposits forever.** If one issuer leaves `oraclePaused()` true, nothing can bring that asset's `managed` to zero. Assets are never removed, and the 1e15 locked shares keep a residual balance even after every holder exits. The owner's only tool is pause, which changes nothing.\n\nBoth follow the brief literally, so they need a scope decision rather than a code change. Redeem and claim are unaffected in both cases, so no funds are at risk. Neither scenario is covered by the current test suite.","treeHash":null,"usage":{"cachedInputTokens":1552496,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":60268,"runtime":"claude","turns":27,"wallClockMs":1133239}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"03845cacb54c3a73","findings":[{"citation":"resolved","description":"redeem and previewRedeem distribute min(managed, available) only. managed[token] rises only in deposit (line 644) and falls in redeem (line 723) and recognizeLoss (line 769); nothing ever raises it to match a balance the issuer credited, and the brief forbids rescue, sweep and removal. The brief does say direct transfers are ignored, so this is reported as a design-scope note rather than an implementation bug, but two ordinary issuer events on Stock Tokens produce exactly that surplus: a corporate action settled as a balance change (a 2:1 split that doubles balances while the feed halves, or a dividend paid in kind), and an issuer burn that is recognized via recognizeLoss and later reversed. In both cases the surplus is unreachable forever and NAV (managed x price) undervalues the vault, so new depositors buy in below true value. Merged from audit_economics and audit_permissions (same root cause). A remedy needs a scope decision (e.g. an anyone-callable recognition of balance - totalOwed above managed); the current build rules forbid adding it.","line":718,"path":"src/BaskVault.sol","reproduction":"Genesis with 3 assets at 100e8, deposits open. USER deposits 100e18 of stock0 (managed[stock0]=100e18). Issuer mints 100e18 of stock0 to the vault (split) and feed0 becomes 50e8. USER redeems balanceOf(USER) with empty minimums. Expected: close to 199e18 of stock0 returned, vault nearly empty. Actual (test/scratch/Proof_econ.t.sol, copied from the specialist proof, both tests fail on this code): amounts[0] = 99_499_990_000_000_000_000 and stock0.balanceOf(vault) = 100.5e18 stays unreachable. Variant: deposit 100e18, issuer burns the vault's 100e18, flagDeficit, +7 days, recognizeLoss (managed=0), issuer mints 100e18 back; redeem all shares returns amounts[0] = 0 while the vault holds 100e18.","severity":"low","snippet":"            uint256 amount = managed[token];\n            if (available < amount) amount = available;","title":"Tokens credited to the vault above managed (stock split, in-kind dividend, custody restored after recognizeLoss) can never be distributed and NAV undercounts them"},{"citation":"resolved","description":"_depositState requires a readable, non-short balance for every listed asset (lines 553-556) and a valid price, including token.oraclePaused() == false, for every asset with managed > 0 (lines 557-558). Assets are never removed, closeAsset only stops new deposits into that asset, and managed can never reach zero through redeem because the 1e15 shares at 0xdEaD are never redeemed (leg = managed * net / supply with net < supply). recognizeLoss only lowers managed by a real balance shortfall and reverts when the balance is unreadable (line 766). So a single issuer that leaves oraclePaused() true, upgrades its token so oraclePaused() or balanceOf reverts, or removes the code, turns the vault redeem-only for its lifetime; pause and close change nothing. Redeem and claim keep working, so no funds are at risk. This follows the brief literally ('a valid price for this token and every asset with managed > 0', 'no asset short or unreadable', 'never removed') and overlaps accepted note (3), so it is a liveness note for a scope decision. Merged from audit_flow (permanent oracle pause) and audit_permissions (unreadable balance).","line":557,"path":"src/BaskVault.sol","reproduction":"(a) Genesis 3 assets, deposit 10e18 into stock0 and stock1. stock0.configure(18, true, false) so oraclePaused() is true. depositStatus(stock1) = (InvalidPrice, stock0). closeAsset(stock0) by the owner: still (InvalidPrice, stock0). USER redeems their whole balance: managed[stock0] = 50_005_012_531_328_321 (> 0). flagDeficit(stock0) reverts InvalidInput, so recognizeLoss cannot zero it. Expected: some role path restores deposits for the other assets; actual: none. (b) 4 listed assets, deposit 10e18 of stock0, vm.etch(stock3, '') with managed[stock3] == 0: depositStatus(stock0) = (Unreadable, stock3), flagDeficit(stock3) reverts TransferFailed(stock3). Both verified in test/scratch/Judge.t.sol (testPermanentOraclePause, testUnreadableEmptyAssetFreezesDeposits).","severity":"low","snippet":"            if (amount != 0 || a.token == token) {\n                if (!_priceOK(a, reads[i], answers[i], times[i])) return (Reason.InvalidPrice, a.token, 0, 0);","title":"One issuer can freeze deposits for the whole vault forever: a listed asset with managed > 0 whose oraclePaused() stays true, or any listed asset whose balanceOf becomes unreadable, blocks every deposi"},{"citation":"resolved","description":"proposeFeed and executeProposal(Feed) run _checkReplacement, which requires the new feed's answer inside the current band (line 454). executeProposal(Band) re-centres the band but reads the current feed and reverts unless it is under 26 hours old (line 386). If the current feed stops updating (deprecated proxy, delisted or acquired stock) and the true price has left the answer/4..answer*4 band, neither tool works, and because _depositState needs a valid price for every asset with managed > 0 and managed never returns to zero, every deposit into every asset is blocked permanently. Redeem and claim are unaffected. The behaviour is literal to the brief ('new answer inside the band, both times'; 're-centre ... under 26 hours old'), so this is a liveness gap in the agreed design needing a scope decision (for example letting a Feed proposal also re-centre, or letting a Band proposal read the proposed feed).","line":454,"path":"src/BaskVault.sol","reproduction":"Genesis with 4 assets at 100e8 (band 25e8..400e8); deposit 10e18 of stock0. feed0 stops updating; a fresh replacement feed reports 500e8. owner.proposeFeed(stock0, fresh) reverts InvalidFeed(fresh) (500e8 > 400e8). owner.proposeBand(stock0); warp +7 days; refresh feeds 1-3; executeProposal(id) reverts InvalidFeed(feed0) (age >= 26 hours). Redeem every USER share: managed[stock0] stays > 0. Next Monday 16:00 UTC with feeds 1-3 fresh: depositStatus(stock1) = (InvalidPrice, stock0). Verified in test/scratch/Judge.t.sol::testFeedBandDeadlock.","severity":"low","snippet":"        if (answer < a.minAnswer || answer > a.maxAnswer) revert InvalidFeed(feed);","title":"Feed replacement and band re-centre depend on each other, so an asset whose feed goes stale while its true price sits outside the stored band can never be re-priced; deposits stay blocked"},{"citation":"resolved","description":"redeem burns the full share amount before the asset loop (lines 709/712) and then lowers managed one asset at a time (line 723) just before each payLeg self-call (line 728). While a Stock Token's transfer is executing, totalSupply is already reduced but managed for every later asset is still at its pre-redeem value. navPerShare and previewRedeem have no reentrancy check and read this mixed state, so a token with a transfer hook (issuers can upgrade tokens) can make any contract that prices BASK through those views observe a share value far above the true one. State-changing paths are nonReentrant, so vault funds are not at risk; the exposure is to external consumers of the views, and the trigger needs issuer-level control of a listed token.","line":728,"path":"src/BaskVault.sol","reproduction":"Three assets at 100e8, 10e18 of each deposited, asset 0 a Stock Token whose transfer() calls vault.navPerShare() and vault.previewRedeem(1e18) before moving tokens. USER redeems half their shares. Observed in test/scratch/Judge.t.sol::testReadOnlyReentrancyMidRedeem: navPerShare before = 1_009_226_028_973_743_912, mid-redeem = 1_683_724_971_189_784_093 (67% high), after = 1_014_272_155_723_489_849; previewRedeem(1e18)[1] before = 3_347_266_329_429_583, mid = 6_694_530_406_761_055 (doubled). Expected: a view read during redeem is consistent with the pre- or post-redeem state, or reverts while entered != 0.","severity":"low","snippet":"            assembly (\"memory-safe\") { paid := call(250000, address(), 0, add(data, 32), mload(data), 0, 0) }","title":"Read-only reentrancy during redeem: navPerShare and previewRedeem return inflated values from inside a leg payment"},{"citation":"resolved","description":"claim pays min(owed, balance) with no regard to managed. A redeem during an issuer pause converts the caller's pro-rata share into owed that later takes priority over everything still managed. If the issuer then burns or freezes part of the custody balance, owed creditors collect 100% first and holders who did not redeem bear the whole loss. This matches the brief ('pays min(caller's owed, vault balance)') and is reported as an economic property for the requester to confirm: during any Stock Token pause the dominant strategy for every holder is to redeem immediately to become senior, which rewards a run on the vault exactly when the token is distressed.","line":744,"path":"src/BaskVault.sol","reproduction":"USER deposits 100e18 stock0, OTHER deposits 100e18 stock0 (managed 200e18). stock0.modes(1,0) so transfers revert. USER redeems all: amounts[0] = 99_749_363_408_521_303_258 deferred, owed[USER][stock0] = that. stock0.modes(0,0); stock0.burn(vault, 100e18). USER claim(stock0, USER) pays 99_749_363_408_521_303_258 in full. OTHER redeems all: amounts[0] = 249_383_383_331_698_618. Expected under pro-rata loss sharing: both receive about 49.9e18. Verified in test/scratch/Judge.t.sol::testOwedSeniority.","severity":"low","snippet":"        if (balance < amount) amount = balance;","title":"Owed claims are paid from the whole vault balance, so a holder who redeems during a transfer freeze becomes senior and the remaining holders absorb the entire issuer haircut"},{"citation":"resolved","description":"The OwedUnderfunded gate requires balance >= totalOwed[token] for the incoming token. claim pays min(owed, balance) and decrements totalOwed by exactly what it pays, so the gap totalOwed - balance never shrinks through any protocol action; recognizeLoss touches only managed. After an issuer burn while deferred legs are outstanding, the asset can never receive deposits again unless someone donates at least the gap directly to the vault. Assets are never removed and the list is capped at 64, so the slot is dead for deposits. Redeem and claim are unaffected. Brief-literal; reported as a permanent-state consequence for the requester's awareness.","line":539,"path":"src/BaskVault.sol","reproduction":"Deposit 1e18 stock1 and 1e18 stock0. stock0.modes(1,0); redeem(50e18): owed[USER][stock0] = totalOwed = 250_626_566_416_040_100. stock0.modes(0,0); stock0.burn(vault, 1e18): balance 0. claim(stock0, USER) returns 0. depositStatus(stock0) = (OwedUnderfunded, stock0). flagDeficit(stock0), +7 days, recognizeLoss(stock0): managed[stock0] = 0; next Monday with fresh feeds depositStatus(stock1) = OK but depositStatus(stock0) is still OwedUnderfunded. Verified in test/scratch/Judge.t.sol::testOwedUnderfundedPermanent.","severity":"low","snippet":"        if (balance < totalOwed[token]) return (Reason.OwedUnderfunded, token, 0, 0);","title":"Once an issuer burn drives a token's vault balance below totalOwed, deposits of that token are blocked permanently because claims lower balance and totalOwed by the same amount"},{"citation":"resolved","description":"navPerShare applies the deposit-time validity rule (26-hour age, band, oraclePaused false) and reverts on the first managed asset that fails it. Equity feeds stop updating outside sessions, so from roughly Saturday until the first Monday round, and all week while one asset is halted or out of band, every call reverts with DepositUnavailable(InvalidPrice, token). The README documents this ('it requires valid prices for managed assets'), allAssets tolerates failed reads and previewRedeem reads no price, so this is an availability note for integrators rather than a defect.","line":810,"path":"src/BaskVault.sol","reproduction":"Monday 16:00 UTC, USER deposits 10e18 stock0 (feeds fresh). navPerShare() = 1_005_025_125_628_140_703. Warp +26 hours + 1 second. navPerShare() reverts DepositUnavailable(10, stock0). Verified in test/scratch/Judge.t.sol::testNavPerShareRevertsWhenStale.","severity":"info","snippet":"            if (!_priceOK(a, ok, answer, updated)) revert DepositUnavailable(Reason.InvalidPrice, a.token);","title":"navPerShare reverts whenever any managed asset's price is invalid, so the only NAV view is unavailable outside market hours and during halts"},{"citation":"resolved","description":"executeProposal(Band) validates only read success, answer > 0 and age under 26 hours, whereas _priceOK (lines 503-518) also requires the answer inside the current band and token.oraclePaused() == false. Execution is permissionless over a 7-day window, so the executor picks the snapshot. A transient answer that deposit pricing rejects (issuer-paused oracle during a corporate action, or a 5x glitch) can be locked in as the new band centre; once the true price returns it falls outside the new band and deposits into that asset (and, if managed > 0, every deposit) revert InvalidPrice until another 7-day band proposal executes. Matches the brief's wording and the README ('may move outside the old band'), so reported as a note on the asymmetry, not a defect.","line":386,"path":"src/BaskVault.sol","reproduction":"Genesis 3 assets with band [25e8, 400e8]. owner.proposeBand(stock0) -> id. Warp +7 days, refresh feeds. stock0.configure(18, true, false) (oraclePaused true); feed0.set(500e8, now). Anyone calls executeProposal(id): succeeds; assets(0).minAnswer = 125e8, maxAnswer = 2000e8. Afterwards with feed0 back at 100e8 and oracle unpaused, depositStatus(stock0) = InvalidPrice. Verified in test/scratch/Judge.t.sol::testBandRecentreIgnoresPauseAndBand.","severity":"info","snippet":"            if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 26 hours) {","title":"Band re-centre executes on an answer that deposit pricing would reject (oracle paused, outside the old band), at a moment chosen by whoever executes"},{"citation":"resolved","description":"transferOwnership refuses next == guardian (line 248) and acceptOwnership refuses msg.sender == guardian (line 255), but proposeGuardian and the Guardian branch of executeProposal only refuse the current owner (lines 341, 395), not pendingOwner. If a guardian proposal naming the pending owner executes, the pending owner can no longer accept and the handover must be re-routed to a different address or the guardian replaced again after another 7 days. Only the owner can create this state and only against its own handover, so impact is a self-inflicted delay; reported for consistency of the distinct-roles invariant.","line":341,"path":"src/BaskVault.sol","reproduction":"owner.transferOwnership(OTHER); owner.proposeGuardian(OTHER) -> id (does not revert); warp +7 days; executeProposal(id) succeeds, guardian() == OTHER. OTHER calls acceptOwnership(): reverts InvalidAddress(). Expected: the proposal is rejected at creation or execution like transferOwnership(guardian) is. Verified in test/scratch/Judge.t.sol::testGuardianProposalCanTargetPendingOwner.","severity":"info","snippet":"        if (next == address(0) || next == owner) revert InvalidAddress();","title":"proposeGuardian accepts the pending owner, after which acceptOwnership reverts; transferOwnership rejects the guardian but the mirror check is missing"}],"hash":"d9be98411a52a6cf19ea0b53d52ceaef2e2ee7ad68c0aea5b509ec1a48777da2","nodeId":"a1f20eef-a2f4-40e3-8717-0578861ab7c7","outcome":"completed","summary":"The review is complete and the judged findings are written to `.imd-findings.json`. The scratch tests I used were removed since no finding needed a proof file.\n\n**Outcome.** No critical, high or medium defect survived reproduction. Redeem and claim cannot be blocked by any role or by a paused, blocked or upgraded Stock Token, and the 64-asset worst case stays under the gas ceiling. All specialist findings reproduced, but each is a liveness or accounting consequence of the brief's own rules rather than a loss-of-funds path, so I recalibrated them to low or info.\n\n| Check | Result |\n|---|---|\n| Full suite | 63 passed, 0 failed |\n| 64-asset redeem worst case | 22.66M gas |\n| BaskVault runtime size | 23,601 bytes |\n\n**Findings kept, 9 total, 6 low and 3 info:**\n\n1. **Surplus above managed is stranded.** A split credit, in-kind dividend or restored custody after recognizeLoss can never reach shareholders. Merged from the economics and permissions specialists. The economics specialist rated it medium; I lowered it because the brief states direct credits are ignored, but it needs a scope decision before the first corporate action.\n2. **One issuer can freeze deposits forever.** A permanently paused oracle or an unreadable balanceOf blocks every deposit, and managed can never reach zero because of the locked shares. Merged two specialist reports.\n3. **Feed and band proposals deadlock** when the current feed goes stale while the true price has left the band.\n4. **Read-only reentrancy during redeem** inflates navPerShare and previewRedeem mid-loop.\n5. **Owed claims are senior** to remaining holders after an issuer haircut, which rewards a run during a token pause.\n6. **OwedUnderfunded is permanent** after an issuer burn with deferred legs outstanding.\n7. navPerShare reverts on any invalid price. Info, since the README documents it.\n8. Band re-centre accepts a paused-oracle or out-of-band answer. Info.\n9. **My own addition:** proposeGuardian accepts the pending owner, which then makes acceptOwnership revert. Info, owner-caused and recoverable.\n\n**Dropped or demoted:** all slither and aderyn leads were false positives, including the FullMath caret which is the correct Newton-Raphson inverse.\n\n**Coverage:** all 26 entry points answered, plus three invariant rows. Ten are marked `finding` and the rest `holds`.","treeHash":null,"usage":{"cachedInputTokens":1125087,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":42672,"runtime":"claude","turns":20,"wallClockMs":739416}}],"verification":[{"checks":[{"durationMs":18255,"exitCode":0,"name":"build","output":"Compiling 28 files with Solc 0.8.26\nSolc 0.8.26 finished in 18.01s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:486:32\n    │\n486 │         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:488:17\n    │\n488 │         return (true, balance > reserved ? balance - reserved : 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:500:26\n    │\n500 │         if (!ok) return (false, 0, 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:521:23\n    │\n521 │         uint256 day = (block.timestamp / 1 days + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:257:9\n    │\n257 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:436:13\n    │\n436 │             IStockToken(token).decimals() != 18\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:437:62\n    │\n437 │                 || IStockFactory(STOCK_FACTORY).tokenAddress(IStockToken(token).uid()) != token\n    │                                                              ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:437:20\n    │\n437 │                 || IStockFactory(STOCK_FACTORY).tokenAddress(IStockToken(token).uid()) != token\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:446:13\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(0)) revert InvalidFeed(feed);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:446:44\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(0)) revert InvalidFeed(feed);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:469:9\n    │\n469 │         emit AssetListed(token, feed, low, high);\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:354:9\n    │\n354 │         emit ProposalCreated(id, kind, token, target, value, ready);\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:434:91\n    │\n434 │         if (assetIndex[token] != 0 || assets.length >= MAX_ASSETS || 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:438:11\n    │\n438 │         ) 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:13\n    │\n444 │             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:446:84\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(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:448:33\n    │\n448 │         if (!ok || 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:458:45\n    │\n458 │         if (answer > type(uint256).max / 4) revert InvalidInput();\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:368:13\n    │\n368 │         if (block.timestamp < p.readyAt) revert ProposalNotReady();\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:371:17\n    │\n371 │             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:386:39\n    │\n386 │             if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 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:386:68\n    │\n386 │             if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 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:382:13\n    │\n382 │             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:390:13\n    │\n390 │             emit BandChanged(p.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:403:9\n    │\n403 │         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:389:48\n    │\n389 │             (a.minAnswer, a.maxAnswer) = _band(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:407:28\n    │\n407 │         return p.active && block.timestamp < p.readyAt + PROPOSAL_WINDOW\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:414:43\n    │\n414 │             if (_pending(proposals[i])) ++count;\n    │                                           ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:421:21\n    │\n421 │                 ids[j] = i;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:449:16\n    │\n449 │         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:506:20\n    │\n506 │                 || updated > block.timestamp || block.timestamp - updated > 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:506:49\n    │\n506 │                 || updated > block.timestamp || block.timestamp - updated > 26 hours\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:505:35\n    │\n505 │             !ok || answer <= 0 || uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer\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:505:68\n    │\n505 │             !ok || answer <= 0 || uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer\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:523:16\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:28\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:40\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:57\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 70200;\n    │                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:548:101\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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:533:13\n    │\n533 │         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:548:29\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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:548:60\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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/FullMath.sol:17:58\n   │\n17 │             if (denominator == 0 || denominator <= high) 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:559:34\n    │\n559 │                 uint256 answer = uint256(answers[i]);\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:574:16\n    │\n574 │         return elapsed >= 1 days ? 0 : bucket - bucket.mulDiv(elapsed, 1 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:606:26\n    │\n606 │         bool probation = block.timestamp < _asset(token).probationUntil;\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:630:13\n    │\n630 │         if (block.timestamp > deadline) revert DeadlineExpired();\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:651:17\n    │\n651 │                 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:237:9\n    │\n237 │         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:657:9\n    │\n657 │         emit Deposited(msg.sender, token, receiver, amount, shares, 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:703:13\n    │\n703 │         if (block.timestamp > deadline) revert DeadlineExpired();\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:730:17\n    │\n730 │                 emit LegPaid(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:734:17\n    │\n734 │                 emit PaymentDeferred(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:737:9\n    │\n737 │         emit Redeemed(msg.sender, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:721:69\n    │\n721 │             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-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, amount, 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:764:30\n    │\n764 │         if (d.amount == 0 || block.timestamp < d.since + 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:771:9\n    │\n771 │         emit LossRecognized(token, loss);\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:792:17\n    │\n792 │                 block.timestamp < a.probationUntil,\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:811:13\n    │\n811 │             nav += amount.mulDiv(uint256(answer), 1e8);\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:810:52\n    │\n810 │             if (!_priceOK(a, ok, answer, updated)) revert DepositUnavailable(Reason.InvalidPrice, a.token);\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:811:34\n    │\n811 │             nav += amount.mulDiv(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\n","passed":true},{"durationMs":365,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 13 tests for test/Deposit.t.sol:DepositTest\n[PASS] testDeadlineReceiverAndMinimumShares() (gas: 476693)\n[PASS] testDeploymentAndFirstDeposit() (gas: 709446)\n[PASS] testDonationDoesNotAffectSharesOrNAV() (gas: 794834)\n[PASS] testExactInRejectsTaxAndLyingTokens() (gas: 1628981)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 727869)\n[PASS] testFuzzFirstDepositRounding(uint96,bool) (runs: 256, μ: 398833, ~: 433007)\nLogs:\n  Bound result 208018781428658307023\n\n[PASS] testGenesisAndOpeningDelay() (gas: 6595387)\n[PASS] testGlobalBucketAndLinearDecay() (gas: 11973118)\n[PASS] testManagedPriceStalenessAndOraclePause() (gas: 10135587)\n[PASS] testMarketBoundariesAllDays() (gas: 395696)\n[PASS] testMarketFreshnessAndPriceBoundaries() (gas: 2189288)\n[PASS] testNAVAndConcentrationCaps() (gas: 842389)\n[PASS] testUnreadableEmptyAssetAlsoBlocksDeposit() (gas: 412572)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 18.54ms (24.30ms CPU time)\n\nRan 6 tests for test/Losses.t.sol:LossesTest\n[PASS] testLargerFlagResetsClockAndUnrecordedLossRemains() (gas: 818347)\n[PASS] testLossDelayNoAutomaticReductionAndMinCurrentShortfall() (gas: 1408524)\n[PASS] testSuccessfulDepositClearsEveryRecoveredRecord() (gas: 1862742)\n[PASS] testTotalLossZeroNAVBlocksDepositButNotRedeem() (gas: 986608)\n[PASS] testUnderfundedOwedBlocksDepositIntoToken() (gas: 899493)\n[PASS] testUnreadableBalanceCannotRecognizeLoss() (gas: 721499)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 18.65ms (4.66ms CPU time)\n\nRan 11 tests for test/Redemption.t.sol:RedemptionTest\n[PASS] testAllUserFacingEntrypointsRejectReentrancy() (gas: 11062880)\n[PASS] testBlockedCallerDefersOnlyBadLegThenClaimsElsewhere() (gas: 1309864)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesBalance() (gas: 958778)\n[PASS] testClaimHasNo250kPaymentLimit() (gas: 1154708)\n[PASS] testEveryUnreadableBalanceOutcomeUsesManaged() (gas: 1625158)\n[PASS] testFuzzRedeemConservesManagedPaidAndOwed(uint96,uint96,bool) (runs: 256, μ: 597412, ~: 577038)\nLogs:\n  Bound result 249990000000003272872\n  Bound result 5745370587330356590370\n\n[PASS] testHostileTransfersRollBackAndCreateDebt() (gas: 2014730)\n[PASS] testOwedIsReservedFromLaterRedemptions() (gas: 718661)\n[PASS] testRedeemFormulaAndNoPriceRead() (gas: 1432435)\n[PASS] testSlippageAndDeadlineAreAtomicEvenAfterEarlierLegPaid() (gas: 1249864)\n[PASS] testUpgradeToNoCodeCannotBlockRedeem() (gas: 483531)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 19.00ms (35.82ms CPU time)\n\nRan 14 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testAssetLimit64() (gas: 128704455)\n[PASS] testBandUsesExecutionAnswerAndStrictFreshness() (gas: 473087)\n[PASS] testCancellationGuardianReplacementAndExpiry() (gas: 983267)\n[PASS] testConstructorAndEmptyDeployment() (gas: 362964)\n[PASS] testFeedChecksTwiceAndSharedChangeCooldown() (gas: 3272597)\n[PASS] testGuardianCannotBecomeOwnerThroughPendingHandover() (gas: 293194)\n[PASS] testListingChecksAndAtomicBatch() (gas: 6611379)\n[PASS] testListingRechecksAtExecutionAndProbationCap() (gas: 4071807)\n[PASS] testNAVCapMaximumAndDelayedRaise() (gas: 332983)\n[PASS] testPauseAndCloseStatus() (gas: 356125)\n[PASS] testReopenCancelledByLaterCloseIncludingSameTimestamp() (gas: 671479)\n[PASS] testRolesCannotTakeAssetsOrMintOrBlockExits() (gas: 1007101)\n[PASS] testRuntimeMatchesProtectedOpcodeAndSizeChecks() (gas: 9903732)\n[PASS] testTwoStepOwnershipAndNoRenounce() (gas: 240570)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 35.96ms (55.06ms CPU time)\n\nRan 3 tests for test/Redemption.t.sol:RedemptionGasTest\n[PASS] test64GasBurningTransfersAndCostlyReadableBalances() (gas: 305982727)\nLogs:\n  64-asset redeem gas: 22663996\n\n[PASS] test64MixedPausedBlockedUpgradedAndHealthyAssets() (gas: 298111483)\nLogs:\n  64-asset redeem gas: 7404841\n\n[PASS] test64UnreadableGasBombs() (gas: 292786019)\nLogs:\n  64-asset redeem gas: 10294652\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 95.34ms (246.30ms CPU time)\n\nRan 6 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testFeeRecipientRedeemsOwnSharesWithoutExtraBurn() (gas: 546003)\n[PASS] testFullPrecisionMathEdges() (gas: 4298)\n[PASS] testFuzzFullPrecisionIdentity(uint256,uint256) (runs: 256, μ: 3775, ~: 3704)\n[PASS] testFuzzMathMatchesSmallProducts(uint128,uint128,uint128) (runs: 256, μ: 3763, ~: 3764)\n[PASS] testFuzzMultiUserConservation(uint256) (runs: 256, μ: 7235715, ~: 7290979)\n[PASS] testShareTransfersAndAllowancesDoNotChangeSupply() (gas: 840907)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 280.04ms (287.23ms CPU time)\n\nRan 6 test suites in 280.60ms (467.53ms CPU time): 53 tests passed, 0 failed, 0 skipped (53 total tests)\n","passed":true},{"durationMs":66,"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.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\":3,\"README.md\":102,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskVault.sol\":815,\"src/FullMath.sol\":42,\"test/Accounting.t.sol\":101,\"test/Base.t.sol\":85,\"test/Deposit.t.sol\":222,\"test/Governance.t.sol\":341,\"test/Losses.t.sol\":115,\"test/Redemption.t.sol\":293,\"test/mocks/Mocks.sol\":183},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":3247,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/BaskVault.sol:520: BaskVault.marketOpen() (src/BaskVault.sol#520-524) uses a weak PRNG: \"day = (block.timestamp / 86400 + 4) % 7 (src/BaskVault.sol#521)\"\n[high/medium] weak-prng at src/BaskVault.sol:520: BaskVault.marketOpen() (src/BaskVault.sol#520-524) uses a weak PRNG: \"time = block.timestamp % 86400 (src/BaskVault.sol#522)\"\n[high/medium] incorrect-exp at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) has bitwise-xor operator ^ instead of the exponentiation operator **: \n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/FullMath.sol:8: FullMath.mulDiv(uint256,uint256,uint256) (src/FullMath.sol#8-41) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/BaskVault.sol:427: BaskVault._asset(address) (src/BaskVault.sol#427-431) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:527: BaskVault._depositState(address) (src/BaskVault.sol#527-566) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:527: BaskVault._depositState(address) (src/BaskVault.sol#527-566) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:802: BaskVault.navPerShare() (src/BaskVault.sol#802-814) uses a dangerous strict equality:\n[medium/medium] uninitialized-local at src/BaskVault.sol:412: BaskVault.pendingProposals().count (src/BaskVault.sol#412) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:804: BaskVault.navPerShare().nav (src/BaskVault.sol#804) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:418: BaskVault.pendingProposals().j (src/BaskVault.sol#418) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:541: BaskVault._depositState(address).fresh (src/BaskVault.sol#541) is a local variable never initialized\n[low/medium] calls-loop at src/BaskVault.sol:433: BaskVault._checkListing(address,address) (src/BaskVault.sol#433-440) has external calls inside a loop: IStockToken(token).decimals() != 18 || IStockFactory(STOCK_FACTORY).tokenAddress(IStockToken(token).uid()) != token (src/BaskVault.sol#436-437)\n[low/medium] calls-loop at src/BaskVault.sol:442: BaskVault._checkFeed(address,address) (src/BaskVault.sol#442-450) has external calls inside a loop: IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(0) (src/BaskVault.sol#446)\n[low/medium] timestamp at src/BaskVault.sol:240: BaskVault._burn(address,uint256) (src/BaskVault.sol#240-245) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:600: BaskVault._checkCaps(address,uint256,uint256,uint256,uint256) (src/BaskVault.sol#600-615) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:683: BaskVault.previewRedeem(uint256) (src/BaskVault.sol#683-696) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:527: BaskVault._depositState(address) (src/BaskVault.sol#527-566) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:572: BaskVault.decayedBucket() (src/BaskVault.sol#572-575) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:698: BaskVault.redeem(uint256,uint256[],uint256) (src/BaskVault.sol#698-738) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:315: BaskVault._proposeAsset(address,address) (src/BaskVault.sol#315-322) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:778: BaskVault.allAssets() (src/BaskVault.sol#778-800) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:625: BaskVault.deposit(address,uint256,address,uint256,uint256) (src/BaskVault.sol#625-658) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:427: BaskVault._asset(address) (src/BaskVault.sol#427-431) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:292: BaskVault.finalizeGenesis() (src/BaskVault.sol#292-296) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:462: BaskVault._list(address,address,uint256) (src/BaskVault.sol#462-470) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:581: BaskVault._quote(address,uint256) (src/BaskVault.sol#581-598) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:520: BaskVault.marketOpen() (src/BaskVault.sol#520-524) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:761: BaskVault.recognizeLoss(address) (src/BaskVault.sol#761-772) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:503: BaskVault._priceOK(BaskVault.Asset,bool,int256,uint256) (src/BaskVault.sol#503-518) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:365: BaskVault.executeProposal(uint256) (src/BaskVault.sol#365-404) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:433: BaskVault._checkListing(address,address) (src/BaskVault.sol#433-440) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:802: BaskVault.navPerShare() (src/BaskVault.sol#802-814) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:406: BaskVault._pending(BaskVault.Proposal) (src/BaskVault.sol#406-409) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:226: BaskVault._transfer(address,address,uint256) (src/BaskVault.sol#226-232) uses timestamp for comparisons","passed":true},{"durationMs":325,"exitCode":0,"name":"aderyn","output":"[high] incorrect-caret-operator at src/FullMath.sol:32: Incorrect use of caret operator\n[high] reentrancy-state-change at src/BaskVault.sol:726: Reentrancy: State change after external call\n[high] weak-randomness at src/BaskVault.sol:522: Weak Randomness\n[low] centralization-risk at src/BaskVault.sol:247: Centralization Risk (14 places)\n[low] costly-loop at src/BaskVault.sol:310: Costly operations inside loop (3 places)\n[low] literal-instead-of-constant at src/BaskVault.sol:293: Literal Instead of Constant (24 places)\n[low] local-variable-shadowing at src/BaskVault.sol:80: Local Variable Shadows State Variable (3 places)\n[low] require-revert-in-loop at src/BaskVault.sol:310: Loop Contains `require`/`revert` (5 places)\n[low] storage-array-length-not-cached at src/BaskVault.sol:546: Storage Array Length not Cached (7 places)\n[low] unchecked-return at src/BaskVault.sol:331: Unchecked Return (4 places)\n[low] uninitialized-local-variable at src/BaskVault.sol:412: Uninitialized Local Variable (5 places)\n[low] unused-public-function at src/BaskVault.sol:683: Public Function Not Used Internally","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"18073358d04c3bbcf5d261b1ff5ed56f37cccd653f168ea7d886f31ba1f54fc2","verifiedTreeHash":"e5bff5da9fb0b7521605edf24d7f43fd0a63331f","verifierVersion":"0.1.0+7471272e"},{"checks":[{"durationMs":22106,"exitCode":0,"name":"build","output":"Compiling 28 files with Solc 0.8.26\nSolc 0.8.26 finished in 21.81s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:486:32\n    │\n486 │         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:488:17\n    │\n488 │         return (true, balance > reserved ? balance - reserved : 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:500:26\n    │\n500 │         if (!ok) return (false, 0, 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:521:23\n    │\n521 │         uint256 day = (block.timestamp / 1 days + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:257:9\n    │\n257 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:436:13\n    │\n436 │             IStockToken(token).decimals() != 18\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:437:62\n    │\n437 │                 || IStockFactory(STOCK_FACTORY).tokenAddress(IStockToken(token).uid()) != token\n    │                                                              ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:437:20\n    │\n437 │                 || IStockFactory(STOCK_FACTORY).tokenAddress(IStockToken(token).uid()) != token\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:446:13\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(0)) revert InvalidFeed(feed);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:446:44\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(0)) revert InvalidFeed(feed);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:469:9\n    │\n469 │         emit AssetListed(token, feed, low, high);\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:354:9\n    │\n354 │         emit ProposalCreated(id, kind, token, target, value, ready);\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:434:91\n    │\n434 │         if (assetIndex[token] != 0 || assets.length >= MAX_ASSETS || 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:438:11\n    │\n438 │         ) 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:13\n    │\n444 │             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:446:84\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(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:448:33\n    │\n448 │         if (!ok || 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:458:45\n    │\n458 │         if (answer > type(uint256).max / 4) revert InvalidInput();\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:368:13\n    │\n368 │         if (block.timestamp < p.readyAt) revert ProposalNotReady();\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:371:17\n    │\n371 │             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:386:39\n    │\n386 │             if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 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:386:68\n    │\n386 │             if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 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:382:13\n    │\n382 │             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:390:13\n    │\n390 │             emit BandChanged(p.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:403:9\n    │\n403 │         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:389:48\n    │\n389 │             (a.minAnswer, a.maxAnswer) = _band(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:407:28\n    │\n407 │         return p.active && block.timestamp < p.readyAt + PROPOSAL_WINDOW\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:421:21\n    │\n421 │                 ids[j] = i;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:414:43\n    │\n414 │             if (_pending(proposals[i])) ++count;\n    │                                           ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:449:16\n    │\n449 │         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:506:20\n    │\n506 │                 || updated > block.timestamp || block.timestamp - updated > 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:506:49\n    │\n506 │                 || updated > block.timestamp || block.timestamp - updated > 26 hours\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:505:35\n    │\n505 │             !ok || answer <= 0 || uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer\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:505:68\n    │\n505 │             !ok || answer <= 0 || uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer\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:523:16\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:28\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:40\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:57\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 70200;\n    │                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:548:101\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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:533:13\n    │\n533 │         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:548:29\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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:548:60\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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/FullMath.sol:17:58\n   │\n17 │             if (denominator == 0 || denominator <= high) 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:559:34\n    │\n559 │                 uint256 answer = uint256(answers[i]);\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:574:16\n    │\n574 │         return elapsed >= 1 days ? 0 : bucket - bucket.mulDiv(elapsed, 1 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:606:26\n    │\n606 │         bool probation = block.timestamp < _asset(token).probationUntil;\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:630:13\n    │\n630 │         if (block.timestamp > deadline) revert DeadlineExpired();\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:651:17\n    │\n651 │                 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:237:9\n    │\n237 │         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:657:9\n    │\n657 │         emit Deposited(msg.sender, token, receiver, amount, shares, 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:703:13\n    │\n703 │         if (block.timestamp > deadline) revert DeadlineExpired();\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:730:17\n    │\n730 │                 emit LegPaid(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:734:17\n    │\n734 │                 emit PaymentDeferred(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:737:9\n    │\n737 │         emit Redeemed(msg.sender, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:721:69\n    │\n721 │             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-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, amount, 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:764:30\n    │\n764 │         if (d.amount == 0 || block.timestamp < d.since + 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:771:9\n    │\n771 │         emit LossRecognized(token, loss);\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:792:17\n    │\n792 │                 block.timestamp < a.probationUntil,\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:811:13\n    │\n811 │             nav += amount.mulDiv(uint256(answer), 1e8);\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:810:52\n    │\n810 │             if (!_priceOK(a, ok, answer, updated)) revert DepositUnavailable(Reason.InvalidPrice, a.token);\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:811:34\n    │\n811 │             nav += amount.mulDiv(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\n","passed":true},{"durationMs":355,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/Losses.t.sol:LossesTest\n[PASS] testLargerFlagResetsClockAndUnrecordedLossRemains() (gas: 818347)\n[PASS] testLossDelayNoAutomaticReductionAndMinCurrentShortfall() (gas: 1408524)\n[PASS] testSuccessfulDepositClearsEveryRecoveredRecord() (gas: 1862742)\n[PASS] testTotalLossZeroNAVBlocksDepositButNotRedeem() (gas: 986608)\n[PASS] testUnderfundedOwedBlocksDepositIntoToken() (gas: 899493)\n[PASS] testUnreadableBalanceCannotRecognizeLoss() (gas: 721499)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 5.04ms (4.48ms CPU time)\n\nRan 13 tests for test/Deposit.t.sol:DepositTest\n[PASS] testDeadlineReceiverAndMinimumShares() (gas: 476693)\n[PASS] testDeploymentAndFirstDeposit() (gas: 709446)\n[PASS] testDonationDoesNotAffectSharesOrNAV() (gas: 794834)\n[PASS] testExactInRejectsTaxAndLyingTokens() (gas: 1628981)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 727869)\n[PASS] testFuzzFirstDepositRounding(uint96,bool) (runs: 256, μ: 394707, ~: 357447)\nLogs:\n  Bound result 249999900000000009595\n\n[PASS] testGenesisAndOpeningDelay() (gas: 6595387)\n[PASS] testGlobalBucketAndLinearDecay() (gas: 11973118)\n[PASS] testManagedPriceStalenessAndOraclePause() (gas: 10135587)\n[PASS] testMarketBoundariesAllDays() (gas: 395696)\n[PASS] testMarketFreshnessAndPriceBoundaries() (gas: 2189288)\n[PASS] testNAVAndConcentrationCaps() (gas: 842389)\n[PASS] testUnreadableEmptyAssetAlsoBlocksDeposit() (gas: 412572)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 25.23ms (30.54ms CPU time)\n\nRan 3 tests for test/Redemption.t.sol:RedemptionGasTest\n[PASS] test64GasBurningTransfersAndCostlyReadableBalances() (gas: 305982727)\nLogs:\n  64-asset redeem gas: 22663996\n\n[PASS] test64MixedPausedBlockedUpgradedAndHealthyAssets() (gas: 298111483)\nLogs:\n  64-asset redeem gas: 7404841\n\n[PASS] test64UnreadableGasBombs() (gas: 292786019)\nLogs:\n  64-asset redeem gas: 10294652\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 112.69ms (258.73ms CPU time)\n\nRan 11 tests for test/Redemption.t.sol:RedemptionTest\n[PASS] testAllUserFacingEntrypointsRejectReentrancy() (gas: 11062880)\n[PASS] testBlockedCallerDefersOnlyBadLegThenClaimsElsewhere() (gas: 1309864)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesBalance() (gas: 958778)\n[PASS] testClaimHasNo250kPaymentLimit() (gas: 1154708)\n[PASS] testEveryUnreadableBalanceOutcomeUsesManaged() (gas: 1625158)\n[PASS] testFuzzRedeemConservesManagedPaidAndOwed(uint96,uint96,bool) (runs: 256, μ: 600123, ~: 577084)\nLogs:\n  Bound result 249990000000000001103\n  Bound result 20514\n\n[PASS] testHostileTransfersRollBackAndCreateDebt() (gas: 2014730)\n[PASS] testOwedIsReservedFromLaterRedemptions() (gas: 718661)\n[PASS] testRedeemFormulaAndNoPriceRead() (gas: 1432435)\n[PASS] testSlippageAndDeadlineAreAtomicEvenAfterEarlierLegPaid() (gas: 1249864)\n[PASS] testUpgradeToNoCodeCannotBlockRedeem() (gas: 483531)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 261.29ms (52.83ms CPU time)\n\nRan 6 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testFeeRecipientRedeemsOwnSharesWithoutExtraBurn() (gas: 546003)\n[PASS] testFullPrecisionMathEdges() (gas: 4298)\n[PASS] testFuzzFullPrecisionIdentity(uint256,uint256) (runs: 256, μ: 3770, ~: 3704)\n[PASS] testFuzzMathMatchesSmallProducts(uint128,uint128,uint128) (runs: 256, μ: 3763, ~: 3764)\n[PASS] testFuzzMultiUserConservation(uint256) (runs: 256, μ: 7249209, ~: 7279139)\n[PASS] testShareTransfersAndAllowancesDoNotChangeSupply() (gas: 840907)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 262.44ms (266.96ms CPU time)\n\nRan 14 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testAssetLimit64() (gas: 128704455)\n[PASS] testBandUsesExecutionAnswerAndStrictFreshness() (gas: 473087)\n[PASS] testCancellationGuardianReplacementAndExpiry() (gas: 983267)\n[PASS] testConstructorAndEmptyDeployment() (gas: 362964)\n[PASS] testFeedChecksTwiceAndSharedChangeCooldown() (gas: 3272597)\n[PASS] testGuardianCannotBecomeOwnerThroughPendingHandover() (gas: 293194)\n[PASS] testListingChecksAndAtomicBatch() (gas: 6611379)\n[PASS] testListingRechecksAtExecutionAndProbationCap() (gas: 4071807)\n[PASS] testNAVCapMaximumAndDelayedRaise() (gas: 332983)\n[PASS] testPauseAndCloseStatus() (gas: 356125)\n[PASS] testReopenCancelledByLaterCloseIncludingSameTimestamp() (gas: 671479)\n[PASS] testRolesCannotTakeAssetsOrMintOrBlockExits() (gas: 1007101)\n[PASS] testRuntimeMatchesProtectedOpcodeAndSizeChecks() (gas: 9903732)\n[PASS] testTwoStepOwnershipAndNoRenounce() (gas: 240570)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 262.76ms (46.21ms CPU time)\n\nRan 6 test suites in 264.16ms (929.45ms CPU time): 53 tests passed, 0 failed, 0 skipped (53 total tests)\n","passed":true},{"durationMs":50,"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.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\":3,\"README.md\":102,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskVault.sol\":815,\"src/FullMath.sol\":42,\"test/Accounting.t.sol\":101,\"test/Base.t.sol\":85,\"test/Deposit.t.sol\":222,\"test/Governance.t.sol\":341,\"test/Losses.t.sol\":115,\"test/Redemption.t.sol\":293,\"test/mocks/Mocks.sol\":183},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"1a584bf7fca59ddd71f4c07f888e52cd4b59a161f1391f8ce5b46ed352214ab7","verifiedTreeHash":"f0938dfa16eff473d631c6b8dfdd2dc7fd426724","verifierVersion":"0.1.0+7471272e"},{"checks":[{"durationMs":33005,"exitCode":0,"name":"build","output":"Compiling 31 files with Solc 0.8.26\nSolc 0.8.26 finished in 32.70s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:486:32\n    │\n486 │         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:488:17\n    │\n488 │         return (true, balance > reserved ? balance - reserved : 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:500:26\n    │\n500 │         if (!ok) return (false, 0, 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:521:23\n    │\n521 │         uint256 day = (block.timestamp / 1 days + 4) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:257:9\n    │\n257 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:436:13\n    │\n436 │             IStockToken(token).decimals() != 18\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:437:62\n    │\n437 │                 || IStockFactory(STOCK_FACTORY).tokenAddress(IStockToken(token).uid()) != token\n    │                                                              ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:437:20\n    │\n437 │                 || IStockFactory(STOCK_FACTORY).tokenAddress(IStockToken(token).uid()) != token\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:446:13\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(0)) revert InvalidFeed(feed);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:446:44\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(0)) revert InvalidFeed(feed);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:469:9\n    │\n469 │         emit AssetListed(token, feed, low, high);\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:354:9\n    │\n354 │         emit ProposalCreated(id, kind, token, target, value, ready);\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:434:91\n    │\n434 │         if (assetIndex[token] != 0 || assets.length >= MAX_ASSETS || 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:438:11\n    │\n438 │         ) 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:13\n    │\n444 │             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:446:84\n    │\n446 │         if (IFeed(feed).decimals() != 8 || IFeed(feed).aggregator() == address(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:448:33\n    │\n448 │         if (!ok || 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:458:45\n    │\n458 │         if (answer > type(uint256).max / 4) revert InvalidInput();\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:368:13\n    │\n368 │         if (block.timestamp < p.readyAt) revert ProposalNotReady();\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:371:17\n    │\n371 │             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:386:39\n    │\n386 │             if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 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:386:68\n    │\n386 │             if (!ok || answer <= 0 || updated > block.timestamp || block.timestamp - updated >= 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:382:13\n    │\n382 │             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:390:13\n    │\n390 │             emit BandChanged(p.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:403:9\n    │\n403 │         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:389:48\n    │\n389 │             (a.minAnswer, a.maxAnswer) = _band(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:407:28\n    │\n407 │         return p.active && block.timestamp < p.readyAt + PROPOSAL_WINDOW\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:414:43\n    │\n414 │             if (_pending(proposals[i])) ++count;\n    │                                           ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:421:21\n    │\n421 │                 ids[j] = i;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:449:16\n    │\n449 │         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:506:20\n    │\n506 │                 || updated > block.timestamp || block.timestamp - updated > 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:506:49\n    │\n506 │                 || updated > block.timestamp || block.timestamp - updated > 26 hours\n    │                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:505:35\n    │\n505 │             !ok || answer <= 0 || uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer\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:505:68\n    │\n505 │             !ok || answer <= 0 || uint256(answer) < a.minAnswer || uint256(answer) > a.maxAnswer\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:523:16\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:28\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:40\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 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:523:57\n    │\n523 │         return day >= 1 && day <= 5 && time >= 55800 && time < 70200;\n    │                                                         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:548:101\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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:533:13\n    │\n533 │         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:548:29\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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:548:60\n    │\n548 │             if (reads[i] && times[i] <= block.timestamp && block.timestamp - times[i] <= 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/FullMath.sol:17:58\n   │\n17 │             if (denominator == 0 || denominator <= high) 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:559:34\n    │\n559 │                 uint256 answer = uint256(answers[i]);\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:574:16\n    │\n574 │         return elapsed >= 1 days ? 0 : bucket - bucket.mulDiv(elapsed, 1 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:606:26\n    │\n606 │         bool probation = block.timestamp < _asset(token).probationUntil;\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:630:13\n    │\n630 │         if (block.timestamp > deadline) revert DeadlineExpired();\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:651:17\n    │\n651 │                 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:237:9\n    │\n237 │         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:657:9\n    │\n657 │         emit Deposited(msg.sender, token, receiver, amount, shares, 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:703:13\n    │\n703 │         if (block.timestamp > deadline) revert DeadlineExpired();\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:730:17\n    │\n730 │                 emit LegPaid(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:734:17\n    │\n734 │                 emit PaymentDeferred(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:737:9\n    │\n737 │         emit Redeemed(msg.sender, shares, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:721:69\n    │\n721 │             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-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, amount, 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:764:30\n    │\n764 │         if (d.amount == 0 || block.timestamp < d.since + 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:771:9\n    │\n771 │         emit LossRecognized(token, loss);\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:792:17\n    │\n792 │                 block.timestamp < a.probationUntil,\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:811:13\n    │\n811 │             nav += amount.mulDiv(uint256(answer), 1e8);\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:810:52\n    │\n810 │             if (!_priceOK(a, ok, answer, updated)) revert DepositUnavailable(Reason.InvalidPrice, a.token);\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:811:34\n    │\n811 │             nav += amount.mulDiv(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\n","passed":true},{"durationMs":10755,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/Redemption.t.sol:RedemptionGasTest\n[PASS] test64GasBurningTransfersAndCostlyReadableBalances() (gas: 305982727)\nLogs:\n  64-asset redeem gas: 22663996\n\n[PASS] test64MixedPausedBlockedUpgradedAndHealthyAssets() (gas: 298111483)\nLogs:\n  64-asset redeem gas: 7404841\n\n[PASS] test64UnreadableGasBombs() (gas: 292786019)\nLogs:\n  64-asset redeem gas: 10294652\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 144.84ms (350.19ms CPU time)\n\nRan 11 tests for test/Redemption.t.sol:RedemptionTest\n[PASS] testAllUserFacingEntrypointsRejectReentrancy() (gas: 11062880)\n[PASS] testBlockedCallerDefersOnlyBadLegThenClaimsElsewhere() (gas: 1309864)\n[PASS] testClaimFailurePreservesDebtAndPartialClaimUsesBalance() (gas: 958778)\n[PASS] testClaimHasNo250kPaymentLimit() (gas: 1154708)\n[PASS] testEveryUnreadableBalanceOutcomeUsesManaged() (gas: 1625158)\n[PASS] testFuzzRedeemConservesManagedPaidAndOwed(uint96,uint96,bool) (runs: 256, μ: 598384, ~: 577071)\nLogs:\n  Bound result 4150580787859058190\n  Bound result 239993779\n\n[PASS] testHostileTransfersRollBackAndCreateDebt() (gas: 2014730)\n[PASS] testOwedIsReservedFromLaterRedemptions() (gas: 718661)\n[PASS] testRedeemFormulaAndNoPriceRead() (gas: 1432435)\n[PASS] testSlippageAndDeadlineAreAtomicEvenAfterEarlierLegPaid() (gas: 1249864)\n[PASS] testUpgradeToNoCodeCannotBlockRedeem() (gas: 483531)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 309.40ms (45.61ms CPU time)\n\nRan 6 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testFeeRecipientRedeemsOwnSharesWithoutExtraBurn() (gas: 546003)\n[PASS] testFullPrecisionMathEdges() (gas: 4298)\n[PASS] testFuzzFullPrecisionIdentity(uint256,uint256) (runs: 256, μ: 3777, ~: 3704)\n[PASS] testFuzzMathMatchesSmallProducts(uint128,uint128,uint128) (runs: 256, μ: 3764, ~: 3764)\n[PASS] testFuzzMultiUserConservation(uint256) (runs: 256, μ: 7257226, ~: 7281781)\n[PASS] testShareTransfersAndAllowancesDoNotChangeSupply() (gas: 840907)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 326.14ms (935.17ms CPU time)\n\nRan 14 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testAssetLimit64() (gas: 128704455)\n[PASS] testBandUsesExecutionAnswerAndStrictFreshness() (gas: 473087)\n[PASS] testCancellationGuardianReplacementAndExpiry() (gas: 983267)\n[PASS] testConstructorAndEmptyDeployment() (gas: 362964)\n[PASS] testFeedChecksTwiceAndSharedChangeCooldown() (gas: 3272597)\n[PASS] testGuardianCannotBecomeOwnerThroughPendingHandover() (gas: 293194)\n[PASS] testListingChecksAndAtomicBatch() (gas: 6611379)\n[PASS] testListingRechecksAtExecutionAndProbationCap() (gas: 4071807)\n[PASS] testNAVCapMaximumAndDelayedRaise() (gas: 332983)\n[PASS] testPauseAndCloseStatus() (gas: 356125)\n[PASS] testReopenCancelledByLaterCloseIncludingSameTimestamp() (gas: 671479)\n[PASS] testRolesCannotTakeAssetsOrMintOrBlockExits() (gas: 1007101)\n[PASS] testRuntimeMatchesProtectedOpcodeAndSizeChecks() (gas: 9903732)\n[PASS] testTwoStepOwnershipAndNoRenounce() (gas: 240570)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 332.69ms (66.71ms CPU time)\n\nRan 6 tests for test/Losses.t.sol:LossesTest\n[PASS] testLargerFlagResetsClockAndUnrecordedLossRemains() (gas: 818347)\n[PASS] testLossDelayNoAutomaticReductionAndMinCurrentShortfall() (gas: 1408524)\n[PASS] testSuccessfulDepositClearsEveryRecoveredRecord() (gas: 1862742)\n[PASS] testTotalLossZeroNAVBlocksDepositButNotRedeem() (gas: 986608)\n[PASS] testUnderfundedOwedBlocksDepositIntoToken() (gas: 899493)\n[PASS] testUnreadableBalanceCannotRecognizeLoss() (gas: 721499)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 332.72ms (5.62ms CPU time)\n\nRan 13 tests for test/Deposit.t.sol:DepositTest\n[PASS] testDeadlineReceiverAndMinimumShares() (gas: 476693)\n[PASS] testDeploymentAndFirstDeposit() (gas: 709446)\n[PASS] testDonationDoesNotAffectSharesOrNAV() (gas: 794834)\n[PASS] testExactInRejectsTaxAndLyingTokens() (gas: 1628981)\n[PASS] testFeeRecipientIsFinalAndNeverCalled() (gas: 727869)\n[PASS] testFuzzFirstDepositRounding(uint96,bool) (runs: 256, μ: 394707, ~: 357447)\nLogs:\n  Bound result 249999901654928188326\n\n[PASS] testGenesisAndOpeningDelay() (gas: 6595387)\n[PASS] testGlobalBucketAndLinearDecay() (gas: 11973118)\n[PASS] testManagedPriceStalenessAndOraclePause() (gas: 10135587)\n[PASS] testMarketBoundariesAllDays() (gas: 395696)\n[PASS] testMarketFreshnessAndPriceBoundaries() (gas: 2189288)\n[PASS] testNAVAndConcentrationCaps() (gas: 842389)\n[PASS] testUnreadableEmptyAssetAlsoBlocksDeposit() (gas: 412572)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 332.77ms (263.31ms CPU time)\n\nRan 6 tests for test/AdversarialSequences.t.sol:AdversarialSequencesTest\n[PASS] testClaimsBelongToCallerEvenAfterSharesAreTransferredAndAllRolesCloseDeposits() (gas: 1180800)\n[PASS] testCompetingFeedProposalsRecheckUniquenessAndKeepFailedProposalPending() (gas: 950464)\n[PASS] testDepositDeferredRedemptionAndClaimEmitAccountingEvents() (gas: 831249)\n[PASS] testFuzzRepeatedBasketRoundTripsCannotCreateValue(uint256,uint256,uint8,bool) (runs: 1000, μ: 6304246, ~: 5504365)\nLogs:\n  Bound result 22221514978\n  Bound result 10567121861\n  Bound result 22353270199\n  Bound result 12\n  Bound result 269715753705572232\n  Bound result 905077225828091262\n  Bound result 611107203205224204\n  Bound result 50050737220814991\n  Bound result 638924116869927164\n  Bound result 87254262246597115\n  Bound result 78900151667597514\n  Bound result 281792470611395620\n  Bound result 652565892611858810\n  Bound result 788579136874117221\n  Bound result 1397021534351442988\n  Bound result 1682498544590774746\n\n[PASS] testOwnerOnlyEntrypointsRejectGuardianAndUnrelatedCaller() (gas: 1308796)\n[PASS] testZeroAndOneWeiRedemptionsAndFullWalletExit() (gas: 1008758)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 332.96ms (340.69ms CPU time)\n\nRan 2 tests for test/StatefulAccounting.t.sol:StatefulSetFeesTest\n[PASS] invariant_SupplyDebtAndIndependentTokenFlowsAgree() (runs: 256, calls: 32768, reverts: 0)\n\n╭---------------+-------------------+-------+---------+----------╮\n| Contract      | Selector          | Calls | Reverts | Discards |\n+================================================================+\n| BasketHandler | advanceTime       | 2814  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | changeIssuerState | 2707  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | claim             | 2744  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | deposit           | 2627  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | donate            | 2779  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | issuerBurn        | 2771  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | lossAction        | 2776  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | pause             | 2712  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | recoverMarket     | 2618  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | redeem            | 2737  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | setFees           | 2787  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | transferShares    | 2696  | 0       | 0        |\n╰---------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 22890\n  Bound result 24000\n  Bound result 14092\n  Bound result 19923252042\n  Bound result 12442\n  Bound result 6101294414015872035\n  Bound result 494146873851749662320\n  Bound result 19813\n  Bound result 155265\n  Bound result 599290589\n  Bound result 24\n  Bound result 3805373874187993767\n  Bound result 17801\n  Bound result 8293408613637865724\n  Bound result 3458314031240941100\n  Bound result 3333333333333323741\n  Bound result 319933\n  Bound result 4999900000000001599\n  Bound result 100000000\n  Bound result 15239\n  Bound result 2436661820954997249\n  Bound result 10807\n  Bound result 5000000000598958826\n  Bound result 581753910894266456530\n  Bound result 9479\n  Bound result 4999900003476405713\n  Bound result 14693\n  Bound result 252033333333314147\n  Bound result 3804\n  Bound result 345600\n  Bound result 18\n  Bound result 10816\n  Bound result 316719084339849389665\n  Bound result 0\n  Bound result 172800\n  Bound result 3591862243238688525\n  Bound result 1423\n  Bound result 4999900001767628801\n  Bound result 12426\n  Bound result 2400000000\n  Bound result 0\n  Bound result 12806\n  Bound result 0\n  Bound result 8223\n  Bound result 8003\n  Bound result 27112\n\n[PASS] testHandlerExercisesDeferredPaymentLossAndRecovery() (gas: 7340063)\nLogs:\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000\n  Bound result 604800\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 10.55s (10.55s CPU time)\n\nRan 2 tests for test/StatefulAccounting.t.sol:StatefulInitiallyUnsetFeesTest\n[PASS] invariant_SupplyDebtAndIndependentTokenFlowsAgree() (runs: 256, calls: 32768, reverts: 0)\n\n╭---------------+-------------------+-------+---------+----------╮\n| Contract      | Selector          | Calls | Reverts | Discards |\n+================================================================+\n| BasketHandler | advanceTime       | 2814  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | changeIssuerState | 2707  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | claim             | 2744  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | deposit           | 2627  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | donate            | 2779  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | issuerBurn        | 2771  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | lossAction        | 2776  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | pause             | 2712  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | recoverMarket     | 2618  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | redeem            | 2737  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | setFees           | 2787  | 0       | 0        |\n|---------------+-------------------+-------+---------+----------|\n| BasketHandler | transferShares    | 2696  | 0       | 0        |\n╰---------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 22636\n  Bound result 24000\n  Bound result 0\n  Bound result 19923252042\n  Bound result 12502\n  Bound result 6101294414015872035\n  Bound result 2019873826288073240\n  Bound result 19984\n  Bound result 155265\n  Bound result 599290589\n  Bound result 24\n  Bound result 3805373874187993767\n  Bound result 2480\n  Bound result 8053977689000842483\n  Bound result 3458314031240941100\n  Bound result 3333333333333323741\n  Bound result 11169\n  Bound result 4999900000000001642\n  Bound result 100000000\n  Bound result 15198\n  Bound result 2436661820954997249\n  Bound result 5293\n  Bound result 5000000000599067026\n  Bound result 386547597540339407960\n  Bound result 24363\n  Bound result 4999900000000003140\n  Bound result 14971\n  Bound result 252033333333314147\n  Bound result 3740\n  Bound result 345600\n  Bound result 18\n  Bound result 2073543814425000758\n  Bound result 13716965793591984\n  Bound result 16\n  Bound result 172800\n  Bound result 492005858032075049\n  Bound result 1957\n  Bound result 4999900001767628801\n  Bound result 12761\n  Bound result 2400000000\n  Bound result 5\n  Bound result 13840\n  Bound result 0\n  Bound result 8968\n  Bound result 18059\n  Bound result 18494\n\n[PASS] testHandlerExercisesDeferredPaymentLossAndRecovery() (gas: 7212615)\nLogs:\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 5000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000\n  Bound result 604800\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 10.66s (10.67s CPU time)\n\nRan 9 test suites in 10.67s (23.33s CPU time): 63 tests passed, 0 failed, 0 skipped (63 total tests)\n","passed":true},{"durationMs":40,"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.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\":3,\"README.md\":102,\"foundry.toml\":13,\"launch.json\":13,\"remappings.txt\":1,\"src/BaskVault.sol\":815,\"src/FullMath.sol\":42,\"test/Accounting.t.sol\":101,\"test/AdversarialSequences.t.sol\":190,\"test/Base.t.sol\":85,\"test/Deposit.t.sol\":222,\"test/Governance.t.sol\":341,\"test/Losses.t.sol\":115,\"test/Redemption.t.sol\":293,\"test/STATEFUL_TESTS.md\":38,\"test/StatefulAccounting.t.sol\":128,\"test/handlers/BasketHandler.sol\":300,\"test/mocks/Mocks.sol\":183},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"3328f25322f629ad2136c964c911d5c04c51e510943aab6986e2cd12da2da204","verifiedTreeHash":"58fc606781f805ef64054ada47b07a08c5ecef34","verifierVersion":"0.1.0+7471272e"}]}