Skip to content

Latest commit

 

History

History
46 lines (29 loc) · 2.11 KB

M-01.md

File metadata and controls

46 lines (29 loc) · 2.11 KB

There is no way to cancel a sale or withdraw ETH unless all NFTs are sold

The FixedPrice contract implements a sale type with a fixed price and a fixed number of NFTs to be sold from the given edition.

The contract will require that all tokens are sold and minted before ETH coming from existing sales can be withdrawn.

Impact

Unless all token ids from the given NFT edition configured during sale creation (sale.finalId - sale.currentId) are sold, all ETH coming from existing sales won't be able to be withdrawn.

This means that, in the worst case, if all but one token is sold, then all ETH from existing sales will be locked in the contract and won't be able to be distributed among the beneficiaries (sale receiver and fee receiver).

PoC

Once the sale has started (block timestamp is after sale start time) the only way to end a sale and take the ETH out is when the last NFT is minted.

This happens in line 73 of the FixedPrice contract:

https://github.com/code-423n4/2022-12-escher/blob/main/src/minters/FixedPrice.sol#L73

function buy(uint256 _amount) external payable {
    Sale memory sale_ = sale;
    IEscher721 nft = IEscher721(sale_.edition);
    require(block.timestamp >= sale_.startTime, "TOO SOON");
    require(_amount * sale_.price == msg.value, "WRONG PRICE");
    uint48 newId = uint48(_amount) + sale_.currentId;
    require(newId <= sale_.finalId, "TOO MANY");

    for (uint48 x = sale_.currentId + 1; x <= newId; x++) {
        nft.mint(msg.sender, x);
    }

    sale.currentId = newId;

    emit Buy(msg.sender, _amount, msg.value, sale);

    if (newId == sale_.finalId) _end(sale);
}

The statement if (newId == sale_.finalId) _end(sale); will require that all token ids from the sale are minted and sold so that the sale can end and the money can be sent to the involved parties (sale receiver and fee receiver).

Recommendation

Implement a mechanism so that the sale receiver (and the fee receiver too) can withdraw ETH from the existing sales. There shouldn't be a negative impact in doing this since the tokens are already sold (buyer paid the expected price and already minted).