sherlock-audit / 2023-04-ajna-judging

4 stars 3 forks source link

LuchoLeonel1 - Missing expiration timestamp in removeQuoteToken #91

Closed sherlock-admin closed 1 year ago

sherlock-admin commented 1 year ago

LuchoLeonel1

high

Missing expiration timestamp in removeQuoteToken

Summary

The function removeQuoteToken doesn't have a deadline.

Vulnerability Detail

The transaction may remain in the mempool for an extended period. If the deadline is not verified, the transaction might occur significantly later than when the user initially submitted it. Consequently, the tx could be executed at a lower price, resulting in a negative impact on the user.

Impact

removeQuoteToken can have a removedAmount very small comparing to the maxAmount the user specified because the tx was in the mempool for too long and it's executed when it's harmfull for the user.

Code Snippet

The removeQuoteToken function doesn't have a check for deadline: https://github.com/sherlock-audit/2023-04-ajna/blob/main/ajna-core/src/base/Pool.sol#L210-L241

function removeQuoteToken(
        uint256 maxAmount_,
        uint256 index_
    ) external override nonReentrant returns (uint256 removedAmount_, uint256 redeemedLP_) {
        _revertIfAuctionClearable(auctions, loans);

        PoolState memory poolState = _accruePoolInterest();

        _revertIfAuctionDebtLocked(deposits, poolState.t0DebtInAuction, index_, poolState.inflator);

        uint256 newLup;
        (
            removedAmount_,
            redeemedLP_,
            newLup
        ) = LenderActions.removeQuoteToken(
            buckets,
            deposits,
            poolState,
            RemoveQuoteParams({
                maxAmount:      Maths.min(maxAmount_, _availableQuoteToken()),
                index:          index_,
                thresholdPrice: Loans.getMax(loans).thresholdPrice
            })
        );

        // update pool interest rate state
        _updateInterestState(poolState, newLup);

        // move quote token amount from pool to lender
        _transferQuoteToken(msg.sender, removedAmount_);
    }

The moveQuoteToken function does have a check for the deadline: https://github.com/sherlock-audit/2023-04-ajna/blob/main/ajna-core/src/base/Pool.sol#L182

function moveQuoteToken(
        uint256 maxAmount_,
        uint256 fromIndex_,
        uint256 toIndex_,
        uint256 expiry_
    ) external override nonReentrant returns (uint256 fromBucketLP_, uint256 toBucketLP_, uint256 movedAmount_) {
        _revertAfterExpiry(expiry_);
        PoolState memory poolState = _accruePoolInterest();

        _revertIfAuctionDebtLocked(deposits, poolState.t0DebtInAuction, fromIndex_, poolState.inflator);

        uint256 newLup;
        (
            fromBucketLP_,
            toBucketLP_,
            movedAmount_,
            newLup
        ) = LenderActions.moveQuoteToken(
            buckets,
            deposits,
            poolState,
            MoveQuoteParams({
                maxAmountToMove: maxAmount_,
                fromIndex:       fromIndex_,
                toIndex:         toIndex_,
                thresholdPrice:  Loans.getMax(loans).thresholdPrice
            })
        );

        // update pool interest rate state
        _updateInterestState(poolState, newLup);
    }

The addQuoteToken also have the same check: https://github.com/sherlock-audit/2023-04-ajna/blob/main/ajna-core/src/base/Pool.sol#L151

Tool used

Manual Review

Recommendation

Add the same _revertAfterExpiry function that is in the addQuoteToken and moveQuoteToken functions.

      function removeQuoteToken(
          uint256 maxAmount_,
          uint256 index_,
  +       uint256 expiry_
      ) external override nonReentrant returns (uint256 removedAmount_, uint256 redeemedLP_) {
  +       _revertAfterExpiry(expiry_);
          _revertIfAuctionClearable(auctions, loans);

          PoolState memory poolState = _accruePoolInterest();

          _revertIfAuctionDebtLocked(deposits, poolState.t0DebtInAuction, index_, poolState.inflator);

          uint256 newLup;
          (
              removedAmount_,
              redeemedLP_,
              newLup
          ) = LenderActions.removeQuoteToken(
              buckets,
              deposits,
              poolState,
              RemoveQuoteParams({
                  maxAmount:      Maths.min(maxAmount_, _availableQuoteToken()),
                  index:          index_,
                  thresholdPrice: Loans.getMax(loans).thresholdPrice
              })
          );

          // update pool interest rate state
          _updateInterestState(poolState, newLup);

          // move quote token amount from pool to lender
          _transferQuoteToken(msg.sender, removedAmount_);
      }