Beautiful Canvas Nightingale
Medium
Due to calling updateInterestRatesAndVirtualBalances
with vars.actualCollateralToLiquidate
that is exclusive of the liquidationProtocolFeeAmount
, the updated interest rates and virtual balance accounting will be inaccurate.
/**
* @notice Burns the collateral aTokens and transfers the underlying to the liquidator.
* @dev The function also updates the state and the interest rate of the collateral reserve.
* @param collateralReserve The data of the collateral reserve
* @param params The additional parameters needed to execute the liquidation function
* @param vars The executeLiquidationCall() function local vars
*/
function _burnCollateralATokens(
DataTypes.ReserveData storage collateralReserve,
DataTypes.ExecuteLiquidationCallParams memory params,
LiquidationCallLocalVars memory vars
) internal {
DataTypes.ReserveCache memory collateralReserveCache = collateralReserve.cache();
collateralReserve.updateState(collateralReserveCache);
collateralReserve.updateInterestRatesAndVirtualBalance(
collateralReserveCache,
params.collateralAsset,
0,
vars.actualCollateralToLiquidate // @audit-info: note that it's EXclusive of the protocolLiquidationFee portion percentage;
);
if (params.receiveAToken) {
_liquidateATokens(reservesData, reservesList, usersConfig, collateralReserve, params, vars);
} else {
_burnCollateralATokens(collateralReserve, params, vars);
}
// Transfer fee to treasury if it is non-zero
if (vars.liquidationProtocolFeeAmount != 0) {
uint256 liquidityIndex = collateralReserve.getNormalizedIncome();
uint256 scaledDownLiquidationProtocolFee = vars.liquidationProtocolFeeAmount.rayDiv(
liquidityIndex
You can see that the actualCollateralToLiquidate
is exclusive of the protocol's liquidation fee portion:
(
vars.actualCollateralToLiquidate,
vars.actualDebtToLiquidate,
vars.liquidationProtocolFeeAmount,
vars.collateralToLiquidateInBaseCurrency
) = _calculateAvailableCollateralToLiquidate(
collateralReserve.configuration,
vars.collateralAssetPrice,
vars.collateralAssetUnit,
vars.debtAssetPrice,
vars.debtAssetUnit,
vars.actualDebtToLiquidate,
vars.userCollateralBalance,
vars.liquidationBonus
);
Because the liquidationProtocolFee
is subtracted from it here in _calculateAvailableCollateralToLiquidate
:
AvailableCollateralToLiquidateLocalVars memory vars;
vars.collateralAssetPrice = collateralAssetPrice;
vars.liquidationProtocolFeePercentage = collateralReserveConfiguration
.getLiquidationProtocolFee();
// This is the base collateral to liquidate based on the given debt to cover
vars.baseCollateral =
((debtAssetPrice * debtToCover * collateralAssetUnit)) /
(vars.collateralAssetPrice * debtAssetUnit);
vars.maxCollateralToLiquidate = vars.baseCollateral.percentMul(liquidationBonus);
if (vars.maxCollateralToLiquidate > userCollateralBalance) {
vars.collateralAmount = userCollateralBalance;
vars.debtAmountNeeded = ((vars.collateralAssetPrice * vars.collateralAmount * debtAssetUnit) /
(debtAssetPrice * collateralAssetUnit)).percentDiv(liquidationBonus);
} else {
vars.collateralAmount = vars.maxCollateralToLiquidate;
vars.debtAmountNeeded = debtToCover;
}
vars.collateralToLiquidateInBaseCurrency =
(vars.collateralAmount * vars.collateralAssetPrice) /
collateralAssetUnit;
if (vars.liquidationProtocolFeePercentage != 0) {
vars.bonusCollateral =
vars.collateralAmount -
vars.collateralAmount.percentDiv(liquidationBonus);
vars.liquidationProtocolFee = vars.bonusCollateral.percentMul(
vars.liquidationProtocolFeePercentage
);
vars.collateralAmount -= vars.liquidationProtocolFee;
}
return (
vars.collateralAmount,
vars.debtAmountNeeded,
vars.liquidationProtocolFee,
vars.collateralToLiquidateInBaseCurrency
);
}
None.
None.
Accounting problem barely contingent on any preconditions.
The accounted interest rates will be incorrect, as the liquidity removed amount will reflect an amount that is lower than the actual liquidity removed amount.
No response
No response