{"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":"8a4b3bd0-acf4-422f-9f68-d02d4d7978ae","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"f69ac386cf74032298805e2d3d927a7d517eebae12f8babc6b837929394b23ed","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":"6b6e960073e210e07523e73dde0deb02f00467600d468a7c348b61abbf7991ec","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":"4cb01bb4cdc7d23330c98eff4b3d18a4adcf280dbc02c127ec0ce46c9c02ac25","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":"a35f4434b93b284f054d65247f53f83ae5f61be68e2085ec701bafe9625c1c2b","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":"e220283fbd8ff4b46592f1375b5d1f270284667b158eec8d799dc2dbb48798cf","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":"00b2cb162d9ba7c1700554feae5bab271b255db555b74299d20feee387261fb2","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"710a59f4bb4f5452a8e412a48a90105d3219f6eb3a3b4ef067bf29915bc11fe5","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"c450affee3e7c51c49ad60b0f9f888cc37f18bc4537f2a7413f08281f8174194","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Basket Protocol vault: an index vault for Stock Tokens on Robinhood Chain (chain id 4663). Contracts only: no launch token, pool or website. BASK is the vault's own ERC-20 share (18 decimals). Say \"Stock Tokens\", never \"tokenized\"; no Robinhood name or logo 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, via_ir, evm cancun, bytecode_hash none; custom errors.\n- If BaskVault exceeds 24,000 bytes of runtime, move views into BaskLens(address vault = $contract:BaskVault); never drop a check.\n- Constructors call no other contract. Time is block.timestamp.\n- No proxy, delegatecall, selfdestruct, rescue or sweep. User-facing state changes are nonReentrant and emit events.\n\nMANIFEST\n1. BaskVault(address owner_, address guardian_): owner_ = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3, guardian_ = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68, written as these literals. Reverts if either is zero or they are equal.\n\nOutside contracts (tests mock exactly these under test/; no fork tests, no vm.env):\n- Token: ERC-20, decimals() <= 18; may have oraclePaused() returns bool.\n- Feed: decimals() <= 18, latestRoundData(); answer = USD per whole token.\n- Pool: Uniswap v3 style token0(), token1(), observe(uint32[]).\n\nASSETS: (token, feed, pool, quoteFeed, minLiquidity, open, retired, hasPause, centre), at most maxAssets. managed[token] is the accounting balance: value never uses balanceOf; tokens sent directly are ignored.\nListing checks (proposal and execution): token not listed; token and feed decimals() <= 18; feed not used by another unretired asset; answer > 0 and under maxAge. At listing: open, centre = answer, hasPause = oraclePaused() returns a bool.\nGenesis: until finalizeGenesis() (once, needs 3+ assets), the owner lists assets with their pools at once; deposits open at finalize.\nAnyone may remove a retired asset with managed and totalOwed 0; its token may then be listed again.\n\nPROPOSALS (owner): list an asset with its pool; new feed (centre = new answer); re-centre on the answer at execution, under maxAge; reopen (cancelled by any later close); retire (closed both times); set an asset's pool, quoteFeed and minLiquidity, or none; resync (managed += balanceOf - managed - totalOwed, if above 0); new guardian; raise NAV_CAP; set feeRecipient (not zero or the vault); change a setting within its bounds. A proposal waits 2 days, then only the owner executes it; it lapses 7 days later; the owner or guardian may cancel it, the guardian not its own replacement. A retired asset is closed for good, voids its pending proposals, is skipped by deposit checks, 0 in NAV.\n\nSETTINGS (start; bounds): band 4 (2-100); maxAge 80 hours, noPoolAge 26 hours (1 hour-30 days); freshCount 0 (0-10), freshHours 4 (1-48); hours Mon-Fri from-to UTC (seconds of day; start 0-0 = always open); poolWindow 1800 s (300-86400); poolDeviation 300 bps (50-2000); feedGas, pauseGas 100,000, poolGas 150,000, balanceGas 50,000, payGas 250,000 (each 20,000-500,000); maxAssets 250; directLimit 25. A change must keep maxAssets >= asset count, maxAssets * (balanceGas + 60,000) <= 28,000,000 and directLimit * (balanceGas + payGas + 60,000) <= 28,000,000.\n\nPRICE is valid only if the feed read succeeds (feedGas), answer > 0, centre / band <= answer <= centre * band, updatedAt <= now, now - updatedAt <= maxAge, oraclePaused() returns false if hasPause (pauseGas), and: if the pool's observe over poolWindow (poolGas; Uniswap OracleLibrary.consult) succeeds with mean liquidity >= minLiquidity, its mean-tick price per whole token in whole quote tokens, times the quoteFeed price (> 0, under maxAge), is within poolDeviation of the feed price in USD; otherwise now - updatedAt <= noPoolAge. value(amount) = amount * answer * 1e18 / 10^(token decimals + feed decimals), rounded down. USD amounts below are dollars times 1e18.\n\ndeposit(tokens[], amounts[], receiver, minSharesOut, deadline) requires:\n- deposits open, not paused, inside hours; each token listed, open, once, amount > 0, vault balance >= totalOwed[token]; receiver not the vault;\n- freshCount or more listed assets updated within freshHours;\n- a valid price for each token and every asset with managed > 0; no asset short or unreadable (see LOSSES).\nPull the tokens; each vault balance must rise by exactly its amount. NAV = sum of value(managed) before; v = sum of value(amounts).\ngross = v if totalSupply is 0, else v * totalSupply / NAV rounded down (revert if NAV is 0). fee = gross * 50 / 10000, rounded up, minted to feeRecipient; no fee while unset. The receiver gets gross - fee; on the first deposit 1e15 of that goes to address(0xdEaD) instead. It must be > 0 and >= minSharesOut. NAV + v <= NAV_CAP (starts 1,000,000; lowering cancels pending raises; never above 10,000,000,000).\n\nredeem(shares, receiver, minAmountsOut[], deadline), receiver not zero, reads no price, ignores every pause and never reverts because of an asset. fee = shares * 50 / 10000 rounded up, transferred to feeRecipient; no fee while unset. net = shares - fee is burned. Per asset with managed > 0: available = balanceOf(vault) - totalOwed[token], floor 0 (static call, balanceGas, 32 bytes copied; else unreadable: available = managed); leg = min(managed, available) * net / totalSupplyBeforeBurn, rounded down; require leg >= minAmountsOut[i] (missing entry = 0); managed -= leg. If at most directLimit assets have managed > 0, each leg is paid to receiver by an external function only the vault may call, given payGas, reverting unless the transfer succeeds, returns nothing or true, and the vault balance falls by exactly leg; if that fails, or above directLimit, owed[receiver][token] and totalOwed[token] grow by leg. claim(tokens[], to), to not zero, pays each min(caller's owed, vault balance) by the same function with no gas limit.\n\nLOSSES. An asset is short when available < managed. Nothing lowers managed automatically. flagDeficit(token), by anyone, records shortfall and time if larger than recorded. recognizeLoss(token), by anyone 7 days or more later, lowers managed by min(recorded, current shortfall) and clears the record. A deposit clears unretired records.\n\nRoles:\n- Owner (two-step transfer, never to the guardian, no renounce): genesis, proposals, cancel; at once: close an asset to deposits, pause and unpause deposits, lower NAV_CAP.\n- Guardian: pause deposits, close an asset, cancel as stated.\n- Nobody can move assets, block redeem or claim, mint outside deposit, change a fee or upgrade.\n\nVIEWS: all assets with feed, answer, updatedAt, band, pool price, open, retired, managed, short, totalOwed; settings; previewDeposit; previewRedeem; depositStatus(tokens[]): reason code and asset at fault; pending proposals.\n\nREVIEW. Accepted, add no mechanism: (1) profit from feed lag under poolDeviation; (2) the owner pairs each token with its true feed and pool; (3) no per-asset limit; (4) moving a thin pool can stop deposits. MUST ATTACK: redeem with paused, blocked or upgraded tokens (maxAssets assets in any state: under 28,000,000 gas); any way a role or a setting blocks redeem.","parentJobId":null,"planHash":"bd661093428b6b0b083c702ffbc6cfc200e969e9ec75a058e1a95a9eb1fbff0a","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"8a4b3bd0-acf4-422f-9f68-d02d4d7978ae","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-985-basket"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51142","feedbackHash":"9300d35c6ededf6a24d3a59b8c9c91b5ad6935536c327e3d86923a73512f1940","nodeKey":"audit_economics","submissionHash":"f69ac386cf74032298805e2d3d927a7d517eebae12f8babc6b837929394b23ed","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51143","feedbackHash":"a73190f1355a3d306d281a2621d5418745de7fa392d2bd2bc680e7aabbb4166e","nodeKey":"audit_flow","submissionHash":"6b6e960073e210e07523e73dde0deb02f00467600d468a7c348b61abbf7991ec","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51507","feedbackHash":"427d2587e3652afdaef67489af56939c98a4063437294d18e2508fa3f04cffef","nodeKey":"audit_judge","submissionHash":"f5e3c1cce06ac1ee7beaabad670e34e5906ef1495ad52bd21b466c699303195b","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52158","feedbackHash":"3c0f2cca349a6b029cbd33eb52c1898368399e9d2ab0bfa068ec0b6f95ac3d63","nodeKey":"audit_judge","submissionHash":"4cb01bb4cdc7d23330c98eff4b3d18a4adcf280dbc02c127ec0ce46c9c02ac25","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52255","feedbackHash":"d732bcb93f6fcbcc03d450469ca882484612fa95b9117505fc7da723acd2ce04","nodeKey":"audit_math","submissionHash":"a35f4434b93b284f054d65247f53f83ae5f61be68e2085ec701bafe9625c1c2b","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52272","feedbackHash":"e70569e2035617d9b175cb051fa874d763d235decca80b8ff99f9dffeaa4e2d3","nodeKey":"audit_permissions","submissionHash":"e220283fbd8ff4b46592f1375b5d1f270284667b158eec8d799dc2dbb48798cf","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51156","feedbackHash":"81f0e18db49b475bcaa7e2080e1f74f79b045e9d37f1a7ccd72175d68d6059d2","nodeKey":"build_contract_project","submissionHash":"ea9620560d989e8f9caad2baf93d41f77ed4a4be4d255cfa8da7a3aa4e9450ba","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51756","feedbackHash":"dc18e0664babeecda9def0638514903a4264a0b50deaed2d60f836bd893c854b","nodeKey":"build_contract_project","submissionHash":"00b2cb162d9ba7c1700554feae5bab271b255db555b74299d20feee387261fb2","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51567","feedbackHash":"67134566521554a18b113eb0cd5e2e4d7d7ff2e4f112ecf4f2f4e1ee362fd7fd","nodeKey":"manifest","submissionHash":"36da079d81f1db02bf31f42709ca36089fa2d6e6aa5113bb8992f49282de889e","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51749","feedbackHash":"1d6b7d604a306c6fb01ede010a3e75483e5b0cb993a1e3cd76d2a78d003cbe9b","nodeKey":"manifest","submissionHash":"710a59f4bb4f5452a8e412a48a90105d3219f6eb3a3b4ef067bf29915bc11fe5","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51171","feedbackHash":"381b8364cc439b10bd0a3951b3f5c8c50b95c7303df7bae93559c0a850a81a45","nodeKey":"write_foundry_tests","submissionHash":"c450affee3e7c51c49ad60b0f9f888cc37f18bc4537f2a7413f08281f8174194","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51585","feedbackHash":"3e16e8ea5f123f954ea0c3b31c64e5285419792b32811f65c398558d1bd732b3","nodeKey":"write_foundry_tests","submissionHash":"2b685e16b95ea98b97677585bcc66a9089aa8f40146a90807f5885fc49272623","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"b67c53643e056d0b3e51cbbbbb95ddc6044f511cb6b148d31df19af757c29f11","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"846e7b0d3897b4e278b6d039ac28bd6060ac1e7a029a28df342db1aa926833c8","device":"83b36551000748bb","findings":[],"hash":"00b2cb162d9ba7c1700554feae5bab271b255db555b74299d20feee387261fb2","nodeId":"9bba37b3-5e7b-481d-b337-118afe77e975","outcome":"completed","summary":"Fixed retirement dilution and tightened receiver, guardian, and trailing-minimum checks. All six findings are answered in [.imd-responses.json](/root/.identitymd/work/8a4b3bd0-acf4-422f-9f68-d02d4d7978ae/9bba37b3-5e7b-481d-b337-118afe77e975/.imd-responses.json).\n\nPermanent-share residuals, zero-NAV behavior, and remaining positional-minimum limitations are documented.\n\nValidation passed: build, 74 tests, unchanged reviewer proof, and formatting. Runtime: 22,881 bytes.","treeHash":"422ef71596982416562ff8a9664cfc6752d9499d","usage":{"cachedInputTokens":2268928,"inputTokens":108451,"model":"gpt-6-astra","outputTokens":21210,"runtime":"codex","turns":7,"wallClockMs":683709}},{"artifacts":[],"attempt":1,"bundleHash":"381640a605f60646826ad698b4eee65d7f31f43aeb9fb7ca5a3b92ac9847a5b8","device":"264c3bd81028b74a","findings":[],"hash":"2b685e16b95ea98b97677585bcc66a9089aa8f40146a90807f5885fc49272623","nodeId":"247b119c-a273-47fd-8d57-5b25dbe0da83","outcome":"completed","summary":"Added offline adversarial, fuzz and invariant tests under `test/`, covering accounting, losses, reentrancy, rollback, governance races and hostile redemptions.\n\n`forge build` and the full `forge test` suite pass, including 16,384 randomized handler calls. The 250-asset upgrade attack redeemed within 14.1 million gas.\n\nNo confirmed defects found. Production contracts and configuration remain unchanged.","treeHash":"58364ad1f791e89a187122a04fc4e93b0f280596","usage":{"cachedInputTokens":1924224,"inputTokens":121375,"model":"gpt-6-astra","outputTokens":27494,"runtime":"codex","turns":7,"wallClockMs":1065670}},{"artifacts":[],"attempt":1,"bundleHash":"91315bd150df26f0bef1b79ae9e02974998b41523f009dc859670efad710444b","device":"165e283901cb9619","findings":[],"hash":"36da079d81f1db02bf31f42709ca36089fa2d6e6aa5113bb8992f49282de889e","nodeId":"23e455f0-acb9-453a-9a84-8fbbcfdd060b","outcome":"completed","summary":"Updated [launch.json](/root/.identitymd/work/8a4b3bd0-acf4-422f-9f68-d02d4d7978ae/23e455f0-acb9-453a-9a84-8fbbcfdd060b/launch.json) for `BaskVault`, retaining the exact owner and guardian literals and clarifying BASK’s supply model.\n\nSchema and constructor ABI checks passed. Runtime: 22,761 bytes. `forge build` succeeded; all 62 tests passed.\n\nOnly `launch.json` changed outside permitted scratch artifacts.","treeHash":"c49ef3db0fd49a2fb58e35f7bde068390e7f358b","usage":{"cachedInputTokens":472448,"inputTokens":46960,"model":"gpt-6-astra","outputTokens":3766,"runtime":"codex","turns":4,"wallClockMs":210767}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4dd67dae195771b6","findings":[{"citation":"resolved","description":"Settlement of the earlier advisory finding 3a640d3b (residual managed) in light of the fix for 82237965 (retired-asset extraction). The extraction fix holds: _depositContext now returns Reason.RetiredBacking whenever a retired asset has managed != 0, and deposit, previewDeposit and depositStatus all share it; all four specialist proofs now stop at the attacker's deposit with DepositUnavailable(16, token) and my own proof passes. The residual still reproduces exactly as before: redeem lowers managed only by floor(min(managed, available) * net / totalSupply) with net < totalSupply because address(0xdEaD) holds 1e15 shares forever, so managed[retired] converges to a positive residual that no redeem can clear, and recognizeLoss needs a shortfall the vault cannot create itself. Combined with the new check, retiring any asset that ever received a deposit is now an irreversible 'deposits off' switch for the whole vault: every deposit of every healthy asset reverts RetiredBacking, removeAsset reverts InvalidAsset, the token can never be relisted, and no owner action (Feed, Recentre, Resync of another asset, Reopen) reopens deposits. Redeem and claim are unaffected, no funds are lost, and the author documents this in README.md and tests it in test/Revision.t.sol::testPermanentSharesKeepResidualAndRetiredDepositRestriction, so this is not a new defect to reopen but the settled form of the earlier advisory: the brief's 'retired ... is skipped by deposit checks' and 'its token may then be listed again' are unreachable for a funded asset. The practical consequence for the owner is that Retire must never be used on a funded asset; a dead feed should be handled with the Feed action instead. If a redeem-only end state after a routine retirement is unacceptable, the alternative route from the first round (value retired holdings in deposit NAV at the frozen centre, keeping them redeemable) avoids it, but that is a scope decision for the author.","line":663,"path":"src/BaskVault.sol","reproduction":"Three 18-decimal $1 tokens with 8-decimal feeds, no pools, feeRecipient unset. alice deposits 100e18 of each (supply 300e18, 1e15 of it at 0xdEaD). Owner closeAsset(token0); propose({action: Retire, token: token0}); warp 2 days; executeProposal. bob deposit([token1],[300e18], bob, 0, now) reverts DepositUnavailable(RetiredBacking, token0) (fix confirmed). alice redeem(balanceOf(alice) = 300e18 - 1e15, alice, [], now): afterwards totalSupply == 1e15 and managed[token0] == 333333333333334. bob's identical deposit still reverts DepositUnavailable(RetiredBacking, token0); removeAsset(token0) reverts InvalidAsset(token0). Expected per the brief: a retired asset is skipped by deposit checks and, once empty, removable and relistable. Actual: deposits of every asset are permanently unavailable and token0 is never removable. test/scratch/Settle.t.sol::test_retiredBackingBlocksDeposit passes on this code and logs supply 1000000000000000, managed0 333333333333334.","severity":"low","snippet":"                if (managed[token] != 0) return (Reason.RetiredBacking, token, 0, prices);","title":"Residual managed on a retired asset is permanent, so the new RetiredBacking restriction makes deposits unavailable for good once any funded asset is retired"}],"hash":"4cb01bb4cdc7d23330c98eff4b3d18a4adcf280dbc02c127ec0ce46c9c02ac25","nodeId":"0ae4a1bd-7e3a-43c7-b2ef-f0dca4440f61","outcome":"completed","summary":"Review settled. The findings file at `.imd-findings.json` holds one low finding and a 22-row coverage record (all 20 entry points plus two invariants). No source files were changed; only `test/scratch/Settle.t.sol` was written, which is not kept.\n\n**Settlement of the six earlier findings**\n\n- **Retired-asset extraction (high): fixed.** Deposits now revert with reason RetiredBacking whenever a retired asset has nonzero managed backing, shared by deposit, previewDeposit and depositStatus. All four specialist proofs and my own first-round proof confirm it: theirs stop at the attacker's deposit with that revert, mine passes.\n- **Redeem to the vault (low): fixed.** Redeem now rejects the vault as receiver with InvalidAddress before any fee or burn.\n- **Trailing minimum dropped by removeAsset (low): fixed.** Any nonzero minimum beyond the registry length reverts Slippage, so the original front-run reverts both before and after removal.\n- **Guardian equal to pending owner (low): fixed.** Rejected at proposal and rechecked at execution, including when the handover starts during the timelock.\n- **ZeroNAV lock (low): dropped.** It still reproduces, but the brief mandates reverting at zero NAV and the permanent dead shares, so the author's dispute holds.\n- **Residual managed on retired assets (low): retained, reworded.** The state reproduces exactly as before (supply 1e15, managed 333333333333334). With the new check it now means retiring any funded asset switches deposits off for good, and the asset can never be removed or relisted. The author documents and tests this. I kept it low: no funds are lost, redeem and claim work, and the alternative route from the first round is a scope decision for the author.\n\n**No new defects.** The fix diff is small and I traced every changed line. The existing suite of 96 tests passes, including the 250-asset redeem gas tests under the 28,000,000 limit.","treeHash":null,"usage":{"cachedInputTokens":850462,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":15788,"runtime":"claude","turns":20,"wallClockMs":368657}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e0f2f45a1b346346","findings":[],"hash":"5b9e9aaf8a8073ac73cc824c2ecf94132f9823f670f8a76f82180f0fc75b8a64","nodeId":"23e455f0-acb9-453a-9a84-8fbbcfdd060b","outcome":"failed","summary":"the task produced no changes; the agent's last message was: [launch.json](/root/.identitymd/work/8a4b3bd0-acf4-422f-9f68-d02d4d7978ae/23e455f0-acb9-453a-9a84-8fbbcfdd060b/launch.json) already matches the accepted implementation and required address literals, so it remains unchanged.\n\n- Schema and constructor ABI checks passed.\n- `forge build` passed.\n- `forge test`: 74 passed, 0 failed.\n- Runtime: 22,881 bytes, below 24,000.\n\nNo tracked files changed.","treeHash":null,"usage":{"cachedInputTokens":641792,"inputTokens":58177,"model":"gpt-6-astra","outputTokens":3968,"runtime":"codex","turns":5,"wallClockMs":240251}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a4c81f495eb81dd0","findings":[{"citation":"resolved","description":"Execution x first-principles seam. _depositContext (line 660) skips retired assets entirely, so the NAV used to price new shares (line 673, 704) excludes managed[token] of every retired asset. redeem (lines 815-820) does not look at retired at all: every asset with managed > 0 pays leg = min(managed, available) * net / supply, retired or not. The two sides of the deposit/redeem pair therefore use different asset sets. Whoever deposits after a Retire proposal executes is minted shares against the shrunken NAV and then redeems a proportional slice of the retired backing that existing holders paid for. Retirement is an owner action, but it is public two days ahead (Proposed event, pendingProposals) and the extraction is done by any unprivileged depositor, so it clears the admin-amplifier gate as a race/asymmetric-formula case. Retirement of a still-transferable, still-valuable token is realistic: a managed asset whose feed goes stale or dead blocks every deposit (deposit requires a valid price for every asset with managed > 0), so the owner is pushed to retire exactly those assets, and a deprecated feed does not make the token worthless. Loss: existing holders lose value(managed[retired]) * newShares / newSupply per post-retirement deposit, repeatable until the retired backing is drained. Note this is how the brief’s text reads (“retired ... 0 in NAV”, redeem “per asset with managed > 0”), so the fix is a scope decision for the author: either value retired assets in NAV at their last centre, or exclude retired assets from redeem legs for shares minted after retirement, or allow retirement only once managed is 0.","line":660,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract ProofToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 v) external {\n        balanceOf[to] += v;\n    }\n\n    function approve(address s, uint256 v) external returns (bool) {\n        allowance[msg.sender][s] = v;\n        return true;\n    }\n\n    function transfer(address to, uint256 v) external returns (bool) {\n        balanceOf[msg.sender] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n}\n\ncontract ProofFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer = 1e8;\n    uint256 public updatedAt = block.timestamp;\n\n    function touch() external {\n        updatedAt = block.timestamp;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// Retiring an asset zeroes it in NAV while redeem still pays it out pro rata.\n/// A depositor arriving after the retirement is priced on the remaining NAV only,\n/// then redeems a share of the retired backing as well: value flows from existing\n/// holders to the new depositor.\ncontract RetiredNavTest is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    BaskVault vault;\n    ProofToken[3] tokens;\n    ProofFeed[3] feeds;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(10 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        for (uint256 i; i < 3; ++i) {\n            tokens[i] = new ProofToken();\n            feeds[i] = new ProofFeed();\n            vm.prank(OWNER);\n            vault.genesisList(address(tokens[i]), address(feeds[i]), address(0), address(0), 0);\n            tokens[i].mint(alice, 1_000e18);\n            tokens[i].mint(bob, 1_000e18);\n            vm.prank(alice);\n            tokens[i].approve(address(vault), type(uint256).max);\n            vm.prank(bob);\n            tokens[i].approve(address(vault), type(uint256).max);\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < 3; ++i) {\n            feeds[i].touch();\n        }\n    }\n\n    function testPostRetirementDepositorExtractsRetiredBacking() public {\n        // Alice deposits 100 token0 + 100 token1, both worth $1: NAV $200, supply 200e18.\n        address[] memory ts = new address[](2);\n        uint256[] memory amts = new uint256[](2);\n        ts[0] = address(tokens[0]);\n        ts[1] = address(tokens[1]);\n        amts[0] = 100e18;\n        amts[1] = 100e18;\n        vm.prank(alice);\n        vault.deposit(ts, amts, alice, 0, block.timestamp);\n        assertEq(vault.totalSupply(), 200e18);\n\n        // Owner closes token0 and retires it through the timelock. token0 still transfers and is still worth $1.\n        vm.prank(OWNER);\n        vault.closeAsset(address(tokens[0]));\n        BaskVault.ProposalData memory d;\n        d.action = BaskVault.Action.Retire;\n        d.token = address(tokens[0]);\n        vm.prank(OWNER);\n        uint256 id = vault.propose(d);\n        vm.warp(block.timestamp + 2 days);\n        _refresh();\n        vm.prank(OWNER);\n        vault.executeProposal(id);\n\n        // Bob deposits $100 of token1. NAV now counts only token1 ($100), so Bob is minted 200e18 shares: half the vault.\n        address[] memory one = new address[](1);\n        uint256[] memory oneAmt = new uint256[](1);\n        one[0] = address(tokens[1]);\n        oneAmt[0] = 100e18;\n        vm.prank(bob);\n        uint256 shares = vault.deposit(one, oneAmt, bob, 0, block.timestamp);\n        assertEq(shares, 200e18);\n\n        // Bob redeems immediately and receives half of token0 as well as half of token1.\n        uint256 t0Before = tokens[0].balanceOf(bob);\n        uint256 t1Before = tokens[1].balanceOf(bob);\n        vm.prank(bob);\n        vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n        uint256 got0 = tokens[0].balanceOf(bob) - t0Before;\n        uint256 got1 = tokens[1].balanceOf(bob) - t1Before;\n\n        // Bob paid $100 and must not take out more than $100 of backing. Currently he takes $150 ($50 of it is Alice's token0).\n        assertLe(got0 + got1, 100e18, \"post-retirement depositor extracted retired backing from existing holders\");\n    }\n}","reproduction":"State: three $1 assets listed, pool-less. (1) alice deposits 100e18 token0 + 100e18 token1: supply 200e18, NAV $200. (2) owner closeAsset(token0); propose(Retire, token0); warp 2 days; executeProposal: token0.retired = true, token0 still transfers. (3) bob deposits 100e18 token1: _depositContext skips token0, NAV = 100e18, gross = 100e18 * 200e18 / 100e18 = 200e18 shares (expected ~100e18 if token0 were valued). (4) bob redeems 200e18 immediately: supply 400e18, net 200e18, leg0 = 100e18 * 200e18 / 400e18 = 50e18 token0, leg1 = 200e18 * 200e18 / 400e18 = 100e18 token1. Bob receives $150 for $100; alice is left with 50e18 token0 + 100e18 token1 = $150 of the $200 she deposited. Test test/scratch/RetiredNav.t.sol asserts bob’s proceeds <= 100e18 and fails with 150000000000000000000 > 100000000000000000000.","severity":"medium","snippet":"            if (a.retired) continue;","title":"Retired asset is 0 in deposit NAV but still paid pro rata by redeem: post-retirement depositors extract existing holders’ backing"},{"citation":"resolved","description":"deposit rejects receiver == address(this) (line 722) but redeem only rejects address(0). With receiver = vault, pay() calls token.transfer(vault, leg): a self-transfer leaves the vault balance unchanged, so the exact-debit check at line 770 reverts, _tryPay returns false and line 827-828 record owed[vault][token] += leg and totalOwed[token] += leg. claim() keys on msg.sender, and the vault never calls claim on itself, so this debt can never be paid and the tokens are stranded (no sweep exists by design). Consequences beyond the redeemer’s own loss: totalOwed[token] stays > 0 forever, which makes removeAsset (line 330 requires totalOwed == 0) impossible for that token for the life of the vault, so a retired token can never be delisted or relisted and its registry slot counts against maxAssets permanently. The cost is dust: redeeming 1e3 shares strands 1e3 wei per funded asset. Fix: reject receiver == address(this) in redeem as deposit already does.","line":786,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract ProofToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 v) external {\n        balanceOf[to] += v;\n    }\n\n    function approve(address s, uint256 v) external returns (bool) {\n        allowance[msg.sender][s] = v;\n        return true;\n    }\n\n    function transfer(address to, uint256 v) external returns (bool) {\n        balanceOf[msg.sender] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n}\n\ncontract ProofFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer = 1e8;\n    uint256 public updatedAt = block.timestamp;\n\n    function touch() external {\n        updatedAt = block.timestamp;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// redeem() accepts receiver == address(vault). A self-transfer never lowers the vault balance,\n/// so pay() reverts and the legs are booked as owed[vault][token] which nobody can ever claim.\n/// totalOwed[token] is then permanently non-zero, which blocks removeAsset() for that token forever.\ncontract RedeemToVaultTest is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    BaskVault vault;\n    ProofToken[3] tokens;\n    ProofFeed[3] feeds;\n    address alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(10 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        for (uint256 i; i < 3; ++i) {\n            tokens[i] = new ProofToken();\n            feeds[i] = new ProofFeed();\n            vm.prank(OWNER);\n            vault.genesisList(address(tokens[i]), address(feeds[i]), address(0), address(0), 0);\n            tokens[i].mint(alice, 1_000e18);\n            vm.prank(alice);\n            tokens[i].approve(address(vault), type(uint256).max);\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n    }\n\n    function testRedeemToVaultStrandsLegsAndPoisonsTotalOwed() public {\n        address[] memory one = new address[](1);\n        uint256[] memory amt = new uint256[](1);\n        one[0] = address(tokens[0]);\n        amt[0] = 100e18;\n        vm.prank(alice);\n        vault.deposit(one, amt, alice, 0, block.timestamp);\n\n        // Redeem a dust amount of shares to the vault itself. Expected: rejected like deposit(receiver = vault).\n        vm.prank(alice);\n        vm.expectRevert(BaskVault.InvalidAddress.selector);\n        vault.redeem(1e3, address(vault), new uint256[](0), block.timestamp);\n    }\n}","reproduction":"State: alice deposited 100e18 token0 (supply 100e18). Call redeem(1e3, address(vault), [], now) as alice. Expected: revert InvalidAddress like deposit. Actual: succeeds; afterwards owed[vault][token0] = 1000, totalOwed[token0] = 1000, managed[token0] = 99999999999999999000, vault balance unchanged at 100e18. No caller can ever reduce owed[vault][token0]; after a later Retire, removeAsset(token0) reverts InvalidAsset forever. Test test/scratch/RedeemToVault.t.sol expects the revert and fails with “next call did not revert as expected”.","severity":"low","snippet":"        if (receiver == address(0)) revert InvalidAddress();","title":"redeem accepts receiver == address(vault): legs are booked as owed to the vault itself, unclaimable forever, and totalOwed[token] is permanently poisoned"},{"citation":"resolved","description":"_validateProposal treats every action up to Resync as requiring an unretired asset (lines 415-418). Retired assets remain redeemable (redeem pays any asset with managed > 0) and the brief defines Resync as “managed += balanceOf - managed - totalOwed, if above 0” with no retirement restriction. Sequence that strands funds: an issuer freeze or seizure drops the vault’s balance (plausible for regulated Stock Tokens), anyone flags the deficit and recognises the loss after 7 days (managed -> 0), the owner retires the apparently dead asset, and the issuer later restores the balance. The restored tokens are neither managed nor owed; the only mechanism that could re-add them (Resync) is refused for retired assets and there is no sweep or rescue by design, so they are locked in the vault forever. The same applies to any donation or mis-sent transfer of a retired token. Fix: allow Action.Resync for retired assets (keep the ban for Feed/Recentre/Reopen/Pool), or allow it only while managed/totalOwed accounting is otherwise consistent.","line":418,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract ProofToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 v) external {\n        balanceOf[to] += v;\n    }\n\n    function confiscate(address from, uint256 v) external {\n        balanceOf[from] -= v;\n    }\n\n    function approve(address s, uint256 v) external returns (bool) {\n        allowance[msg.sender][s] = v;\n        return true;\n    }\n\n    function transfer(address to, uint256 v) external returns (bool) {\n        balanceOf[msg.sender] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n}\n\ncontract ProofFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer = 1e8;\n    uint256 public updatedAt = block.timestamp;\n\n    function touch() external {\n        updatedAt = block.timestamp;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// Tokens that return to the vault after a recognised loss on a retired asset can never be\n/// re-added to managed: Resync is rejected for retired assets, and there is no sweep.\ncontract RetiredResyncTest is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    BaskVault vault;\n    ProofToken[3] tokens;\n    ProofFeed[3] feeds;\n    address alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(10 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        for (uint256 i; i < 3; ++i) {\n            tokens[i] = new ProofToken();\n            feeds[i] = new ProofFeed();\n            vm.prank(OWNER);\n            vault.genesisList(address(tokens[i]), address(feeds[i]), address(0), address(0), 0);\n            tokens[i].mint(alice, 1_000e18);\n            vm.prank(alice);\n            tokens[i].approve(address(vault), type(uint256).max);\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < 3; ++i) {\n            feeds[i].touch();\n        }\n    }\n\n    function testRecoveredTokensOfRetiredAssetAreStranded() public {\n        address[] memory one = new address[](1);\n        uint256[] memory amt = new uint256[](1);\n        one[0] = address(tokens[0]);\n        amt[0] = 100e18;\n        vm.prank(alice);\n        vault.deposit(one, amt, alice, 0, block.timestamp);\n\n        // Issuer freezes the vault's holding: balance drops to zero; anyone flags and, 7 days later, recognises the loss.\n        tokens[0].confiscate(address(vault), 100e18);\n        vault.flagDeficit(address(tokens[0]));\n        vm.warp(block.timestamp + 7 days);\n        vault.recognizeLoss(address(tokens[0]));\n        assertEq(vault.managed(address(tokens[0])), 0);\n\n        // Owner retires the apparently dead asset.\n        vm.prank(OWNER);\n        vault.closeAsset(address(tokens[0]));\n        BaskVault.ProposalData memory d;\n        d.action = BaskVault.Action.Retire;\n        d.token = address(tokens[0]);\n        vm.prank(OWNER);\n        uint256 id = vault.propose(d);\n        vm.warp(block.timestamp + 2 days);\n        _refresh();\n        vm.prank(OWNER);\n        vault.executeProposal(id);\n\n        // The issuer returns the tokens to the vault.\n        tokens[0].mint(address(vault), 100e18);\n        assertEq(tokens[0].balanceOf(address(vault)), 100e18);\n\n        // Expected: the owner can resync so holders redeem the recovered tokens. Actual: InvalidAsset, funds stranded forever.\n        d.action = BaskVault.Action.Resync;\n        vm.prank(OWNER);\n        uint256 resync = vault.propose(d);\n        vm.warp(block.timestamp + 2 days);\n        _refresh();\n        vm.prank(OWNER);\n        vault.executeProposal(resync);\n        assertEq(vault.managed(address(tokens[0])), 100e18);\n    }\n}","reproduction":"State: alice deposited 100e18 token0. (1) token0.confiscate(vault, 100e18); flagDeficit(token0); warp 7 days; recognizeLoss(token0): managed[token0] = 0. (2) owner closeAsset(token0); propose(Retire); warp 2 days; executeProposal: retired. (3) token0.mint(vault, 100e18): vault balance 100e18, managed 0, totalOwed 0. (4) owner propose({action: Resync, token: token0}). Expected: accepted, and after execution managed[token0] = 100e18 so holders can redeem the recovered tokens. Actual: propose reverts InvalidAsset(token0) at line 418; the 100e18 can never leave the vault. Test test/scratch/RetiredResync.t.sol fails with InvalidAsset(0x2e23...).","severity":"low","snippet":"            if (a.retired) revert InvalidAsset(d.token);","title":"Resync is rejected for retired assets, so tokens that return to the vault after a recognised loss on a retired asset are stranded with no recovery path"},{"citation":"resolved","description":"The upper bound is implemented exactly (ceil(answer/band) > centre is equivalent to answer > centre*band). The lower bound compares against the integer-floored centre / band, so when centre is not divisible by band an answer strictly below the real quotient still passes. One-unit boundary asymmetry; no value impact beyond the price-gate boundary. If the brief’s “centre / band <= answer” is meant in exact arithmetic, use answer * band < centre as the lower test.","line":594,"path":"src/BaskVault.sol","reproduction":"Asset listed with centre = 123456789 (feed decimals 8), band = 4. Feed answer = 30864197, updatedAt = now, no pool. Real centre/band = 30864197.25 > answer, so expected priceStatus = Band. Actual: 30864197 < 123456789/4 = 30864197 is false, so _price returns OK and deposits proceed. Upper side check: answer = 493827157 (= 4*centre + 1) is correctly rejected.","severity":"info","snippet":"        if (answer < a.centre / band || answer / band + (answer % band == 0 ? 0 : 1) > a.centre) {","title":"Band lower bound uses floored centre / band while the upper bound is exact, so an answer one unit below centre/band is accepted"}],"hash":"6b6e960073e210e07523e73dde0deb02f00467600d468a7c348b61abbf7991ec","nodeId":"e27dfaf5-c821-4bff-96e3-b5a7aab46911","outcome":"completed","summary":"The review is complete. No source files were changed; the working tree shows only the findings file and the scratch tests, both git-ignored.\n\n**Outcome.** The vault's control flow is tight: redeem reads no price, no role or setting can make it revert, gas stays under the 28M bound at the setting limits, governance epochs void stale proposals correctly, and the periphery libraries decode and bound external returns properly. I found one medium defect and two low ones, each reproduced with a failing Foundry test, plus one boundary note.\n\n**Findings written to `.imd-findings.json`:**\n\n1. **Medium. Retired assets are zero in deposit NAV but redeem still pays them.** A depositor arriving after a Retire executes is priced on the shrunken NAV and then redeems a slice of the retired backing. Concrete run: Alice holds $200 of two assets, owner retires one, Bob deposits $100 and immediately redeems $150. Retirement is the realistic owner response to a dead feed, and the extraction is unprivileged. The brief's text produces this, so the fix is a scope decision for the author.\n2. **Low. `redeem` accepts the vault itself as receiver.** Self-transfer never lowers the balance, so the legs are booked as owed to the vault and can never be claimed. The side effect is that the token's total owed stays nonzero forever, which blocks removal of that asset permanently. Costs dust to trigger.\n3. **Low. Resync is refused for retired assets.** Tokens restored by an issuer after a recognised loss on a retired asset have no path back into accounting and no sweep exists, so they are stranded.\n4. **Info. Band lower bound uses a floored quotient**, so an answer one unit below the real centre/band is accepted while the upper bound is exact.\n\n**Coverage.** All 20 listed entry points have a row, plus four invariant and periphery rows. Entry points marked holds were traced through their checks, state writes and failure paths. Findings attach to deposit, redeem and propose.\n\n**Not reached.** I did not independently re-measure gas beyond rerunning the author's Gas suite, and I did not fuzz the oracle math beyond the existing reciprocal and tick tests.","treeHash":null,"usage":{"cachedInputTokens":2166599,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":64908,"runtime":"claude","turns":36,"wallClockMs":1356903}},{"artifacts":[],"attempt":2,"bundleHash":"9a8589db3aa1e7292fd8d3e3709210601a10e21480df55d0a258dea1a3024991","device":"f6c59a24920668f6","findings":[],"hash":"710a59f4bb4f5452a8e412a48a90105d3219f6eb3a3b4ef067bf29915bc11fe5","nodeId":"23e455f0-acb9-453a-9a84-8fbbcfdd060b","outcome":"completed","summary":"Updated [launch.json](/root/.identitymd/work/8a4b3bd0-acf4-422f-9f68-d02d4d7978ae/23e455f0-acb9-453a-9a84-8fbbcfdd060b/launch.json) to clarify fee timing and deferred redemption payments, preserving the required constructor literals.\n\n- Manifest and constructor ABI checks passed.\n- `forge build` passed.\n- `forge test`: 74 passed, 0 failed.\n- Runtime: 22,881 bytes, below 24,000.\n\nOnly `launch.json` changed.","treeHash":"2a2db426ed0aa73f42a357dfe20a8381680efb77","usage":{"cachedInputTokens":776192,"inputTokens":39829,"model":"gpt-6-astra","outputTokens":5474,"runtime":"codex","turns":5,"wallClockMs":278352}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e06554fd2816f9d7","findings":[{"citation":"resolved","description":"Seam: boundary (retired flag) x invariant (share value conserved across deposit/redeem). _depositContext skips retired assets (line 660), so `nav` at line 673 is the value of unretired holdings only. redeem (lines 810-829) iterates every asset with managed > 0, retired or not, and pays `min(managed, available) * net / supply` of each. The two formulas value the same share differently: deposit mints `value * supply / nav` shares against the smaller NAV, redeem returns a pro-rata slice of everything, including the retired token. Whoever deposits after a retirement and redeems at once is paid part of the retired asset that belonged to the holders present at retirement. The transfer is bounded only by the retired asset's remaining value and the 1% round-trip fee (0% while feeRecipient is unset). A second consequence of the same exclusion is a permanent deposit lock: once every funded asset is retired, `nav == 0` with `supply != 0` reverts every deposit with ZeroNAV (line 703) even for new, healthy listings, because no deposit can ever raise `nav` above zero while supply stays positive (the 1e15 dead shares can never be burned). Fixing this needs a scope decision: either a retired asset with managed > 0 must not be redeemable through the ordinary pro-rata path (strand it until removed, or distribute it to the holders of record at retirement), or deposits must be refused while any retired asset still holds managed > 0. Simply valuing it in NAV is not possible since retirement is used precisely when the price can no longer be validated. The REVIEW.md note 'Retired positions have zero deposit NAV but remain redeemable' documents the mechanism but not that it is extractable by an unprivileged depositor.","line":660,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract LeakToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 v) external {\n        balanceOf[to] += v;\n    }\n\n    function approve(address s, uint256 v) external returns (bool) {\n        allowance[msg.sender][s] = v;\n        return true;\n    }\n\n    function transfer(address to, uint256 v) external returns (bool) {\n        balanceOf[msg.sender] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n}\n\ncontract LeakFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer;\n    uint256 public updatedAt;\n\n    constructor(int256 a) {\n        answer = a;\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 a, uint256 t) external {\n        answer = a;\n        updatedAt = t;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// Deposit values shares against a NAV that excludes retired assets, while redeem pays retired assets pro rata.\n/// A depositor who enters after a retirement and leaves at once takes part of the retired asset from earlier holders.\ncontract RetiredAssetValueLeakTest is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    BaskVault vault;\n    LeakToken[3] tokens;\n    LeakFeed[3] feeds;\n    address alice = makeAddr(\"alice\");\n    address attacker = makeAddr(\"attacker\");\n\n    function setUp() public {\n        vm.warp(10 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        for (uint256 i; i < 3; ++i) {\n            tokens[i] = new LeakToken();\n            feeds[i] = new LeakFeed(1e8);\n            vm.prank(OWNER);\n            vault.genesisList(address(tokens[i]), address(feeds[i]), address(0), address(0), 0);\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < 3; ++i) {\n            feeds[i].set(1e8, vm.getBlockTimestamp());\n        }\n    }\n\n    function testLateDepositorTakesRetiredAssetFromEarlierHolders() public {\n        // Alice funds the vault with 100 of each token ($300 NAV, 300e18 shares).\n        address[] memory ts = new address[](3);\n        uint256[] memory amts = new uint256[](3);\n        for (uint256 i; i < 3; ++i) {\n            ts[i] = address(tokens[i]);\n            amts[i] = 100e18;\n            tokens[i].mint(alice, 100e18);\n            vm.prank(alice);\n            tokens[i].approve(address(vault), 100e18);\n        }\n        vm.prank(alice);\n        vault.deposit(ts, amts, alice, 0, vm.getBlockTimestamp());\n        assertEq(vault.totalSupply(), 300e18);\n\n        // Owner closes and retires token 2. Its 100 tokens stay in the vault, redeemable, but count 0 in NAV.\n        vm.prank(OWNER);\n        vault.closeAsset(address(tokens[2]));\n        BaskVault.ProposalData memory d;\n        d.action = BaskVault.Action.Retire;\n        d.token = address(tokens[2]);\n        vm.prank(OWNER);\n        uint256 id = vault.propose(d);\n        vm.warp(vm.getBlockTimestamp() + 2 days);\n        _refresh();\n        vm.prank(OWNER);\n        vault.executeProposal(id);\n\n        (,,, uint256 nav) = vault.previewDeposit(_one(address(tokens[0])), _amount(1e18));\n        assertEq(nav, 200e18, \"retired asset excluded from NAV\");\n\n        // Attacker deposits 200 of token 0 ($200) and receives 300e18 shares: half the supply.\n        tokens[0].mint(attacker, 200e18);\n        vm.prank(attacker);\n        tokens[0].approve(address(vault), 200e18);\n        vm.prank(attacker);\n        uint256 shares = vault.deposit(_one(address(tokens[0])), _amount(200e18), attacker, 0, vm.getBlockTimestamp());\n        assertEq(shares, 300e18);\n\n        // Attacker redeems at once and is paid half of every managed asset, including the retired one.\n        vm.prank(attacker);\n        uint256[] memory legs = vault.redeem(shares, attacker, new uint256[](0), vm.getBlockTimestamp());\n        assertEq(legs[2], 50e18, \"half of the retired asset leaves with the attacker\");\n\n        uint256 usdOut = tokens[0].balanceOf(attacker) + tokens[1].balanceOf(attacker) + tokens[2].balanceOf(attacker);\n        // Expected: a round trip through the vault should not be profitable at the expense of earlier holders.\n        // Actual: the attacker put in $200 and leaves with $250 of tokens (150 + 50 + 50).\n        assertLe(usdOut, 200e18, \"deposit/redeem round trip extracts value from existing holders\");\n    }\n\n    function _one(address t) internal pure returns (address[] memory a) {\n        a = new address[](1);\n        a[0] = t;\n    }\n\n    function _amount(uint256 v) internal pure returns (uint256[] memory a) {\n        a = new uint256[](1);\n        a[0] = v;\n    }\n}","reproduction":"State: three 18-decimal tokens listed with 8-decimal $1.00 feeds, no pools, feeRecipient unset. 1) Alice deposits 100e18 of each (NAV $300, totalSupply 300e18). 2) Owner closes token2, proposes Retire, waits 2 days, executes. previewDeposit now reports nav = 200e18; managed[token2] is still 100e18. 3) Attacker deposits 200e18 of token0: gross = 200e18 * 300e18 / 200e18 = 300e18 shares (half of the new 600e18 supply). 4) Attacker redeems 300e18 at once: legs = [150e18, 50e18, 50e18]. Expected: a round trip through the vault returns at most the $200 deposited (less fees). Actual: attacker receives tokens worth $250 (150 + 50 + 50); Alice's remaining 300e18 shares now back 150e18 token0, 50e18 token1, 50e18 token2 instead of 100/100/100. Variant: with only token0 funded, retire token0, then any deposit of token1 reverts ZeroNAV() forever (test/scratch/RedeemToVault.t.sol::testDepositBlockedForeverOnceEveryFundedAssetIsRetired). The proof test fails on the current code with '250000000000000000000 > 200000000000000000000' and passes once the retired asset can no longer be captured by a post-retirement depositor (either path above).","severity":"medium","snippet":"            if (a.retired) continue;","title":"Deposit prices shares on a NAV that excludes retired assets while redeem pays retired assets pro rata, so a deposit/redeem round trip takes retired-asset value from earlier holders"},{"citation":"resolved","description":"Boundary: sentinel receiver. deposit rejects receiver == address(this) (line 722) but redeem only rejects zero (line 786). With receiver == address(this), pay() calls token.transfer(vault, leg): a standard token self-transfer succeeds but leaves the vault balance unchanged, so the exact-debit check in pay (line 770) reverts, _tryPay returns false, and lines 827-828 record owed[address(this)][token] += leg and totalOwed[token] += leg. claim() reads owed[msg.sender] and the vault can never be msg.sender of claim (its only self-call is pay), so that debt is unclaimable for good. Effects: (a) the redeemer's tokens are locked in the vault forever (self-harm), (b) totalOwed[token] stays >= leg permanently, so removeAsset (line 330) reverts for that token after it is retired and the token can never be relisted, and (c) `available = balance - totalOwed` is permanently reduced by the stranded amount for deposit and redeem accounting. Any share holder with enough shares for leg >= 1 wei can do this to every funded asset in one call. Fix: reject receiver == address(this) in redeem (and `to == address(this)` in claim, which currently just reverts in pay) the same way deposit does.","line":786,"path":"src/BaskVault.sol","reproduction":"State: token0 funded with 100e18 by Alice (100e18 shares), feeRecipient unset. 1) Alice transfers 1e18 shares to griefer. 2) griefer calls redeem(1e18, address(vault), [], now). Expected: either revert InvalidAddress like deposit, or payment to a usable receiver. Actual: returns legs[0] = 1e18, owed[vault][token0] = 1e18, totalOwed[token0] = 1e18, managed[token0] = 99e18, token balance unchanged. 3) Owner closes and retires token0, Alice redeems all her shares. 4) removeAsset(token0) reverts InvalidAsset(token0) because totalOwed[token0] == 1e18, and no call path can ever lower it (test/scratch/RedeemToVault.t.sol::testRedeemToVaultStrandsDebtAndBlocksRemoval).","severity":"low","snippet":"        if (receiver == address(0)) revert InvalidAddress();","title":"redeem accepts the vault itself as receiver: the leg is booked as owed to the vault, can never be claimed, and keeps totalOwed non-zero so removeAsset is blocked forever"}],"hash":"a35f4434b93b284f054d65247f53f83ae5f61be68e2085ec701bafe9625c1c2b","nodeId":"483cf28a-f613-4a3e-9dc5-cbd145896ace","outcome":"completed","summary":"Review complete. The findings are in `.imd-findings.json` (2 findings, 24 coverage rows). Git reports no tracked changes: only the findings file and `test/scratch/` were created, and `.imd-findings.json` and scratch are ignored.\n\n**What I found**\n\n- **Medium: retired-asset valuation asymmetry.** Deposit computes NAV without retired assets (`_depositContext` skips them at `src/BaskVault.sol:660`), but redeem pays every asset with managed > 0 pro rata. A depositor who enters after a retirement and redeems at once takes part of the retired asset from earlier holders. Proof test: $200 in, $250 out, with Alice's backing dropping from 100/100/100 to 150/50/50. The same exclusion also locks deposits permanently with ZeroNAV once every funded asset is retired. The fix needs a scope decision, which I describe in the finding, since the spec itself says retired assets are 0 in NAV.\n- **Low: redeem with the vault as receiver.** Deposit rejects the vault as receiver, redeem does not. The self-transfer fails the exact-debit check, the leg is booked as owed to the vault, nobody can ever claim it, and `totalOwed` stays non-zero so `removeAsset` is blocked forever for that token.\n\n**What held in my area (math precision, boundary, numerical gap)**\n\n- Share, fee, value, cap and leg arithmetic all round against the actor. A 3000-run fuzz across 18/8, 6/18 and 0/0 decimal pairs never lowered a remaining holder's USD claim through a stranger's deposit and redeem.\n- Band check uses ceiling division to avoid overflow, pool quote carries 18 extra decimals within uint128, and the oracle library matches Uniswap's consult and quote math including negative-tick floor and accumulator wrap.\n- Setting bounds are exact integer equivalents of the spec. The redeem gas guarantee holds: 27.91M at the extreme 50 assets × 500k balance gas with fees and non-zero minimums, 26.75M at 350 × 20k. The margin at the extreme is about 88k, which I noted in coverage rather than as a defect.\n- Static-analysis leads (weak PRNG, shift order, strict equality) were all false positives on inspection.\n\n**Not reached:** I did not trace the access-control and flow areas beyond what touched arithmetic. Those belong to the other specialists.","treeHash":null,"usage":{"cachedInputTokens":3866775,"inputTokens":866,"model":"claude-fable-5-1","outputTokens":70952,"runtime":"claude","turns":42,"wallClockMs":911373}},{"artifacts":[],"attempt":1,"bundleHash":"2f368afecb617454cd723d21cb05f959fb2e0a224ce0ea423cf1fb0f822eb5a9","device":"194b47a372650d59","findings":[],"hash":"c450affee3e7c51c49ad60b0f9f888cc37f18bc4537f2a7413f08281f8174194","nodeId":"247b119c-a273-47fd-8d57-5b25dbe0da83","outcome":"completed","summary":"Added six tests covering all 16 setting boundaries, proposal revalidation, and redemption/claim availability, including 1,000 fuzz cases.\n\n`forge build` and the full suite passed: 96 tests, zero failures, including existing invariants and gas attacks. Changes are confined to `test/`.","treeHash":"7ee3758a894af6595abc71d119c3424ab35bf1fb","usage":{"cachedInputTokens":1821568,"inputTokens":113889,"model":"gpt-6-astra","outputTokens":7744,"runtime":"codex","turns":6,"wallClockMs":280037}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ef31844bb462de78","findings":[{"citation":"resolved","description":"Trust gap (economics x asymmetry, triggered by an owner action). _depositContext skips every retired asset (line 660), so a retired position with managed > 0 contributes nothing to NAV and new shares are priced only on the unretired assets. redeem (lines 810-830) pays every asset whose managed bit is set, retired or not, pro rata to net/supply. The two formulas are not economically symmetric: shares minted after a retirement are sold without charging for the retired tokens, yet redeem them. Anyone can back-run the owner's Retire execution (a public, 2-day-timelocked proposal) with deposit+redeem and take up to retired_managed * V/(NAV+V) from existing holders, minus the 0.5% fee each way when a fee recipient is set. With NAV_CAP at 1,000,000 the extraction is bounded by the cap but repeatable by many actors. This is the behaviour the brief literally specifies (retired = '0 in NAV'; redeem pays every asset with managed > 0), so the fix needs a scope decision: either retirement must only be executable once managed[token] == 0 (after loss recognition or a full drain), or retired positions must be valued (e.g. at the frozen centre) in deposit NAV, or redeem must skip retired legs. Reported so the author can choose; the minimal code change is to add 'managed[d.token] == 0' to the Retire validation in _validateProposal.","line":660,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract ScratchToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 v) external {\n        balanceOf[to] += v;\n    }\n\n    function approve(address s, uint256 v) external returns (bool) {\n        allowance[msg.sender][s] = v;\n        return true;\n    }\n\n    function transfer(address to, uint256 v) external returns (bool) {\n        balanceOf[msg.sender] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n}\n\ncontract ScratchFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer;\n    uint256 public updatedAt;\n\n    constructor(int256 a) {\n        answer = a;\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 a, uint256 t) external {\n        answer = a;\n        updatedAt = t;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// Retired asset is excluded from deposit NAV but still paid pro rata by redeem.\n/// A depositor arriving after a retirement captures part of the retired position\n/// that existing holders paid for.\ncontract RetireDilutionTest is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    BaskVault vault;\n    ScratchToken[3] tokens;\n    ScratchFeed[3] feeds;\n    address holder = makeAddr(\"holder\");\n    address attacker = makeAddr(\"attacker\");\n\n    function setUp() public {\n        vm.warp(10 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        for (uint256 i; i < 3; ++i) {\n            tokens[i] = new ScratchToken();\n            feeds[i] = new ScratchFeed(1e8); // $1 per whole token\n            vm.prank(OWNER);\n            vault.genesisList(address(tokens[i]), address(feeds[i]), address(0), address(0), 0);\n            tokens[i].mint(holder, 1_000e18);\n            tokens[i].mint(attacker, 1_000e18);\n            vm.prank(holder);\n            tokens[i].approve(address(vault), type(uint256).max);\n            vm.prank(attacker);\n            tokens[i].approve(address(vault), type(uint256).max);\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < 3; ++i) feeds[i].set(1e8, block.timestamp);\n    }\n\n    function test_depositAfterRetireCapturesRetiredBacking() public {\n        // Existing holder deposits 100 of each token: NAV $300.\n        address[] memory ts = new address[](3);\n        uint256[] memory amts = new uint256[](3);\n        for (uint256 i; i < 3; ++i) {\n            ts[i] = address(tokens[i]);\n            amts[i] = 100e18;\n        }\n        vm.prank(holder);\n        vault.deposit(ts, amts, holder, 0, block.timestamp);\n\n        // Owner closes and retires token0 (still worth $1 off-chain, 100 units in vault).\n        vm.prank(OWNER);\n        vault.closeAsset(address(tokens[0]));\n        BaskVault.ProposalData memory d;\n        d.action = BaskVault.Action.Retire;\n        d.token = address(tokens[0]);\n        vm.prank(OWNER);\n        uint256 id = vault.propose(d);\n        vm.warp(block.timestamp + 2 days);\n        _refresh();\n        vm.prank(OWNER);\n        try vault.executeProposal(id) {}\n        catch {\n            // A fix that refuses to retire a funded position closes the window; nothing to exploit.\n            return;\n        }\n\n        // Attacker deposits 200 of token1 and token2 ($200 at NAV $200 -> 50% of supply).\n        address[] memory ts2 = new address[](2);\n        uint256[] memory amts2 = new uint256[](2);\n        ts2[0] = address(tokens[1]);\n        ts2[1] = address(tokens[2]);\n        amts2[0] = 100e18;\n        amts2[1] = 100e18;\n        vm.prank(attacker);\n        uint256 shares = vault.deposit(ts2, amts2, attacker, 0, block.timestamp);\n\n        // Attacker redeems immediately and receives a share of the retired token0.\n        vm.prank(attacker);\n        vault.redeem(shares, attacker, new uint256[](0), block.timestamp);\n\n        // Every token is worth $1, so the attacker's combined balance is their dollar position.\n        // Expected: a deposit-then-redeem round trip never returns more than was put in.\n        // Actual: attacker leaves with 3050e18 (50e18 of token0 taken from the holder).\n        uint256 total =\n            tokens[0].balanceOf(attacker) + tokens[1].balanceOf(attacker) + tokens[2].balanceOf(attacker);\n        assertLe(total, 3_000e18, \"post-retirement depositor extracted retired backing from holders\");\n    }\n}","reproduction":"Owner lists tokens T0,T1,T2 each with an 8-decimal $1 feed, finalizes genesis. Holder deposits 100e18 of each (NAV $300, supply 300e18). Owner closeAsset(T0), proposes Retire(T0), warps 2 days, executes. Attacker deposits 100e18 of T1 and 100e18 of T2 (value $200 at NAV $200 -> 200e18 shares, 50% of supply) and immediately redeems them with minAmountsOut empty. Expected: attacker gets back only T1/T2. Actual: amounts[0] == 50e18 of T0 and tokens[0].balanceOf(attacker) rises from 1000e18 to 1050e18; the holder's remaining claim on T0 falls from 100e18 to 50e18. Attacker's combined T0+T1+T2 balance goes from 3000e18 to 3050e18. Scratch test test/scratch/RetireDilution.t.sol fails with 'post-retirement depositor extracted retired backing from holders: 3050000000000000000000 > 3000000000000000000000'.","severity":"medium","snippet":"            if (a.retired) continue;","title":"Retired asset is excluded from deposit NAV but still paid by redeem: post-retirement depositors capture existing holders' retired backing"},{"citation":"resolved","description":"Asymmetry between the deposit and redeem branches. deposit rejects receiver == address(this) (line 722) but redeem only rejects address(0) (line 786) and claim only rejects to == address(0) (line 835). When receiver is the vault, pay() transfers vault -> vault, the balance does not fall, the 'beforeBalance - afterBalance != amount' check reverts the sandboxed payment, and redeem records owed[address(this)][token] += leg and totalOwed[token] += leg. The vault has no code path to call claim on itself, so those tokens are frozen forever, and totalOwed[token] can never reach 0 again, which permanently blocks removeAsset (and therefore relisting) for that token once it is retired. Caller's own funds only, but the brief says nothing may permanently block the registry lifecycle and the parallel deposit guard shows the intent. Fix: add 'receiver == address(this)' to the redeem check and 'to == address(this)' to claim.","line":786,"path":"src/BaskVault.sol","reproduction":"After the Base.t.sol fixture (3 assets, alice deposits 100e18 of tokens[0]): alice calls vault.redeem(10e18, address(vault), new uint256[](0), block.timestamp). Expected: revert InvalidAddress like deposit does. Actual: succeeds; vault.owed(address(vault), tokens[0]) == 10e18 and vault.totalOwed(tokens[0]) == 10e18 with no way to claim them (scratch test test_redeemToVault logs both values).","severity":"low","snippet":"        if (receiver == address(0)) revert InvalidAddress();","title":"redeem/claim accept the vault as receiver; deferred legs then become owed to the vault itself and are unrecoverable"},{"citation":"resolved","description":"Inconsistent guards on the owner != guardian invariant. transferOwnership rejects next == guardian (line 279) and acceptOwnership rejects msg.sender == guardian (line 286), but the Guardian action only rejects target == owner (line 431), not target == pendingOwner. Executing Guardian(target = pendingOwner) leaves pendingOwner set to an address that can never accept, so the two-step handover silently dies and the owner must run a second 2-day Guardian proposal before the handover can complete. Only the owner can create this state, so impact is operational, but it is the one gap in an otherwise complete set of mutual exclusion checks. Fix: also revert when d.target == pendingOwner in _validateProposal (checked at both propose and execute).","line":431,"path":"src/BaskVault.sol","reproduction":"Owner calls transferOwnership(bob). Owner proposes Guardian with target = bob, warps 2 days, executes (succeeds: bob != owner). bob calls acceptOwnership(). Expected: handover completes, or the Guardian proposal is rejected. Actual: acceptOwnership reverts InvalidAddress and pendingOwner stays bob (scratch test test_guardianTargetPendingOwner).","severity":"low","snippet":"            if (d.target == address(0) || d.target == owner) revert InvalidAddress();","title":"Guardian proposal does not reject the pending owner, so a later guardian change bricks an in-flight ownership handover until yet another guardian proposal"},{"citation":"resolved","description":"Asymmetry between the index space the redeemer sees when building minAmountsOut and the one redeem applies it to. removeAsset is permissionless and moves the last asset into the removed slot (lines 333-340). redeem indexes minAmountsOut by current registry index (lines 812 and 821). If any retired, empty asset sits in the middle of the registry, anyone can front-run a redeem with removeAsset: the redeemer's minimum for the last asset (now at the removed index) is applied to the slot formerly holding the removed asset, and the entry at the old last index is ignored entirely, so the moved asset is paid with no slippage floor. No price is read in redeem so the exposure is to shortfall-driven legs (leg = min(managed, available) * net / supply), i.e. a user who set a floor to avoid redeeming into a confiscated/short asset loses that protection. Fix options that keep the interface: have redeem take the expected assets.length (or a registry version) and revert on mismatch, or remove by clearing the slot without reordering.","line":338,"path":"src/BaskVault.sol","reproduction":"Base fixture plus two more assets X (index 3) and Y (index 4) listed by proposal; alice deposits 100e18 of Y; owner closes and retires X (managed 0). alice prepares redeem(10e18, alice, mins, deadline) with mins = [0,0,0,0,1e18] intending the 1e18 floor for Y. Before it mines, anyone calls removeAsset(X): Y moves to index 3. Expected: the floor still applies to Y. Actual: redeem returns an amounts array of length 4, mins[4] is never read, mins[3] == 0 applies to Y; had Y been short so that its leg was below 1e18 the redeem would still have gone through (scratch test test_removeAssetShiftsIndices).","severity":"low","snippet":"        assets[index] = last;","title":"removeAsset swap-removes registry indices, so a redeem's minAmountsOut built against the previous ordering silently protects the wrong asset"}],"hash":"e220283fbd8ff4b46592f1375b5d1f270284667b158eec8d799dc2dbb48798cf","nodeId":"40292f4a-fe50-4877-84d5-718065c0a7d0","outcome":"completed","summary":"Review complete. `.imd-findings.json` holds four findings and a 23-row coverage record covering all 20 entry points plus three invariants. No source files were changed; the only writes are the findings file and scratch tests under `test/scratch/`.\n\n**Findings**\n\n1. **Medium: retired assets are free to late depositors.** The deposit NAV skips retired assets at `src/BaskVault.sol:660`, but redeem still pays them pro rata. Anyone who deposits and redeems right after a Retire execution takes part of the retired backing from existing holders. The proof test fails on the current code with the attacker ending at 3050 units after starting with 3000. This is the behaviour the brief literally specifies, so the fix needs a scope decision. The minimal change is to refuse Retire while the asset has managed balance.\n2. **Low: redeem and claim accept the vault itself as receiver.** Deposit rejects it, redeem does not. Deferred legs become owed to the vault forever, and the token can never be removed or relisted.\n3. **Low: a Guardian proposal may target the pending owner.** Executing it bricks the in-flight ownership handover until yet another guardian proposal. Only the owner can cause it.\n4. **Low: `removeAsset` reorders registry indices.** A redeem's minAmountsOut built against the old ordering silently protects the wrong asset after a front-running removal.\n\n**What holds**\n\nThe role model matches the brief: owner and guardian powers, two-step ownership that never reaches the guardian, guardian cancellation excluding its own replacement, proposal revalidation at execution, and epoch voiding on retire, close, remove and cap lowering. No role or in-bounds setting can block redeem or claim. I re-ran the author's seven worst-case gas scenarios and traced that the one redeem storage path they do not exercise is unreachable. Static-analysis leads on shift order, reentrancy in claim and timestamp use were checked and are false positives.\n\n**Not reached in depth**\n\nPool oracle math and tick quoting in `PoolOracle.sol` and `TickMath.sol` are outside the permissions area and only got a skim.","treeHash":null,"usage":{"cachedInputTokens":2666582,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":53878,"runtime":"claude","turns":37,"wallClockMs":800450}},{"artifacts":[],"attempt":1,"bundleHash":"1e11517f9c79b4808b13c213daa4299a15389b30bfcb238a95f4346da3da6d95","device":"1ccda5cdb3f24f3e","findings":[],"hash":"ea9620560d989e8f9caad2baf93d41f77ed4a4be4d255cfa8da7a3aa4e9450ba","nodeId":"9bba37b3-5e7b-481d-b337-118afe77e975","outcome":"completed","summary":"Implemented the Basket/BASK vault, launch manifest, vendored dependencies, tests, and operational documentation.\n\n- `forge build` passes.\n- All **62 tests** pass.\n- `forge fmt --check` passes.\n- Runtime: **22,761 bytes**.\n- Highest tested redemption gas: **27,978,583**, including calldata.\n\nDeployment parameters and responsibilities are documented in `README.md`; adversarial results are in `REVIEW.md`.","treeHash":"cf8e2384b42c544a88422944efa730119368a840","usage":{"cachedInputTokens":4967296,"inputTokens":152117,"model":"gpt-6-astra","outputTokens":70515,"runtime":"codex","turns":9,"wallClockMs":2568207}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2dc755dfe7bd177c","findings":[{"citation":"resolved","description":"_depositContext skips every retired asset (line 660), so the NAV that prices new shares (line 673, used at line 704) omits managed[token] of a retired asset. redeem (lines 810-829) pays every asset whose managed bit is set, retired or not: leg = min(managed, available) * net / supply. The two sides of the deposit/redeem pair value the same share on different asset sets. Whoever deposits after a Retire proposal executes is minted shares against the shrunken NAV and immediately redeems a pro-rata slice of the retired holdings that the holders present at retirement paid for. Profit = X * R / (A + X) where R is the retired position's value, A the remaining NAV and X the deposit, approaching R as X grows (bounded only by NAV_CAP and repeatable); no fee while feeRecipient is unset, 1% round trip otherwise. The trigger is routine and public: a funded asset whose feed goes stale or dies blocks every deposit (a valid price is required for every asset with managed > 0), so the owner is pushed to retire exactly those assets, the Retire proposal is visible for 2 days (Proposed event / pendingProposals), and the extraction is done by any unprivileged depositor. Because redeem rounds down against a supply that always includes the 1e15 dead shares, managed of the retired asset never reaches zero (see finding 2), so the window stays open as long as the token has value. Reported by all four specialists (permissions, economics, math, flow); merged. The code implements the brief's literal text ('retired ... 0 in NAV'; redeem 'per asset with managed > 0'), so the fix is a scope decision for the author: value retired holdings in deposit NAV at their frozen centre, exclude retired legs for shares minted after retirement, allow Retire only once managed[token] == 0, or refuse deposits while any retired asset still holds managed > 0. The attached proof passes under each of those routes.","line":660,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract PlainToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 v) external {\n        balanceOf[to] += v;\n    }\n\n    function approve(address s, uint256 v) external returns (bool) {\n        allowance[msg.sender][s] = v;\n        return true;\n    }\n\n    function transfer(address to, uint256 v) external returns (bool) {\n        balanceOf[msg.sender] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n}\n\ncontract PlainFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer;\n    uint256 public updatedAt;\n\n    constructor(int256 a) {\n        answer = a;\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 a, uint256 t) external {\n        answer = a;\n        updatedAt = t;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// A retired asset is excluded from the NAV that prices new shares (_depositContext skips\n/// `retired`), but redeem pays every asset with managed > 0, retired or not. A depositor who\n/// enters after retirement is therefore sold shares without paying for the retired holdings\n/// and redeems a pro-rata slice of them at once, at the expense of the holders present at\n/// retirement. This test passes under any of the fix routes: valuing the retired position in\n/// deposit NAV, excluding it from redeem for post-retirement shares, refusing retirement\n/// while managed > 0, or refusing deposits while a retired asset still holds managed > 0.\ncontract RetiredAssetDilutionTest is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    BaskVault vault;\n    PlainToken[3] tokens;\n    PlainFeed[3] feeds;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(10 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        for (uint256 i; i < 3; ++i) {\n            tokens[i] = new PlainToken();\n            feeds[i] = new PlainFeed(1e8); // $1 per whole token\n            vm.prank(OWNER);\n            vault.genesisList(address(tokens[i]), address(feeds[i]), address(0), address(0), 0);\n            tokens[i].mint(alice, 1_000e18);\n            tokens[i].mint(bob, 1_000e18);\n            vm.prank(alice);\n            tokens[i].approve(address(vault), type(uint256).max);\n            vm.prank(bob);\n            tokens[i].approve(address(vault), type(uint256).max);\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < 3; ++i) {\n            feeds[i].set(1e8, block.timestamp);\n        }\n    }\n\n    function testPostRetirementDepositorExtractsRetiredBacking() public {\n        // Alice funds the basket: 100 of each $1 token -> NAV $300, supply 300e18.\n        address[] memory ts = new address[](3);\n        uint256[] memory amts = new uint256[](3);\n        for (uint256 i; i < 3; ++i) {\n            ts[i] = address(tokens[i]);\n            amts[i] = 100e18;\n        }\n        vm.prank(alice);\n        vault.deposit(ts, amts, alice, 0, block.timestamp);\n        assertEq(vault.totalSupply(), 300e18);\n\n        // Owner closes token0 and retires it through the 2-day proposal. token0 still transfers.\n        vm.prank(OWNER);\n        vault.closeAsset(address(tokens[0]));\n        BaskVault.ProposalData memory d;\n        d.action = BaskVault.Action.Retire;\n        d.token = address(tokens[0]);\n        vm.prank(OWNER);\n        uint256 id = vault.propose(d);\n        vm.warp(block.timestamp + 2 days);\n        _refresh();\n        vm.prank(OWNER);\n        try vault.executeProposal(id) {} catch {\n            // Fixed by refusing to retire an asset that still has managed > 0.\n            return;\n        }\n        assertTrue(vault.asset(address(tokens[0])).retired);\n        assertEq(vault.managed(address(tokens[0])), 100e18);\n\n        // Bob deposits $300 of token1. Current code prices him against NAV $200 (token0 skipped).\n        address[] memory one = new address[](1);\n        one[0] = address(tokens[1]);\n        uint256[] memory amt = new uint256[](1);\n        amt[0] = 300e18;\n        uint256 shares;\n        vm.prank(bob);\n        try vault.deposit(one, amt, bob, 0, block.timestamp) returns (uint256 s) {\n            shares = s;\n        } catch {\n            // Fixed by refusing deposits while a retired asset still holds managed > 0.\n            return;\n        }\n\n        // Bob redeems everything in the same block.\n        vm.prank(bob);\n        uint256[] memory legs = vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n        uint256 bobOut = legs[0] + legs[1] + legs[2]; // every token is $1\n        uint256 aliceBacking =\n            vault.managed(address(tokens[0])) + vault.managed(address(tokens[1])) + vault.managed(address(tokens[2]));\n        emit log_named_uint(\"bob token0 (retired) received\", legs[0]);\n        emit log_named_uint(\"bob value in  ($)\", 300e18);\n        emit log_named_uint(\"bob value out ($)\", bobOut);\n        emit log_named_uint(\"alice backing before ($)\", 300e18);\n        emit log_named_uint(\"alice backing after  ($)\", aliceBacking);\n\n        // Expected: a same-block deposit/redeem round trip returns at most what was put in,\n        // and existing holders keep their backing. Actual: bob gets $360 for $300 and alice's\n        // backing falls from $300 to $240.\n        assertLe(bobOut, 300e18, \"post-retirement depositor extracted retired backing from existing holders\");\n        assertGe(aliceBacking, 300e18, \"existing holder lost backing to a round-trip depositor\");\n    }\n}","reproduction":"Three 18-decimal $1 tokens with 8-decimal feeds, no pools, feeRecipient unset. (1) alice deposits 100e18 of each: NAV $300, totalSupply 300e18. (2) owner closeAsset(token0); propose({action: Retire, token: token0}); warp 2 days; executeProposal: asset(token0).retired == true, managed[token0] still 100e18. (3) bob deposit([token1],[300e18], bob, 0, now): _depositContext skips token0 so nav = 200e18, gross = 300e18 * 300e18 / 200e18 = 450e18 shares (expected 300e18 if token0 were valued). (4) bob redeem(450e18, bob, [], now): legs = managed * 450e18 / 750e18 = [60e18 token0, 240e18 token1, 60e18 token2] = $360 for $300 in. alice's remaining backing: 40e18 + 160e18 + 40e18 = $240 (was $300). Expected: a same-block deposit/redeem round trip returns at most the value put in and existing holders keep their backing; actual: bob gains $60 and alice loses $60. test/scratch/RetiredAssetDilution.t.sol fails on this code with '360000000000000000000 > 300000000000000000000'. The specialists' proofs (Proof_01b221a6ddc4, Proof_40ff5003a3c1, Proof_629a20493dbf, Proof_dde9c358324a) all fail on this code for the same reason.","severity":"high","snippet":"            if (a.retired) continue;","title":"Retired asset is 0 in deposit NAV but still paid pro rata by redeem: any depositor after a retirement extracts the retired backing from existing holders"},{"citation":"resolved","description":"removeAsset requires managed[token] == 0. redeem lowers managed only by leg = floor(min(managed, available) * net / totalSupply) (line 820) and net < totalSupply on every call because address(0xdEaD) holds 1e15 shares that no one can redeem, so leg < managed whenever managed > 0 and managed converges to a positive residual instead of zero. The only other decrement is recognizeLoss, which needs available < managed; nothing inside the vault creates that (payments reduce balance and managed equally, claims reduce balance and totalOwed equally), so without an external confiscation the residual is permanent. The brief's 'Anyone may remove a retired asset with managed and totalOwed 0; its token may then be listed again' is therefore unreachable for any asset that received a deposit: the token can never be relisted (_index[token] != 0 rejects List), the registry slot counts against maxAssets forever, every redeem keeps paying a balance read for it, and the extraction window of finding 1 never closes. Reported by audit_economics; reproduced.","line":330,"path":"src/BaskVault.sol","reproduction":"Base fixture (three $1 tokens). alice deposits 100e18 of each (supply 300e18, 1e15 of it at 0xdEaD). Owner closeAsset(token0); Retire proposal executed. alice redeem(balanceOf(alice) = 300e18 - 1e15, alice, [], now). Afterwards totalSupply == 1e15 and managed[token0] == 333333333333334 (> 0). removeAsset(token0) reverts InvalidAsset(token0). previewRedeem(1e15) would pay the residual only to a holder of the dead shares, which does not exist. Expected: once every redeemable share is gone a retired asset is removable and its token relistable; actual: never. Scratch test test/scratch/Verify.t.sol::test_residualManaged (passes, i.e. confirms the state).","severity":"low","snippet":"        if (!_assets[token].retired || managed[token] != 0 || totalOwed[token] != 0) revert InvalidAsset(token);","title":"A retired asset that was ever funded can never be removed or relisted: floor-rounded legs against the permanent 1e15 dead shares leave managed > 0 forever"},{"citation":"resolved","description":"deposit rejects receiver == address(this) (line 722) but redeem only rejects address(0). With receiver == address(this), pay() executes token.transfer(vault, leg): a standard self-transfer leaves the vault balance unchanged, so the exact-debit check at line 770 reverts, _tryPay returns false, and lines 827-828 record owed[address(this)][token] += leg and totalOwed[token] += leg. claim() is keyed on msg.sender and the vault never calls claim on itself (its only self-call is pay), so the debt is unclaimable for good: the redeemer's tokens are stranded (self-harm), and totalOwed[token] >= leg permanently, which makes removeAsset (line 330) impossible for that token after retirement. In practice finding 2 already blocks removal of every funded asset, so the added damage is the stranded tokens and the inconsistency with deposit's guard. Reported by permissions, math and flow; merged.","line":786,"path":"src/BaskVault.sol","reproduction":"Base fixture; alice deposits 100e18 of token0 (supply 100e18). alice calls redeem(1e18, address(vault), [], now). Expected: revert InvalidAddress like deposit. Actual: returns legs[0] = 1e18; owed[vault][token0] == 1e18, totalOwed[token0] == 1e18, managed[token0] == 99e18, vault balance unchanged at 100e18; no call path lowers owed[vault][token0]. Scratch test test/scratch/Verify.t.sol::test_redeemToVault logs these values.","severity":"low","snippet":"        if (receiver == address(0)) revert InvalidAddress();","title":"redeem accepts the vault itself as receiver: the leg is booked as owed to the vault, can never be claimed, and totalOwed[token] stays non-zero so removeAsset is blocked for that token"},{"citation":"resolved","description":"redeem matches minAmountsOut[i] to assets[i] at execution time (lines 812, 821). removeAsset, callable by anyone once a retired asset has managed == 0 and totalOwed == 0, moves the last asset into the freed slot (lines 338-340). A redeem submitted with a minimum for the last asset can be front-run by removeAsset: the funded asset moves to a lower index whose minimum is 0, and the original index is beyond assets.length and ignored, so the redeemer's protection against a shortfall is lost without any revert (or, conversely, a floor lands on the wrong asset and causes a spurious Slippage revert). README documents 'refresh this order', but the reorder is unprivileged and can be timed against a specific transaction. Impact is bounded to the difference between the expected and the actual leg. Reported by permissions and economics; merged.","line":338,"path":"src/BaskVault.sol","reproduction":"Base fixture. alice deposits 100e18 of token2 (index 2; only funded asset). Owner closeAsset(token0); Retire executed (token0 at index 0 with managed 0 is now removable by anyone). Issuer confiscates 60e18 of token2 from the vault (available 40e18 < managed 100e18). alice submits redeem(50e18, alice, [0,0,50e18], now): without interference it reverts Slippage (leg = 40e18 * 50e18 / 100e18 = 20e18 < 50e18). Attacker front-runs with removeAsset(token0): assets becomes [token2, token1]. alice's identical redeem now succeeds, returns a 2-entry array with legs[0] = 20e18 against her stated 50e18 floor for token2. Scratch test test/scratch/Verify.t.sol::test_removeAssetShiftsMins.","severity":"low","snippet":"        assets[index] = last;","title":"Permissionless removeAsset swap-removes registry indices, so a pending redeem's minAmountsOut can be front-run onto the wrong asset and its floor silently dropped"},{"citation":"resolved","description":"NAV counts only unretired assets with managed > 0. When every funded asset is retired (rotating a basket whose Stock Tokens were delisted) or every funded asset's loss is recognized, nav == 0 while totalSupply >= 1e15 forever (address(0xdEaD) can never redeem), so every deposit reverts ZeroNAV, including deposits of healthy, freshly listed assets. The vault cannot be refunded through its only minting path. The escape is an owner donation of an unretired token followed by a 2-day Resync; the next deposit is then priced against a dust NAV (1e18 value for 1e15 supply in the reproduction), which also re-opens finding 1 against the still-redeemable retired holdings. The code matches the brief's 'revert if NAV is 0'; the permanent lock is the unstated consequence. Reported by economics and math; merged.","line":703,"path":"src/BaskVault.sol","reproduction":"Base fixture. alice deposits 100e18 of token0. Owner closeAsset(token0); Retire executed. deposit([token1],[1e18], alice, 0, now) reverts ZeroNAV although token1 is open, fresh and readable. alice redeems all her shares: totalSupply == 1e15; the same deposit still reverts ZeroNAV. After tokens[1].mint(vault, 1e18) and an executed Resync(token1) the deposit succeeds and mints 1e15 shares for 1e18 value. Scratch test test/scratch/Verify.t.sol::test_zeroNavLock.","severity":"low","snippet":"        if (supply != 0 && nav == 0) revert ZeroNAV();","title":"Once every funded asset is retired or written off, deposits revert ZeroNAV forever (supply can never return to zero because of the dead shares); only an owner donation plus Resync can reopen them"},{"citation":"resolved","description":"transferOwnership rejects next == guardian (line 279) and acceptOwnership rejects msg.sender == guardian (line 286), but the Guardian action only rejects target == owner, not target == pendingOwner, at both propose and execute. Executing Guardian(target = pendingOwner) leaves pendingOwner set to an address that can never accept; the handover silently dies until the owner runs a second 2-day Guardian proposal (or starts a new transfer). Only the owner can create this state, so impact is operational; it is the one gap in an otherwise complete owner != guardian exclusion. Reported by permissions; reproduced.","line":431,"path":"src/BaskVault.sol","reproduction":"Owner transferOwnership(bob). Owner propose({action: Guardian, target: bob}); warp 2 days; executeProposal succeeds (bob != owner); guardian() == bob. bob calls acceptOwnership(): expected either the handover completes or the Guardian proposal was rejected; actual: reverts InvalidAddress and pendingOwner() stays bob. Scratch test test/scratch/Verify.t.sol::test_guardianPendingOwner.","severity":"low","snippet":"            if (d.target == address(0) || d.target == owner) revert InvalidAddress();","title":"Guardian proposal does not reject the pending owner, so executing it strands an in-flight ownership handover until another 2-day Guardian proposal"}],"hash":"f5e3c1cce06ac1ee7beaabad670e34e5906ef1495ad52bd21b466c699303195b","nodeId":"0ae4a1bd-7e3a-43c7-b2ef-f0dca4440f61","outcome":"completed","summary":"The review is complete. `.imd-findings.json` is written (6 findings, 22 coverage rows), all snippets match the tree, the embedded proof compiles and fails on the current code, and `test/scratch/` is removed — `git status` shows only the findings file (which is gitignored/untracked as expected).\n\n## Summary\n\n**Specialist findings, judged**\n\n| Reported by | Verdict | Severity |\n|---|---|---|\n| Retired asset 0 in NAV but paid by redeem (all 4 areas) | **Kept, merged into one** — all four proofs fail for the stated reason; I wrote a fix-agnostic proof that passes under any of the four fix routes | **High** (unprivileged loss of principal from existing holders, triggered by a routine, publicly-announced owner action) |\n| Retired funded asset can never be removed (dead-share rounding) | Kept — `managed[token0] == 333333333333334` at supply `1e15`, no in-vault path lowers it | Low |\n| `redeem(receiver = vault)` strands debt / poisons `totalOwed` (3 areas) | Kept, merged | Low |\n| `removeAsset` reorders indices, `minAmountsOut` front-runnable (2 areas) | Kept, merged | Low |\n| ZeroNAV permanent deposit lock | Kept (separate root cause from #1); recovery via donation+Resync noted | Low |\n| Guardian proposal accepts `pendingOwner` | Kept | Low |\n| Resync refused for retired assets \"strands tokens forever\" | **Dropped** — `removeAsset → List → Resync` recovers them (my test confirms `managed == 100e18` afterwards) | — |\n| Band floor one-unit asymmetry | Dropped — integer `centre / band` is what the brief's text says | — |\n\n**My own pass** (Pashov/ToB mindset, MUST-ATTACK items): redeem reads no price and ignores every pause/close/cap/hours/freshness setting; minimum `balanceGas`/`payGas` only defer legs to claimable debt; `claim` has no gas cap; the gas suite reruns cleanly at 250–350 assets with paused/burning/no-code tokens under 28M; `pay` is vault-only with an exact-debit check and bounded return copies; reentrancy via token callbacks is blocked everywhere including `pay`→`claim`. Slither/aderyn leads (shift order, weak-PRNG, strict equalities, claim \"reentrancy\") all checked and are false positives. I found nothing beyond what the specialists reported.\n\nOne note for the author on finding 1: the code implements the brief's literal text, so it needs a scope decision rather than a silent change; the proof is written to pass under each of the four reasonable fixes.","treeHash":null,"usage":{"cachedInputTokens":1630337,"inputTokens":391,"model":"claude-fable-5-1","outputTokens":42967,"runtime":"claude","turns":31,"wallClockMs":625492}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e57a8e639cccfbab","findings":[{"citation":"resolved","description":"_depositContext skips retired assets entirely (line 660), so NAV used to price new shares omits whatever the vault still holds of a retired token. redeem (lines 810-830) iterates every funded registry entry regardless of `retired`, so the same holdings are paid out pro rata to every share. The two sides of the deposit/redeem pair value the vault differently. Right after Retire executes (a normal owner path: closeAsset, then a 2-day Retire proposal; the token keeps its real balance and `managed`), anyone can deposit any open asset, receive shares priced on NAV minus the retired position, and redeem in the same block to receive a slice of the retired position for free. Profit = X * R / (A + X) where R is the retired position's value, A the remaining NAV and X the deposit; it approaches R as X grows (bounded by NAV_CAP). Existing holders lose exactly that amount. No fee is charged while feeRecipient is unset; with fees the round trip costs 1%. The residual `managed` of a retired asset can never reach zero through redemptions (see finding 2), so the window stays open as long as the retired token has value. Economic Security guide: 'Exploit path divergence / view-write asymmetry between deposit and withdraw'; Invariant guide: 'deposit(X) -> withdraw(all) must not return more than X'. The spec sentence 'retired ... 0 in NAV' is what the code implements, so the fix needs a scope decision: either also exclude retired assets from redeem (and give holders a separate pro-rata claim on them) or keep valuing retired holdings in NAV at their last price while they remain redeemable.","line":660,"path":"src/BaskVault.sol","proof":"// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {BaskVault} from \"src/BaskVault.sol\";\n\ncontract DilutionToken {\n    uint8 public constant decimals = 18;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 v) external {\n        balanceOf[to] += v;\n    }\n\n    function approve(address s, uint256 v) external returns (bool) {\n        allowance[msg.sender][s] = v;\n        return true;\n    }\n\n    function transfer(address to, uint256 v) external returns (bool) {\n        balanceOf[msg.sender] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n\n    function transferFrom(address f, address to, uint256 v) external returns (bool) {\n        allowance[f][msg.sender] -= v;\n        balanceOf[f] -= v;\n        balanceOf[to] += v;\n        return true;\n    }\n}\n\ncontract DilutionFeed {\n    uint8 public constant decimals = 8;\n    int256 public answer;\n    uint256 public updatedAt;\n\n    constructor(int256 a) {\n        answer = a;\n        updatedAt = block.timestamp;\n    }\n\n    function set(int256 a, uint256 t) external {\n        answer = a;\n        updatedAt = t;\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return (1, answer, updatedAt, updatedAt, 1);\n    }\n}\n\n/// Retiring an asset zeroes it in deposit NAV while redeem still pays it pro rata.\n/// A depositor after retirement buys shares priced without the retired holdings and\n/// immediately redeems a slice of them, at the expense of existing holders.\ncontract RetiredDilutionTest is Test {\n    address constant OWNER = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3;\n    address constant GUARDIAN = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68;\n    BaskVault vault;\n    DilutionToken[3] tokens;\n    DilutionFeed[3] feeds;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(10 days);\n        vault = new BaskVault(OWNER, GUARDIAN);\n        for (uint256 i; i < 3; ++i) {\n            tokens[i] = new DilutionToken();\n            feeds[i] = new DilutionFeed(1e8); // $1 per whole token\n            vm.prank(OWNER);\n            vault.genesisList(address(tokens[i]), address(feeds[i]), address(0), address(0), 0);\n            tokens[i].mint(alice, 1_000e18);\n            tokens[i].mint(bob, 1_000e18);\n            vm.prank(alice);\n            tokens[i].approve(address(vault), type(uint256).max);\n            vm.prank(bob);\n            tokens[i].approve(address(vault), type(uint256).max);\n        }\n        vm.prank(OWNER);\n        vault.finalizeGenesis();\n    }\n\n    function _refresh() internal {\n        for (uint256 i; i < 3; ++i) {\n            feeds[i].set(1e8, block.timestamp);\n        }\n    }\n\n    function testDepositAfterRetireExtractsRetiredHoldings() public {\n        // Alice funds the basket: 100 of each token, $300 NAV, 300e18 shares.\n        address[] memory ts = new address[](3);\n        uint256[] memory amts = new uint256[](3);\n        for (uint256 i; i < 3; ++i) {\n            ts[i] = address(tokens[i]);\n            amts[i] = 100e18;\n        }\n        vm.prank(alice);\n        vault.deposit(ts, amts, alice, 0, block.timestamp);\n        assertEq(vault.totalSupply(), 300e18);\n\n        // Owner closes token0 and retires it (2-day proposal). Token0 still holds $100 of value.\n        vm.prank(OWNER);\n        vault.closeAsset(address(tokens[0]));\n        BaskVault.ProposalData memory d;\n        d.action = BaskVault.Action.Retire;\n        d.token = address(tokens[0]);\n        vm.prank(OWNER);\n        uint256 id = vault.propose(d);\n        vm.warp(block.timestamp + 2 days);\n        _refresh();\n        vm.prank(OWNER);\n        vault.executeProposal(id);\n        assertTrue(vault.asset(address(tokens[0])).retired);\n        assertEq(vault.managed(address(tokens[0])), 100e18);\n\n        // Bob deposits $300 of token1. NAV excludes the retired asset, so NAV = $200.\n        address[] memory one = new address[](1);\n        one[0] = address(tokens[1]);\n        uint256[] memory amt = new uint256[](1);\n        amt[0] = 300e18;\n        vm.prank(bob);\n        uint256 shares = vault.deposit(one, amt, bob, 0, block.timestamp);\n\n        // Bob redeems everything in the same block and receives a slice of every asset, including the retired one.\n        vm.prank(bob);\n        uint256[] memory legs = vault.redeem(shares, bob, new uint256[](0), block.timestamp);\n        uint256 bobOut = legs[0] + legs[1] + legs[2]; // all tokens are $1, so this is Bob's USD value out\n        emit log_named_uint(\"bob token0 (retired) received\", legs[0]);\n        emit log_named_uint(\"bob value in  ($)\", 300e18);\n        emit log_named_uint(\"bob value out ($)\", bobOut);\n\n        // Alice's remaining claim: managed of every asset, all priced at $1.\n        uint256 aliceValue =\n            vault.managed(address(tokens[0])) + vault.managed(address(tokens[1])) + vault.managed(address(tokens[2]));\n        emit log_named_uint(\"alice value before ($)\", 300e18);\n        emit log_named_uint(\"alice value after  ($)\", aliceValue);\n\n        // Expected: a depositor cannot take out more than they put in through a deposit/redeem round trip.\n        assertLe(bobOut, 300e18, \"depositor extracted value from existing holders via retired asset\");\n        assertGe(aliceValue, 300e18, \"existing holder lost value to a round-trip depositor\");\n    }\n}","reproduction":"State: three $1 tokens (18 dec, 8-dec feeds) listed; alice deposits 100e18 of each -> totalSupply 300e18, managed 100e18 each. Owner: closeAsset(token0); propose(Retire token0); warp 2 days; executeProposal -> token0.retired = true, managed[token0] still 100e18. Bob: deposit([token1],[300e18], bob, 0, now). Expected (fair): NAV $300 -> 300e18 shares. Actual: NAV = $200 (token0 skipped) -> gross = 300e18*300e18/200e18 = 450e18 shares. Bob: redeem(450e18, bob, [], now) -> legs = managed*450/750: token0 60e18, token1 240e18, token2 60e18 = $360 out for $300 in. Alice's remaining managed: 40e18 + 160e18 + 40e18 = $240 (was $300). Bob gained $60 = 60% of the retired position with a single-block deposit/redeem.","severity":"high","snippet":"            if (a.retired) continue;","title":"Retired asset is excluded from deposit NAV but still paid by redeem: any depositor extracts retired holdings from existing holders"},{"citation":"resolved","description":"removeAsset requires managed[token] == 0. redeem lowers managed by leg = floor(min(managed, available) * net / totalSupply) and net is always strictly below totalSupply because address(0xdEaD) holds 1e15 shares that can never be redeemed, so leg < managed on every call and managed converges to a positive residual instead of zero. Nothing else lowers managed except recognizeLoss, which needs a real shortfall that only the token issuer can create (the vault cannot move its own balance). The spec's 'its token may then be listed again' path is therefore unreachable for any asset that received a deposit, the registry slot counts against maxAssets forever, every redeem keeps paying balance-read gas for it, and the extraction window of finding 1 stays open for as long as the token has value. Invariant guide: 'abuse boundaries: last participant / dust'.","line":330,"path":"src/BaskVault.sol","reproduction":"Base fixture (three $1 tokens). alice: deposit 100e18 of each (supply 300e18, dead 1e15). Owner: closeAsset(token0); Retire proposal executed. alice: redeem(balanceOf(alice)) -> totalSupply == 1e15, managed[token0] == 333333333333334 (> 0). removeAsset(token0) -> reverts InvalidAsset(token0). Expected: once every redeemable share is gone a retired asset should be removable; actual: it never is, because no further redeem can produce leg == managed (requires net == totalSupply, impossible with the dead shares).","severity":"low","snippet":"        if (!_assets[token].retired || managed[token] != 0 || totalOwed[token] != 0) revert InvalidAsset(token);","title":"A retired asset that was ever funded can never be removed: redeem floor-rounding and the permanent 1e15 dead shares keep managed > 0"},{"citation":"resolved","description":"NAV counts only unretired assets with managed > 0. If every funded asset is retired (the natural way to rotate a basket whose Stock Tokens were delisted: close old, retire old, list new) or every funded asset's loss is recognized, nav == 0 while totalSupply >= 1e15 forever because address(0xdEaD) can never redeem. Every deposit then reverts with ZeroNAV, including deposits of healthy newly listed assets, so the vault can never be refunded through its only minting path. The only escape is an owner donation plus a Resync proposal (2 days), which then prices new shares against a dust NAV and reproduces the extraction of finding 1 against the still-redeemable retired holdings. redeem and claim are unaffected. Flow Gap guide, seam execution x first principles: every step is correct but the end state contradicts the vault's purpose of accepting deposits.","line":703,"path":"src/BaskVault.sol","reproduction":"Base fixture. alice: deposit([token0],[100e18]). Owner: closeAsset(token0); Retire(token0) executed. alice: deposit([token1],[1e18], alice, 0, now) -> reverts ZeroNAV (token1 is open, fresh, readable). alice: redeem(balanceOf(alice)) -> totalSupply == 1e15 (dead shares only). deposit([token1],[1e18]) still reverts ZeroNAV. Expected: an open, priced asset can be deposited into a basket with no live holdings; actual: no deposit is possible ever again without an owner donation and Resync.","severity":"low","snippet":"        if (supply != 0 && nav == 0) revert ZeroNAV();","title":"Deposits are permanently disabled once NAV reaches 0 while supply > 0, which the dead shares make irreversible (retire-all or total loss)"},{"citation":"resolved","description":"minAmountsOut[i] is matched to assets[i] at execution time, but removeAsset (callable by anyone whenever a retired asset has managed == 0 and totalOwed == 0) swap-removes and moves the last asset to the freed index. A redeem submitted with a minimum for the last asset can be front-run by removeAsset: the funded asset moves to a lower index whose minimum is 0 (the removed asset had no holdings), and the original index is now beyond assets.length and ignored. The redeemer's protection against a shortfall or deficit appearing in the same window is lost without any revert. Conversely a minimum can land on the wrong asset and cause a spurious Slippage revert. The precondition (a removable retired asset existing) is created by routine owner actions, and the amplifier is unprivileged. Impact is bounded to the difference between the expected and actual leg, so low.","line":821,"path":"src/BaskVault.sol","reproduction":"Base fixture. alice: deposit([token2],[100e18]) (token2 at index 2 is the only funded asset). Owner: closeAsset(token0); Retire(token0) executed (token0 index 0, managed 0, removable by anyone). Issuer confiscates 60e18 of token2 from the vault (available 40e18 < managed 100e18). alice submits redeem(50e18, alice, [0,0,50e18], now): without interference it reverts Slippage (leg = 40e18*50/100 = 20e18 < 50e18), as intended. Attacker front-runs with removeAsset(token0): assets becomes [token2, token1]. alice's identical redeem now succeeds and pays legs[0] = 20e18 against her stated minimum of 50e18 for token2. Expected: her minimum protects token2 regardless of registry order; actual: it is applied to index 2, which no longer exists.","severity":"low","snippet":"            if (i < minAmountsOut.length && leg < minAmountsOut[i]) revert Slippage();","title":"redeem slippage guard is keyed by mutable registry index; permissionless removeAsset reorders the registry and silently drops a redeemer's minimum"}],"hash":"f69ac386cf74032298805e2d3d927a7d517eebae12f8babc6b837929394b23ed","nodeId":"213c2db8-6570-45f3-a4c8-71ec6e418260","outcome":"completed","summary":"The review is complete. The findings file is written and valid, no source files were changed, and the working tree holds only the ignored build outputs plus the findings file.\n\n**Outcome**\n\nI found one high-severity economic defect and three low-severity ones. All four have concrete reproductions, and the high one carries a Foundry proof that fails on the current code.\n\n**Findings written to `.imd-findings.json`**\n\n1. **High. Retired asset dilution.** Deposit NAV skips retired assets, but redeem still pays them pro rata. After the owner retires a token that still has holdings, anyone can deposit, redeem in the same block, and walk away with a slice of the retired position. In the proof, a $300 deposit returns $360 and the existing holder drops from $300 to $240. The code matches the spec's \"0 in NAV\" wording, so the fix needs a scope decision: exclude retired holdings from redeem as well, or keep valuing them in NAV.\n2. **Low. Funded retired assets can never be removed.** Redeem legs round down and the dead shares keep supply above zero, so managed converges to dust and never hits zero. Removal and relisting are unreachable, and the window for finding 1 stays open.\n3. **Low. Permanent deposit lockout at zero NAV.** Retiring every funded asset or recognizing a total loss leaves NAV at 0 with supply above 0 forever. Every later deposit reverts, including deposits of healthy new assets.\n4. **Low. Slippage guard keyed by mutable index.** A permissionless removal reorders the registry, so a redeemer's minimum for the last asset is silently dropped when front-run.\n\n**What held**\n\n- Redeem cannot be reverted by any role, setting, or hostile token. I measured the worst cases the author's suite did not cover: 280 direct hostile legs at the direct-limit bound used 27.12M gas, and 350 deferred hostile legs used 26.72M, both under 28M.\n- Share conservation, the managed bitmap, and the owed accounting invariants hold on every path.\n- All 20 entry points have coverage rows, plus five invariant rows.\n\n**Not reached**\n\nDeposit gas at the asset cap with realistic feeds and pools was not measured. The spec only bounds redeem, so I left it out rather than report an unproven lead.","treeHash":null,"usage":{"cachedInputTokens":2182780,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":62696,"runtime":"claude","turns":33,"wallClockMs":924393}}],"verification":[{"checks":[{"durationMs":32159,"exitCode":0,"name":"build","output":"Compiling 31 files with Solc 0.8.26\nSolc 0.8.26 finished in 31.86s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:19:26\n   │\n19 │         if (!ok) return (false, 0, 0);\n   │                          ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:479:21\n    │\n479 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:42:21\n   │\n42 │             return (false, 0, 0);\n   │                     ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:51:40\n   │\n51 │         if (secondsDelta == 0) return (false, 0, 0);\n   │                                        ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:54:54\n   │\n54 │         if (mean < -887272 || mean > 887272) return (false, 0, 0);\n   │                                                      ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:481:17\n    │\n481 │         return (true, uint256(signedAnswer), updatedAt);\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:21\n    │\n523 │             return (false, 0, 0);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:56:51\n   │\n56 │         if (harmonic > type(uint128).max) return (false, 0, 0);\n   │                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:57:17\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                 ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:633:23\n    │\n633 │         uint256 day = (block.timestamp / 1 days + 3) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:86\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                      ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:105\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                                         ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:21\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                     ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:33\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                                 ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:28\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                            ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:42\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                                          ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:23\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                       ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:36\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:289:9\n    │\n289 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:400:13\n    │\n400 │             guardian = d.target;\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:279:65\n    │\n279 │     function transferOwnership(address next) external onlyOwner nonReentrant {\n    │                                                                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:294:63\n    │\n294 │     function setDepositsPaused(bool paused) external onlyRole nonReentrant {\n    │                                                               ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:300:58\n    │\n300 │     function closeAsset(address token) external onlyRole nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:307:58\n    │\n307 │     function lowerNAVCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:317:9\n    │\n317 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:323:51\n    │\n323 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:349:69\n    │\n349 │     function propose(ProposalData calldata data) external onlyOwner nonReentrant returns (uint256 id) {\n    │                                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:358:9\n    │\n358 │         emit Proposed(id, data, p.readyAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:361:59\n    │\n361 │     function cancelProposal(uint256 id) external onlyRole nonReentrant {\n    │                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:369:61\n    │\n369 │     function executeProposal(uint256 id) external onlyOwner nonReentrant {\n    │                                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:513:9\n    │\n513 │         emit AssetListed(token, feed, pool);\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:398:13\n    │\n398 │             emit Resynced(d.token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:408:9\n    │\n408 │         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:376:59\n    │\n376 │             _list(d.token, d.target, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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:392:55\n    │\n392 │             _setPool(a, d.token, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:451:50\n    │\n451 │             if (s[i] < 20_000 || s[i] > 500_000) revert InvalidSetting();\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:467:16\n    │\n467 │         return uint8(d);\n    │                ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:478:41\n    │\n478 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\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:478:72\n    │\n478 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\n    │                                                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:479:47\n    │\n479 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\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:481:23\n    │\n481 │         return (true, uint256(signedAnswer), updatedAt);\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:530:29\n    │\n530 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:530:62\n    │\n530 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                                                              ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:532:32\n    │\n532 │         baseIsToken0 = address(uint160(t0)) == token;\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:533:43\n    │\n533 │         quoteDecimals = _decimals(address(uint160(baseIsToken0 ? t1 : t0)));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:624:13\n    │\n624 │         if (block.timestamp - updatedAt > _settings[2]) return (Reason.NoPoolAge, answer, updatedAt, 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:606:64\n    │\n606 │             (ok, tick, liquidity) = PoolOracle.consult(a.pool, uint32(_settings[7]), _settings[11]);\n    │                                                                ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:635:16\n    │\n635 │         return day < 5 && time >= from && time < to;\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:635:27\n    │\n635 │         return day < 5 && time >= from && time < to;\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:635:43\n    │\n635 │         return day < 5 && time >= from && time < to;\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:686:86\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\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:686:47\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                                               ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:686:29\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:702:34\n    │\n702 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:726:13\n    │\n726 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:755:17\n    │\n755 │                 emit DeficitCleared(token);\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:761:9\n    │\n761 │         emit Deposit(msg.sender, receiver, value, 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:735:22\n    │\n735 │             if (!ok) revert BalanceUnreadable(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:742:17\n    │\n742 │                 revert PaymentFailed();\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:747:17\n    │\n747 │                 revert PaymentFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:776:9\n    │\n776 │         emit Payment(token, receiver, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:813:23\n    │\n813 │                     ++count;\n    │                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:790:13\n    │\n790 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:840:9\n    │\n840 │         emit Redeem(msg.sender, receiver, shares, net, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:804:40\n    │\n804 │             if (minAmountsOut[i] != 0) revert Slippage();\n    │                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:821:72\n    │\n821 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:830:69\n    │\n830 │             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:855:13\n    │\n855 │             this.pay(token, to, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:855:13\n    │\n855 │             this.pay(token, to, amount);\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:856:13\n    │\n856 │             emit Claimed(msg.sender, to, token, amount);\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:850:22\n    │\n850 │             if (!ok) revert BalanceUnreadable(token);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:868:9\n    │\n868 │         emit DeficitFlagged(token, shortfall, block.timestamp);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:874:30\n    │\n874 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert NotReady();\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:882:9\n    │\n882 │         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:968:13\n    │\n968 │         if (block.timestamp > p.readyAt + 7 days) return ProposalState.Expired;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:969:16\n    │\n969 │         return block.timestamp < p.readyAt ? ProposalState.Waiting : ProposalState.Ready;\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:989:21\n    │\n989 │                 ids[n] = id;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":608,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Oracle.t.sol:OracleTest\n[PASS] testAllAssetsViewContainsBalancesAndFaults() (gas: 610014)\n[PASS] testBadAnswerFutureAndMalformedRead() (gas: 679199)\n[PASS] testBandBoundariesWithoutPool() (gas: 895149)\n[PASS] testEveryManagedAssetValidatedAndUnmanagedStaleAllowed() (gas: 996920)\n[PASS] testFreshnessCountAndBoundary() (gas: 1151064)\n[PASS] testHoursWeekdaysAndExactEdges() (gas: 2332972)\n[PASS] testMixedQuoteDecimalsAndReversePoolDirection() (gas: 3369459)\n[PASS] testPauseDetectionAndUnreadablePause() (gas: 2353802)\n[PASS] testPoolDeviationAndQuoteFeedCannotFallBack() (gas: 808912)\n[PASS] testPoolLiquidityAndMalformedObserveFallBack() (gas: 1248227)\n[PASS] testValidPoolCanUseOlderFeedButFallbackCannot() (gas: 886946)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 58.42ms (13.95ms CPU time)\n\nRan 13 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] testAllLossDoesNotBlockRedeemAndPreventsDepositAtZeroNAV() (gas: 915718)\n[PASS] testBalanceReturnBombCopiesOnlyWord() (gas: 493398)\n[PASS] testClaimCannotBeBlockedByBalanceGasSetting() (gas: 1799623)\n[PASS] testClaimHasNoPayGasLimitAndPausesDoNotApply() (gas: 1403243)\n[PASS] testDepositInputCannotConsumeUnderfundedOwed() (gas: 1293730)\n[PASS] testDepositSettingsAndGovernanceCannotVetoExit() (gas: 5980770)\n[PASS] testFeeOnTransferAndFalseDepositAreAtomic() (gas: 1023429)\n[PASS] testFuzzBrokenTransferNeverBlocksOtherLegs(uint8) (runs: 256, μ: 1004287, ~: 1006885)\nLogs:\n  Bound result 1\n\n[PASS] testFuzzUnreadableBalanceUsesManaged(uint8) (runs: 256, μ: 840577, ~: 736096)\nLogs:\n  Bound result 1\n\n[PASS] testMinOutputForZeroLegRevertsOnlyByUserChoice() (gas: 519272)\n[PASS] testPausedTokenDefersAndOtherLegsProceed() (gas: 1010189)\n[PASS] testReentrantDepositRedeemClaimAndRoleChangesFail() (gas: 1776795)\n[PASS] testUpgradeToNoCodeStillRedeemsAsDebt() (gas: 759465)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 58.45ms (111.24ms CPU time)\n\nRan 17 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDeferredClaimAndPartialLiquidity() (gas: 1561740)\n[PASS] testDeploymentAndFirstDeposit() (gas: 431590)\n[PASS] testDonationIgnoredUntilResyncAndShareMath() (gas: 1404594)\n[PASS] testERC20AllowancesAndNoBurnByTransfer() (gas: 546884)\n[PASS] testERC20TransferEventTopics() (gas: 407258)\n[PASS] testFeesRoundUpMintAndTransfer() (gas: 899576)\n[PASS] testFirstDepositMustExceedLockAndFees() (gas: 1119554)\n[PASS] testFuzzConservation(uint96,uint96,bool,bool) (runs: 256, μ: 1050800, ~: 1000367)\nLogs:\n  Bound result 99999000000001518969461\n  Bound result 51498376178371199\n\n[PASS] testFuzzDecimalValuation(uint8,uint8,uint32) (runs: 256, μ: 2176917, ~: 2183407)\nLogs:\n  Bound result 3\n  Bound result 7\n  Bound result 70\n\n[PASS] testInputValidationAndCap() (gas: 834433)\n[PASS] testLargerDeficitRestartsClockAndDepositClears() (gas: 1031603)\n[PASS] testNoAutomaticLossAndSevenDayRecognition() (gas: 1138532)\n[PASS] testRedeemDirectHasNoPriceDependency() (gas: 1128687)\n[PASS] testRemovalMovesFundedAssetIndexAndLossClearsBitmap() (gas: 1832438)\n[PASS] testResyncExcludesOwed() (gas: 1365564)\n[PASS] testRuntimeHasNoForbiddenOpcodes() (gas: 9907171)\n[PASS] testSlippageAndDeadlineAtomicity() (gas: 910683)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 68.07ms (145.80ms CPU time)\n\nRan 3 tests for test/Oracle.t.sol:OracleMathTest\n[PASS] testFullPrecisionMultiplicationAvoidsIntermediateOverflow() (gas: 3968)\n[PASS] testFuzzQuoteReciprocal(int24) (runs: 256, μ: 13394, ~: 13415)\nLogs:\n  Bound result -78763\n\n[PASS] testNegativeTickRoundsDownAndWrapsAccumulators() (gas: 127764)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 82.08ms (80.89ms CPU time)\n\nRan 11 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testConstructorsAndGenesis() (gas: 4250)\n[PASS] testFeedAndRecentreUseExecutionAnswer() (gas: 965219)\n[PASS] testLaterCloseVoidsReopen() (gas: 819191)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 2481524)\n[PASS] testLowerCapVoidsRaisesAndBounds() (gas: 750691)\n[PASS] testOwnerAndGuardianPowers() (gas: 1096275)\n[PASS] testRemoveAndRelistDoesNotReviveOldProposals() (gas: 1632083)\n[PASS] testRetirementVoidsProposalsAndStopsDepositsButRedeems() (gas: 2336577)\n[PASS] testSettingGasBoundsAndRevalidation() (gas: 1907623)\n[PASS] testTimelockBoundariesAndPendingViews() (gas: 730296)\n[PASS] testTwoStepOwnerNeverGuardianEvenAfterProposal() (gas: 270792)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 82.23ms (8.43ms CPU time)\n\nRan 12 tests for test/Revision.t.sol:RevisionTest\n[PASS] testEmptyRetiredAssetStillSkipsDepositChecks() (gas: 995719)\n[PASS] testFuzzRedeemToVaultCannotBurnSharesOrCreateDebt(bool,bool) (runs: 256, μ: 894006, ~: 931716)\n[PASS] testFuzzRetiredBackingCheckUsesAccountingEvenWhenUnreadable(uint8,bool) (runs: 256, μ: 2088334, ~: 2131849)\nLogs:\n  Bound result 1\n\n[PASS] testGuardianExecutionRechecksPendingOwner() (gas: 411663)\n[PASS] testMultipleRemovalsCannotDropEarlierTrailingMinimum() (gas: 1589273)\n[PASS] testOnlyCompleteRecognizedLossClearsRetiredBacking() (gas: 2477994)\n[PASS] testPermanentSharesKeepResidualAndRetiredDepositRestriction() (gas: 1742218)\n[PASS] testRemovalCannotSilentlyDropTrailingMinimum() (gas: 1217844)\n[PASS] testRetiredBackingCannotBeAcquiredByNewDepositor() (gas: 1506624)\n[PASS] testRetiredDebtWithoutManagedDoesNotBlockDepositOrClaim() (gas: 2158335)\n[PASS] testUnrelatedGuardianReplacementPreservesOwnershipHandover() (gas: 520783)\n[PASS] testZeroNAVRequiresBackingEvenWhenOnlyPermanentSharesRemain() (gas: 1670942)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 82.28ms (152.75ms CPU time)\n\nRan 7 tests for test/Gas.t.sol:GasTest\n[PASS] testGas250AllBalancesBurnStipend() (gas: 424891477)\nLogs:\n  redemption gas (cold state, before refunds): 26604927\n\n[PASS] testGas250Paused() (gas: 413831744)\nLogs:\n  redemption gas (cold state, before refunds): 15447429\n\n[PASS] testGas254AtDefaultBalanceGasBound() (gas: 432014594)\nLogs:\n  redemption gas (cold state, before refunds): 27029340\n\n[PASS] testGas350AtMinimumBalanceGas() (gas: 584880791)\nLogs:\n  redemption gas (cold state, before refunds): 26717673\n\n[PASS] testGasMaximumBalanceBudgetWithFees() (gas: 169437124)\nLogs:\n  redemption gas (cold state, before refunds): 27924736\n\n[PASS] testGasMaximumDirectPaymentsBurnEntireBudget() (gas: 391902980)\nLogs:\n  redemption gas (cold state, before refunds): 27611179\n\n[PASS] testGasSparse350AssetsMaximumPayBudget() (gas: 602268445)\nLogs:\n  redemption gas (cold state, before refunds): 27978671\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 523.13ms (1.87s CPU time)\n\nRan 7 test suites in 524.01ms (954.66ms CPU time): 74 tests passed, 0 failed, 0 skipped (74 total tests)\n","passed":true},{"durationMs":34,"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.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose((uint8,address,address,address,address,uint256,uint8))\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeAsset(address)\",\"BaskVault.setDepositsPaused(bool)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":10,\"LICENSE\":339,\"README.md\":139,\"REVIEW.md\":53,\"foundry.toml\":15,\"launch.json\":13,\"src/BaskVault.sol\":999,\"src/libraries/Calls.sol\":31,\"src/libraries/FullMath.LICENSE\":21,\"src/libraries/FullMath.sol\":107,\"src/libraries/PoolOracle.sol\":69,\"src/libraries/TickMath.sol\":56,\"test/Accounting.t.sol\":293,\"test/Adversarial.t.sol\":213,\"test/Base.t.sol\":124,\"test/Gas.t.sol\":174,\"test/Governance.t.sol\":303,\"test/Oracle.t.sol\":212,\"test/Revision.t.sol\":274,\"test/mocks/Mocks.sol\":261},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4495,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/BaskVault.sol:628: BaskVault._insideHours() (src/BaskVault.sol#628-636) uses a weak PRNG: \"day = (block.timestamp / 86400 + 3) % 7 (src/BaskVault.sol#633)\"\n[high/medium] weak-prng at src/BaskVault.sol:628: BaskVault._insideHours() (src/BaskVault.sol#628-636) uses a weak PRNG: \"time = block.timestamp % 86400 (src/BaskVault.sol#634)\"\n[medium/medium] reentrancy-no-eth at src/BaskVault.sol:843: Reentrancy in BaskVault.claim(address[],address) (src/BaskVault.sol#843-858):\n[medium/medium] uninitialized-local at src/BaskVault.sol:800: BaskVault.redeem(uint256,address,uint256[],uint256).count (src/BaskVault.sol#800) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:657: BaskVault._depositContext(address[]).fresh (src/BaskVault.sol#657) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:674: BaskVault._depositContext(address[]).updatedAt (src/BaskVault.sol#674) is a local variable never initialized\n[low/medium] calls-loop at src/BaskVault.sol:843: BaskVault.claim(address[],address) (src/BaskVault.sol#843-858) has external calls inside a loop: this.pay(token,to,amount) (src/BaskVault.sol#855)\n[low/medium] timestamp at src/BaskVault.sol:628: BaskVault._insideHours() (src/BaskVault.sol#628-636) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:638: BaskVault._depositContext(address[]) (src/BaskVault.sol#638-690) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:785: BaskVault.redeem(uint256,address,uint256[],uint256) (src/BaskVault.sol#785-841) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:871: BaskVault.recognizeLoss(address) (src/BaskVault.sol#871-883) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:719: BaskVault.deposit(address[],uint256[],address,uint256,uint256) (src/BaskVault.sol#719-762) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:585: BaskVault._price(address) (src/BaskVault.sol#585-626) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:961: BaskVault.proposalStatus(uint256) (src/BaskVault.sol#961-970) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:470: BaskVault._feed(address) (src/BaskVault.sol#470-482) uses timestamp for comparisons","passed":true},{"durationMs":470,"exitCode":0,"name":"aderyn","output":"[high] incorrect-caret-operator at src/libraries/FullMath.sol:86: Incorrect use of caret operator\n[high] incorrect-shift-order at src/BaskVault.sol:565: Incorrect Assembly Shift Parameter Order\n[high] reentrancy-state-change at src/BaskVault.sol:855: Reentrancy: State change after external call\n[high] weak-randomness at src/BaskVault.sol:634: Weak Randomness\n[low] centralization-risk at src/BaskVault.sol:279: Centralization Risk (9 places)\n[low] costly-loop at src/BaskVault.sol:732: Costly operations inside loop (4 places)\n[low] internal-function-used-once at src/libraries/Calls.sol:6: Internal Function Used Only Once\n[low] large-numeric-literal at src/BaskVault.sol:218: Large Numeric Literal (12 places)\n[low] literal-instead-of-constant at src/BaskVault.sol:218: Literal Instead of Constant (69 places)\n[low] local-variable-shadowing at src/BaskVault.sol:123: Local Variable Shadows State Variable (2 places)\n[low] non-reentrant-not-first at src/BaskVault.sol:279: `nonReentrant` is Not the First Modifier (9 places)\n[low] push-zero-opcode at src/libraries/TickMath.sol:2: PUSH0 Opcode\n[low] require-revert-in-loop at src/BaskVault.sol:450: Loop Contains `require`/`revert` (9 places)\n[low] state-change-without-event at src/BaskVault.sol:229: State Change Without Event\n[low] storage-array-length-not-cached at src/BaskVault.sol:658: Storage Array Length not Cached (4 places)\n[low] unchecked-return at src/BaskVault.sol:415: Unchecked Return (8 places)\n[low] uninitialized-local-variable at src/BaskVault.sol:649: Uninitialized Local Variable (8 places)\n[low] unsafe-erc20-operation at src/BaskVault.sol:736: Unsafe ERC20 Operation (2 places)","passed":true},{"durationMs":5286,"exitCode":0,"name":"proof 8223796551d7","output":"Compiling 25 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.77s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-31e0409f/Proof_8223796551d7.t.sol:RetiredAssetDilutionTest\n[PASS] testPostRetirementDepositorExtractsRetiredBacking() (gas: 960643)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.31ms (320.02µs CPU time)\n\nRan 1 test suite in 2.63ms (1.31ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"00b2cb162d9ba7c1700554feae5bab271b255db555b74299d20feee387261fb2","verifiedTreeHash":"422ef71596982416562ff8a9664cfc6752d9499d","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":36305,"exitCode":0,"name":"build","output":"Compiling 35 files with Solc 0.8.26\nSolc 0.8.26 finished in 36.00s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:19:26\n   │\n19 │         if (!ok) return (false, 0, 0);\n   │                          ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:478:21\n    │\n478 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:42:21\n   │\n42 │             return (false, 0, 0);\n   │                     ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:480:17\n    │\n480 │         return (true, uint256(signedAnswer), updatedAt);\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:51:40\n   │\n51 │         if (secondsDelta == 0) return (false, 0, 0);\n   │                                        ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:522:21\n    │\n522 │             return (false, 0, 0);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:54:54\n   │\n54 │         if (mean < -887272 || mean > 887272) return (false, 0, 0);\n   │                                                      ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:56:51\n   │\n56 │         if (harmonic > type(uint128).max) return (false, 0, 0);\n   │                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:57:17\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                 ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:632:23\n    │\n632 │         uint256 day = (block.timestamp / 1 days + 3) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:86\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                      ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:105\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                                         ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:21\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                     ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:33\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                                 ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:28\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                            ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:42\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                                          ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:23\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                       ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:36\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:288:9\n    │\n288 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:399:13\n    │\n399 │             guardian = d.target;\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:278:65\n    │\n278 │     function transferOwnership(address next) external onlyOwner nonReentrant {\n    │                                                                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:293:63\n    │\n293 │     function setDepositsPaused(bool paused) external onlyRole nonReentrant {\n    │                                                               ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:299:58\n    │\n299 │     function closeAsset(address token) external onlyRole nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:306:58\n    │\n306 │     function lowerNAVCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:316:9\n    │\n316 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:322:51\n    │\n322 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:348:69\n    │\n348 │     function propose(ProposalData calldata data) external onlyOwner nonReentrant returns (uint256 id) {\n    │                                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:357:9\n    │\n357 │         emit Proposed(id, data, p.readyAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:360:59\n    │\n360 │     function cancelProposal(uint256 id) external onlyRole nonReentrant {\n    │                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:368:61\n    │\n368 │     function executeProposal(uint256 id) external onlyOwner nonReentrant {\n    │                                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:512:9\n    │\n512 │         emit AssetListed(token, feed, pool);\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:397:13\n    │\n397 │             emit Resynced(d.token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:407:9\n    │\n407 │         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:375:59\n    │\n375 │             _list(d.token, d.target, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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:391:55\n    │\n391 │             _setPool(a, d.token, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:450:50\n    │\n450 │             if (s[i] < 20_000 || s[i] > 500_000) revert InvalidSetting();\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:466:16\n    │\n466 │         return uint8(d);\n    │                ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:477:41\n    │\n477 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\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:477:72\n    │\n477 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\n    │                                                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:478:47\n    │\n478 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\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:480:23\n    │\n480 │         return (true, uint256(signedAnswer), updatedAt);\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:529:29\n    │\n529 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:529:62\n    │\n529 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                                                              ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:531:32\n    │\n531 │         baseIsToken0 = address(uint160(t0)) == token;\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:532:43\n    │\n532 │         quoteDecimals = _decimals(address(uint160(baseIsToken0 ? t1 : t0)));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:623:13\n    │\n623 │         if (block.timestamp - updatedAt > _settings[2]) return (Reason.NoPoolAge, answer, updatedAt, 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:605:64\n    │\n605 │             (ok, tick, liquidity) = PoolOracle.consult(a.pool, uint32(_settings[7]), _settings[11]);\n    │                                                                ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:634:16\n    │\n634 │         return day < 5 && time >= from && time < to;\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:634:27\n    │\n634 │         return day < 5 && time >= from && time < to;\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:634:43\n    │\n634 │         return day < 5 && time >= from && time < to;\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:681:86\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\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:681:47\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                                               ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:681:29\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:697:34\n    │\n697 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:721:13\n    │\n721 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:750:17\n    │\n750 │                 emit DeficitCleared(token);\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:756:9\n    │\n756 │         emit Deposit(msg.sender, receiver, value, 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:730:22\n    │\n730 │             if (!ok) revert BalanceUnreadable(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:737:17\n    │\n737 │                 revert PaymentFailed();\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:742:17\n    │\n742 │                 revert PaymentFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:771:9\n    │\n771 │         emit Payment(token, receiver, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:804:23\n    │\n804 │                     ++count;\n    │                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:785:13\n    │\n785 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:831:9\n    │\n831 │         emit Redeem(msg.sender, receiver, shares, net, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:812:72\n    │\n812 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:821:69\n    │\n821 │             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:846:13\n    │\n846 │             this.pay(token, to, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:846:13\n    │\n846 │             this.pay(token, to, amount);\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:847:13\n    │\n847 │             emit Claimed(msg.sender, to, token, amount);\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:841:22\n    │\n841 │             if (!ok) revert BalanceUnreadable(token);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:859:9\n    │\n859 │         emit DeficitFlagged(token, shortfall, block.timestamp);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:865:30\n    │\n865 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert NotReady();\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:873:9\n    │\n873 │         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:959:13\n    │\n959 │         if (block.timestamp > p.readyAt + 7 days) return ProposalState.Expired;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:960:16\n    │\n960 │         return block.timestamp < p.readyAt ? ProposalState.Waiting : ProposalState.Ready;\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:980:21\n    │\n980 │                 ids[n] = id;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":4994,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testConstructorsAndGenesis() (gas: 4236)\n[PASS] testFeedAndRecentreUseExecutionAnswer() (gas: 965389)\n[PASS] testLaterCloseVoidsReopen() (gas: 819355)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 2481699)\n[PASS] testLowerCapVoidsRaisesAndBounds() (gas: 750926)\n[PASS] testOwnerAndGuardianPowers() (gas: 1090053)\n[PASS] testRemoveAndRelistDoesNotReviveOldProposals() (gas: 1632332)\n[PASS] testRetirementVoidsProposalsAndSkipsChecksButRedeems() (gas: 2681801)\n[PASS] testSettingGasBoundsAndRevalidation() (gas: 1910237)\n[PASS] testTimelockBoundariesAndPendingViews() (gas: 730472)\n[PASS] testTwoStepOwnerNeverGuardianEvenAfterProposal() (gas: 1020619)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 79.09ms (5.07ms CPU time)\n\nRan 2 tests for test/RegistryExit.t.sol:RegistryExitTest\n[PASS] test_MaxAssetsWithMissingTokenCodeStillRedeemUnder28MillionAndCanClaimAfterRecovery() (gas: 417754220)\nLogs:\n  250 upgraded assets: cold redemption gas including calldata: 14105199\n\n[PASS] test_RemovalAcrossBitmapWordsLossAndResyncPreserveRedeemLegs() (gas: 377871981)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 220.41ms (401.39ms CPU time)\n\nRan 3 tests for test/Oracle.t.sol:OracleMathTest\n[PASS] testFullPrecisionMultiplicationAvoidsIntermediateOverflow() (gas: 3968)\n[PASS] testFuzzQuoteReciprocal(int24) (runs: 256, μ: 13476, ~: 13522)\nLogs:\n  Bound result 4746\n\n[PASS] testNegativeTickRoundsDownAndWrapsAccumulators() (gas: 127764)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 247.83ms (246.73ms CPU time)\n\nRan 11 tests for test/Oracle.t.sol:OracleTest\n[PASS] testAllAssetsViewContainsBalancesAndFaults() (gas: 610071)\n[PASS] testBadAnswerFutureAndMalformedRead() (gas: 679433)\n[PASS] testBandBoundariesWithoutPool() (gas: 895418)\n[PASS] testEveryManagedAssetValidatedAndUnmanagedStaleAllowed() (gas: 997103)\n[PASS] testFreshnessCountAndBoundary() (gas: 1151597)\n[PASS] testHoursWeekdaysAndExactEdges() (gas: 2333942)\n[PASS] testMixedQuoteDecimalsAndReversePoolDirection() (gas: 3369704)\n[PASS] testPauseDetectionAndUnreadablePause() (gas: 2354067)\n[PASS] testPoolDeviationAndQuoteFeedCannotFallBack() (gas: 809080)\n[PASS] testPoolLiquidityAndMalformedObserveFallBack() (gas: 1248491)\n[PASS] testValidPoolCanUseOlderFeedButFallbackCannot() (gas: 887198)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 250.07ms (10.76ms CPU time)\n\nRan 13 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] testAllLossDoesNotBlockRedeemAndPreventsDepositAtZeroNAV() (gas: 915726)\n[PASS] testBalanceReturnBombCopiesOnlyWord() (gas: 493358)\n[PASS] testClaimCannotBeBlockedByBalanceGasSetting() (gas: 1800354)\n[PASS] testClaimHasNoPayGasLimitAndPausesDoNotApply() (gas: 1403589)\n[PASS] testDepositInputCannotConsumeUnderfundedOwed() (gas: 1294089)\n[PASS] testDepositSettingsAndGovernanceCannotVetoExit() (gas: 5984313)\n[PASS] testFeeOnTransferAndFalseDepositAreAtomic() (gas: 1023485)\n[PASS] testFuzzBrokenTransferNeverBlocksOtherLegs(uint8) (runs: 256, μ: 1003078, ~: 1007130)\nLogs:\n  Bound result 1\n\n[PASS] testFuzzUnreadableBalanceUsesManaged(uint8) (runs: 256, μ: 835987, ~: 735842)\nLogs:\n  Bound result 1\n\n[PASS] testMinOutputForZeroLegRevertsOnlyByUserChoice() (gas: 519144)\n[PASS] testPausedTokenDefersAndOtherLegsProceed() (gas: 1010197)\n[PASS] testReentrantDepositRedeemClaimAndRoleChangesFail() (gas: 1776811)\n[PASS] testUpgradeToNoCodeStillRedeemsAsDebt() (gas: 759473)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 250.07ms (333.68ms CPU time)\n\nRan 17 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDeferredClaimAndPartialLiquidity() (gas: 1562146)\n[PASS] testDeploymentAndFirstDeposit() (gas: 431638)\n[PASS] testDonationIgnoredUntilResyncAndShareMath() (gas: 1404889)\n[PASS] testERC20AllowancesAndNoBurnByTransfer() (gas: 546932)\n[PASS] testERC20TransferEventTopics() (gas: 407306)\n[PASS] testFeesRoundUpMintAndTransfer() (gas: 899639)\n[PASS] testFirstDepositMustExceedLockAndFees() (gas: 1119801)\n[PASS] testFuzzConservation(uint96,uint96,bool,bool) (runs: 256, μ: 1057911, ~: 1000430)\nLogs:\n  Bound result 1000000000000000001\n  Bound result 68916908866174311\n\n[PASS] testFuzzDecimalValuation(uint8,uint8,uint32) (runs: 256, μ: 2176863, ~: 2183587)\nLogs:\n  Bound result 5\n  Bound result 10\n  Bound result 812\n\n[PASS] testInputValidationAndCap() (gas: 834650)\n[PASS] testLargerDeficitRestartsClockAndDepositClears() (gas: 1031699)\n[PASS] testNoAutomaticLossAndSevenDayRecognition() (gas: 1138561)\n[PASS] testRedeemDirectHasNoPriceDependency() (gas: 1128695)\n[PASS] testRemovalMovesFundedAssetIndexAndLossClearsBitmap() (gas: 1832428)\n[PASS] testResyncExcludesOwed() (gas: 1366025)\n[PASS] testRuntimeHasNoForbiddenOpcodes() (gas: 9831776)\n[PASS] testSlippageAndDeadlineAtomicity() (gas: 910739)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 250.24ms (354.46ms CPU time)\n\nRan 12 tests for test/BasketEdges.t.sol:BasketEdgesTest\n[PASS] testFuzz_DonationCannotChangeDepositPriceBeforeResync(uint128,uint96) (runs: 1000, μ: 919377, ~: 919341)\nLogs:\n  Bound result 20106656245\n\n[PASS] testFuzz_LossRecognitionCannotExceedRecordedOrCurrentDeficit(uint96,uint96) (runs: 1000, μ: 669047, ~: 669278)\nLogs:\n  Bound result 13126\n  Bound result 2\n\n[PASS] testFuzz_RepeatedRoundTripsCannotCreateStockTokens(uint96,uint8,bool) (runs: 1000, μ: 2815707, ~: 2400751)\nLogs:\n  Bound result 20514\n  Bound result 3\n\n[PASS] test_AllProposalKindsRejectNonOwnersAndPayRejectsRoles() (gas: 1006624)\n[PASS] test_ClaimBatchFailureRollsBackEarlierPaymentAndDuplicateIsIdempotent() (gas: 1748558)\n[PASS] test_FeeRecipientCanDepositAndRedeemWithoutLosingSelfTransferredFee() (gas: 949224)\n[PASS] test_LateDepositFailureRollsBackEarlierTransfersAndAllowances() (gas: 606813)\n[PASS] test_LateRedeemSlippageRollsBackPaymentDebtFeeAndBurn() (gas: 1453915)\n[PASS] test_ListingAndFeedProposalsRevalidateFeedUniqueness() (gas: 2955642)\n[PASS] test_ReentrantRedeemRejectsAnOtherwiseAuthorizedShareholder() (gas: 1420440)\n[PASS] test_ResyncUsesExecutionBalanceAndNeverCountsOwedOrWritesOffLoss() (gas: 1646144)\n[PASS] test_RetireRequiresClosedAgainAtExecutionAndCannotExecuteTwice() (gas: 773098)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 250.26ms (737.19ms CPU time)\n\nRan 7 tests for test/Gas.t.sol:GasTest\n[PASS] testGas250AllBalancesBurnStipend() (gas: 424897413)\nLogs:\n  redemption gas (cold state, before refunds): 26604839\n\n[PASS] testGas250Paused() (gas: 413837680)\nLogs:\n  redemption gas (cold state, before refunds): 15447341\n\n[PASS] testGas254AtDefaultBalanceGasBound() (gas: 432020976)\nLogs:\n  redemption gas (cold state, before refunds): 27029252\n\n[PASS] testGas350AtMinimumBalanceGas() (gas: 584889827)\nLogs:\n  redemption gas (cold state, before refunds): 26717585\n\n[PASS] testGasMaximumBalanceBudgetWithFees() (gas: 169442690)\nLogs:\n  redemption gas (cold state, before refunds): 27924648\n\n[PASS] testGasMaximumDirectPaymentsBurnEntireBudget() (gas: 391905114)\nLogs:\n  redemption gas (cold state, before refunds): 27611091\n\n[PASS] testGasSparse350AssetsMaximumPayBudget() (gas: 602274519)\nLogs:\n  redemption gas (cold state, before refunds): 27978583\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 480.35ms (1.81s CPU time)\n\nRan 2 tests for test/BasketInvariant.t.sol:BasketInvariantTest\n[PASS]\nBasketInvariantTest invariants:\n[PASS] invariant_CustodyAndLiabilitiesMatchIndependentFlows\n[PASS] invariant_ShareSupplyAndPermanentLock\n BasketInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | advanceTime    | 1292  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | claim          | 1241  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | configure      | 1244  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | confiscate     | 1316  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 1302  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1251  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1278  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | pause          | 1227  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1206  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1286  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | resync         | 1209  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenState     | 1254  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1278  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 999990000000000241336\n  Bound result 163997\n  Bound result 999990000000878340193\n  Bound result 6177\n  Bound result 12600\n  Bound result 999990000000000032401\n  Bound result 10584455093849666000\n  Bound result 50000\n  Bound result 999990000000000012751\n  Bound result 25729478136985866474\n  Bound result 50000000000000000000\n  Bound result 18776\n  Bound result 5533\n  Bound result 50000000000000000000\n  Bound result 3867\n  Bound result 299\n  Bound result 24177872946847429851\n  Bound result 20000\n  Bound result 5475\n  Bound result 999990000000000010001\n  Bound result 256\n  Bound result 2308\n  Bound result 999990000000000006364\n  Bound result 17083665000000000003\n  Bound result 8192\n  Bound result 100000000\n  Bound result 999990000000000000256\n\n[PASS] test_HandlerReachesDebtRecoveryAndLossRecognition() (gas: 2391793)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 0\n  Bound result 20000000000000000000\n  Bound result 10000000000000000000\n  Bound result 604800\n  Bound result 10000000000000000000\n  Bound result 0\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 4.91s (4.91s CPU time)\n\nRan 9 test suites in 4.91s (6.94s CPU time): 78 tests passed, 0 failed, 0 skipped (78 total tests)\n","passed":true},{"durationMs":41,"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.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose((uint8,address,address,address,address,uint256,uint8))\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeAsset(address)\",\"BaskVault.setDepositsPaused(bool)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":10,\"LICENSE\":339,\"README.md\":135,\"REVIEW.md\":50,\"foundry.toml\":15,\"launch.json\":13,\"src/BaskVault.sol\":990,\"src/libraries/Calls.sol\":31,\"src/libraries/FullMath.LICENSE\":21,\"src/libraries/FullMath.sol\":107,\"src/libraries/PoolOracle.sol\":69,\"src/libraries/TickMath.sol\":56,\"test/Accounting.t.sol\":293,\"test/Adversarial.t.sol\":213,\"test/Base.t.sol\":124,\"test/BasketEdges.t.sol\":276,\"test/BasketInvariant.t.sol\":100,\"test/Gas.t.sol\":174,\"test/Governance.t.sol\":301,\"test/Oracle.t.sol\":212,\"test/README.md\":20,\"test/RegistryExit.t.sol\":175,\"test/handlers/BasketHandler.sol\":352,\"test/mocks/Mocks.sol\":261,\"test/mocks/ReentryProbe.sol\":25},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"2b685e16b95ea98b97677585bcc66a9089aa8f40146a90807f5885fc49272623","verifiedTreeHash":"58364ad1f791e89a187122a04fc4e93b0f280596","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":26922,"exitCode":0,"name":"build","output":"Compiling 30 files with Solc 0.8.26\nSolc 0.8.26 finished in 26.56s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:19:26\n   │\n19 │         if (!ok) return (false, 0, 0);\n   │                          ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:478:21\n    │\n478 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:480:17\n    │\n480 │         return (true, uint256(signedAnswer), updatedAt);\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:522:21\n    │\n522 │             return (false, 0, 0);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:42:21\n   │\n42 │             return (false, 0, 0);\n   │                     ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:51:40\n   │\n51 │         if (secondsDelta == 0) return (false, 0, 0);\n   │                                        ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:54:54\n   │\n54 │         if (mean < -887272 || mean > 887272) return (false, 0, 0);\n   │                                                      ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:56:51\n   │\n56 │         if (harmonic > type(uint128).max) return (false, 0, 0);\n   │                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:57:17\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\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:632:23\n    │\n632 │         uint256 day = (block.timestamp / 1 days + 3) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:86\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                      ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:105\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                                         ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:21\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                     ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:33\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                                 ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:28\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                            ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:42\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                                          ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:23\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                       ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:36\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:288:9\n    │\n288 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:399:13\n    │\n399 │             guardian = d.target;\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:278:65\n    │\n278 │     function transferOwnership(address next) external onlyOwner nonReentrant {\n    │                                                                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:293:63\n    │\n293 │     function setDepositsPaused(bool paused) external onlyRole nonReentrant {\n    │                                                               ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:299:58\n    │\n299 │     function closeAsset(address token) external onlyRole nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:306:58\n    │\n306 │     function lowerNAVCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:316:9\n    │\n316 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:322:51\n    │\n322 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:348:69\n    │\n348 │     function propose(ProposalData calldata data) external onlyOwner nonReentrant returns (uint256 id) {\n    │                                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:357:9\n    │\n357 │         emit Proposed(id, data, p.readyAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:360:59\n    │\n360 │     function cancelProposal(uint256 id) external onlyRole nonReentrant {\n    │                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:368:61\n    │\n368 │     function executeProposal(uint256 id) external onlyOwner nonReentrant {\n    │                                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:512:9\n    │\n512 │         emit AssetListed(token, feed, pool);\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:397:13\n    │\n397 │             emit Resynced(d.token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:407:9\n    │\n407 │         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:375:59\n    │\n375 │             _list(d.token, d.target, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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:391:55\n    │\n391 │             _setPool(a, d.token, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:450:50\n    │\n450 │             if (s[i] < 20_000 || s[i] > 500_000) revert InvalidSetting();\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:466:16\n    │\n466 │         return uint8(d);\n    │                ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:477:41\n    │\n477 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\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:477:72\n    │\n477 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\n    │                                                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:478:47\n    │\n478 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\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:480:23\n    │\n480 │         return (true, uint256(signedAnswer), updatedAt);\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:529:29\n    │\n529 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:529:62\n    │\n529 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                                                              ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:531:32\n    │\n531 │         baseIsToken0 = address(uint160(t0)) == token;\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:532:43\n    │\n532 │         quoteDecimals = _decimals(address(uint160(baseIsToken0 ? t1 : t0)));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:623:13\n    │\n623 │         if (block.timestamp - updatedAt > _settings[2]) return (Reason.NoPoolAge, answer, updatedAt, 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:605:64\n    │\n605 │             (ok, tick, liquidity) = PoolOracle.consult(a.pool, uint32(_settings[7]), _settings[11]);\n    │                                                                ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:634:16\n    │\n634 │         return day < 5 && time >= from && time < to;\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:634:27\n    │\n634 │         return day < 5 && time >= from && time < to;\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:634:43\n    │\n634 │         return day < 5 && time >= from && time < to;\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:681:47\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\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:681:86\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                                                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:681:29\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:697:34\n    │\n697 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:721:13\n    │\n721 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:750:17\n    │\n750 │                 emit DeficitCleared(token);\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:756:9\n    │\n756 │         emit Deposit(msg.sender, receiver, value, 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:730:22\n    │\n730 │             if (!ok) revert BalanceUnreadable(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:737:17\n    │\n737 │                 revert PaymentFailed();\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:742:17\n    │\n742 │                 revert PaymentFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:771:9\n    │\n771 │         emit Payment(token, receiver, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:804:23\n    │\n804 │                     ++count;\n    │                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:785:13\n    │\n785 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:831:9\n    │\n831 │         emit Redeem(msg.sender, receiver, shares, net, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:812:72\n    │\n812 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:821:69\n    │\n821 │             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:846:13\n    │\n846 │             this.pay(token, to, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:846:13\n    │\n846 │             this.pay(token, to, amount);\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:847:13\n    │\n847 │             emit Claimed(msg.sender, to, token, amount);\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:841:22\n    │\n841 │             if (!ok) revert BalanceUnreadable(token);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:859:9\n    │\n859 │         emit DeficitFlagged(token, shortfall, block.timestamp);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:865:30\n    │\n865 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert NotReady();\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:873:9\n    │\n873 │         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:959:13\n    │\n959 │         if (block.timestamp > p.readyAt + 7 days) return ProposalState.Expired;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:960:16\n    │\n960 │         return block.timestamp < p.readyAt ? ProposalState.Waiting : ProposalState.Ready;\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:980:21\n    │\n980 │                 ids[n] = id;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":888,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Oracle.t.sol:OracleTest\n[PASS] testAllAssetsViewContainsBalancesAndFaults() (gas: 610071)\n[PASS] testBadAnswerFutureAndMalformedRead() (gas: 679433)\n[PASS] testBandBoundariesWithoutPool() (gas: 895418)\n[PASS] testEveryManagedAssetValidatedAndUnmanagedStaleAllowed() (gas: 997103)\n[PASS] testFreshnessCountAndBoundary() (gas: 1151597)\n[PASS] testHoursWeekdaysAndExactEdges() (gas: 2333942)\n[PASS] testMixedQuoteDecimalsAndReversePoolDirection() (gas: 3369704)\n[PASS] testPauseDetectionAndUnreadablePause() (gas: 2354067)\n[PASS] testPoolDeviationAndQuoteFeedCannotFallBack() (gas: 809080)\n[PASS] testPoolLiquidityAndMalformedObserveFallBack() (gas: 1248491)\n[PASS] testValidPoolCanUseOlderFeedButFallbackCannot() (gas: 887198)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 50.27ms (9.65ms CPU time)\n\nRan 11 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testConstructorsAndGenesis() (gas: 4236)\n[PASS] testFeedAndRecentreUseExecutionAnswer() (gas: 965389)\n[PASS] testLaterCloseVoidsReopen() (gas: 819355)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 2481699)\n[PASS] testLowerCapVoidsRaisesAndBounds() (gas: 750926)\n[PASS] testOwnerAndGuardianPowers() (gas: 1090053)\n[PASS] testRemoveAndRelistDoesNotReviveOldProposals() (gas: 1632332)\n[PASS] testRetirementVoidsProposalsAndSkipsChecksButRedeems() (gas: 2681801)\n[PASS] testSettingGasBoundsAndRevalidation() (gas: 1910237)\n[PASS] testTimelockBoundariesAndPendingViews() (gas: 730472)\n[PASS] testTwoStepOwnerNeverGuardianEvenAfterProposal() (gas: 1020619)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 54.30ms (7.42ms CPU time)\n\nRan 3 tests for test/Oracle.t.sol:OracleMathTest\n[PASS] testFullPrecisionMultiplicationAvoidsIntermediateOverflow() (gas: 3968)\n[PASS] testFuzzQuoteReciprocal(int24) (runs: 256, μ: 13460, ~: 13451)\nLogs:\n  Bound result 68002\n\n[PASS] testNegativeTickRoundsDownAndWrapsAccumulators() (gas: 127764)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 54.28ms (5.35ms CPU time)\n\nRan 17 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDeferredClaimAndPartialLiquidity() (gas: 1562146)\n[PASS] testDeploymentAndFirstDeposit() (gas: 431638)\n[PASS] testDonationIgnoredUntilResyncAndShareMath() (gas: 1404889)\n[PASS] testERC20AllowancesAndNoBurnByTransfer() (gas: 546932)\n[PASS] testERC20TransferEventTopics() (gas: 407306)\n[PASS] testFeesRoundUpMintAndTransfer() (gas: 899639)\n[PASS] testFirstDepositMustExceedLockAndFees() (gas: 1119801)\n[PASS] testFuzzConservation(uint96,uint96,bool,bool) (runs: 256, μ: 1074237, ~: 1000430)\nLogs:\n  Bound result 99999000000000000000059\n  Bound result 183\n\n[PASS] testFuzzDecimalValuation(uint8,uint8,uint32) (runs: 256, μ: 2177817, ~: 2183751)\nLogs:\n  Bound result 11\n  Bound result 2\n  Bound result 133\n\n[PASS] testInputValidationAndCap() (gas: 834650)\n[PASS] testLargerDeficitRestartsClockAndDepositClears() (gas: 1031699)\n[PASS] testNoAutomaticLossAndSevenDayRecognition() (gas: 1138561)\n[PASS] testRedeemDirectHasNoPriceDependency() (gas: 1128695)\n[PASS] testRemovalMovesFundedAssetIndexAndLossClearsBitmap() (gas: 1832428)\n[PASS] testResyncExcludesOwed() (gas: 1366025)\n[PASS] testRuntimeHasNoForbiddenOpcodes() (gas: 9831776)\n[PASS] testSlippageAndDeadlineAtomicity() (gas: 910739)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 54.36ms (131.57ms CPU time)\n\nRan 13 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] testAllLossDoesNotBlockRedeemAndPreventsDepositAtZeroNAV() (gas: 915726)\n[PASS] testBalanceReturnBombCopiesOnlyWord() (gas: 493358)\n[PASS] testClaimCannotBeBlockedByBalanceGasSetting() (gas: 1800354)\n[PASS] testClaimHasNoPayGasLimitAndPausesDoNotApply() (gas: 1403589)\n[PASS] testDepositInputCannotConsumeUnderfundedOwed() (gas: 1294089)\n[PASS] testDepositSettingsAndGovernanceCannotVetoExit() (gas: 5984313)\n[PASS] testFeeOnTransferAndFalseDepositAreAtomic() (gas: 1023485)\n[PASS] testFuzzBrokenTransferNeverBlocksOtherLegs(uint8) (runs: 256, μ: 1018125, ~: 1007130)\nLogs:\n  Bound result 2\n\n[PASS] testFuzzUnreadableBalanceUsesManaged(uint8) (runs: 256, μ: 842075, ~: 736079)\nLogs:\n  Bound result 3\n\n[PASS] testMinOutputForZeroLegRevertsOnlyByUserChoice() (gas: 519144)\n[PASS] testPausedTokenDefersAndOtherLegsProceed() (gas: 1010197)\n[PASS] testReentrantDepositRedeemClaimAndRoleChangesFail() (gas: 1776811)\n[PASS] testUpgradeToNoCodeStillRedeemsAsDebt() (gas: 759473)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 56.72ms (103.76ms CPU time)\n\nRan 7 tests for test/Gas.t.sol:GasTest\n[PASS] testGas250AllBalancesBurnStipend() (gas: 424897413)\nLogs:\n  redemption gas (cold state, before refunds): 26604839\n\n[PASS] testGas250Paused() (gas: 413837680)\nLogs:\n  redemption gas (cold state, before refunds): 15447341\n\n[PASS] testGas254AtDefaultBalanceGasBound() (gas: 432020976)\nLogs:\n  redemption gas (cold state, before refunds): 27029252\n\n[PASS] testGas350AtMinimumBalanceGas() (gas: 584889827)\nLogs:\n  redemption gas (cold state, before refunds): 26717585\n\n[PASS] testGasMaximumBalanceBudgetWithFees() (gas: 169442690)\nLogs:\n  redemption gas (cold state, before refunds): 27924648\n\n[PASS] testGasMaximumDirectPaymentsBurnEntireBudget() (gas: 391905114)\nLogs:\n  redemption gas (cold state, before refunds): 27611091\n\n[PASS] testGasSparse350AssetsMaximumPayBudget() (gas: 602274519)\nLogs:\n  redemption gas (cold state, before refunds): 27978583\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 796.38ms (2.50s CPU time)\n\nRan 6 test suites in 797.13ms (1.07s CPU time): 62 tests passed, 0 failed, 0 skipped (62 total tests)\n","passed":true},{"durationMs":51,"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.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose((uint8,address,address,address,address,uint256,uint8))\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeAsset(address)\",\"BaskVault.setDepositsPaused(bool)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":10,\"LICENSE\":339,\"README.md\":135,\"REVIEW.md\":50,\"foundry.toml\":15,\"launch.json\":13,\"src/BaskVault.sol\":990,\"src/libraries/Calls.sol\":31,\"src/libraries/FullMath.LICENSE\":21,\"src/libraries/FullMath.sol\":107,\"src/libraries/PoolOracle.sol\":69,\"src/libraries/TickMath.sol\":56,\"test/Accounting.t.sol\":293,\"test/Adversarial.t.sol\":213,\"test/Base.t.sol\":124,\"test/Gas.t.sol\":174,\"test/Governance.t.sol\":301,\"test/Oracle.t.sol\":212,\"test/mocks/Mocks.sol\":261},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"36da079d81f1db02bf31f42709ca36089fa2d6e6aa5113bb8992f49282de889e","verifiedTreeHash":"c49ef3db0fd49a2fb58e35f7bde068390e7f358b","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":26610,"exitCode":0,"name":"build","output":"Compiling 31 files with Solc 0.8.26\nSolc 0.8.26 finished in 26.32s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:19:26\n   │\n19 │         if (!ok) return (false, 0, 0);\n   │                          ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:479:21\n    │\n479 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:481:17\n    │\n481 │         return (true, uint256(signedAnswer), updatedAt);\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:42:21\n   │\n42 │             return (false, 0, 0);\n   │                     ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:51:40\n   │\n51 │         if (secondsDelta == 0) return (false, 0, 0);\n   │                                        ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:54:54\n   │\n54 │         if (mean < -887272 || mean > 887272) return (false, 0, 0);\n   │                                                      ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:56:51\n   │\n56 │         if (harmonic > type(uint128).max) return (false, 0, 0);\n   │                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:57:17\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                 ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:21\n    │\n523 │             return (false, 0, 0);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:86\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                      ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:105\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                                         ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:633:23\n    │\n633 │         uint256 day = (block.timestamp / 1 days + 3) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:21\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                     ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:33\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                                 ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:28\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                            ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:42\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                                          ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:23\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                       ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:36\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:289:9\n    │\n289 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:400:13\n    │\n400 │             guardian = d.target;\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:279:65\n    │\n279 │     function transferOwnership(address next) external onlyOwner nonReentrant {\n    │                                                                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:294:63\n    │\n294 │     function setDepositsPaused(bool paused) external onlyRole nonReentrant {\n    │                                                               ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:300:58\n    │\n300 │     function closeAsset(address token) external onlyRole nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:307:58\n    │\n307 │     function lowerNAVCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:317:9\n    │\n317 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:323:51\n    │\n323 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:349:69\n    │\n349 │     function propose(ProposalData calldata data) external onlyOwner nonReentrant returns (uint256 id) {\n    │                                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:358:9\n    │\n358 │         emit Proposed(id, data, p.readyAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:361:59\n    │\n361 │     function cancelProposal(uint256 id) external onlyRole nonReentrant {\n    │                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:369:61\n    │\n369 │     function executeProposal(uint256 id) external onlyOwner nonReentrant {\n    │                                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:513:9\n    │\n513 │         emit AssetListed(token, feed, pool);\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:398:13\n    │\n398 │             emit Resynced(d.token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:408:9\n    │\n408 │         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:376:59\n    │\n376 │             _list(d.token, d.target, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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:392:55\n    │\n392 │             _setPool(a, d.token, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:451:50\n    │\n451 │             if (s[i] < 20_000 || s[i] > 500_000) revert InvalidSetting();\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:467:16\n    │\n467 │         return uint8(d);\n    │                ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:478:41\n    │\n478 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\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:478:72\n    │\n478 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\n    │                                                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:479:47\n    │\n479 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\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:481:23\n    │\n481 │         return (true, uint256(signedAnswer), updatedAt);\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:530:29\n    │\n530 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:530:62\n    │\n530 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                                                              ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:532:32\n    │\n532 │         baseIsToken0 = address(uint160(t0)) == token;\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:533:43\n    │\n533 │         quoteDecimals = _decimals(address(uint160(baseIsToken0 ? t1 : t0)));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:624:13\n    │\n624 │         if (block.timestamp - updatedAt > _settings[2]) return (Reason.NoPoolAge, answer, updatedAt, 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:606:64\n    │\n606 │             (ok, tick, liquidity) = PoolOracle.consult(a.pool, uint32(_settings[7]), _settings[11]);\n    │                                                                ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:635:16\n    │\n635 │         return day < 5 && time >= from && time < to;\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:635:27\n    │\n635 │         return day < 5 && time >= from && time < to;\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:635:43\n    │\n635 │         return day < 5 && time >= from && time < to;\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:686:47\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\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:686:86\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                                                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:686:29\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:702:34\n    │\n702 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:726:13\n    │\n726 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:755:17\n    │\n755 │                 emit DeficitCleared(token);\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:761:9\n    │\n761 │         emit Deposit(msg.sender, receiver, value, 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:735:22\n    │\n735 │             if (!ok) revert BalanceUnreadable(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:742:17\n    │\n742 │                 revert PaymentFailed();\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:747:17\n    │\n747 │                 revert PaymentFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:776:9\n    │\n776 │         emit Payment(token, receiver, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:813:23\n    │\n813 │                     ++count;\n    │                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:790:13\n    │\n790 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:840:9\n    │\n840 │         emit Redeem(msg.sender, receiver, shares, net, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:804:40\n    │\n804 │             if (minAmountsOut[i] != 0) revert Slippage();\n    │                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:821:72\n    │\n821 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:830:69\n    │\n830 │             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:855:13\n    │\n855 │             this.pay(token, to, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:855:13\n    │\n855 │             this.pay(token, to, amount);\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:856:13\n    │\n856 │             emit Claimed(msg.sender, to, token, amount);\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:850:22\n    │\n850 │             if (!ok) revert BalanceUnreadable(token);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:868:9\n    │\n868 │         emit DeficitFlagged(token, shortfall, block.timestamp);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:874:30\n    │\n874 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert NotReady();\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:882:9\n    │\n882 │         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:968:13\n    │\n968 │         if (block.timestamp > p.readyAt + 7 days) return ProposalState.Expired;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:969:16\n    │\n969 │         return block.timestamp < p.readyAt ? ProposalState.Waiting : ProposalState.Ready;\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:989:21\n    │\n989 │                 ids[n] = id;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":534,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Oracle.t.sol:OracleTest\n[PASS] testAllAssetsViewContainsBalancesAndFaults() (gas: 610014)\n[PASS] testBadAnswerFutureAndMalformedRead() (gas: 679199)\n[PASS] testBandBoundariesWithoutPool() (gas: 895149)\n[PASS] testEveryManagedAssetValidatedAndUnmanagedStaleAllowed() (gas: 996920)\n[PASS] testFreshnessCountAndBoundary() (gas: 1151064)\n[PASS] testHoursWeekdaysAndExactEdges() (gas: 2332972)\n[PASS] testMixedQuoteDecimalsAndReversePoolDirection() (gas: 3369459)\n[PASS] testPauseDetectionAndUnreadablePause() (gas: 2353802)\n[PASS] testPoolDeviationAndQuoteFeedCannotFallBack() (gas: 808912)\n[PASS] testPoolLiquidityAndMalformedObserveFallBack() (gas: 1248227)\n[PASS] testValidPoolCanUseOlderFeedButFallbackCannot() (gas: 886946)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 40.85ms (8.01ms CPU time)\n\nRan 3 tests for test/Oracle.t.sol:OracleMathTest\n[PASS] testFullPrecisionMultiplicationAvoidsIntermediateOverflow() (gas: 3968)\n[PASS] testFuzzQuoteReciprocal(int24) (runs: 256, μ: 13394, ~: 13442)\nLogs:\n  Bound result 21397\n\n[PASS] testNegativeTickRoundsDownAndWrapsAccumulators() (gas: 127764)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 46.47ms (45.42ms CPU time)\n\nRan 11 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testConstructorsAndGenesis() (gas: 4250)\n[PASS] testFeedAndRecentreUseExecutionAnswer() (gas: 965219)\n[PASS] testLaterCloseVoidsReopen() (gas: 819191)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 2481524)\n[PASS] testLowerCapVoidsRaisesAndBounds() (gas: 750691)\n[PASS] testOwnerAndGuardianPowers() (gas: 1096275)\n[PASS] testRemoveAndRelistDoesNotReviveOldProposals() (gas: 1632083)\n[PASS] testRetirementVoidsProposalsAndStopsDepositsButRedeems() (gas: 2336577)\n[PASS] testSettingGasBoundsAndRevalidation() (gas: 1907623)\n[PASS] testTimelockBoundariesAndPendingViews() (gas: 730296)\n[PASS] testTwoStepOwnerNeverGuardianEvenAfterProposal() (gas: 270792)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 63.45ms (9.30ms CPU time)\n\nRan 13 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] testAllLossDoesNotBlockRedeemAndPreventsDepositAtZeroNAV() (gas: 915718)\n[PASS] testBalanceReturnBombCopiesOnlyWord() (gas: 493398)\n[PASS] testClaimCannotBeBlockedByBalanceGasSetting() (gas: 1799623)\n[PASS] testClaimHasNoPayGasLimitAndPausesDoNotApply() (gas: 1403243)\n[PASS] testDepositInputCannotConsumeUnderfundedOwed() (gas: 1293730)\n[PASS] testDepositSettingsAndGovernanceCannotVetoExit() (gas: 5980770)\n[PASS] testFeeOnTransferAndFalseDepositAreAtomic() (gas: 1023429)\n[PASS] testFuzzBrokenTransferNeverBlocksOtherLegs(uint8) (runs: 256, μ: 1003457, ~: 1006885)\nLogs:\n  Bound result 8\n\n[PASS] testFuzzUnreadableBalanceUsesManaged(uint8) (runs: 256, μ: 828515, ~: 735859)\nLogs:\n  Bound result 1\n\n[PASS] testMinOutputForZeroLegRevertsOnlyByUserChoice() (gas: 519272)\n[PASS] testPausedTokenDefersAndOtherLegsProceed() (gas: 1010189)\n[PASS] testReentrantDepositRedeemClaimAndRoleChangesFail() (gas: 1776795)\n[PASS] testUpgradeToNoCodeStillRedeemsAsDebt() (gas: 759465)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 70.17ms (114.77ms CPU time)\n\nRan 17 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDeferredClaimAndPartialLiquidity() (gas: 1561740)\n[PASS] testDeploymentAndFirstDeposit() (gas: 431590)\n[PASS] testDonationIgnoredUntilResyncAndShareMath() (gas: 1404594)\n[PASS] testERC20AllowancesAndNoBurnByTransfer() (gas: 546884)\n[PASS] testERC20TransferEventTopics() (gas: 407258)\n[PASS] testFeesRoundUpMintAndTransfer() (gas: 899576)\n[PASS] testFirstDepositMustExceedLockAndFees() (gas: 1119554)\n[PASS] testFuzzConservation(uint96,uint96,bool,bool) (runs: 256, μ: 1085320, ~: 1118921)\nLogs:\n  Bound result 99999000000000000000057\n  Bound result 655131632548\n\n[PASS] testFuzzDecimalValuation(uint8,uint8,uint32) (runs: 256, μ: 2177204, ~: 2183675)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 700\n\n[PASS] testInputValidationAndCap() (gas: 834433)\n[PASS] testLargerDeficitRestartsClockAndDepositClears() (gas: 1031603)\n[PASS] testNoAutomaticLossAndSevenDayRecognition() (gas: 1138532)\n[PASS] testRedeemDirectHasNoPriceDependency() (gas: 1128687)\n[PASS] testRemovalMovesFundedAssetIndexAndLossClearsBitmap() (gas: 1832438)\n[PASS] testResyncExcludesOwed() (gas: 1365564)\n[PASS] testRuntimeHasNoForbiddenOpcodes() (gas: 9907171)\n[PASS] testSlippageAndDeadlineAtomicity() (gas: 910683)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 70.20ms (138.52ms CPU time)\n\nRan 12 tests for test/Revision.t.sol:RevisionTest\n[PASS] testEmptyRetiredAssetStillSkipsDepositChecks() (gas: 995719)\n[PASS] testFuzzRedeemToVaultCannotBurnSharesOrCreateDebt(bool,bool) (runs: 256, μ: 892751, ~: 885615)\n[PASS] testFuzzRetiredBackingCheckUsesAccountingEvenWhenUnreadable(uint8,bool) (runs: 256, μ: 2074802, ~: 2020046)\nLogs:\n  Bound result 2\n\n[PASS] testGuardianExecutionRechecksPendingOwner() (gas: 411663)\n[PASS] testMultipleRemovalsCannotDropEarlierTrailingMinimum() (gas: 1589273)\n[PASS] testOnlyCompleteRecognizedLossClearsRetiredBacking() (gas: 2477994)\n[PASS] testPermanentSharesKeepResidualAndRetiredDepositRestriction() (gas: 1742218)\n[PASS] testRemovalCannotSilentlyDropTrailingMinimum() (gas: 1217844)\n[PASS] testRetiredBackingCannotBeAcquiredByNewDepositor() (gas: 1506624)\n[PASS] testRetiredDebtWithoutManagedDoesNotBlockDepositOrClaim() (gas: 2158335)\n[PASS] testUnrelatedGuardianReplacementPreservesOwnershipHandover() (gas: 520783)\n[PASS] testZeroNAVRequiresBackingEvenWhenOnlyPermanentSharesRemain() (gas: 1670942)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 80.71ms (133.17ms CPU time)\n\nRan 7 tests for test/Gas.t.sol:GasTest\n[PASS] testGas250AllBalancesBurnStipend() (gas: 424891477)\nLogs:\n  redemption gas (cold state, before refunds): 26604927\n\n[PASS] testGas250Paused() (gas: 413831744)\nLogs:\n  redemption gas (cold state, before refunds): 15447429\n\n[PASS] testGas254AtDefaultBalanceGasBound() (gas: 432014594)\nLogs:\n  redemption gas (cold state, before refunds): 27029340\n\n[PASS] testGas350AtMinimumBalanceGas() (gas: 584880791)\nLogs:\n  redemption gas (cold state, before refunds): 26717673\n\n[PASS] testGasMaximumBalanceBudgetWithFees() (gas: 169437124)\nLogs:\n  redemption gas (cold state, before refunds): 27924736\n\n[PASS] testGasMaximumDirectPaymentsBurnEntireBudget() (gas: 391902980)\nLogs:\n  redemption gas (cold state, before refunds): 27611179\n\n[PASS] testGasSparse350AssetsMaximumPayBudget() (gas: 602268445)\nLogs:\n  redemption gas (cold state, before refunds): 27978671\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 457.13ms (1.71s CPU time)\n\nRan 7 test suites in 458.26ms (828.98ms CPU time): 74 tests passed, 0 failed, 0 skipped (74 total tests)\n","passed":true},{"durationMs":35,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BaskVault.acceptOwnership()\",\"BaskVault.approve(address,uint256)\",\"BaskVault.cancelProposal(uint256)\",\"BaskVault.claim(address[],address)\",\"BaskVault.closeAsset(address)\",\"BaskVault.deposit(address[],uint256[],address,uint256,uint256)\",\"BaskVault.executeProposal(uint256)\",\"BaskVault.finalizeGenesis()\",\"BaskVault.flagDeficit(address)\",\"BaskVault.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose((uint8,address,address,address,address,uint256,uint8))\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeAsset(address)\",\"BaskVault.setDepositsPaused(bool)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":10,\"LICENSE\":339,\"README.md\":139,\"REVIEW.md\":53,\"foundry.toml\":15,\"launch.json\":13,\"src/BaskVault.sol\":999,\"src/libraries/Calls.sol\":31,\"src/libraries/FullMath.LICENSE\":21,\"src/libraries/FullMath.sol\":107,\"src/libraries/PoolOracle.sol\":69,\"src/libraries/TickMath.sol\":56,\"test/Accounting.t.sol\":293,\"test/Adversarial.t.sol\":213,\"test/Base.t.sol\":124,\"test/Gas.t.sol\":174,\"test/Governance.t.sol\":303,\"test/Oracle.t.sol\":212,\"test/Revision.t.sol\":274,\"test/mocks/Mocks.sol\":261},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"710a59f4bb4f5452a8e412a48a90105d3219f6eb3a3b4ef067bf29915bc11fe5","verifiedTreeHash":"2a2db426ed0aa73f42a357dfe20a8381680efb77","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":37043,"exitCode":0,"name":"build","output":"Compiling 37 files with Solc 0.8.26\nSolc 0.8.26 finished in 36.76s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:19:26\n   │\n19 │         if (!ok) return (false, 0, 0);\n   │                          ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:479:21\n    │\n479 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:481:17\n    │\n481 │         return (true, uint256(signedAnswer), updatedAt);\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:42:21\n   │\n42 │             return (false, 0, 0);\n   │                     ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:523:21\n    │\n523 │             return (false, 0, 0);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:51:40\n   │\n51 │         if (secondsDelta == 0) return (false, 0, 0);\n   │                                        ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:54:54\n   │\n54 │         if (mean < -887272 || mean > 887272) return (false, 0, 0);\n   │                                                      ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:56:51\n   │\n56 │         if (harmonic > type(uint128).max) return (false, 0, 0);\n   │                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:57:17\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                 ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[weak-prng]: weak randomness derived from a predictable on-chain value\n    ╭▸ src/BaskVault.sol:633:23\n    │\n633 │         uint256 day = (block.timestamp / 1 days + 3) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:86\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                      ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:105\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                                         ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:21\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                     ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:33\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                                 ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:28\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                            ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:42\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                                          ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:23\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                       ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:36\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:289:9\n    │\n289 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:400:13\n    │\n400 │             guardian = d.target;\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:279:65\n    │\n279 │     function transferOwnership(address next) external onlyOwner nonReentrant {\n    │                                                                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:294:63\n    │\n294 │     function setDepositsPaused(bool paused) external onlyRole nonReentrant {\n    │                                                               ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:300:58\n    │\n300 │     function closeAsset(address token) external onlyRole nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:307:58\n    │\n307 │     function lowerNAVCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:317:9\n    │\n317 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:323:51\n    │\n323 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:349:69\n    │\n349 │     function propose(ProposalData calldata data) external onlyOwner nonReentrant returns (uint256 id) {\n    │                                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:358:9\n    │\n358 │         emit Proposed(id, data, p.readyAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:361:59\n    │\n361 │     function cancelProposal(uint256 id) external onlyRole nonReentrant {\n    │                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:369:61\n    │\n369 │     function executeProposal(uint256 id) external onlyOwner nonReentrant {\n    │                                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:513:9\n    │\n513 │         emit AssetListed(token, feed, pool);\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:398:13\n    │\n398 │             emit Resynced(d.token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:408:9\n    │\n408 │         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:376:59\n    │\n376 │             _list(d.token, d.target, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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:392:55\n    │\n392 │             _setPool(a, d.token, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:451:50\n    │\n451 │             if (s[i] < 20_000 || s[i] > 500_000) revert InvalidSetting();\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:467:16\n    │\n467 │         return uint8(d);\n    │                ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:478:41\n    │\n478 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\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:478:72\n    │\n478 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\n    │                                                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:479:47\n    │\n479 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\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:481:23\n    │\n481 │         return (true, uint256(signedAnswer), updatedAt);\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:530:29\n    │\n530 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:530:62\n    │\n530 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                                                              ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:532:32\n    │\n532 │         baseIsToken0 = address(uint160(t0)) == token;\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:533:43\n    │\n533 │         quoteDecimals = _decimals(address(uint160(baseIsToken0 ? t1 : t0)));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:624:13\n    │\n624 │         if (block.timestamp - updatedAt > _settings[2]) return (Reason.NoPoolAge, answer, updatedAt, 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:606:64\n    │\n606 │             (ok, tick, liquidity) = PoolOracle.consult(a.pool, uint32(_settings[7]), _settings[11]);\n    │                                                                ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:635:16\n    │\n635 │         return day < 5 && time >= from && time < to;\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:635:27\n    │\n635 │         return day < 5 && time >= from && time < to;\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:635:43\n    │\n635 │         return day < 5 && time >= from && time < to;\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:686:86\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\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:686:47\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                                               ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:686:29\n    │\n686 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:702:34\n    │\n702 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:726:13\n    │\n726 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:755:17\n    │\n755 │                 emit DeficitCleared(token);\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:761:9\n    │\n761 │         emit Deposit(msg.sender, receiver, value, 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:735:22\n    │\n735 │             if (!ok) revert BalanceUnreadable(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:742:17\n    │\n742 │                 revert PaymentFailed();\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:747:17\n    │\n747 │                 revert PaymentFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:776:9\n    │\n776 │         emit Payment(token, receiver, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:813:23\n    │\n813 │                     ++count;\n    │                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:790:13\n    │\n790 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:840:9\n    │\n840 │         emit Redeem(msg.sender, receiver, shares, net, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:804:40\n    │\n804 │             if (minAmountsOut[i] != 0) revert Slippage();\n    │                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:821:72\n    │\n821 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:830:69\n    │\n830 │             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:855:13\n    │\n855 │             this.pay(token, to, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:855:13\n    │\n855 │             this.pay(token, to, amount);\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:856:13\n    │\n856 │             emit Claimed(msg.sender, to, token, amount);\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:850:22\n    │\n850 │             if (!ok) revert BalanceUnreadable(token);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:868:9\n    │\n868 │         emit DeficitFlagged(token, shortfall, block.timestamp);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:874:30\n    │\n874 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert NotReady();\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:882:9\n    │\n882 │         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:968:13\n    │\n968 │         if (block.timestamp > p.readyAt + 7 days) return ProposalState.Expired;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:969:16\n    │\n969 │         return block.timestamp < p.readyAt ? ProposalState.Waiting : ProposalState.Ready;\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:989:21\n    │\n989 │                 ids[n] = id;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":4669,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testConstructorsAndGenesis() (gas: 4250)\n[PASS] testFeedAndRecentreUseExecutionAnswer() (gas: 965219)\n[PASS] testLaterCloseVoidsReopen() (gas: 819191)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 2481524)\n[PASS] testLowerCapVoidsRaisesAndBounds() (gas: 750691)\n[PASS] testOwnerAndGuardianPowers() (gas: 1096275)\n[PASS] testRemoveAndRelistDoesNotReviveOldProposals() (gas: 1632083)\n[PASS] testRetirementVoidsProposalsAndStopsDepositsButRedeems() (gas: 2336577)\n[PASS] testSettingGasBoundsAndRevalidation() (gas: 1907623)\n[PASS] testTimelockBoundariesAndPendingViews() (gas: 730296)\n[PASS] testTwoStepOwnerNeverGuardianEvenAfterProposal() (gas: 270792)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 5.12ms (3.77ms CPU time)\n\nRan 2 tests for test/RegistryExit.t.sol:RegistryExitTest\n[PASS] test_MaxAssetsWithMissingTokenCodeStillRedeemUnder28MillionAndCanClaimAfterRecovery() (gas: 417748235)\nLogs:\n  250 upgraded assets: cold redemption gas including calldata: 14105287\n\n[PASS] test_RemovalAcrossBitmapWordsLossAndResyncPreserveRedeemLegs() (gas: 377871243)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 195.36ms (377.49ms CPU time)\n\nRan 17 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDeferredClaimAndPartialLiquidity() (gas: 1561740)\n[PASS] testDeploymentAndFirstDeposit() (gas: 431590)\n[PASS] testDonationIgnoredUntilResyncAndShareMath() (gas: 1404594)\n[PASS] testERC20AllowancesAndNoBurnByTransfer() (gas: 546884)\n[PASS] testERC20TransferEventTopics() (gas: 407258)\n[PASS] testFeesRoundUpMintAndTransfer() (gas: 899576)\n[PASS] testFirstDepositMustExceedLockAndFees() (gas: 1119554)\n[PASS] testFuzzConservation(uint96,uint96,bool,bool) (runs: 256, μ: 1053221, ~: 1118884)\nLogs:\n  Bound result 99999001874973779733501\n  Bound result 13697744383469273580147\n\n[PASS] testFuzzDecimalValuation(uint8,uint8,uint32) (runs: 256, μ: 2176112, ~: 2183401)\nLogs:\n  Bound result 0\n  Bound result 7\n  Bound result 672\n\n[PASS] testInputValidationAndCap() (gas: 834433)\n[PASS] testLargerDeficitRestartsClockAndDepositClears() (gas: 1031603)\n[PASS] testNoAutomaticLossAndSevenDayRecognition() (gas: 1138532)\n[PASS] testRedeemDirectHasNoPriceDependency() (gas: 1128687)\n[PASS] testRemovalMovesFundedAssetIndexAndLossClearsBitmap() (gas: 1832438)\n[PASS] testResyncExcludesOwed() (gas: 1365564)\n[PASS] testRuntimeHasNoForbiddenOpcodes() (gas: 9907171)\n[PASS] testSlippageAndDeadlineAtomicity() (gas: 910683)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 236.52ms (385.32ms CPU time)\n\nRan 13 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] testAllLossDoesNotBlockRedeemAndPreventsDepositAtZeroNAV() (gas: 915718)\n[PASS] testBalanceReturnBombCopiesOnlyWord() (gas: 493398)\n[PASS] testClaimCannotBeBlockedByBalanceGasSetting() (gas: 1799623)\n[PASS] testClaimHasNoPayGasLimitAndPausesDoNotApply() (gas: 1403243)\n[PASS] testDepositInputCannotConsumeUnderfundedOwed() (gas: 1293730)\n[PASS] testDepositSettingsAndGovernanceCannotVetoExit() (gas: 5980770)\n[PASS] testFeeOnTransferAndFalseDepositAreAtomic() (gas: 1023429)\n[PASS] testFuzzBrokenTransferNeverBlocksOtherLegs(uint8) (runs: 256, μ: 1010482, ~: 1007122)\nLogs:\n  Bound result 11\n\n[PASS] testFuzzUnreadableBalanceUsesManaged(uint8) (runs: 256, μ: 854078, ~: 736096)\nLogs:\n  Bound result 3\n\n[PASS] testMinOutputForZeroLegRevertsOnlyByUserChoice() (gas: 519272)\n[PASS] testPausedTokenDefersAndOtherLegsProceed() (gas: 1010189)\n[PASS] testReentrantDepositRedeemClaimAndRoleChangesFail() (gas: 1776795)\n[PASS] testUpgradeToNoCodeStillRedeemsAsDebt() (gas: 759465)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 241.65ms (288.55ms CPU time)\n\nRan 12 tests for test/Revision.t.sol:RevisionTest\n[PASS] testEmptyRetiredAssetStillSkipsDepositChecks() (gas: 995719)\n[PASS] testFuzzRedeemToVaultCannotBurnSharesOrCreateDebt(bool,bool) (runs: 256, μ: 917249, ~: 931716)\n[PASS] testFuzzRetiredBackingCheckUsesAccountingEvenWhenUnreadable(uint8,bool) (runs: 256, μ: 2045603, ~: 2020046)\nLogs:\n  Bound result 0\n\n[PASS] testGuardianExecutionRechecksPendingOwner() (gas: 411663)\n[PASS] testMultipleRemovalsCannotDropEarlierTrailingMinimum() (gas: 1589273)\n[PASS] testOnlyCompleteRecognizedLossClearsRetiredBacking() (gas: 2477994)\n[PASS] testPermanentSharesKeepResidualAndRetiredDepositRestriction() (gas: 1742218)\n[PASS] testRemovalCannotSilentlyDropTrailingMinimum() (gas: 1217844)\n[PASS] testRetiredBackingCannotBeAcquiredByNewDepositor() (gas: 1506624)\n[PASS] testRetiredDebtWithoutManagedDoesNotBlockDepositOrClaim() (gas: 2158335)\n[PASS] testUnrelatedGuardianReplacementPreservesOwnershipHandover() (gas: 520783)\n[PASS] testZeroNAVRequiresBackingEvenWhenOnlyPermanentSharesRemain() (gas: 1670942)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 241.68ms (349.75ms CPU time)\n\nRan 6 tests for test/Settings.t.sol:SettingsTest\n[PASS] testFuzz_AnyAllowedSettingPreservesRedemptionAndClaim(uint8,uint256) (runs: 1000, μ: 1731121, ~: 1731631)\nLogs:\n  Bound result 3\n  Bound result 7\n\n[PASS] test_EverySettingAcceptsBothEndpointsAndPreservesExit() (gas: 55270862)\n[PASS] test_EverySettingRejectsOutsideBoundsAndMaxUintAtomically() (gas: 8096203)\n[PASS] test_PendingAssetLimitRechecksNewListing() (gas: 2500198)\n[PASS] test_PendingDirectLimitRechecksRaisedPaymentBudget() (gas: 2554155)\n[PASS] test_PendingHoursRecheckOtherEndpoint() (gas: 1944316)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 241.69ms (271.10ms CPU time)\n\nRan 3 tests for test/Oracle.t.sol:OracleMathTest\n[PASS] testFullPrecisionMultiplicationAvoidsIntermediateOverflow() (gas: 3968)\n[PASS] testFuzzQuoteReciprocal(int24) (runs: 256, μ: 13407, ~: 13415)\nLogs:\n  Bound result 7683\n\n[PASS] testNegativeTickRoundsDownAndWrapsAccumulators() (gas: 127764)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 273.35ms (240.68ms CPU time)\n\nRan 11 tests for test/Oracle.t.sol:OracleTest\n[PASS] testAllAssetsViewContainsBalancesAndFaults() (gas: 610014)\n[PASS] testBadAnswerFutureAndMalformedRead() (gas: 679199)\n[PASS] testBandBoundariesWithoutPool() (gas: 895149)\n[PASS] testEveryManagedAssetValidatedAndUnmanagedStaleAllowed() (gas: 996920)\n[PASS] testFreshnessCountAndBoundary() (gas: 1151064)\n[PASS] testHoursWeekdaysAndExactEdges() (gas: 2332972)\n[PASS] testMixedQuoteDecimalsAndReversePoolDirection() (gas: 3369459)\n[PASS] testPauseDetectionAndUnreadablePause() (gas: 2353802)\n[PASS] testPoolDeviationAndQuoteFeedCannotFallBack() (gas: 808912)\n[PASS] testPoolLiquidityAndMalformedObserveFallBack() (gas: 1248227)\n[PASS] testValidPoolCanUseOlderFeedButFallbackCannot() (gas: 886946)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 281.94ms (7.14ms CPU time)\n\nRan 12 tests for test/BasketEdges.t.sol:BasketEdgesTest\n[PASS] testFuzz_DonationCannotChangeDepositPriceBeforeResync(uint128,uint96) (runs: 1000, μ: 919201, ~: 919161)\nLogs:\n  Bound result 1648\n\n[PASS] testFuzz_LossRecognitionCannotExceedRecordedOrCurrentDeficit(uint96,uint96) (runs: 1000, μ: 669029, ~: 669230)\nLogs:\n  Bound result 8524\n  Bound result 6488\n\n[PASS] testFuzz_RepeatedRoundTripsCannotCreateStockTokens(uint96,uint8,bool) (runs: 1000, μ: 2871016, ~: 2488464)\nLogs:\n  Bound result 201\n  Bound result 11\n\n[PASS] test_AllProposalKindsRejectNonOwnersAndPayRejectsRoles() (gas: 1006576)\n[PASS] test_ClaimBatchFailureRollsBackEarlierPaymentAndDuplicateIsIdempotent() (gas: 1748200)\n[PASS] test_FeeRecipientCanDepositAndRedeemWithoutLosingSelfTransferredFee() (gas: 949294)\n[PASS] test_LateDepositFailureRollsBackEarlierTransfersAndAllowances() (gas: 606741)\n[PASS] test_LateRedeemSlippageRollsBackPaymentDebtFeeAndBurn() (gas: 1453849)\n[PASS] test_ListingAndFeedProposalsRevalidateFeedUniqueness() (gas: 2955468)\n[PASS] test_ReentrantRedeemRejectsAnOtherwiseAuthorizedShareholder() (gas: 1420568)\n[PASS] test_ResyncUsesExecutionBalanceAndNeverCountsOwedOrWritesOffLoss() (gas: 1645718)\n[PASS] test_RetireRequiresClosedAgainAtExecutionAndCannotExecuteTwice() (gas: 772976)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 282.00ms (826.08ms CPU time)\n\nRan 7 tests for test/Gas.t.sol:GasTest\n[PASS] testGas250AllBalancesBurnStipend() (gas: 424891477)\nLogs:\n  redemption gas (cold state, before refunds): 26604927\n\n[PASS] testGas250Paused() (gas: 413831744)\nLogs:\n  redemption gas (cold state, before refunds): 15447429\n\n[PASS] testGas254AtDefaultBalanceGasBound() (gas: 432014594)\nLogs:\n  redemption gas (cold state, before refunds): 27029340\n\n[PASS] testGas350AtMinimumBalanceGas() (gas: 584880791)\nLogs:\n  redemption gas (cold state, before refunds): 26717673\n\n[PASS] testGasMaximumBalanceBudgetWithFees() (gas: 169437124)\nLogs:\n  redemption gas (cold state, before refunds): 27924736\n\n[PASS] testGasMaximumDirectPaymentsBurnEntireBudget() (gas: 391902980)\nLogs:\n  redemption gas (cold state, before refunds): 27611179\n\n[PASS] testGasSparse350AssetsMaximumPayBudget() (gas: 602268445)\nLogs:\n  redemption gas (cold state, before refunds): 27978671\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 445.34ms (1.68s CPU time)\n\nRan 2 tests for test/BasketInvariant.t.sol:BasketInvariantTest\n[PASS]\nBasketInvariantTest invariants:\n[PASS] invariant_CustodyAndLiabilitiesMatchIndependentFlows\n[PASS] invariant_ShareSupplyAndPermanentLock\n BasketInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭---------------+----------------+-------+---------+----------╮\n| Contract      | Selector       | Calls | Reverts | Discards |\n+=============================================================+\n| BasketHandler | advanceTime    | 1245  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | claim          | 1255  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | configure      | 1255  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | confiscate     | 1235  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | deposit        | 1290  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | donate         | 1328  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | flag           | 1270  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | pause          | 1262  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | recognize      | 1252  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | redeem         | 1241  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | resync         | 1302  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | tokenState     | 1178  | 0       | 0        |\n|---------------+----------------+-------+---------+----------|\n| BasketHandler | transferShares | 1271  | 0       | 0        |\n╰---------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 19400\n  Bound result 18000\n  Bound result 88996474970776679452\n  Bound result 214989\n  Bound result 1118\n  Bound result 999990000000000013898\n  Bound result 13\n  Bound result 19806\n  Bound result 95\n  Bound result 14640\n  Bound result 16\n  Bound result 0\n  Bound result 14400\n  Bound result 6\n  Bound result 2294\n  Bound result 38896824982602708103\n  Bound result 6070\n  Bound result 1181\n  Bound result 611627\n  Bound result 51920982716015181260\n  Bound result 999990000000000009051\n  Bound result 931\n  Bound result 999990000000000017454\n  Bound result 131072\n  Bound result 10005542815075473570\n  Bound result 6176\n  Bound result 1797\n  Bound result 999990000000000011090\n  Bound result 1024\n  Bound result 999990000000000024001\n  Bound result 3339534970132749318\n  Bound result 8367\n  Bound result 16\n  Bound result 7879\n  Bound result 978000764993183288618\n\n[PASS] test_HandlerReachesDebtRecoveryAndLossRecognition() (gas: 2391134)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 0\n  Bound result 20000000000000000000\n  Bound result 10000000000000000000\n  Bound result 604800\n  Bound result 10000000000000000000\n  Bound result 0\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 4.60s (4.59s CPU time)\n\nRan 11 test suites in 4.60s (7.04s CPU time): 96 tests passed, 0 failed, 0 skipped (96 total tests)\n","passed":true},{"durationMs":34,"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.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose((uint8,address,address,address,address,uint256,uint8))\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeAsset(address)\",\"BaskVault.setDepositsPaused(bool)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":10,\"LICENSE\":339,\"README.md\":139,\"REVIEW.md\":53,\"foundry.toml\":15,\"launch.json\":13,\"src/BaskVault.sol\":999,\"src/libraries/Calls.sol\":31,\"src/libraries/FullMath.LICENSE\":21,\"src/libraries/FullMath.sol\":107,\"src/libraries/PoolOracle.sol\":69,\"src/libraries/TickMath.sol\":56,\"test/Accounting.t.sol\":293,\"test/Adversarial.t.sol\":213,\"test/Base.t.sol\":124,\"test/BasketEdges.t.sol\":276,\"test/BasketInvariant.t.sol\":100,\"test/Gas.t.sol\":174,\"test/Governance.t.sol\":303,\"test/Oracle.t.sol\":212,\"test/README.md\":22,\"test/RegistryExit.t.sol\":175,\"test/Revision.t.sol\":274,\"test/Settings.t.sol\":156,\"test/handlers/BasketHandler.sol\":352,\"test/mocks/Mocks.sol\":261,\"test/mocks/ReentryProbe.sol\":25},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c450affee3e7c51c49ad60b0f9f888cc37f18bc4537f2a7413f08281f8174194","verifiedTreeHash":"7ee3758a894af6595abc71d119c3424ab35bf1fb","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":23685,"exitCode":0,"name":"build","output":"Compiling 30 files with Solc 0.8.26\nSolc 0.8.26 finished in 23.40s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:478:21\n    │\n478 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:38\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:19:26\n   │\n19 │         if (!ok) return (false, 0, 0);\n   │                          ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:42:21\n   │\n42 │             return (false, 0, 0);\n   │                     ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:480:17\n    │\n480 │         return (true, uint256(signedAnswer), updatedAt);\n    │                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:25:63\n   │\n25 │         uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/BaskVault.sol:522:21\n    │\n522 │             return (false, 0, 0);\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:26:23\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:51:40\n   │\n51 │         if (secondsDelta == 0) return (false, 0, 0);\n   │                                        ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:54:54\n   │\n54 │         if (mean < -887272 || mean > 887272) return (false, 0, 0);\n   │                                                      ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:54:24\n   │\n54 │         sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:56:51\n   │\n56 │         if (harmonic > type(uint128).max) return (false, 0, 0);\n   │                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/libraries/PoolOracle.sol:57:17\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\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:632:23\n    │\n632 │         uint256 day = (block.timestamp / 1 days + 3) % 7;\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/weak-prng\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:86\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                      ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:39:105\n   │\n39 │             offset0 != 64 || offset1 != 160 || length0 != 2 || length1 != 2 || t0 != int56(t0) || t1 != int56(t1)\n   │                                                                                                         ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:21\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                     ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:48:33\n   │\n48 │             delta = int56(t1) - int56(t0);\n   │                                 ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:28\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                            ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:49:42\n   │\n49 │             secondsDelta = uint160(l1) - uint160(l0);\n   │                                          ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:23\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                       ━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/PoolOracle.sol:57:36\n   │\n57 │         return (true, int24(mean), uint128(harmonic));\n   │                                    ━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `owner` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:288:9\n    │\n288 │         owner = msg.sender;\n    │         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `guardian` is changed without an event but is used for access control\n    ╭▸ src/BaskVault.sol:399:13\n    │\n399 │             guardian = d.target;\n    │             ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:278:65\n    │\n278 │     function transferOwnership(address next) external onlyOwner nonReentrant {\n    │                                                                 ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:293:63\n    │\n293 │     function setDepositsPaused(bool paused) external onlyRole nonReentrant {\n    │                                                               ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:299:58\n    │\n299 │     function closeAsset(address token) external onlyRole nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:306:58\n    │\n306 │     function lowerNAVCap(uint256 cap) external onlyOwner nonReentrant {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:316:9\n    │\n316 │         nonReentrant\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:322:51\n    │\n322 │     function finalizeGenesis() external onlyOwner nonReentrant {\n    │                                                   ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:348:69\n    │\n348 │     function propose(ProposalData calldata data) external onlyOwner nonReentrant returns (uint256 id) {\n    │                                                                     ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:357:9\n    │\n357 │         emit Proposed(id, data, p.readyAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:360:59\n    │\n360 │     function cancelProposal(uint256 id) external onlyRole nonReentrant {\n    │                                                           ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/BaskVault.sol:368:61\n    │\n368 │     function executeProposal(uint256 id) external onlyOwner nonReentrant {\n    │                                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:512:9\n    │\n512 │         emit AssetListed(token, feed, pool);\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:397:13\n    │\n397 │             emit Resynced(d.token, extra);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:407:9\n    │\n407 │         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:375:59\n    │\n375 │             _list(d.token, d.target, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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:391:55\n    │\n391 │             _setPool(a, d.token, d.pool, d.quoteFeed, uint128(d.value));\n    │                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:450:50\n    │\n450 │             if (s[i] < 20_000 || s[i] > 500_000) revert InvalidSetting();\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:466:16\n    │\n466 │         return uint8(d);\n    │                ━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:477:41\n    │\n477 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\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:477:72\n    │\n477 │         if (!ok || signedAnswer <= 0 || updatedAt > block.timestamp || block.timestamp - updatedAt > _settings[1]) {\n    │                                                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:478:47\n    │\n478 │             return (false, signedAnswer > 0 ? uint256(signedAnswer) : 0, updatedAt);\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:480:23\n    │\n480 │         return (true, uint256(signedAnswer), updatedAt);\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:529:29\n    │\n529 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:529:62\n    │\n529 │                 || (address(uint160(t0)) != token && address(uint160(t1)) != token)\n    │                                                              ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:531:32\n    │\n531 │         baseIsToken0 = address(uint160(t0)) == token;\n    │                                ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:532:43\n    │\n532 │         quoteDecimals = _decimals(address(uint160(baseIsToken0 ? t1 : t0)));\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:623:13\n    │\n623 │         if (block.timestamp - updatedAt > _settings[2]) return (Reason.NoPoolAge, answer, updatedAt, 0);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/BaskVault.sol:605:64\n    │\n605 │             (ok, tick, liquidity) = PoolOracle.consult(a.pool, uint32(_settings[7]), _settings[11]);\n    │                                                                ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:634:16\n    │\n634 │         return day < 5 && time >= from && time < to;\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:634:27\n    │\n634 │         return day < 5 && time >= from && time < to;\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:634:43\n    │\n634 │         return day < 5 && time >= from && time < to;\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:681:47\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\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:681:86\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                                                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:681:29\n    │\n681 │             if (readable && block.timestamp - updatedAt <= _settings[4] * 1 hours) ++fresh;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/TickMath.sol:26:50\n   │\n26 │         if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n   │                                                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:33:39\n   │\n33 │                 if (denominator == 0) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/FullMath.sol:42:39\n   │\n42 │             if (denominator <= prod1) revert MathOverflow();\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:697:34\n    │\n697 │             if (amounts[i] == 0) revert InvalidInput();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:721:13\n    │\n721 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:750:17\n    │\n750 │                 emit DeficitCleared(token);\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:756:9\n    │\n756 │         emit Deposit(msg.sender, receiver, value, 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:730:22\n    │\n730 │             if (!ok) revert BalanceUnreadable(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:737:17\n    │\n737 │                 revert PaymentFailed();\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:742:17\n    │\n742 │                 revert PaymentFailed();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:771:9\n    │\n771 │         emit Payment(token, receiver, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/BaskVault.sol:804:23\n    │\n804 │                     ++count;\n    │                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:785:13\n    │\n785 │         if (block.timestamp > deadline) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:831:9\n    │\n831 │         emit Redeem(msg.sender, receiver, shares, net, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:812:72\n    │\n812 │                 if (i < minAmountsOut.length && minAmountsOut[i] != 0) revert Slippage();\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BaskVault.sol:821:69\n    │\n821 │             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:846:13\n    │\n846 │             this.pay(token, to, amount);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/BaskVault.sol:846:13\n    │\n846 │             this.pay(token, to, amount);\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:847:13\n    │\n847 │             emit Claimed(msg.sender, to, token, amount);\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:841:22\n    │\n841 │             if (!ok) revert BalanceUnreadable(token);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BaskVault.sol:859:9\n    │\n859 │         emit DeficitFlagged(token, shortfall, block.timestamp);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:865:30\n    │\n865 │         if (d.amount == 0 || block.timestamp < d.since + 7 days) revert NotReady();\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:873:9\n    │\n873 │         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:959:13\n    │\n959 │         if (block.timestamp > p.readyAt + 7 days) return ProposalState.Expired;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BaskVault.sol:960:16\n    │\n960 │         return block.timestamp < p.readyAt ? ProposalState.Waiting : ProposalState.Ready;\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:980:21\n    │\n980 │                 ids[n] = id;\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":589,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/Oracle.t.sol:OracleMathTest\n[PASS] testFullPrecisionMultiplicationAvoidsIntermediateOverflow() (gas: 3968)\n[PASS] testFuzzQuoteReciprocal(int24) (runs: 256, μ: 13348, ~: 13291)\nLogs:\n  Bound result -90477\n\n[PASS] testNegativeTickRoundsDownAndWrapsAccumulators() (gas: 127764)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 45.68ms (5.74ms CPU time)\n\nRan 11 tests for test/Governance.t.sol:GovernanceTest\n[PASS] testConstructorsAndGenesis() (gas: 4236)\n[PASS] testFeedAndRecentreUseExecutionAnswer() (gas: 965389)\n[PASS] testLaterCloseVoidsReopen() (gas: 819355)\n[PASS] testListingChecksAtProposalAndExecution() (gas: 2481699)\n[PASS] testLowerCapVoidsRaisesAndBounds() (gas: 750926)\n[PASS] testOwnerAndGuardianPowers() (gas: 1090053)\n[PASS] testRemoveAndRelistDoesNotReviveOldProposals() (gas: 1632332)\n[PASS] testRetirementVoidsProposalsAndSkipsChecksButRedeems() (gas: 2681801)\n[PASS] testSettingGasBoundsAndRevalidation() (gas: 1910237)\n[PASS] testTimelockBoundariesAndPendingViews() (gas: 730472)\n[PASS] testTwoStepOwnerNeverGuardianEvenAfterProposal() (gas: 1020619)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 55.36ms (9.30ms CPU time)\n\nRan 13 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] testAllLossDoesNotBlockRedeemAndPreventsDepositAtZeroNAV() (gas: 915726)\n[PASS] testBalanceReturnBombCopiesOnlyWord() (gas: 493358)\n[PASS] testClaimCannotBeBlockedByBalanceGasSetting() (gas: 1800354)\n[PASS] testClaimHasNoPayGasLimitAndPausesDoNotApply() (gas: 1403589)\n[PASS] testDepositInputCannotConsumeUnderfundedOwed() (gas: 1294089)\n[PASS] testDepositSettingsAndGovernanceCannotVetoExit() (gas: 5984313)\n[PASS] testFeeOnTransferAndFalseDepositAreAtomic() (gas: 1023485)\n[PASS] testFuzzBrokenTransferNeverBlocksOtherLegs(uint8) (runs: 256, μ: 1010618, ~: 1007130)\nLogs:\n  Bound result 1\n\n[PASS] testFuzzUnreadableBalanceUsesManaged(uint8) (runs: 256, μ: 843577, ~: 736079)\nLogs:\n  Bound result 1\n\n[PASS] testMinOutputForZeroLegRevertsOnlyByUserChoice() (gas: 519144)\n[PASS] testPausedTokenDefersAndOtherLegsProceed() (gas: 1010197)\n[PASS] testReentrantDepositRedeemClaimAndRoleChangesFail() (gas: 1776811)\n[PASS] testUpgradeToNoCodeStillRedeemsAsDebt() (gas: 759473)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 60.47ms (112.28ms CPU time)\n\nRan 11 tests for test/Oracle.t.sol:OracleTest\n[PASS] testAllAssetsViewContainsBalancesAndFaults() (gas: 610071)\n[PASS] testBadAnswerFutureAndMalformedRead() (gas: 679433)\n[PASS] testBandBoundariesWithoutPool() (gas: 895418)\n[PASS] testEveryManagedAssetValidatedAndUnmanagedStaleAllowed() (gas: 997103)\n[PASS] testFreshnessCountAndBoundary() (gas: 1151597)\n[PASS] testHoursWeekdaysAndExactEdges() (gas: 2333942)\n[PASS] testMixedQuoteDecimalsAndReversePoolDirection() (gas: 3369704)\n[PASS] testPauseDetectionAndUnreadablePause() (gas: 2354067)\n[PASS] testPoolDeviationAndQuoteFeedCannotFallBack() (gas: 809080)\n[PASS] testPoolLiquidityAndMalformedObserveFallBack() (gas: 1248491)\n[PASS] testValidPoolCanUseOlderFeedButFallbackCannot() (gas: 887198)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 60.53ms (10.80ms CPU time)\n\nRan 17 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDeferredClaimAndPartialLiquidity() (gas: 1562146)\n[PASS] testDeploymentAndFirstDeposit() (gas: 431638)\n[PASS] testDonationIgnoredUntilResyncAndShareMath() (gas: 1404889)\n[PASS] testERC20AllowancesAndNoBurnByTransfer() (gas: 546932)\n[PASS] testERC20TransferEventTopics() (gas: 407306)\n[PASS] testFeesRoundUpMintAndTransfer() (gas: 899639)\n[PASS] testFirstDepositMustExceedLockAndFees() (gas: 1119801)\n[PASS] testFuzzConservation(uint96,uint96,bool,bool) (runs: 256, μ: 1064237, ~: 1118792)\nLogs:\n  Bound result 99999000000000000019526\n  Bound result 5338\n\n[PASS] testFuzzDecimalValuation(uint8,uint8,uint32) (runs: 256, μ: 2177296, ~: 2183828)\nLogs:\n  Bound result 9\n  Bound result 0\n  Bound result 3\n\n[PASS] testInputValidationAndCap() (gas: 834650)\n[PASS] testLargerDeficitRestartsClockAndDepositClears() (gas: 1031699)\n[PASS] testNoAutomaticLossAndSevenDayRecognition() (gas: 1138561)\n[PASS] testRedeemDirectHasNoPriceDependency() (gas: 1128695)\n[PASS] testRemovalMovesFundedAssetIndexAndLossClearsBitmap() (gas: 1832428)\n[PASS] testResyncExcludesOwed() (gas: 1366025)\n[PASS] testRuntimeHasNoForbiddenOpcodes() (gas: 9831776)\n[PASS] testSlippageAndDeadlineAtomicity() (gas: 910739)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 60.57ms (156.09ms CPU time)\n\nRan 7 tests for test/Gas.t.sol:GasTest\n[PASS] testGas250AllBalancesBurnStipend() (gas: 424897413)\nLogs:\n  redemption gas (cold state, before refunds): 26604839\n\n[PASS] testGas250Paused() (gas: 413837680)\nLogs:\n  redemption gas (cold state, before refunds): 15447341\n\n[PASS] testGas254AtDefaultBalanceGasBound() (gas: 432020976)\nLogs:\n  redemption gas (cold state, before refunds): 27029252\n\n[PASS] testGas350AtMinimumBalanceGas() (gas: 584889827)\nLogs:\n  redemption gas (cold state, before refunds): 26717585\n\n[PASS] testGasMaximumBalanceBudgetWithFees() (gas: 169442690)\nLogs:\n  redemption gas (cold state, before refunds): 27924648\n\n[PASS] testGasMaximumDirectPaymentsBurnEntireBudget() (gas: 391905114)\nLogs:\n  redemption gas (cold state, before refunds): 27611091\n\n[PASS] testGasSparse350AssetsMaximumPayBudget() (gas: 602274519)\nLogs:\n  redemption gas (cold state, before refunds): 27978583\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 516.07ms (1.77s CPU time)\n\nRan 6 test suites in 517.01ms (798.69ms CPU time): 62 tests passed, 0 failed, 0 skipped (62 total tests)\n","passed":true},{"durationMs":41,"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.genesisList(address,address,address,address,uint128)\",\"BaskVault.lowerNAVCap(uint256)\",\"BaskVault.pay(address,address,uint256)\",\"BaskVault.propose((uint8,address,address,address,address,uint256,uint8))\",\"BaskVault.recognizeLoss(address)\",\"BaskVault.redeem(uint256,address,uint256[],uint256)\",\"BaskVault.removeAsset(address)\",\"BaskVault.setDepositsPaused(bool)\",\"BaskVault.transfer(address,uint256)\",\"BaskVault.transferFrom(address,address,uint256)\",\"BaskVault.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":10,\"LICENSE\":339,\"README.md\":135,\"REVIEW.md\":50,\"foundry.toml\":15,\"launch.json\":13,\"src/BaskVault.sol\":990,\"src/libraries/Calls.sol\":31,\"src/libraries/FullMath.LICENSE\":21,\"src/libraries/FullMath.sol\":107,\"src/libraries/PoolOracle.sol\":69,\"src/libraries/TickMath.sol\":56,\"test/Accounting.t.sol\":293,\"test/Adversarial.t.sol\":213,\"test/Base.t.sol\":124,\"test/Gas.t.sol\":174,\"test/Governance.t.sol\":301,\"test/Oracle.t.sol\":212,\"test/mocks/Mocks.sol\":261},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4184,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/BaskVault.sol:627: BaskVault._insideHours() (src/BaskVault.sol#627-635) uses a weak PRNG: \"time = block.timestamp % 86400 (src/BaskVault.sol#633)\"\n[high/medium] weak-prng at src/BaskVault.sol:274: BaskVault._fee(uint256) (src/BaskVault.sol#274-276) uses a weak PRNG: \"amount % 200 == 0 (src/BaskVault.sol#275)\"\n[high/medium] weak-prng at src/BaskVault.sol:584: BaskVault._price(address) (src/BaskVault.sol#584-625) uses a weak PRNG: \"answer % band == 0 (src/BaskVault.sol#594)\"\n[high/medium] weak-prng at src/BaskVault.sol:627: BaskVault._insideHours() (src/BaskVault.sol#627-635) uses a weak PRNG: \"day = (block.timestamp / 86400 + 3) % 7 (src/BaskVault.sol#632)\"\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:687: BaskVault._depositQuote(address[],uint256[]) (src/BaskVault.sol#687-712) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:360: BaskVault.cancelProposal(uint256) (src/BaskVault.sol#360-366) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:459: BaskVault._requireAsset(address) (src/BaskVault.sol#459-461) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:834: BaskVault.claim(address[],address) (src/BaskVault.sol#834-849) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:780: BaskVault.redeem(uint256,address,uint256[],uint256) (src/BaskVault.sol#780-832) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:780: BaskVault.redeem(uint256,address,uint256[],uint256) (src/BaskVault.sol#780-832) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:549: BaskVault._writeManaged(address,uint256) (src/BaskVault.sol#549-552) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:515: BaskVault._poolConfig(address,address,address,uint256) (src/BaskVault.sol#515-534) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:584: BaskVault._price(address) (src/BaskVault.sol#584-625) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:627: BaskVault._insideHours() (src/BaskVault.sol#627-635) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:851: BaskVault.flagDeficit(address) (src/BaskVault.sol#851-860) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:274: BaskVault._fee(uint256) (src/BaskVault.sol#274-276) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/BaskVault.sol:687: BaskVault._depositQuote(address[],uint256[]) (src/BaskVault.sol#687-712) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/BaskVault.sol:834: Reentrancy in BaskVault.claim(address[],address) (src/BaskVault.sol#834-849):\n[medium/medium] uninitialized-local at src/BaskVault.sol:795: BaskVault.redeem(uint256,address,uint256[],uint256).count (src/BaskVault.sol#795) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:656: BaskVault._depositContext(address[]).fresh (src/BaskVault.sol#656) is a local variable never initialized\n[medium/medium] uninitialized-local at src/BaskVault.sol:669: BaskVault._depositContext(address[]).updatedAt (src/BaskVault.sol#669) is a local variable never initialized\n[low/medium] calls-loop at src/BaskVault.sol:834: BaskVault.claim(address[],address) (src/BaskVault.sol#834-849) has external calls inside a loop: this.pay(token,to,amount) (src/BaskVault.sol#846)\n[low/medium] timestamp at src/BaskVault.sol:637: BaskVault._depositContext(address[]) (src/BaskVault.sol#637-685) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:441: BaskVault._validateSetting(BaskVault.Setting,uint256) (src/BaskVault.sol#441-457) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:549: BaskVault._writeManaged(address,uint256) (src/BaskVault.sol#549-552) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:780: BaskVault.redeem(uint256,address,uint256[],uint256) (src/BaskVault.sol#780-832) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:459: BaskVault._requireAsset(address) (src/BaskVault.sol#459-461) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:278: BaskVault.transferOwnership(address) (src/BaskVault.sol#278-282) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:714: BaskVault.deposit(address[],uint256[],address,uint256,uint256) (src/BaskVault.sol#714-757) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:687: BaskVault._depositQuote(address[],uint256[]) (src/BaskVault.sol#687-712) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:834: BaskVault.claim(address[],address) (src/BaskVault.sol#834-849) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:244: BaskVault._transfer(address,address,uint256) (src/BaskVault.sol#244-250) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:862: BaskVault.recognizeLoss(address) (src/BaskVault.sol#862-874) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:328: BaskVault.removeAsset(address) (src/BaskVault.sol#328-346) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:497: BaskVault._list(address,address,address,address,uint128) (src/BaskVault.sol#497-513) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:927: BaskVault.previewRedeem(uint256) (src/BaskVault.sol#927-941) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:489: BaskVault._validateListing(address,address) (src/BaskVault.sol#489-495) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:761: BaskVault.pay(address,address,uint256) (src/BaskVault.sol#761-772) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:410: BaskVault._validateProposal(BaskVault.ProposalData) (src/BaskVault.sol#410-439) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:368: BaskVault.executeProposal(uint256) (src/BaskVault.sol#368-408) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:306: BaskVault.lowerNAVCap(uint256) (src/BaskVault.sol#306-311) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:274: BaskVault._fee(uint256) (src/BaskVault.sol#274-276) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:463: BaskVault._decimals(address) (src/BaskVault.sol#463-467) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:851: BaskVault.flagDeficit(address) (src/BaskVault.sol#851-860) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:952: BaskVault.proposalStatus(uint256) (src/BaskVault.sol#952-961) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:897: BaskVault.allAssets() (src/BaskVault.sol#897-917) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:284: BaskVault.acceptOwnership() (src/BaskVault.sol#284-291) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:584: BaskVault._price(address) (src/BaskVault.sol#584-625) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:360: BaskVault.cancelProposal(uint256) (src/BaskVault.sol#360-366) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:469: BaskVault._feed(address) (src/BaskVault.sol#469-481) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:515: BaskVault._poolConfig(address,address,address,uint256) (src/BaskVault.sol#515-534) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:572: BaskVault._available(address) (src/BaskVault.sol#572-576) uses timestamp for comparisons\n[low/medium] timestamp at src/BaskVault.sol:627: BaskVault._insideHours() (src/BaskVault.sol#627-635) uses timestamp for comparisons","passed":true},{"durationMs":388,"exitCode":0,"name":"aderyn","output":"[high] incorrect-caret-operator at src/libraries/FullMath.sol:86: Incorrect use of caret operator\n[high] incorrect-shift-order at src/BaskVault.sol:564: Incorrect Assembly Shift Parameter Order\n[high] reentrancy-state-change at src/BaskVault.sol:846: Reentrancy: State change after external call\n[high] weak-randomness at src/BaskVault.sol:633: Weak Randomness\n[low] centralization-risk at src/BaskVault.sol:278: Centralization Risk (9 places)\n[low] costly-loop at src/BaskVault.sol:727: Costly operations inside loop (4 places)\n[low] internal-function-used-once at src/libraries/Calls.sol:6: Internal Function Used Only Once\n[low] large-numeric-literal at src/BaskVault.sol:217: Large Numeric Literal (12 places)\n[low] literal-instead-of-constant at src/BaskVault.sol:217: Literal Instead of Constant (69 places)\n[low] local-variable-shadowing at src/BaskVault.sol:122: Local Variable Shadows State Variable (2 places)\n[low] non-reentrant-not-first at src/BaskVault.sol:278: `nonReentrant` is Not the First Modifier (9 places)\n[low] push-zero-opcode at src/libraries/TickMath.sol:2: PUSH0 Opcode\n[low] require-revert-in-loop at src/BaskVault.sol:449: Loop Contains `require`/`revert` (8 places)\n[low] state-change-without-event at src/BaskVault.sol:228: State Change Without Event\n[low] storage-array-length-not-cached at src/BaskVault.sol:657: Storage Array Length not Cached (4 places)\n[low] unchecked-return at src/BaskVault.sol:414: Unchecked Return (8 places)\n[low] uninitialized-local-variable at src/BaskVault.sol:648: Uninitialized Local Variable (8 places)\n[low] unsafe-erc20-operation at src/BaskVault.sol:731: Unsafe ERC20 Operation (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ea9620560d989e8f9caad2baf93d41f77ed4a4be4d255cfa8da7a3aa4e9450ba","verifiedTreeHash":"cf8e2384b42c544a88422944efa730119368a840","verifierVersion":"0.1.0+ad90ce4c"}]}