Summary
Vulnerability Details
We can see that in NFTLiquidator :: endAuction() and NFTLiquidator :: buyBackNFT
both cases ETH get transfered to Stability pool
function endAuction(uint256 tokenId) external {
TokenData storage data = tokenData[tokenId];
if (block.timestamp < data.auctionEndTime) revert AuctionNotEnded();
if (data.highestBidder == address(0)) revert NoBidsPlaced();
address winner = data.highestBidder;
uint256 winningBid = data.highestBid;
delete tokenData[tokenId];
nftContract.transferFrom(address(this), winner, tokenId);
payable(stabilityPool).transfer(winningBid);
emit AuctionEnded(tokenId, winner, winningBid);
}
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/pools/StabilityPool/NFTLiquidator.sol#L140-L154
function buyBackNFT(uint256 tokenId) external payable {
TokenData storage data = tokenData[tokenId];
if (block.timestamp >= data.auctionEndTime) revert AuctionHasEnded();
if (nftContract.ownerOf(tokenId) != address(this)) revert NFTNotInLiquidation();
uint256 price = data.debt * 11 / 10;
if (msg.value < price) revert InsufficientPayment(price);
if (data.highestBidder != address(0)) {
payable(data.highestBidder).transfer(data.highestBid);
delete tokenData[tokenId];
nftContract.transferFrom(address(this), msg.sender, tokenId);
payable(stabilityPool).transfer(price);
if (msg.value > price) {
payable(msg.sender).transfer(msg.value - price);
}
emit BuybackCompleted(tokenId, msg.sender, price);
}
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/pools/StabilityPool/NFTLiquidator.sol#L160-L183
But Stability pool never has any fallback()
or receive()
function which will allow Stability pool to receive those ETH ,
So as we know In Solidity, when using the .transfer()
method, the recipient contract must have a receive()
or fallback()
function to accept Ether.
Impact
endAuction()
and bayBackNFT()
always gonna fail
Tools Used
mannual review
Recommendations
implement a receive(
) or fallback()
function in StabilityPool
contract