Skip to content

Latest commit

 

History

History
80 lines (59 loc) · 3.06 KB

090.md

File metadata and controls

80 lines (59 loc) · 3.06 KB

Cheerful Gunmetal Moose

Medium

deficit storage position could break core invariant

Summary

_reserves is an internal storage variable that maps reserves to their DataTypes.ReserveData. in ReserveData struct, deficit took a storage position, that in a previous version (piror to 3.2) was occupied by currentStableBorrowRate , which was deprecated on version 3.2 :

// OLD VERSION

 struct ReserveData {
    //stores the reserve configuration
    ReserveConfigurationMap configuration;
    //the liquidity index. Expressed in ray
    uint128 liquidityIndex;
    //the current supply rate. Expressed in ray
    uint128 currentLiquidityRate;
    //variable borrow index. Expressed in ray
    uint128 variableBorrowIndex;
    //the current variable borrow rate. Expressed in ray
   uint128 currentVariableBorrowRate;
    //the current stable borrow rate. Expressed in ray
>   uint128 currentStableBorrowRate;
    //timestamp of last update
    uint40 lastUpdateTimestamp;
    //the id of the reserve. Represents the position in the list of the active reserves 
    uint16 id;

//...

 }
// v3.3

struct ReserveData {
    //stores the reserve configuration
    ReserveConfigurationMap configuration;
    //the liquidity index. Expressed in ray
    uint128 liquidityIndex;
    //the current supply rate. Expressed in ray
    uint128 currentLiquidityRate;
    //variable borrow index. Expressed in ray
    uint128 variableBorrowIndex;
    //the current variable borrow rate. Expressed in ray
    uint128 currentVariableBorrowRate;
    /// @notice reused `__deprecatedStableBorrowRate` storage from pre 3.2
    // the current accumulate deficit in underlying tokens
>   uint128 deficit;
    //timestamp of last update
    uint40 lastUpdateTimestamp;
    //the id of the reserve. Represents the position in the list of the active reserves
    uint16 id;

//...

}

This approach is actually a good one, to avoid corrupting the state of storage data. currentStableBorrowRate was uint128 (16 bytes) and deficit is uint128 (16 bytes), so it fits perfectly.

But the problem is that currentStableBorrowRate could still hold data, and there is no method or logic to clear it's storage which will break the invariant : The deficit of all reserves should initially be zero, even if bad debt was created before the protocol upgrade..

Root Cause

The upgrade reuses the storage slot of currentStableBorrowRate as deficit without clearing old data.

Impact

Invariant Violation

Mitigation

Clear Data on Upgrade: Reset deficit for all reserves during the migration.