sherlock-audit/2023-03-teller-judging

J4de - The calculation time methods of `calculateNextDueDate` and `_canLiquidateLoan` are inconsistent

sherlock-admin opened this issue · 2 comments

J4de

medium

The calculation time methods of calculateNextDueDate and _canLiquidateLoan are inconsistent

Summary

The calculation time methods of calculateNextDueDate and _canLiquidateLoan are inconsistent

Vulnerability Detail

File: TellerV2.sol
 854     function calculateNextDueDate(uint256 _bidId)
 855         public
 856         view
 857         returns (uint32 dueDate_)
 858     {
 859         Bid storage bid = bids[_bidId];
 860         if (bids[_bidId].state != BidState.ACCEPTED) return dueDate_;
 861
 862         uint32 lastRepaidTimestamp = lastRepaidTimestamp(_bidId);
 863
 864         // Calculate due date if payment cycle is set to monthly
 865         if (bidPaymentCycleType[_bidId] == PaymentCycleType.Monthly) {
 866             // Calculate the cycle number the last repayment was made
 867             uint256 lastPaymentCycle = BPBDTL.diffMonths(
 868                 bid.loanDetails.acceptedTimestamp,
 869               

The calculateNextDueDate function is used by the borrower to query the date of the next repayment. Generally speaking, the borrower will think that as long as the repayment is completed at this point in time, the collateral will not be liquidated.

File: TellerV2.sol
 953     function _canLiquidateLoan(uint256 _bidId, uint32 _liquidationDelay)
 954         internal
 955         view
 956         returns (bool)
 957     {
 958         Bid storage bid = bids[_bidId];
 959
 960         // Make sure loan cannot be liquidated if it is not active
 961         if (bid.state != BidState.ACCEPTED) return false;
 962
 963         if (bidDefaultDuration[_bidId] == 0) return false;
 964
 965         return (uint32(block.timestamp) -
 966             _liquidationDelay -
 967             lastRepaidTimestamp(_bidId) >
 968             bidDefaultDuration[_bidId]);
 969     }

However, when the _canLiquidateLoan function actually judges whether it can be liquidated, the time calculation mechanism is completely different from that of calculateNextDueDate function, which may cause that if the time point calculated by _canLiquidateLoan is earlier than the time point of calculateNextDueDate function, the borrower may also be liquidated in the case of legal repayment.

Borrowers cannot query the specific liquidation time point, but can only query whether they can be liquidated through the isLoanDefaulted function or isLoanLiquidateable function. When they query that they can be liquidated, they may have already been liquidated.

Impact

Borrowers may be liquidated if repayments are made on time.

Code Snippet

https://github.com/teller-protocol/teller-protocol-v2/blob/cb66c9e348cdf1fd6d9b0416a49d663f5b6a693c/packages/contracts/contracts/TellerV2.sol#L953-L969

Tool used

Manual Review

Recommendation

It is recommended to verify that the liquidation time point cannot be shorter than the repayment period and allow users to query the exact liquidation time point.

Fix looks good. Liquidation logic has been revised to align it with dueDate