code-423n4 / 2024-06-size-validation

1 stars 0 forks source link

Rounding issue in `getCreditPositionProRataAssignedCollateral` calculation. #705

Closed c4-bot-1 closed 4 months ago

c4-bot-1 commented 4 months ago

Lines of code

https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/LoanLibrary.sol#L182 https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/LoanLibrary.sol#L157

Vulnerability details

Impact

The proportional collateral assigned to CreditPosition may be slightly lower than expected.

Proof of Concept

If debtPosition.futureValue is not zero(not repaid yet), then the pro-rata collateral assigned to a CreditPosition is

function getCreditPositionProRataAssignedCollateral(State storage state, CreditPosition memory creditPosition)
        public
        view
        returns (uint256)
    {
        DebtPosition storage debtPosition = getDebtPosition(state, creditPosition.debtPositionId);

        uint256 debtPositionCollateral = getDebtPositionAssignedCollateral(state, debtPosition);
        uint256 creditPositionCredit = creditPosition.credit;
        uint256 debtPositionFutureValue = debtPosition.futureValue;

        if (debtPositionFutureValue != 0) {
@>          return Math.mulDivDown(debtPositionCollateral, creditPositionCredit, debtPositionFutureValue); 
        } else {
            return 0;
        }
    }

And debtPositionCollateral is

function getDebtPositionAssignedCollateral(State storage state, DebtPosition memory debtPosition)
        public
        view
        returns (uint256)
    {
        uint256 debt = state.data.debtToken.balanceOf(debtPosition.borrower);
        uint256 collateral = state.data.collateralToken.balanceOf(debtPosition.borrower);

        if (debt != 0) {
@>          return Math.mulDivDown(collateral, debtPosition.futureValue, debt);
        } else {
            return 0;
        }
    }

Therefore,

creditPositionProRataAssignedCollateral = debtPositionCollateral * creditPositionCredit / debtPositionFutureValue 
= (collateral * debtPosition.futureValue / debt) * creditPosition.credit / debtPosition.futureValue 
= (collateral * debtPosition.futureValue * creditPosition.credit) / (debt * debtPosition.futureValue) 
= collateral * creditPosition.credit / debt

debtPosition.futureValue is used in both of denominator and nominator. So it may rounds down twice in above calculation.

Tools Used

Manual review

Recommended Mitigation Steps

    function getCreditPositionProRataAssignedCollateral(State storage state, CreditPosition memory creditPosition)
        public
        view
        returns (uint256)
    {
        DebtPosition storage debtPosition = getDebtPosition(state, creditPosition.debtPositionId);

--      uint256 debtPositionCollateral = getDebtPositionAssignedCollateral(state, debtPosition);
++      uint256 debt = state.data.debtToken.balanceOf(debtPosition.borrower);
++      uint256 collateral = state.data.collateralToken.balanceOf(debtPosition.borrower);
        uint256 creditPositionCredit = creditPosition.credit;
        uint256 debtPositionFutureValue = debtPosition.futureValue;

--      if (debtPositionFutureValue != 0) {
--          return Math.mulDivDown(debtPositionCollateral, creditPositionCredit, debtPositionFutureValue); 
++      if (debtPositionFutureValue != 0 && debt != 0) {
++          return Math.mulDivDown(collateral, creditPositionCredit, debt); 
        } else {
            return 0;
        }
    }

Assessed type

Math