lidofinance / core

Lido DAO smart contracts
https://lido.fi
GNU General Public License v3.0
382 stars 193 forks source link

Fix: too high simulated share rate #730

Closed TheDZhon closed 1 year ago

TheDZhon commented 1 year ago

Allow the simulated share rate to be either higher or lower within the defined bounds. A brief explanation was added to the code (see the key extracts below). Test cases to illustrate both possible scenarios are provided with the current PR.

Resolves the issue with the missed AccountingOracle reports on Görli. The weakness has been discovered internally and hasn't been reported by external teams yet.

Previously existing test cases with submits between ref_slot and submit data block didn't trigger revert because of insufficient TVL change.


        // the simulated share rate can be either higher or lower than the actual one
        // in case of new user-submitted ether & minted `stETH` between the oracle reference slot
        // and the actual report delivery slot
        //
        // lower it can be for a negative token rebase (token rebase >= one off CL balance decrease)
        // higher it can be for a positive token rebase (token rebase <= max positive token rebase)
        //
        // user-submitted ether & minted `stETH` don't exceed the current staking rate limit
        // (see Lido.getCurrentStakeLimit())
        //
        // thus, the `simulatedShareRateDeviationBPLimit` (L) should be set as follows:
        // L = 2 * SRL * max(CLD, MPR),
        // where:
        // - CLD is one-off CL balance decrease (as BP),
        // - MPR is max positive token rebase (as BP),
        // - SRL is staking rate limit normalized by TVL (`maxStakeLimit / totalPooledEther`)
        //   totalPooledEther should be chosen as a reasonable lower bound of the protocol TVL
        //
        uint256 simulatedShareDiff = Math256.absDiff(actualShareRate, _simulatedShareRate);
        uint256 simulatedShareDeviation = (MAX_BASIS_POINTS * simulatedShareDiff) / actualShareRate;

        if (simulatedShareDeviation > _limitsList.simulatedShareRateDeviationBPLimit) {
            revert IncorrectSimulatedShareRate(_simulatedShareRate, actualShareRate);
        }