code-423n4 / 2023-12-initcapital-findings

3 stars 3 forks source link

Users can avoid liquidation by splitting their positions into smaller ones #40

Closed c4-bot-2 closed 8 months ago

c4-bot-2 commented 8 months ago

Lines of code

https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L120

Vulnerability details

Impact

Bad debt creation, as the total sum of positions could yield a signicant underwater position, but they would likely not be liquidated as it wouldn't compensate liquidators.

Proof of Concept

A recent, random transaction on Mantle shows a gas fee of 0.47 MNT, having used 137050 gas.

A liquidation call consumes around 300k gas. This value was gathered by running test testLiquidatePosition() in TestInitCore.sol and measuring the gas left before and after the initcore.liquidate() call in _liquidate().

The gas cost is expected to be bigger than 0.47 MNT as the liquidation call uses 300k gas, but the mentioned transaction only used around 137k. The relationship is not linear as the gas cost depends on both L1 and L2 fees, and the L1 fees won't increase significantly, but the value is likely to be bigger.

In any case, using this value as reference, MNT costs around 0.57 USD, so the fee is around 0.27 USD.

The effectiveness of this attack also depends on the liquidation incentive, but let's say it is 10%. The break even point with the previous data would be txnFee = 0.1*positionSize (=) positionSize = 10txnFee = 2.7 USD. So, users could split their positions into smaller positions of 2.7 USD and not likely be liquidated.

If the gas cost or value of Mantle goes up, this attack becomes even more likely as the positions can be increasingly bigger.

Here is a POC showing that a position with really small debt can be created (0.7 USD). Place it in TestInitCore.sol to run it.

function test_POC_Borrow_SmallPosition() public {
    address token = USDT;
    uint collAmts = 1e36 / initOracle.getPrice_e36(token);
    uint borrAmts = 0.7e36 / initOracle.getPrice_e36(token);

    address pool = address(lendingPools[token]);
    _setFixedRateIRM(pool, 1e18); // 100% per sec

    // whale funds the pool
    _fundPool(pool, 1e29);

    // create position
    uint posId = _createPos(ALICE, ALICE, 1);

    // collateralized
    deal(token, ALICE, collAmts);
    _collateralizePosition(ALICE, posId, pool, collAmts, bytes(''));

    // borrow
    _borrow(ALICE, posId, pool, borrAmts, bytes(''));
}

Tools Used

Vscode, Foundry, Mantle Block Explorer

Recommended Mitigation Steps

Either insert a minimum borrowing amount or place a base liquidation incentive to cover gas costs.

Assessed type

Other

c4-judge commented 8 months ago

hansfriese marked the issue as primary issue

c4-sponsor commented 8 months ago

fez-init (sponsor) disputed

fez-init commented 8 months ago

This is the expected behavior. The attacker has no gain from this, and should be losing money with gas fees. These bad debts should also be minimal that it can be ignored (should be much less than the interest accrual).

hansfriese commented 8 months ago

Agree with the sponsor.

c4-judge commented 8 months ago

hansfriese marked the issue as unsatisfactory: Invalid