Skip to content
Contract · NFT

Auction

English auction with minimum bid increments, automatic refunds and settlement.

All templates
NFT
~1.6M gas
Ethereum
Post-deploy checklist
  1. Confirm NFT contract + tokenId exist and are owned by the seller
  2. Approve the auction contract to transfer the NFT
  3. Verify start price and min increment (wei, not ETH UI units)
  4. After end, settle so winner receives the NFT and seller receives ETH
Configure & deploy

ERC721 contract that holds the asset being auctioned.

The specific NFT id. Must be owned by the account that will transfer/approve the auction.

Opening bid in wei (1e17 = 0.1 ETH). Use the Unit Converter tool for ETH → wei.

Auction length from deploy/start. 86400 = 24 hours.

Minimum amount a new bid must exceed the current bid by.

Use cases
  • Art auctions
  • 1-of-1 NFT sales
  • Charity bidding
EnglishAuction.solsolidity
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0 (Wizard / Contracts MCP patterns)
// Compiled with Solidity ^0.8.24 — Ethereum Toolset browser solc
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract EnglishAuction is ReentrancyGuard {
    IERC721 public immutable nft;
    uint256 public immutable tokenId;
    address public immutable seller;
    uint64 public immutable endsAt;
    uint256 public immutable minIncrement;

    address public highestBidder;
    uint256 public highestBid;
    bool public settled;
    mapping(address => uint256) public refunds;

    constructor(IERC721 _nft, uint256 _tokenId, uint256 _start, uint64 _duration, uint256 _minIncrement) {
        nft = _nft; tokenId = _tokenId; seller = msg.sender;
        highestBid = _start; endsAt = uint64(block.timestamp) + _duration; minIncrement = _minIncrement;
    }

    function bid() external payable {
        require(block.timestamp < endsAt, "ended");
        require(msg.value >= highestBid + minIncrement, "bid too low");
        if (highestBidder != address(0)) refunds[highestBidder] += highestBid;
        highestBidder = msg.sender;
        highestBid = msg.value;
    }

    function withdraw() external nonReentrant {
        uint256 amt = refunds[msg.sender];
        refunds[msg.sender] = 0;
        payable(msg.sender).transfer(amt);
    }

    function settle() external nonReentrant {
        require(block.timestamp >= endsAt && !settled, "not ready");
        settled = true;
        if (highestBidder == address(0)) {
            nft.safeTransferFrom(address(this), seller, tokenId);
        } else {
            payable(seller).transfer(highestBid);
            nft.safeTransferFrom(address(this), highestBidder, tokenId);
        }
    }
}