Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Get utilization rate function is wrongly implemented

Summary

Get utilization rate function is wrongly implemented due to usage of variables which have different decimals.

Vulnerability Details

following is utlization function

function getUtilizationRate() internal view returns (uint256) {
uint256 totalBorrowed = lendingPool.getNormalizedDebt();
uint256 totalDeposits = stabilityPool.getTotalDeposits();
if (totalDeposits == 0) return 0;
return (totalBorrowed * 100) / totalDeposits;
}

Now getnormalizedDebt returns the following

function getNormalizedDebt() external view returns (uint256) {
return reserve.usageIndex;
}

And this usage index is in terms of 1e27 as can be seen from the constructor of the lending pool

constructor(
address _reserveAssetAddress,
address _rTokenAddress,
address _debtTokenAddress,
address _raacNFTAddress,
address _priceOracleAddress,
uint256 _initialPrimeRate
) Ownable(msg.sender) {
if (
_reserveAssetAddress == address(0) ||
_rTokenAddress == address(0) ||
_debtTokenAddress == address(0) ||
_raacNFTAddress == address(0) ||
_priceOracleAddress == address(0) ||
_initialPrimeRate == 0
) revert AddressCannotBeZero();
reserveAssetToken = IERC20(_reserveAssetAddress);
raacNFT = IRAACNFT(_raacNFTAddress);
priceOracle = IRAACHousePrices(_priceOracleAddress);
rToken = IRToken(_rTokenAddress);
debtToken = IDebtToken(_debtTokenAddress);
// Initialize reserve data
reserve.liquidityIndex = uint128(WadRayMath.RAY); // 1e27
====>> reserve.usageIndex = uint128(WadRayMath.RAY);
reserve.lastUpdateTimestamp = uint40(block.timestamp);
// Addresses
reserve.reserveRTokenAddress = address(_rTokenAddress);
reserve.reserveAssetAddress = address(_reserveAssetAddress);
reserve.reserveDebtTokenAddress = address(_debtTokenAddress);
// Prime Rate
rateData.primeRate = uint256(_initialPrimeRate);
rateData.baseRate = rateData.primeRate.percentMul(25_00); // 25% of prime rate
rateData.optimalRate = rateData.primeRate.percentMul(50_00); // 50% of prime rate
rateData.maxRate = rateData.primeRate.percentMul(400_00); // 400% of prime rate
rateData.optimalUtilizationRate = WadRayMath.RAY.percentMul(80_00); // 80% in RAY (27 decimals)
rateData.protocolFeeRate = 0; // 0% in RAY (27 decimals)
// Initialize liquidation parameters
liquidationThreshold = BASE_LIQUIDATION_THRESHOLD;
healthFactorLiquidationThreshold = BASE_HEALTH_FACTOR_LIQUIDATION_THRESHOLD;
liquidationGracePeriod = BASE_LIQUIDATION_GRACE_PERIOD;
}
function getTotalDeposits() external view returns (uint256) {
return rToken.balanceOf(address(this));
}

Plus total deposits in stability pools are interms of r token which doesn't have 27 decimals therefore the following function will not return values between 0-100 which it should be

function getUtilizationRate() internal view returns (uint256) {
uint256 totalBorrowed = lendingPool.getNormalizedDebt();
uint256 totalDeposits = stabilityPool.getTotalDeposits();
if (totalDeposits == 0) return 0;
return (totalBorrowed * 100) / totalDeposits;
}

Impact

Wrong utilization rate

Tools Used

Manual

Recommendations

Redesign this function

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACMinter::getUtilizationRate incorrectly mixes stability pool deposits with lending pool debt index instead of using proper lending pool metrics

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACMinter::getUtilizationRate incorrectly mixes stability pool deposits with lending pool debt index instead of using proper lending pool metrics

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.