Huge Tiger Pike
High
The absence of a check on the returned boolean value from claimCollateralAsNFTLender()
can lead to a successful claim without the lender receiving any assets or retaining ownership of the accepted lend offer. This vulnerability specifically arises in scenarios involving defaulted loans with multiple accepted lend offers, particularly when an auction has not been initialized.
In DebitaV3Loan:361, there is a missing check on the returned bool value from claimCollateralAsNFTLender()
No response
No response
- a loan with more than 1 acceptedOffers needs to default
- a lender must invoke
claimCollateralAsLender()
before auction is initiated
The lender is unable to access any proceeds from a future auction. The proceeds would be permanently locked in the loan contract.
Added to test/fork/Loan/ratio/TwoLenderLoanReceipt.t.sol
function testLenderLosingOwnership() public {
MatchOffers();
vm.warp(block.timestamp + 8640010); // loan defaults
// Verify first lender's ownership
uint lenderId = DebitaV3LoanContract.getLoanData()._acceptedOffers[0].lenderID;
assertEq(firstLender, ownershipsContract.ownerOf(lenderId));
// Check that no NFT or ERC20 is received from claiming
address prevReceiptOwner = receiptContract.ownerOf(receiptID);
uint256 prevBalance = AEROContract.balanceOf(firstLender);
DebitaV3LoanContract.claimCollateralAsLender(0);
assertEq(prevReceiptOwner, receiptContract.ownerOf(receiptID));
assertEq(prevBalance, AEROContract.balanceOf(firstLender));
// Ownership NFT was burned, expect reverts
vm.expectRevert();
ownershipsContract.ownerOf(lenderId);
vm.expectRevert();
DebitaV3LoanContract.claimCollateralAsLender(0);
vm.expectRevert();
DebitaV3LoanContract.createAuctionForCollateral(0);
// Second lender starts auction
vm.startPrank(secondLender);
DebitaV3LoanContract.createAuctionForCollateral(1);
// Buyer purchases collateral NFT from auction
vm.startPrank(buyer);
deal(AERO, buyer, 1000e18);
AEROContract.approve(address(auction), 100e18);
auction.buyNFT();
vm.stopPrank();
// First lender cannot claim any proceedings
vm.expectRevert();
DebitaV3LoanContract.claimCollateralAsLender(0);
// Second lender receives their portion
uint256 prevBalanceSecondLender = AEROContract.balanceOf(secondLender);
vm.startPrank(secondLender);
DebitaV3LoanContract.claimCollateralAsLender(1);
assertTrue(prevBalanceSecondLender < AEROContract.balanceOf(secondLender));
vm.stopPrank();
}
if (m_loan.isCollateralNFT) {
- claimCollateralAsNFTLender(index);
+ require(claimCollateralAsNFTLender(index), "claim not successful");
} else {