You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
GenericLogic::calculateUserAccountData assumes same price decimals for all price feeds
Summary
Pool assumes that all oracles have the same price decimals, while it's a rule of thumb that USD feeds use 8 decimals and ETH feeds use 18 decimals, this is not always the case as we can see with AML/USD for example with 18 decimals, this can lead to severe miscalculation of positions health factor
This would lead to miscalculations of positions health if price feeds have different decimals.
Internal pre-conditions
No response
External pre-conditions
No response
Attack Path
No response
Impact
Significant miscalculations in positions health
PoC
No response
Mitigation
A strict mitigation would be to verify oracle decimals on setReserveConfiguration
function setReserveConfiguration(
mapping(address => DataTypes.ReserveData) storage _reserves,
address asset,
address rateStrategyAddress,
address source,
DataTypes.ReserveConfigurationMap memory config
) public {
require(asset != address(0), PoolErrorsLib.ZERO_ADDRESS_NOT_VALID);
_reserves[asset].configuration = config;
// set if values are non-0
if (rateStrategyAddress != address(0)) _reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
if (source != address(0)) _reserves[asset].oracle = source;
require(config.getDecimals() >= 6, 'not enough decimals');
+ require(IAggregatorV3Interface(source).decimals() == 8, 'invalid oracle decimals');//or 18 depending on base currency
// validation of the parameters: the LTV can
// only be lower or equal than the liquidation threshold
// (otherwise a loan against the asset would cause instantaneous liquidation)
require(config.getLtv() <= config.getLiquidationThreshold(), PoolErrorsLib.INVALID_RESERVE_PARAMS);
if (config.getLiquidationThreshold() != 0) {
// liquidation bonus must be bigger than 100.00%, otherwise the liquidator would receive less
// collateral than needed to cover the debt
require(config.getLiquidationBonus() > PercentageMath.PERCENTAGE_FACTOR, PoolErrorsLib.INVALID_RESERVE_PARAMS);
// if threshold * bonus is less than PERCENTAGE_FACTOR, it's guaranteed that at the moment
// a loan is taken there is enough collateral available to cover the liquidation bonus
require(
config.getLiquidationThreshold().percentMul(config.getLiquidationBonus()) <= PercentageMath.PERCENTAGE_FACTOR,
PoolErrorsLib.INVALID_RESERVE_PARAMS
);
emit PoolEventsLib.CollateralConfigurationChanged(
asset, config.getLtv(), config.getLiquidationThreshold(), config.getLiquidationThreshold()
);
}
}
A more lenient mitigation would be to normalize all price feed to the same decimals in _getPositionBalanceInBaseCurrency
sherlock-admin3
changed the title
Shiny Daisy Osprey - GenericLogic::calculateUserAccountData assumes same price decimals for all price feeds
Honour - GenericLogic::calculateUserAccountData assumes same price decimals for all price feeds
Oct 3, 2024
Honour
Medium
GenericLogic::calculateUserAccountData assumes same price decimals for all price feeds
Summary
Pool assumes that all oracles have the same price decimals, while it's a rule of thumb that USD feeds use 8 decimals and ETH feeds use 18 decimals, this is not always the case as we can see with AML/USD for example with 18 decimals, this can lead to severe miscalculation of positions health factor
Root Cause
In
GenericLogic::calculateUserAccountData
https://github.com/sherlock-audit/2024-06-new-scope/blob/main/zerolend-one/contracts/core/pool/logic/GenericLogic.sol#L106-L119
The
_getPositionBalanceInBaseCurrency
function returns the position balance in base currency with the price feed precision.https://github.com/sherlock-audit/2024-06-new-scope/blob/main/zerolend-one/contracts/core/pool/logic/GenericLogic.sol#L207-L219
This would lead to miscalculations of positions health if price feeds have different decimals.
Internal pre-conditions
No response
External pre-conditions
No response
Attack Path
No response
Impact
Significant miscalculations in positions health
PoC
No response
Mitigation
setReserveConfiguration
function setReserveConfiguration( mapping(address => DataTypes.ReserveData) storage _reserves, address asset, address rateStrategyAddress, address source, DataTypes.ReserveConfigurationMap memory config ) public { require(asset != address(0), PoolErrorsLib.ZERO_ADDRESS_NOT_VALID); _reserves[asset].configuration = config; // set if values are non-0 if (rateStrategyAddress != address(0)) _reserves[asset].interestRateStrategyAddress = rateStrategyAddress; if (source != address(0)) _reserves[asset].oracle = source; require(config.getDecimals() >= 6, 'not enough decimals'); + require(IAggregatorV3Interface(source).decimals() == 8, 'invalid oracle decimals');//or 18 depending on base currency // validation of the parameters: the LTV can // only be lower or equal than the liquidation threshold // (otherwise a loan against the asset would cause instantaneous liquidation) require(config.getLtv() <= config.getLiquidationThreshold(), PoolErrorsLib.INVALID_RESERVE_PARAMS); if (config.getLiquidationThreshold() != 0) { // liquidation bonus must be bigger than 100.00%, otherwise the liquidator would receive less // collateral than needed to cover the debt require(config.getLiquidationBonus() > PercentageMath.PERCENTAGE_FACTOR, PoolErrorsLib.INVALID_RESERVE_PARAMS); // if threshold * bonus is less than PERCENTAGE_FACTOR, it's guaranteed that at the moment // a loan is taken there is enough collateral available to cover the liquidation bonus require( config.getLiquidationThreshold().percentMul(config.getLiquidationBonus()) <= PercentageMath.PERCENTAGE_FACTOR, PoolErrorsLib.INVALID_RESERVE_PARAMS ); emit PoolEventsLib.CollateralConfigurationChanged( asset, config.getLtv(), config.getLiquidationThreshold(), config.getLiquidationThreshold() ); } }
_getPositionBalanceInBaseCurrency
Duplicate of #166
The text was updated successfully, but these errors were encountered: