sherlock-audit / 2023-07-blueberry-judging

2 stars 1 forks source link

RadCet - Miscalculate liquidation by using `getIsolatedCollateralValue` without call `accrue` beforehand #78

Closed sherlock-admin2 closed 1 year ago

sherlock-admin2 commented 1 year ago

RadCet

high

Miscalculate liquidation by using getIsolatedCollateralValue without call accrue beforehand

Summary

function getIsolatedCollateralValue using to computes the total USD value of the isolated collateral for a given position., and we should call accrue for corresponding isolated underlying collateral token of the position need to calculate. However, function isLiquidatable and _validateMaxLTV using getIsolatedCollateralValue not follow this rule.

Vulnerability Detail

function isLiquidatable determines if a given position can be liquidated based on its risk ratio. It already calculate the interest accrue of debt token in liquidate but not isolated underlying collateral token. It calls getPositionRisk to calculate the risk ratio of a specified position. However, getPositionRisk call getIsolatedCollateralValue without calling accrue before hand, leading to miscalculate risk ratio.

Impact

Interest accrual plays a crucial role in determining the liquidation threshold for a borrower's position. By missing the interest accrual, the outstanding debt and interest owed by the borrower may be underestimated. As a result, the liquidation threshold may not accurately reflect the borrower's actual risk exposure, potentially leading to a delayed or inaccurate liquidation process. Furthermore, if the interest accrual is not factored into the risk ratio calculation, lenders may not be compensated for the additional interest they are entitled to. This can lead to financial losses for lenders

Code Snippet

isLiquidatable

function isLiquidatable(uint256 positionId) public returns (bool) {
        return
            getPositionRisk(positionId) >=
            banks[positions[positionId].underlyingToken].liqThreshold;
    }

getPositionRisk

function getPositionRisk(uint256 positionId) public returns (uint256 risk) {
        uint256 pv = getPositionValue(positionId);
        uint256 ov = getDebtValue(positionId);
        uint256 cv = getIsolatedCollateralValue(positionId);

        if (
            (cv == 0 && pv == 0 && ov == 0) || pv >= ov /// Closed position or Overcollateralized position
        ) {
            risk = 0;
        } else if (cv == 0) {
            /// Sth bad happened to isolated underlying token
            risk = Constants.DENOMINATOR;
        } else {
            risk = ((ov - pv) * Constants.DENOMINATOR) / cv;
        }
    }

_validateMaxLTV

function _validateMaxLTV(uint256 strategyId) internal {
        uint positionId = bank.POSITION_ID();
        IBank.Position memory pos = bank.getPositionInfo(positionId);
        uint256 debtValue = bank.getDebtValue(positionId);
        uint uValue = bank.getIsolatedCollateralValue(positionId);

        if (
            debtValue >
            (uValue * maxLTV[strategyId][pos.underlyingToken]) /
                Constants.DENOMINATOR
        ) revert Errors.EXCEED_MAX_LTV();
    }

Tool used

Manual Review

Recommendation

Need to call accrue before calculate isolated collateral for a given position value

Duplicate of #16

sherlock-admin2 commented 1 year ago

1 comment(s) were left on this issue during the judging contest.

0xyPhilic commented:

invalid because rewards are accounted for in the position value