56406 sc insight getestimatedyield never updates after snapshots

Submitted on Oct 15th 2025 at 16:28:34 UTC by @spongebob for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #56406

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/MYTStrategy.sol

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

getEstimatedYield simply returns params.estimatedYield and that struct field is only populated in the constructor via _params.estimatedYield (no setter or later writes).

https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/MYTStrategy.sol#L285

 function getEstimatedYield() public view returns (uint256) {
        return params.estimatedYield;
    }

snapshotYield updates the mutable state estApr/estApy and emits YieldUpdated, but never copies the result back into params.estimatedYield.

https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/MYTStrategy.sol#L196-L215

// Add incentives to calculation if applicable
        uint256 rewardsRatePerSec;
        if (params.additionalIncentives == true) rewardsRatePerSec = _computeRewardsRatePerSecond();

        // Combine rates
        uint256 totalRatePerSec = baseRatePerSec + rewardsRatePerSec;
        uint256 apr = totalRatePerSec * SECONDS_PER_YEAR; // simple annualization (APR)
        uint256 apy = _approxAPY(totalRatePerSec);

        // Smoothing factor
        // TODO need to figure out how to ramp this up
        // Since first call is 0 the second call will be skewed
        // perhaps no smoothing on second pass
        uint256 alpha = 7e17; // 0.7
        estApr = _lerp(estApr, apr, alpha);
        estApy = _lerp(estApy, apy, alpha);

        lastSnapshotTime = uint64(currentTime);
        lastIndex = newIndex;

Because no other code touches params.estimatedYield, external callers of getEstimatedYield() always see the original constructor value even after snapshots run, so the method surfaces stale data.

Recommendation

Update snapshotYield() to write params.estimatedYield = estApy; so the getter reflects the freshest snapshot.

Proof of Concept

Add this test to MYTStrategy.t.sol and run forge test --mt testPOC_GetEstimatedYield_Returns_Stale_Data -vvvv

Was this helpful?