Multiliquid

Multiliquid: TreasuryDelegate

Cantina Security Report

Organization

@multiliquid

Engagement Type

Cantina Reviews

Period

-


Findings

Medium Risk

1 findings

1 fixed

0 acknowledged

Low Risk

4 findings

3 fixed

1 acknowledged

Informational

7 findings

7 fixed

0 acknowledged

Gas Optimizations

4 findings

4 fixed

0 acknowledged


Medium Risk1 finding

  1. Loss of yield for the new user when rates are not posted during the merge

    Severity

    Severity: Medium

    Likelihood: Medium

    ×

    Impact: Medium

    Submitted by

    rvierdiiev


    Description

    In TreasuryDelegate._mergeWithheldCredits, when a new user's withheld credits are merged, lastAccrualDay[user] is always set to block.timestamp / 1 days - 1:

    if (userCredits == 0) {    lastAccrualDay[user] = block.timestamp / 1 days - 1;}

    However, _calculateCreditMultiplier skips days without posted rates:

    for (uint256 day = startDay; day < currentDay; day++) {    if (!ratePosted[day]) {        // Skip days without posted rates (weekends until backfilled)        continue;    }    // ... apply rate}

    This creates a scenario where users permanently lose yield for days without posted rates at merge time:

    1. User deposits on Friday (Day 8). Rates exist for weekdays only.
    2. On Monday (Day 11), merge runs. _calculateCreditMultiplier iterates days 8–10 but skips days 9–10 (weekend, no rates posted).
    3. Merged credits receive yield only for Day 8.
    4. lastAccrualDay is set to currentDay - 1 = Day 10.
    5. Future accrual loops start from lastAccrualDay + 1 = Day 11, permanently skipping days 9–10.
    6. Even if weekend rates are backfilled later via correctDailyRate, those days are never applied to this user since accrual has already advanced past them.

    The user loses yield for any days that didn't have posted rates at the time their withheld credits merged.

    Recommendation

    Set lastAccrualDay to the minimum of currentDay - 1 and lastRatePostingDay to ensure accrual doesn't advance beyond days with posted rates:

    if (userCredits == 0) {    uint256 targetDay = block.timestamp / 1 days - 1;    lastAccrualDay[user] = targetDay < lastRatePostingDay ? targetDay : lastRatePostingDay;}

Low Risk4 findings

  1. Future timestamp check skipped when MAX_AGE is 0 inside ChroniclePriceAdapter

    Severity

    Severity: Low

    Likelihood: Low

    ×

    Impact: Low

    Submitted by

    rvierdiiev


    Description

    In ChroniclePriceAdapter.getPrice(), the check timestamp > block.timestamp is inside the if (MAX_AGE != 0) block. When MAX_AGE is 0 (staleness disabled), that block is skipped, so future timestamps are not rejected. A future timestamp is invalid regardless of max age.

    Recommendation

    if (timestamp > block.timestamp) revert InvalidPrice();if (MAX_AGE != 0) {    if (block.timestamp - timestamp > MAX_AGE) revert StalePrice(timestamp, MAX_AGE);}
  2. User may enjoy higher yield when withdrawing stablecoins close to backfill time

    State

    Acknowledged

    Severity

    Severity: Low

    Likelihood: Medium

    ×

    Impact: Low

    Submitted by

    HickupHH3


    Description

    The specification says that the user may lose a few basis points if withdrawing on weekends. While this is true for withheld credits because they can't be merged, it isn't necessarily true for main credits since it uses the lastRatePostingDay: if the future days to be backfilled have lower APY, then the user actually benefits.

    Using the E2E backfill example:

    • Sat 9am posts for Friday's rate of 4.52% APY
    • Tuesday 9am backfills with Sat + Sun + Mon rates of 4.5%, 4.5% & 4.48% APY respectively

    If the user withdraws on Monday, then the better rate of 4.52% is applied on the time elapsed since Sat.

    Although is true generally for any case where the next posted day rate is lower than the current one, it's just a bit more pronounced on weekends because of the multi-day delay.

    Proof of Concept

    function testBackFillBetterRate() external {    usdc.mint(alice, ALICE_DEPOSIT * 2);
        for (uint i = 1; i <= 4; i++) {        _simulateDailyWorker(startDay + i, RATE_W1_A);    }
        // ========== DAY 5 (Friday) ==========    // Alice deposits 2 x 10,000 USDC (stablecoin, T+1 earning)    vm.warp((startDay + 1) * 1 days + 14 hours); // 2pm user action    _swapUSDCIntoTreasury(alice, ALICE_DEPOSIT);    _swapUSDCIntoTreasury(alice, ALICE_DEPOSIT);    uint256 aliceTreasuryAmount = treasury.balanceOf(alice);
        _simulateDailyWorker(startDay + 5, RATE_W1_B);
    
        // we warp 15 minutes before backfill to show worst case in swapping prior to rates swap    vm.warp((startDay + 9) * 1 days + 9 hours - 15 minutes);    uint256 aliceUsdcBefore = usdc.balanceOf(alice);    _swapTreasuryToUSDC(alice, aliceTreasuryAmount / 2, 0);    uint256 aliceUsdcAfter = usdc.balanceOf(alice);    uint256 aliceUsdcRedeemedBeforeBackfill = aliceUsdcAfter - aliceUsdcBefore;
        // backfill weekend    _backfillWeekend(weekendRate1, RATE_W2_A, startDay + 6, startDay + 7, startDay + 8);
        // perform equivalent withdrawal    aliceUsdcBefore = aliceUsdcAfter;    _swapTreasuryToUSDC(alice, aliceTreasuryAmount / 2, 0);    aliceUsdcAfter = usdc.balanceOf(alice);    uint256 aliceUsdcRedeemedAfterBackfill = aliceUsdcAfter - aliceUsdcBefore;
        console.log("aliceUsdcRedeemedBeforeBackfill", aliceUsdcRedeemedBeforeBackfill);    console.log("aliceUsdcRedeemedAfterBackfill", aliceUsdcRedeemedAfterBackfill);    assertGt(aliceUsdcRedeemedBeforeBackfill, aliceUsdcRedeemedAfterBackfill);}

    Recommendation

    Partially mitigate by posting a slightly smaller APY rates for Fridays, and / or adjusting future APYs to account for potential deficits.

  3. Minted treasury fee tokens are unbacked

    Severity

    Severity: Low

    Likelihood: High

    ×

    Impact: Medium

    Submitted by

    HickupHH3


    Description

    By themselves, the treasury tokens have no intrinsic value, and must be backed by credits. The absence of adding withheld credits when minting the treasury tokens to the vault and custodian for the various swaps results in them not being able to redeem the fees; at least, not on-chain.

    Recommendation

    Add withheld credits in addition to the mints. The isRWA field for mints is recommended to be as such:

    • RWA -> stablecoin = deployStablecoin(): isRWA = true
    • RWA -> RWA = exchangeRWAs(): isRWA = true
    • stablecoin -> treasury = _exchangeStablecoinsMint(): isRWA = false
    • treasury -> stablecoin = _exchangeStablecoinsRedeem: isRWA = false
  4. Posted rates according to natspec result in higher than expected yields

    Severity

    Severity: Low

    Likelihood: Medium

    ×

    Impact: Low

    Submitted by

    HickupHH3


    Description

    In the natspec and tests, the posted rate uses a simple conversion from the expected APY. However, this will result in slightly higher APY rates than expected due to the daily compounding formula.

    For example, if we want to post a rate of 5% APY,

    (1+rf365)365=1.05(1 + \frac{r-f}{365})^{365} = 1.05

    where f is the management fee.

    Solving for r, we get

    r=365[1.051/3651]+fr = 365 * [1.05^{1/365} - 1] + f

    which gives a net value of 48793425246426160 < 5e16.

    Proof Of Concept

    function test_fullYearAPYRate() public {    uint256 apy = 0.05e18; // 5% APY    uint256 multiplier = _computeMultiplier(apy, 365, WAD);    console.log("Default 5% multiplier", multiplier);
        apy = 48793425246426160;    multiplier = _computeMultiplier(apy, 365, WAD);    console.log("Adjusted 5% multiplier", multiplier);}

    yields

    [PASS] test_fullYearAPYRate() (gas: 270214)Logs:  Default 5% APY 1051267496467462356  Adjusted 5% APY 1050000000000021131

    Recommendation

    Switch the APY calculation to be additive:

    multiplier += apy / DAYS_PER_YEAR;

    Otherwise, r should be calculated as per the formula below.

    r=365[(1+y)1/3651]+fr = 365 * [(1 + y)^{1/365} - 1] + f

    where y is the expected APY (e.g. 4.5% APY -> y = 0.045)

Informational7 findings

  1. WithheldCreditsDeque.toArray() lacks unchecked wrapper

    Severity

    Severity: Informational

    Likelihood: Low

    ×

    Impact: Low

    Submitted by

    HickupHH3


    Description

    The queue indexes can wrap around: specifically, with pushFront(), the start index is decremented and with pushBack(), the end index is incremented. Hence, toArray() would revert with addition overflow in any scenario where both pushFront() and pushBack() are invoked.

    Proof of Concept

    // SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.13;
    import {Test, stdError} from "forge-std/Test.sol";import {WithheldCreditsDeque} from "src/upgrades/ProtocolStablecoinDelegates/WithheldCreditsDeque.sol";
    contract WitheldCreditsDequeTest is Test {    using WithheldCreditsDeque for WithheldCreditsDeque.Deque;
        WithheldCreditsDeque.Deque private deque;
        /// forge-config: default.allow_internal_expect_revert = true    function test_toArrayFailsAfterPushFront() external {        WithheldCreditsDeque.WithheldCredits memory withheldCredit = WithheldCreditsDeque.WithheldCredits({            tokenAddress: address(0),            credits: 100,            releaseTimestamp: block.timestamp + 1 days,            earningStartTimestamp: block.timestamp + 1 days,            isRWA: true        });        // pushFront is to decrement front index to type(uint128.max)        deque.pushFront(withheldCredit);        // pushBack is to avoid decrementing front index, and have i = 1 for overflow        deque.pushBack(withheldCredit);
            vm.expectRevert(stdError.arithmeticError);        deque.toArray();    }}

    Recommendation

    - result[i] = deque._data[deque._begin + uint128(i)];+ unchecked { result[i] = deque._data[deque._begin + uint128(i)]; }
  2. Simplify withheld-credits consumption in _getYieldAmount and _getAmountForTargetValue functions

    Severity

    Severity: Informational

    Likelihood: Low

    ×

    Impact: Low

    Submitted by

    rvierdiiev


    Description

    In TreasuryDelegate, two view functions simulate LIFO consumption of withheld credits by iterating over the deque. In both cases, when execution reaches the loop, the caller has already ensured that the requested amount is at least the total withheld credits, so the loop always consumes all withheld credits.

    1. _getYieldAmount

    • Early return when redeemValue < totalWithheldCredits[user] (returns redeemValue).
    • So when the withheld loop runs, redeemValue >= totalWithheldCredits[user].
    • The loop consumes withheld credits LIFO until remaining is 0; it always consumes all withheld, so after the loop: totalValue = totalWithheldCredits[user], remaining = redeemValue - totalWithheldCredits[user].

    2. _getAmountForTargetValue

    • Early return when targetDollars < totalWithheldCredits[user] (returns targetDollars).
    • So when the withheld loop runs, targetDollars >= totalWithheldCredits[user].
    • The loop consumes withheld credits LIFO until remainingValue is 0; it always consumes all withheld, so after the loop: totalCredits = totalWithheldCredits[user], remainingValue = targetDollars - totalWithheldCredits[user].

    In both functions, the loop is therefore redundant: the outcome is a fixed assignment. Replacing the loop with that assignment preserves behavior and saves gas.

    Recommendation

    In _getYieldAmount: Replace the withheld-credits loop with:

    remaining = redeemValue - totalWithheldCredits[user];totalValue = totalWithheldCredits[user];

    In _getAmountForTargetValue: Replace the withheld-credits loop with:

    totalCredits = totalWithheldCredits[user];remainingValue = targetDollars - totalWithheldCredits[user];
  3. MAX_AGE is not configurable in ChroniclePriceAdapter and ChainlinkPriceAdapter

    Severity

    Severity: Informational

    Likelihood: Low

    ×

    Impact: Low

    Submitted by

    rvierdiiev


    Description

    • ChainlinkPriceAdapter: MAX_AGE is a constant (1 days), so it cannot be set to another value at deployment or changed later.
    • ChroniclePriceAdapter: MAX_AGE is set in the constructor and stored as immutable, so it is fixed at deployment and cannot be updated afterward.

    Recommendation

    Support configuring max age at deployment and updating it later: (1) add a constructor parameter (and, for Chainlink, replace the constant with a stored value) so max age can be set per deployment, and (2) add an admin-only setter (e.g. setMaxAge()) so max age can be changed when needed without redeploying.

  4. Break out of loop if daily rate not posted

    Severity

    Severity: Informational

    Submitted by

    HickupHH3


    Description

    If the daily rate hasn't been posted, the for-loop can be broken out because daily rates need to be posted in sequential order, so subsequent days will not have rates posted too.

    Recommendation

    if (!ratePosted[day]) {   // Skip days without posted rates (weekends until backfilled)-  continue;+  break;}
  5. Sanity check band != 0

    Severity

    Severity: Informational

    Submitted by

    HickupHH3


    Description

    band == 0 is used as an existence check, should revert for 0 amounts as well

    Recommendation

    - if (band >= WAD) revert InvalidRate();+ if (band == 0 || band >= WAD) revert InvalidRate();
  6. TreasuryDelegate initializer does not validate initial rate against management fee

    Severity

    Severity: Informational

    Likelihood: Low

    ×

    Impact: Low

    Submitted by

    rvierdiiev


    Description

    In postDailyRate() and correctDailyRate(), gross rate is required to be at least the management fee, and the stored rate is the net rate (grossRate - managementFee). In initialize(), the first day’s rate is stored with no check against managementFee, and managementFee is not set there (it remains 0). So the initializer does not enforce the same “gross rate >= management fee” rule, and the first day’s rate is not derived as a net rate after management fee.

    Recommendation

    If the first day’s rate should follow the same semantics as later rates: (1) add an initialManagementFee parameter to set managementFee in the initializer, and (2) require initialRate >= managementFee and store dailyRates[currentDay] = initialRate - managementFee, so the same validation and net-rate logic apply from day one.

  7. Whitelist checks can be more robust

    Severity

    Severity: Informational

    Submitted by

    HickupHH3


    Description and Recommendation

    For the JTRSY and ULTRA whitelist checks,

    function checkTransferRestriction(address from, address to, uint256 value) public view returns (bool) {   return detectTransferRestriction(from, to, value) == SUCCESS_CODE_ID;}
    function _onTransfer(address from, address to, uint256 value) internal {        require(            hook == address(0)                || IHook(hook).onERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))                    == IHook.onERC20Transfer.selector,            "Tranche/restrictions-failed"        );}
    • ULTRA should also check the from field
    function _beforeTokenTransfer(	address from,	address to,	uint256 amount) internal override {	super._beforeTokenTransfer(from, to, amount);	if (to != _clawbackAdmin) {		if (address(KYCContract) != address(0)) {			require(				KYCContract.isKYC(from) &&					KYCContract.isKYC(to),				"Ultra: both sender and receiver need to be KYC approved"			);		}	}}

    Multiliquid

    Fixed in f903d82 and 0604235.

    Cantina

    Fixed.

Gas Optimizations4 findings

  1. Redundant null address checks

    Severity

    Severity: Gas optimization

    Submitted by

    HickupHH3


    Description

    The null address check is redundant as the subsequent call to _mint does it:

    if (account == address(0)) {   revert ERC20InvalidReceiver(address(0));}

    Recommendation

    Consider removing it.

  2. finalLastAccrualDay can read from accrualEndDay instead of storage value lastAccrualDay[user]

    Severity

    Severity: Gas optimization

    Submitted by

    HickupHH3


    Description

    accrualEndDay can be initialized, then finalLastAccrualDay can use its value instead of doing a repeated SLOAD.

    Recommendation

    diff --git a/src/upgrades/ProtocolStablecoinDelegates/TreasuryDelegate.sol b/src/upgrades/ProtocolStablecoinDelegates/TreasuryDelegate.solindex 47695e0..17de25d 100644--- a/src/upgrades/ProtocolStablecoinDelegates/TreasuryDelegate.sol+++ b/src/upgrades/ProtocolStablecoinDelegates/TreasuryDelegate.sol@@ -722,7 +722,7 @@ contract TreasuryDelegate is StablecoinDelegateBase, IYieldBearingDelegate {         uint256 userCredits = credits[user];         uint256 currentDay = block.timestamp / 1 days;         uint256 accrualStartDay = lastAccrualDay[user];-        uint256 accrualEndDay;+        uint256 accrualEndDay = accrualStartDay;          uint256 userMultiplier = yieldMultiplier[user];         if (userMultiplier == 0) userMultiplier = WAD;@@ -769,7 +769,7 @@ contract TreasuryDelegate is StablecoinDelegateBase, IYieldBearingDelegate {         // - Complete if we've processed up to targetDay         // - Complete if next day has no rate posted (can't continue anyway)         // - Complete if user has no existing credits (nothing to catch up on)-        uint256 finalLastAccrualDay = lastAccrualDay[user];+        uint256 finalLastAccrualDay = accrualEndDay;         uint256 nextDayToProcess = finalLastAccrualDay + 1;         isComplete = (userCredits == 0) || (finalLastAccrualDay >= targetDay)             || !ratePosted[nextDayToProcess];

    Here's the gas diff. 1 fuzz test testFuzz_DaysAccrued(uint256) skews the overall gas reduction to be a net increase, which I assume to be an outlier.

    ↓ TreasuryDelegateExtremeValuesTest::test_LongTerm_ExtremCompounding_TenYears() (gas: 196696296196695936 | -360 -0.000%)↓ TreasuryDelegateExtremeValuesTest::test_LongTerm_TenYears_NoOverflow() (gas: 196696273196695913 | -360 -0.000%)↓ TreasuryDelegateExtremeValuesTest::test_LongTerm_FiveYears() (gas: 9856059298560232 | -360 -0.000%)↓ TreasuryDelegateHighMultiplierFeeTest::testBug_HighMultiplierSwapShouldWorkButReverts() (gas: 7831885578318135 | -720 -0.001%)↓ TreasuryDelegateHighMultiplierFeeTest::testFeeScalingWithYield() (gas: 9058373290582832 | -900 -0.001%)↓ TreasuryDelegateExtremeValuesTest::testFuzz_AccrualDays(uint256) (gas: 2521956325219203 | -360 -0.001%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_GasUsage_LongInactivity() (gas: 5252262852521728 | -900 -0.002%)↓ TreasuryDelegateExtremeValuesTest::test_LongTerm_OneYear() (gas: 1998389819983538 | -360 -0.002%)↓ TreasuryDelegateExtremeValuesTest::test_ExtremeAPY_VerySmall() (gas: 1998290819982548 | -360 -0.002%)↓ TreasuryDelegateExtremeValuesTest::test_Precision_MultiplierAccumulation() (gas: 1998282019982460 | -360 -0.002%)↓ TreasuryDelegateExtremeValuesTest::test_SmallDeposit_ThousandWei_YieldCalculation() (gas: 1996418219963822 | -360 -0.002%)↓ TreasuryDelegateExtremeValuesTest::test_SmallDeposit_OneWei_EarnsYield() (gas: 1993060619930246 | -360 -0.002%)↓ TreasuryDelegateAliceScenarioTest::testAliceScenarioExactOut() (gas: 2014390020143180 | -720 -0.004%)↓ TreasuryDelegateStablecoinYieldTest::testYieldMultiplierScalesOutput() (gas: 1985783519857115 | -720 -0.004%)↓ TreasuryDelegateAliceScenarioTest::testAliceScenarioStablecoinWithdrawal() (gas: 1982126219820542 | -720 -0.004%)↓ TreasuryDelegateAliceScenarioTest::testAliceScenarioStablecoinWithdrawalSunday() (gas: 1980912019808400 | -720 -0.004%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_MultipleCalls_FullCatchUp() (gas: 1962019019619110 | -1080 -0.006%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_LimitsToMaxDays() (gas: 55407605540220 | -540 -0.010%)↓ TreasuryDelegateStablecoinYieldTest::testYieldMultiplierScalesFees() (gas: 58200645819344 | -720 -0.012%)↓ TreasuryDelegateYieldTest::testConstantAPYYieldAccrual() (gas: 24658832465523 | -360 -0.015%)↓ TreasuryDelegateRevertTest::testRevert_DepositNonWhitelistedStablecoin() (gas: 11546171154437 | -180 -0.016%)↓ TreasuryDelegateExtremeValuesTest::test_LargeDeposit_WithYieldMultiplier() (gas: 20655162065156 | -360 -0.017%)↓ TreasuryDelegateInvariantTest::testInvariant2_MultiplierBounds_WithYield() (gas: 20390172038657 | -360 -0.018%)↓ TreasuryDelegateExtremeValuesTest::testFuzz_APYValues(uint256) (gas: 20357792035419 | -360 -0.018%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_ZeroMaxDays_Unlimited() (gas: 30484863047946 | -540 -0.018%)↓ TreasuryDelegateExtremeValuesTest::test_RateEdgeCase_DailyRateChanges() (gas: 20082562007896 | -360 -0.018%)↓ TreasuryDelegateExactOutFeeBugTest::testSwapIntoRWAExactOutWithExtremeYield() (gas: 39129603912240 | -720 -0.018%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_YieldMatchesFullAccrual() (gas: 60642536062633 | -1620 -0.027%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_DelaysWithheldMergeUntilCaughtUp() (gas: 32116523210752 | -900 -0.028%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_ReturnsCorrectDaysAccrued() (gas: 30699043069004 | -900 -0.029%)↓ TreasuryDelegateExactOutFeeBugTest::testSwapIntoRWAExactOutWithBothFees() (gas: 23851422384422 | -720 -0.030%)↓ TreasuryDelegateExactOutFeeBugTest::testSwapIntoRWAExactOutUserGetsExactOutput() (gas: 23198442319124 | -720 -0.031%)↓ TreasuryDelegateExactOutFeeBugTest::testExactOutBugMathExplanation() (gas: 23165492315829 | -720 -0.031%)↓ TreasuryDelegateExactOutFeeBugTest::testSwapIntoRWAExactOutCreditsReduction() (gas: 23093612308641 | -720 -0.031%)↓ TreasuryDelegateExactOutFeeBugTest::testSwapIntoRWAExactOutFeeCollection() (gas: 23083002307580 | -720 -0.031%)↓ TreasuryDelegateHighMultiplierFeeTest::testCombinedFeesAtModerateMultiplier() (gas: 22814362280716 | -720 -0.032%)↓ TreasuryDelegateExactOutFeeBugTest::testSwapIntoRWAExactInNoFeeBug() (gas: 22350272234307 | -720 -0.032%)↓ TreasuryDelegateDepositTest::testDepositAfterYieldAccrual() (gas: 22307152229995 | -720 -0.032%)↓ TreasuryDelegateHighMultiplierFeeTest::testVaultReceivesFaceValueTokensNotYieldValue() (gas: 22194892218769 | -720 -0.032%)↓ TreasuryDelegateDepositTest::testDepositExactInWithAllFees() (gas: 534205534025 | -180 -0.034%)↓ TreasuryDelegateRedemptionTest::testPartialRedemptionPreservesYield() (gas: 21275982126878 | -720 -0.034%)↓ TreasuryDelegateWithheldYieldBugTest::testRWAWithheldCreditsNoYieldOnEarlyRedemption() (gas: 527370527190 | -180 -0.034%)↓ TreasuryDelegateSwapFeeTest::testFeeChangesWithVolume() (gas: 507546507366 | -180 -0.035%)↓ TreasuryDelegateRevertTest::testRevert_RedeemToNonWhitelistedStablecoin() (gas: 15121381511598 | -540 -0.036%)↓ TreasuryDelegateMultiUserTest::testUsersSameDepositDifferentYield() (gas: 38926283891188 | -1440 -0.037%)↓ TreasuryDelegateYieldTest::testYieldAccrualWithManagementFee() (gas: 971061970701 | -360 -0.037%)↓ TreasuryDelegateDepositTest::testDepositExactInWithAcceptanceFee() (gas: 484774484594 | -180 -0.037%)↓ TreasuryDelegateExtremeValuesTest::test_ExtremeAPY_HundredPercent() (gas: 961376961016 | -360 -0.037%)↓ TreasuryDelegateInvariantTest::testInvariant7_LastAccrualDay_NotFuture() (gas: 960785960425 | -360 -0.037%)↓ TreasuryDelegateSwapFeeTest::testAcceptanceFeeGoesToCustody() (gas: 474819474639 | -180 -0.038%)↓ TreasuryDelegateCreditsForTargetValueTest::testAccrueAndGetAmountForTargetValue() (gas: 947746947386 | -360 -0.038%)↓ TreasuryDelegateCreditsForTargetValueTest::testGetAmountForTargetValue_ConsistentWithGetYieldAmount() (gas: 942829942469 | -360 -0.038%)↓ TreasuryDelegateCreditsForTargetValueTest::testGetAmountForTargetValue_WithYield() (gas: 941842941482 | -360 -0.038%)↓ TreasuryDelegateDepositTest::testDepositExactInWithProtocolFee() (gas: 469544469364 | -180 -0.038%)↓ TreasuryDelegateWithheldYieldBugTest::testGetAmountForTargetValueWithWithheldCredits() (gas: 468338468158 | -180 -0.038%)↓ TreasuryDelegateWithheldYieldBugTest::testGetYieldAmountForWithheldCredits() (gas: 468055467875 | -180 -0.038%)↓ TreasuryDelegateYieldTest::testYieldAccrualWithMidpointDeposit() (gas: 27681632767083 | -1080 -0.039%)↓ TreasuryDelegateDepositTest::testUSDCDepositExactOut() (gas: 460926460746 | -180 -0.039%)↓ TreasuryDelegateYieldTest::testManagementFeeChangeAffectsFutureRates() (gas: 916369916009 | -360 -0.039%)↓ TreasuryDelegateFuzzTest::testFuzz_ProtocolFeeRate(uint128) (gas: 454871454691 | -180 -0.040%)↓ TreasuryDelegateSwapFeeTest::testProtocolFeeGoesToVault() (gas: 454561454381 | -180 -0.040%)↓ TreasuryDelegateExtremeValuesTest::test_FeeEdgeCase_MaxProtocolFee() (gas: 450948450768 | -180 -0.040%)↓ TreasuryDelegateYieldTest::testYieldAccrualWithMidpointDepositExactOut() (gas: 27020272700947 | -1080 -0.040%)↓ TreasuryDelegateExtremeValuesTest::test_Precision_FeeRounding() (gas: 450172449992 | -180 -0.040%)↓ TreasuryDelegateDepositTest::testDepositExactInZeroFee() (gas: 420067419887 | -180 -0.043%)↓ TreasuryDelegateFuzzTest::testFuzz_DepositAmount(uint256) (gas: 416974416794 | -180 -0.043%)↓ DeploymentDayUnderflowTest::testDeploymentDayWithCreditsViewFunctionsWork() (gas: 415993415813 | -180 -0.043%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testSwapStablecoinToStablecoinDepositNoYield() (gas: 414555414375 | -180 -0.043%)↓ TreasuryDelegateDepositTest::testDepositLargeAmount() (gas: 411571411391 | -180 -0.044%)↓ TreasuryDelegateDepositTest::testDepositSmallAmount() (gas: 411564411384 | -180 -0.044%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_MultiplierAccumulatesCorrectly() (gas: 20493362048436 | -900 -0.044%)↓ TreasuryDelegateExtremeValuesTest::testFuzz_DepositAmounts(uint256) (gas: 409453409273 | -180 -0.044%)↓ TreasuryDelegateExtremeValuesTest::test_SmallDeposit_OneWei() (gas: 405597405417 | -180 -0.044%)↓ TreasuryDelegateExtremeValuesTest::test_LargeDeposit_SafeMaximum() (gas: 405581405401 | -180 -0.044%)↓ TreasuryDelegateExtremeValuesTest::test_LargeDeposit_Uint128Max() (gas: 405558405378 | -180 -0.044%)↓ TreasuryDelegateStablecoinYieldTest::testAccrualBeforeRedemption() (gas: 964988964556 | -432 -0.045%)↓ TreasuryDelegateInvariantTest::testInvariant2_MultiplierBounds_ZeroRate() (gas: 787491787131 | -360 -0.046%)↓ TreasuryDelegateDepositTest::testDepositExactOutMatchesExactIn() (gas: 757809757449 | -360 -0.048%)↓ TreasuryDelegateStablecoinYieldTest::testRedemptionWithStaleMultiplier() (gas: 15026101501890 | -720 -0.048%)↓ TreasuryDelegateExtremeValuesTest::test_ExtremeAPY_ZeroPercent() (gas: 698055697695 | -360 -0.052%)↓ TreasuryDelegateInvariantTest::testInvariant4_NoDoubleCounting_DuringMerge() (gas: 550085549797 | -288 -0.052%)↓ TreasuryDelegatePartialDayTest::testPartialDayInterestOnDeposit() (gas: 687495687135 | -360 -0.052%)↓ TreasuryDelegateInvariantTest::testInvariant2_MultiplierBounds_AfterDeposit() (gas: 543691543403 | -288 -0.053%)↓ TreasuryDelegateWithheldYieldBugTest::testGetYieldAmountWithNoWithheldCredits() (gas: 678970678610 | -360 -0.053%)↓ TreasuryDelegateInvariantTest::testInvariant7_LastAccrualDay_AfterFirstRate() (gas: 540486540198 | -288 -0.053%)↓ TreasuryDelegateInvariantTest::testInvariant6_NoNegativeBacking_MultiUser() (gas: 10044181003878 | -540 -0.054%)↓ TreasuryDelegateYieldTest::testRWAToTreasuryExactOutRedemption() (gas: 10620501061474 | -576 -0.054%)↓ TreasuryDelegateYieldTest::testFullYieldCycleWithManagementFee() (gas: 10423081041732 | -576 -0.055%)↓ TreasuryDelegateYieldTest::testFullRedemptionResetsMultiplier() (gas: 10392881038712 | -576 -0.055%)↓ TreasuryDelegateYieldTest::testWithheldCreditsMergeWithPartialYieldForMissingRates() (gas: 505130504842 | -288 -0.057%)↓ DeploymentDayUnderflowTest::testOneDayAfterDeploymentPartialYieldWorks() (gas: 498618498330 | -288 -0.058%)↓ TreasuryDelegateInvariantTest::testInvariant8_CorrectionWithinSeriesDoesNotAffectLast() (gas: 986268985692 | -576 -0.058%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testCalculateStablecoinToStablecoinWithYieldMatchesSwap() (gas: 986202985626 | -576 -0.058%)↓ TreasuryDelegateStablecoinYieldTest::testUSDCToTreasuryYieldRedemptionToUSDC() (gas: 985984985408 | -576 -0.058%)↓ TreasuryDelegateExtremeValuesTest::test_LargeDeposit_Multiple() (gas: 920277919737 | -540 -0.059%)↓ TreasuryDelegateRedemptionTest::testFullRedemptionResetsState() (gas: 980236979660 | -576 -0.059%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_WithheldCreditsYieldMatchesFullAccrual() (gas: 36739923671832 | -2160 -0.059%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testSwapStablecoinToStablecoinRedemptionWithYield() (gas: 977516976940 | -576 -0.059%)↓ TreasuryDelegateRedemptionTest::testRedeemEntireBalance() (gas: 972982972406 | -576 -0.059%)↓ TreasuryDelegateStablecoinYieldTest::testManualAccrualThenRedeem() (gas: 971135970559 | -576 -0.059%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testSwapIntoRWAWithFeesAndYieldScaling() (gas: 12103751209655 | -720 -0.059%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testSwapIntoRWAExactOutWithYieldScaling() (gas: 12036481202928 | -720 -0.060%)↓ TreasuryDelegatePartialDayTest::testMultipleDepositsAtDifferentTimes() (gas: 721749721317 | -432 -0.060%)↓ TreasuryDelegateInvariantTest::testInvariant4_NoDoubleCounting_StaggeredDeposits() (gas: 718497718065 | -432 -0.060%)↓ TreasuryDelegateSameDayE2EStablecoin::testMultiUserDifferentDepositTimes() (gas: 14276581426794 | -864 -0.061%)↓ TreasuryDelegateCreditsForTargetValueTest::testExactOut_MatchesViewFunction() (gas: 11871671186447 | -720 -0.061%)↓ TreasuryDelegatePartialDayTest::testPartialDayInterestOnWithdrawal() (gas: 712127711695 | -432 -0.061%)↓ TreasuryDelegatePartialDayTest::testDailyInterestAcrossDifferentRates() (gas: 712074711642 | -432 -0.061%)↓ TreasuryDelegateSwapFeeTest::testStablecoinSwapExactOutWithFees() (gas: 11853201184600 | -720 -0.061%)↓ TreasuryDelegateWeekendBackfillTest::testStablecoin_LongWeekendBackfill() (gas: 705802705370 | -432 -0.061%)↓ TreasuryDelegateDepositTest::testMultipleDepositsWeightedAverageMultiplier() (gas: 11687851168065 | -720 -0.062%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_WithheldCreditsOnly_StillMerges() (gas: 455490455202 | -288 -0.063%)↓ TreasuryDelegateMultiUserTest::testMultipleUsersIndependentMultipliers() (gas: 17890551787903 | -1152 -0.064%)↓ TreasuryDelegatePartialDayTest::testFirstPartialDayYield() (gas: 670456670024 | -432 -0.064%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_InterfaceCompliance() (gas: 445881445593 | -288 -0.065%)↓ TreasuryDelegateWeekendBackfillTest::testStablecoin_DepositFridayBackfillMondayWithdrawMonday() (gas: 668062667630 | -432 -0.065%)↓ TreasuryDelegateYieldTest::testPartialExactOutRedemptionPreservesMultiplier() (gas: 11091341108414 | -720 -0.065%)↓ TreasuryDelegateYieldTest::testPartialRedemptionPreservesMultiplier() (gas: 11073771106657 | -720 -0.065%)↓ TreasuryDelegateWeekendBackfillTest::testStablecoin_DepositSaturdayBackfillMondayWithdrawMonday() (gas: 663883663451 | -432 -0.065%)↓ TreasuryDelegateSwapFeeTest::testStablecoinSwapExactInWithFees() (gas: 11034041102684 | -720 -0.065%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testSwapIntoRWAWithYieldScaling() (gas: 10961911095471 | -720 -0.066%)↓ TreasuryDelegateSecondaryMarketTest::testSecondaryBuyerCanRedeemAfterDeposit() (gas: 876544875968 | -576 -0.066%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testCalculateRWAAmtWithYieldMatchesSwap() (gas: 10919791091259 | -720 -0.066%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testSwapStablecoinToStablecoinExactOutWithYield() (gas: 10870831086363 | -720 -0.066%)↓ TreasuryDelegateSecondaryMarketTest::testExactOutRedemptionEnforcesCredits() (gas: 537203536843 | -360 -0.067%)↓ TreasuryDelegateRedemptionTest::testPartialUSDCRedemptionPreservesMultiplier() (gas: 10690021068282 | -720 -0.067%)↓ TreasuryDelegateRedemptionTest::testPartialRedemption75Percent() (gas: 10688271068107 | -720 -0.067%)↓ TreasuryDelegateRedemptionTest::testPartialRedemption25Percent() (gas: 10686241067904 | -720 -0.067%)↓ TreasuryDelegateSameDayE2EStablecoin::test24HourAndOneMinuteYield() (gas: 636676636244 | -432 -0.068%)↓ TreasuryDelegateSameDayE2E::testMultiUserDifferentDepositTimes() (gas: 18774441876148 | -1296 -0.069%)↓ TreasuryDelegateExtremeValuesTest::test_FeeEdgeCase_CombinedHighFees() (gas: 622159621727 | -432 -0.069%)↓ TreasuryDelegateSameDayE2EStablecoin::testMidnightCrossingYield() (gas: 621603621171 | -432 -0.069%)↓ TreasuryDelegateInvariantTest::testFIFO_MergeOrdering() (gas: 828350827774 | -576 -0.070%)↓ TreasuryDelegateWeekendBackfillTest::testStablecoin_DepositSundayNightBackfillMondayWithdrawMonday() (gas: 620983620551 | -432 -0.070%)↓ TreasuryDelegateYieldTest::testBackfillMissingRatesAllowsContinuedAccrual() (gas: 768610768070 | -540 -0.070%)↓ TreasuryDelegateYieldTest::testWithdrawalWithMissingRates() (gas: 811829811253 | -576 -0.071%)↓ TreasuryDelegateRedemptionTest::testFullRedemptionWithMaxFees() (gas: 601264600832 | -432 -0.072%)↓ TreasuryDelegatePartialDayExploitTest::testExploit_MultiDayGap() (gas: 749963749423 | -540 -0.072%)↓ TreasuryDelegateFuzzTest::testFuzz_CombinedFees(uint128,uint256) (gas: 588086587656 | -430 -0.073%)↓ TreasuryDelegateInvariantTest::testEvent_WithheldCreditsReduced() (gas: 586320585888 | -432 -0.074%)↓ TreasuryDelegateSameDayE2EStablecoin::testLIFOPendingCreditsRemovedOnWithdrawWithYield() (gas: 583078582646 | -432 -0.074%)↓ TreasuryDelegateSameDayE2EStablecoin::testDepositBeforeFirstRatePostNextDayWithYield() (gas: 582860582428 | -432 -0.074%)↓ TreasuryDelegateWeekendBackfillTest::testStablecoin_WithdrawSaturdayBeforeBackfill() (gas: 578645578213 | -432 -0.075%)↓ TreasuryDelegateFuzzTest::testFuzz_PartialRedemption(uint256,uint256) (gas: 577558577126 | -432 -0.075%)↓ TreasuryDelegateExtremeValuesTest::test_DequeStress_MergeAndNewDeposits() (gas: 721809721269 | -540 -0.075%)↓ TreasuryDelegateExtremeValuesTest::testFuzz_PartialRedemptions(uint256,uint256) (gas: 572761572329 | -432 -0.075%)↓ TreasuryDelegateWithheldYieldBugTest::testReleasedCreditsProperlYReceiveYield() (gas: 763614763038 | -576 -0.075%)↓ TreasuryDelegateRedemptionTest::testRedeemSmallAmount() (gas: 570359569927 | -432 -0.076%)↓ TreasuryDelegateSameDayE2E::testYieldOnlyForCompleteDays() (gas: 565875565443 | -432 -0.076%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_IsCompleteWhenCaughtUp() (gas: 706644706104 | -540 -0.076%)↓ TreasuryDelegateSwapFeeTest::testRedemptionFeeGoesToCustody() (gas: 559801559369 | -432 -0.077%)↓ TreasuryDelegateWithheldYieldBugTest::testWithheldCreditsDoNotReceiveYield() (gas: 555825555393 | -432 -0.078%)↓ TreasuryDelegateInvariantTest::testFuzz_Invariant1_CreditConservation(uint256,uint256,uint256) (gas: 921228920508 | -720 -0.078%)↓ TreasuryDelegateSwapFeeTest::testChangeFeesMidOperation() (gas: 549388548956 | -432 -0.079%)↓ TreasuryDelegateExtremeValuesTest::test_BatchAccrue_MixedUsers() (gas: 684358683818 | -540 -0.079%)↓ TreasuryDelegateWeekendBackfillTest::testMixed_StablecoinAndRWAOverWeekend() (gas: 911474910754 | -720 -0.079%)↓ TreasuryDelegateWithheldYieldBugTest::testRedemptionAtExactReleaseTimestamp() (gas: 542236541804 | -432 -0.080%)↓ TreasuryDelegateExtremeValuesTest::test_FullWithdrawal_ClearsState() (gas: 716962716386 | -576 -0.080%)↓ TreasuryDelegateInvariantTest::testInvariant3_WithheldCreditsOrdering_MultipleDeposits() (gas: 11187041117804 | -900 -0.080%)↓ TreasuryDelegateWeekendBackfillTest::testRWA_DepositFridayBackfillMondayWithdrawMonday() (gas: 715916715340 | -576 -0.080%)↓ TreasuryDelegateInvariantTest::testLIFO_WithdrawalOrdering() (gas: 893129892409 | -720 -0.081%)↓ TreasuryDelegateWeekendBackfillTest::testRWA_DepositSaturdayBackfillMondayWithdrawMonday() (gas: 712560711984 | -576 -0.081%)↓ TreasuryDelegateSameDayE2EStablecoin::testMultipleDepositsSameDayWithdrawNextDay() (gas: 889998889278 | -720 -0.081%)↓ TreasuryDelegateCreditsForTargetValueTest::testGetAmountForTargetValue_SingleBucket_WADMultiplier() (gas: 444204443844 | -360 -0.081%)↓ TreasuryDelegateInvariantTest::testInvariant1_CreditConservation_SingleUser() (gas: 664867664327 | -540 -0.081%)↓ TreasuryDelegateRevertTest::testRevert_DepositInsufficientUSDCApproval() (gas: 221473221293 | -180 -0.081%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_StopsAtMissingRate() (gas: 663171662631 | -540 -0.081%)↓ TreasuryDelegateInvariantTest::testLIFO_WithheldBeforeMainCredits() (gas: 877616876896 | -720 -0.082%)↓ TreasuryDelegateDoubleCountingTest::testNoDoubleCountWhenMissingDaysPostedAfterMerge() (gas: 874510873790 | -720 -0.082%)↓ TreasuryDelegatePartialDayExploitTest::testExploit_PartialDayToFullDayDoubleCount() (gas: 652465651925 | -540 -0.083%)↓ TreasuryDelegateMultiliquidSwapIntegrationTest::testMultiUserYieldIndependence() (gas: 13665521365400 | -1152 -0.084%)↓ TreasuryDelegateDepositTest::testDepositAfterPartialRedemption() (gas: 12752981274218 | -1080 -0.085%)↓ TreasuryDelegateSameDayE2E::testZeroNetRateAfterManagementFee() (gas: 672020671444 | -576 -0.086%)↓ TreasuryDelegateRedemptionTest::testRedeemUpToCreditLimit() (gas: 502618502186 | -432 -0.086%)↓ TreasuryDelegateWithheldYieldBugTest::testExactOutRedemptionWithWithheldCredits() (gas: 625610625070 | -540 -0.086%)↓ TreasuryDelegateRedemptionTest::testSecondaryBuyerCanRedeemAfterDeposit() (gas: 499708499276 | -432 -0.086%)↓ TreasuryDelegatePartialDayTest::testWithdrawBeforeEarningStartDayCompletesNoYield() (gas: 499571499139 | -432 -0.086%)↓ TreasuryDelegateStablecoinYieldTest::testNoYieldOnSameDayDeposit() (gas: 498130497698 | -432 -0.087%)↓ TreasuryDelegateExtremeValuesTest::test_WithdrawalOrder_LIFOFromWithheld() (gas: 829051828331 | -720 -0.087%)↓ TreasuryDelegateFuzzTest::testFuzz_RedemptionAmount(uint256) (gas: 496740496308 | -432 -0.087%)↓ TreasuryDelegateSameDayE2E::testSameDayDepositWithdrawNoYield() (gas: 495882495450 | -432 -0.087%)↓ TreasuryDelegateSameDayE2E::testMultipleDepositsSameDayFullWithdraw() (gas: 821281820561 | -720 -0.088%)↓ TreasuryDelegateFuzzTest::testFuzz_DepositRedeemInvariant(uint256) (gas: 492006491574 | -432 -0.088%)↓ TreasuryDelegateDoubleCountingTest::testStablecoinMergeWaitsForStartDayRatePosted() (gas: 489859489427 | -432 -0.088%)↓ TreasuryDelegateInvariantTest::testInvariant3_WithheldCreditsOrdering_AfterPartialMerge() (gas: 12231181222038 | -1080 -0.088%)↓ TreasuryDelegateInvariantTest::testFuzz_TotalCreditsNeverExceedDeposits(uint256[3],uint256[3]) (gas: 14550661453778 | -1288 -0.089%)↓ TreasuryDelegateSameDayE2E::testLIFOPendingCreditsRemovedOnWithdraw() (gas: 486510486078 | -432 -0.089%)↓ TreasuryDelegateSameDayE2E::testDepositBeforeFirstRatePost() (gas: 485640485208 | -432 -0.089%)↓ TreasuryDelegateWithheldYieldBugTest::testMultipleWithheldBucketsNoYield() (gas: 11251501124142 | -1008 -0.090%)↓ TreasuryDelegateSecondaryMarketTest::testRWARedemptionEnforcesCredits() (gas: 599775599235 | -540 -0.090%)↓ TreasuryDelegateInvariantTest::testInvariant5_ZeroCreditsCannotRedeem() (gas: 591725591185 | -540 -0.091%)↓ TreasuryDelegateInvariantTest::testInvariant1_CreditConservation_MultiUser() (gas: 17697631768143 | -1620 -0.092%)↓ TreasuryDelegateWeekendBackfillTest::testRWA_WithdrawSaturdayBeforeBackfill() (gas: 624866624290 | -576 -0.092%)↓ TreasuryDelegateWeekendBackfillTest::testStablecoin_MultipleUsersOverWeekend() (gas: 14013481400052 | -1296 -0.092%)↓ TreasuryDelegateSameDayE2E::testPartialSameDayWithdraw() (gas: 931200930336 | -864 -0.093%)↓ TreasuryDelegateSameDayE2EStablecoin::testSameDayDepositWithdrawNoYield() (gas: 465540465108 | -432 -0.093%)↓ TreasuryDelegateSameDayE2EStablecoin::testPartialSameDayWithdrawNoYield() (gas: 929769928905 | -864 -0.093%)↓ TreasuryDelegateSecondaryMarketTest::testSecondaryBuyerCannotRedeemWithoutCredits() (gas: 579523578983 | -540 -0.093%)↓ TreasuryDelegateSameDayE2EStablecoin::testLIFOPendingCreditsRemovedOnWithdrawNoYield() (gas: 457043456611 | -432 -0.095%)↓ TreasuryDelegateSameDayE2EStablecoin::testDepositBeforeFirstRatePostSameDayNoYield() (gas: 456306455874 | -432 -0.095%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_AlreadyUpToDate_ReturnsComplete() (gas: 452306451874 | -432 -0.096%)↓ TreasuryDelegateSameDayE2EStablecoin::testMultipleDepositsSameDayFullWithdrawNoYield() (gas: 751944751224 | -720 -0.096%)↓ TreasuryDelegateWithheldYieldBugTest::testMixedWithheldAndMainCreditsYieldCalculation() (gas: 902244901380 | -864 -0.096%)↓ TreasuryDelegateInvariantTest::testInvariant5_RedemptionBoundedByCredits() (gas: 559926559386 | -540 -0.096%)↓ TreasuryDelegateSameDayE2EStablecoin::test23Hours59MinutesNoYield() (gas: 447351446919 | -432 -0.097%)↓ TreasuryDelegateExtremeValuesTest::test_DequeStress_PartialWithdrawals() (gas: 17799661778238 | -1728 -0.097%)↓ TreasuryDelegateExtremeValuesTest::test_BatchAccrue_ManyUsers() (gas: 2965168429622884 | -28800 -0.097%)↓ TreasuryDelegateAliceScenarioTest::testAliceScenarioExactMultiplier() (gas: 586861586285 | -576 -0.098%)↓ TreasuryDelegateRedemptionTest::testRedeemMoreThanCreditsReverts() (gas: 534492533952 | -540 -0.101%)↓ TreasuryDelegateRevertTest::testRevert_DepositInsufficientUSDCBalance() (gas: 175890175710 | -180 -0.102%)↓ TreasuryDelegateSameDayE2E::testLIFOOrderPendingThenCredits() (gas: 973442972434 | -1008 -0.104%)↓ TreasuryDelegateRevertTest::testRevert_RedeemInsufficientTreasuryBalance() (gas: 521484520944 | -540 -0.104%)↓ TreasuryDelegateWithheldYieldBugTest::testPartialWithheldRedemptionNoYield() (gas: 693408692688 | -720 -0.104%)↓ TreasuryDelegateRevertTest::testRevert_RedeemCustodyInsufficientUSDCWithCredits() (gas: 506789506249 | -540 -0.107%)↓ TreasuryDelegateRedemptionTest::testSecondaryBuyerCannotRedeemWithoutCredits() (gas: 333896333536 | -360 -0.108%)↓ TreasuryDelegateSameDayE2E::testFullE2EScenario() (gas: 24040292401437 | -2592 -0.108%)↓ TreasuryDelegateRevertTest::testRevert_RedeemCustodyInsufficientUSDC() (gas: 492543492003 | -540 -0.110%)↓ TreasuryDelegateSameDayE2EStablecoin::testFullE2EScenario() (gas: 23483362345744 | -2592 -0.110%)↓ TreasuryDelegateInvariantTest::testEvent_MainCreditsReduced() (gas: 649599648879 | -720 -0.111%)↓ TreasuryDelegateSameDayE2EStablecoin::testLIFOOrderPendingThenCredits() (gas: 906704905696 | -1008 -0.111%)↓ TreasuryDelegateWeekendBackfillTest::testRWA_MultipleUsersOverWeekend() (gas: 15348401533112 | -1728 -0.113%)↓ TreasuryDelegateExtremeValuesTest::test_DequeStress_ManyDepositsOneDay() (gas: 79112037902203 | -9000 -0.114%)↓ TreasuryDelegateRevertTest::testRevert_SwapWithoutStablecoinCustodySet() (gas: 95136549502007 | -11647 -0.122%)↓ TreasuryDelegateRevertTest::testRevert_SwapWithoutRWACustodySet() (gas: 95134169501769 | -11647 -0.122%)↓ TreasuryDelegateSecondaryMarketTest::testMultipleDepositsAccumulateCredits() (gas: 697521696657 | -864 -0.124%)↓ TreasuryDelegateSecondaryMarketTest::testPartialTransferAliceKeepsCredits() (gas: 700663699763 | -900 -0.128%)↓ TreasuryDelegateRedemptionTest::testMultiplePartialRedemptions() (gas: 11201631118723 | -1440 -0.129%)↓ TreasuryDelegateSecondaryMarketTest::testRedemptionCappedByCredits() (gas: 551536550816 | -720 -0.131%)↓ TreasuryDelegateYieldTest::testSecondDepositWithMissingRateForDepositDay() (gas: 10612761059836 | -1440 -0.136%)↓ TreasuryDelegateExtremeValuesTest::test_DequeStress_RapidDepositWithdraw() (gas: 15903501588190 | -2160 -0.136%)↓ TreasuryDelegateExtremeValuesTest::test_Precision_ManyAccrualCycles() (gas: 66013206583140 | -18180 -0.275%)↓ TreasuryDelegatePagedAccrualTest::test_PagedAccrual_NoCredits_ReturnsComplete() (gas: 5543855258 | -180 -0.325%)↓ TreasuryDelegate30DayE2ETest::testFull30DayMultiUserE2E() (gas: 55504605529724 | -20736 -0.374%)↓ TreasuryDelegateExtremeValuesTest::test_BatchAccrue_UsersWithNoCredits() (gas: 223862222962 | -900 -0.402%)↓ TreasuryDelegateSameRateTest::testFull70DayMultiUserE2E() (gas: 1370407713647629 | -56448 -0.412%)↓ TreasuryDelegatePagedAccrualTest::testFuzz_PagedAccrual_MaxDays(uint256) (gas: 1371356213608910 | -104652 -0.763%)↑ TreasuryDelegatePagedAccrualTest::testFuzz_PagedAccrual_CompleteAfterMultipleCalls(uint256,uint256) (gas: 62037476255973 | 52226 0.842%)↑ TreasuryDelegateFuzzTest::testFuzz_DaysAccrued(uint256) (gas: 95362959908510 | 372215 3.903%)--------------------------------------------------------------------------------Total tests: 1261, ↑ 2, ↓ 236, ━ 1023Overall gas change: 26145 (0.001%)
  3. Unreachable yieldMultiplier initialization

    Severity

    Severity: Gas optimization

    Submitted by

    HickupHH3


    Description

    The referenced code is redundant because _accrueInterest() will do the initialization:

    uint256 userMultiplier = yieldMultiplier[user];if (userMultiplier == 0) userMultiplier = WAD;...if (yieldMultiplier[user] != userMultiplier) {   yieldMultiplier[user] = userMultiplier;}

    Recommendation

    Remove the referenced lines, maybe convert to a dev comment that initialization should have been executed in _accrueInterest().

  4. Early return can be inclusive of equality case

    Severity

    Severity: Gas optimization

    Submitted by

    HickupHH3


    Description

    The equality case where redeemValue == totalWithheldCredits[user] & targetDollars == totalWithheldCredits[user] can be included in the early return.

    Recommendation

    - if (redeemValue < totalWithheldCredits[user]) {+ if (redeemValue <= totalWithheldCredits[user]) {   return redeemValue;}
    - if (targetDollars < totalWithheldCredits[user]) {+ if (targetDollars <= totalWithheldCredits[user]) {