code-423n4 / 2024-02-wise-lending-findings

8 stars 6 forks source link

Small positions will not pose incentive to be liquidated bringing `poolMarkets` down #277

Closed c4-bot-6 closed 3 months ago

c4-bot-6 commented 4 months ago

Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/WiseSecurity/WiseSecurity.sol#L1092-L1109 https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/WiseLending.sol#L1553-L1581

Vulnerability details

Impact

There is no incentive for liquidators to liquidate small positions (even under $100), especially on Mainnet, this will result in bad debt accrued for the WiseLending system because no one will be willing to remove the position and FEE_MANAGER will not be able to split the bad debt between depositors.

Proof of Concept

If we take a look at the current gas prices on Mainnet:

Priority Low Average High
Gwei 75 75 80
Price $7 $7 $7,45

We can see the current transaction prices varying and in peak hours they can be up to 5 times more, without additional costs of liquidation logic execution.

That way if there are many borrow positions eligible for liquidation but with unsatisfactory incentives for liquidators (liquidator receives less than the cost of executing the liquidation) and they approach insolvency, receiving roughly 5.90 USD incentive for the 100 USD borrow, it will lead to big harm for the protocol since they will result in an unaccounted bad debt for the system, without a proper way to be mitigated.

We can see in the code that there is no validation for the minimum borrowable amount, it has only to be enough to keep the position healthy.

In fact, there is a check for the minDepositEthValue when depositing:

WiseSecurity.sol#L1092-L1109

function _checkMinDepositValue(
    address _token,
    uint256 _amount
)
    private
    view
    returns (bool)
{
    if (minDepositEthValue == ONE_WEI) {
        return true;
    }

    if (_getTokensInEth(_token, _amount) < minDepositEthValue) {
        revert DepositAmountTooSmall();
    }

    return true;
}

But it can do nothing to prevent this malicious action to be executed.

Important note is that positions can become insolvent unintentionally, by borrowers leaving dust amounts of borrowed tokens when closing their positions.

For the borrow flow, there is no minimum borrowable amount.

WiseLending.sol#L1553-L1581

function _handleBorrowExactAmount(
    uint256 _nftId,
    address _poolToken,
    uint256 _amount,
    bool _onBehalf
)
    private
    returns (uint256)
{
    uint256 shares = calculateBorrowShares(
        {
            _poolToken: _poolToken,
            _amount: _amount,
            _maxSharePrice: true
        }
    );

    _coreBorrowTokens(
        {
            _caller: msg.sender,
            _nftId: _nftId,
            _poolToken: _poolToken,
            _amount: _amount,
            _shares: shares,
            _onBehalf: _onBehalf
        }
    );

    return shares;

Tools Used

Manual Review

Recommended Mitigation Steps

Similar to the deposit functions, consider adding minBorrowEthValue to prevent such scenarios, otherwise to keep the solvency of the whole poolMarket admins of Wise will have to liquidate such a positions, losing money in gas fees without receiving anything back.

Assessed type

Invalid Validation

GalloDaSballo commented 4 months ago

Worth considering

c4-pre-sort commented 4 months ago

GalloDaSballo marked the issue as sufficient quality report

c4-pre-sort commented 4 months ago

GalloDaSballo marked the issue as primary issue

vonMangoldt commented 4 months ago

Can also be circumvented by just paying back after borrowing. Doesnt really add any value imo

c4-judge commented 3 months ago

trust1995 marked issue #255 as primary and marked this issue as a duplicate of 255

c4-judge commented 3 months ago

trust1995 marked the issue as satisfactory