Salty Amethyst Caribou
High
Once Bids are accepted, the state is changed from PENDING to others. Moreover if the borrower canceled the bid, the state is changed to CANCELED. But despite of this, these types of bids are re-acceptable.
In TellerV2.sol::lenderAcceptBid#L500
, it checks to see if a pending loan has expired.
function lenderAcceptBid(uint256 _bidId)
external
override
pendingBid(_bidId, "lab")
whenProtocolNotPaused
returns (
uint256 amountToProtocol,
uint256 amountToMarketplace,
uint256 amountToBorrower
)
{
...
@> require(!isLoanExpired(_bidId), "BE");
...
}
However, in isLoanExpired()
function, it returns false
if the bid.state
is not equal to BidState.PENDING
and if bidExpirationTime[_bidId]
is equal to 0.TellerV2.sol::isLoanExpired#L1176-L1184
function isLoanExpired(uint256 _bidId) public view returns (bool) {
Bid storage bid = bids[_bidId];
@> if (bid.state != BidState.PENDING) return false;
@> if (bidExpirationTime[_bidId] == 0) return false;
return (uint32(block.timestamp) >
bid.loanDetails.timestamp + bidExpirationTime[_bidId]);
}
Following this function, if the state of Bids aren't PENDING
,for example Bids were already canceled by borrower or already accepted once, it returns false
and the require in lenderAcceptBid()#L500
is passed. The case of bidExpirationTime[_bidId] == 0
is also passed.
No response
No response
No response
If the accepted bids are accepted again, previous lenders lost their assets and borrowers also lost their totalRepaid assets.
No response
Fix isLoanExpired()
function by following:
function isLoanExpired(uint256 _bidId) public view returns (bool) {
Bid storage bid = bids[_bidId];
@> if (bid.state != BidState.PENDING) return true;
@> if (bidExpirationTime[_bidId] == 0) return true;
return (uint32(block.timestamp) >
bid.loanDetails.timestamp + bidExpirationTime[_bidId]);
}