sherlock-audit / 2024-09-predict-fun-judging

5 stars 4 forks source link

Aycozzynfada - Denial of Service in Auction Function Causing Loss of Funds for lenders #262

Open sherlock-admin3 opened 1 month ago

sherlock-admin3 commented 1 month ago

Aycozzynfada

High

Denial of Service in Auction Function Causing Loss of Funds for lenders

Summary

The auction function in the provided code has a vulnerability that prevents the lender from auctioning a loan if more than 24 hours have passed since the loan was called. This denial of service can lead to financial losses for the lender and disrupt the platform’s operations.

Root Cause

https://github.com/sherlock-audit/2024-09-predict-fun/blob/main/predict-dot-loan/contracts/PredictDotLoan.sol#L563-L583

The vulnerability arises from the _assertAuctionIsActive(timeElapsed) check, which reverts the transaction if the timeElapsed exceeds a day. -A lender due to personal reasons or due to protocol circumstances(which entails protocol being paused, or off-chain/on-chain downtime), might be forced to auction their loan a day after calling the loan. -in the_assertAuctionIsActive(timeElapsed), the current time.stamp is used to assess if auction has started or not by calling _assertAuctionIsActive() and because the timeElapsed is beyond a day, the lender is denied the opportunity to initiate their aunction before it even started.


  function auction(uint256 loanId) external nonReentrant whenNotPaused {
        Loan storage loan = loans[loanId];

        _assertLoanStatus(loan.status, LoanStatus.Called);

        _assertLenderIsNotBorrower(msg.sender, loan.borrower);

        _assertNewLenderIsNotTheSameAsOldLender(msg.sender, loan.lender);

        uint256 callTime = loan.callTime;
        uint256 timeElapsed = block.timestamp - callTime;  //current timestamp is used to calculate time Elapsed

        _assertAuctionIsActive(timeElapsed);// lender makes call after a day to   _assertAuctionIsActive() which reverts even before //even aunction started

        // If the question is resolved in the middle of the auction, the lender can wait for the auction to be over
        // and seize the collateral
        _assertQuestionPriceUnavailable(loan.questionType, positionQuestion[loan.positionId]);

        uint256 interestRatePerSecond = _auctionCurrentInterestRatePerSecond(timeElapsed);

        loan.status = LoanStatus.Auctioned;

        uint256 _nextLoanId = nextLoanId;
 function call(uint256 loanId) external nonReentrant {
        Loan storage loan = loans[loanId];

        _assertAuthorizedCaller(loan.lender);
        _assertLoanStatus(loan.status, LoanStatus.Active);

        if (loan.startTime + loan.minimumDuration > block.timestamp) {
            revert LoanNotMatured();
        }

        if (_isQuestionPriceAvailable(loan.questionType, positionQuestion[loan.positionId])) {
            _seize(loanId, loan);
        } else {
            loan.status = LoanStatus.Called;
            loan.callTime = block.timestamp;

            emit LoanCalled(loanId);
        }
    }

Internal pre-conditions

-A loan must be in the Called status. -The lender must attempt to auction the loan after more than 24 hours have passed since the loan was called.

External pre-conditions

No response

Attack Path

  1. A lender calls the auction function on a loan that has been in the Called status for more than 24 hours.
  2. The function calculates timeElapsed as the difference between the current block timestamp and the callTime.
  3. The _assertAuctionIsActive(timeElapsed) check fails because timeElapsed exceeds the allowed 24-hour period.
  4. The transaction reverts, preventing the lender from auctioning the loan.

Impact

The lender is unable to auction the loan, potentially leading to significant financial losses.

PoC

No response

Mitigation

Modify the _assertAuctionIsActive logic to allow for a more flexible auction period for the lenders or remove the strict 24-hour constraint, for lenders intending to aunction.