Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

ETH Transferred Without Address Checks

Description

  • The contract should validate that ETH recipients can properly receive transfers before attempting to send funds.

  • The BidBeastsMarketplace::settleAuction() and BidBeastsMarketplace::withdrawAllFailedCredits() functions transfer ETH without checking if the recipient address can receive the funds, potentially causing failed transfers and inconsistent state.

function settleAuction(uint256 tokenId) external isListed(tokenId) {
function withdrawAllFailedCredits(address _receiver) external {

Risk

Likelihood:

  • Occurs whenever ETH recipients are contracts without proper receive functions

  • Particularly likely with smart contract wallets or proxy contracts

Impact:

  • Failed transfers result in inconsistent contract state

  • Users may lose access to funds if transfers consistently fail

Proof of Concept

function test_HIGH_H1_ETHTransferWithoutChecksSettleAuction() public {
uint256 tokenId = _mintAndListNFT(ALICE, MIN_PRICE, 0);
// Bob places bid
vm.prank(BOB);
market.placeBid{value: MIN_PRICE + 0.1 ether}(tokenId);
// Make Alice unable to receive ether (simulating contract without receive function)
vm.etch(ALICE, type(RevertingContract).runtimeCode);
// End auction
vm.warp(block.timestamp + 16 minutes);
// Settle auction - this will result in failed transfer to Alice
// But the auction still settles and NFT is transferred
vm.prank(CHARLIE);
market.settleAuction(tokenId);
// Alice should have failed transfer credits
uint256 aliceCredits = market.failedTransferCredits(ALICE);
assertGt(aliceCredits, 0, "Alice should have failed transfer credits");
// NFT was still transferred to Bob despite Alice not receiving payment
assertEq(nft.ownerOf(tokenId), BOB, "Bob should own NFT");
}

Recommended Mitigation

+ function _isContract(address account) internal view returns (bool) {
+ return account.code.length > 0;
+ }
+
+ function _canReceiveEther(address recipient) internal view returns (bool) {
+ if (!_isContract(recipient)) return true;
+ // Additional checks for contract compatibility could be added
+ return true; // Simplified check
+ }
function settleAuction(uint256 tokenId) external isListed(tokenId) {
+ require(_canReceiveEther(listings[tokenId].seller), "Seller cannot receive ETH");
// ... rest of function
}
Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.