Lucene search

K
code423n4Code4renaCODE423N4:2023-12-PARTICLE-FINDINGS-ISSUES-34
HistoryDec 21, 2023 - 12:00 a.m.

liquidatePosition() change LOAN_TERM may result in the borrower paying additional liquidation fees.

2023-12-2100:00:00
Code4rena
github.com
6
vulnerability
liquidation
fees
modification
mitigation
loanterm
administrator
liensnapshot

6.7 Medium

AI Score

Confidence

Low

Lines of code

Vulnerability details

Vulnerability details

Currently, there are three ways to close a position:

  1. The borrower voluntarily closes it through closePosition().
  2. If Premium is insufficient, it is forcibly closed by liquidatePosition().
  3. After the loan expires, LP forcibly closes it by setting lien.renewalCutoffTime.

The third way is judged as follows:

    function liquidatePosition(
        DataStruct.ClosePositionParams calldata params,
        address borrower
    ) external override nonReentrant {
...

        if (
            !((closeCache.tokenFromPremium < liquidateCache.tokenFromOwed ||
                closeCache.tokenToPremium < liquidateCache.tokenToOwed) ||
@>            (lien.startTime < lps.getRenewalCutoffTime(lien.tokenId) &&
@>                  lien.startTime + LOAN_TERM < block.timestamp)) 
        ) {
            revert Errors.LiquidationNotMet();
        }

The problem is that this LOAN_TERM can be modified by the administrator.

For example: LOAN_TERM changes from 14 days to 7 days.

The borrower sees 14 days at the time of borrowing, and plans to close the position after 13 days to avoid being forcibly closed and losing the liquidation fee.

However, because the administrator changed LOAN_TERM to 7 days, it was liquidated in advance, resulting in the borrower need to pay the liquidation fee tokenPremium * LIQUIDATION_REWARD_FACTOR/Base.BASIS_POINT.

The loan contract should not be modified during the loan process. It is unreasonable to lose a liquidation fee as a result.

It is recommended that each lien should save the current LOAN_TERM as a snapshot.

Impact

Changing LOAN_TERM from large to small may cause the borrower’s position to be liquidated in advance, resulting in additional liquidation fees.

Recommended Mitigation

Add a loanTerm snapshot to lien.

    function openPosition(
        DataStruct.OpenPositionParams calldata params
    ) public override nonReentrant returns (uint96 lienId, uint256 collateralTo) {
..

        liens[keccak256(abi.encodePacked(msg.sender, lienId = _nextRecordId++))] = Lien.Info({
            tokenId: uint40(params.tokenId),
            liquidity: params.liquidity,
            token0PremiumPortion: cache.token0PremiumPortion,
            token1PremiumPortion: cache.token1PremiumPortion,
            startTime: uint32(block.timestamp),
+          loanTerm: LOAN_TERM,
            feeGrowthInside0LastX128: cache.feeGrowthInside0LastX128,
            feeGrowthInside1LastX128: cache.feeGrowthInside1LastX128,
            zeroForOne: params.zeroForOne
        });

    function liquidatePosition(
        DataStruct.ClosePositionParams calldata params,
        address borrower
    ) external override nonReentrant {
...
        if (
            !((closeCache.tokenFromPremium < liquidateCache.tokenFromOwed ||
                closeCache.tokenToPremium < liquidateCache.tokenToOwed) ||
                (lien.startTime < lps.getRenewalCutoffTime(lien.tokenId) &&
-                   lien.startTime + LOAN_TERM < block.timestamp)) 
+                   lien.startTime + lien.loanTerm < block.timestamp)) 
        ) {
            revert Errors.LiquidationNotMet();
        }

library Lien {
    struct Info {
        uint40 tokenId;
        uint128 liquidity;
        uint24 token0PremiumPortion;
        uint24 token1PremiumPortion;
        uint32 startTime;
+      uint256 loanTerm;
        uint256 feeGrowthInside0LastX128;
        uint256 feeGrowthInside1LastX128;
        bool zeroForOne;
    }



## Assessed type

Other  

The text was updated successfully, but these errors were encountered:

All reactions

6.7 Medium

AI Score

Confidence

Low