Skip to content
Contract · NFT

NFT Marketplace

List, buy and cancel NFT offers with EIP-2981 royalty enforcement.

All templates
NFT
~2.2M gas
Ethereum
Post-deploy checklist
  1. Deploy (or select) an ERC721 that implements ERC2981 if you need royalties
  2. Verify marketplace source so traders can audit fee paths
  3. Approve the marketplace on each NFT before listing
  4. Smoke-test list → buy → cancel on a testnet
Configure & deploy

No constructor fields

This marketplace deploys with an empty constructor. Configure listings, fees, and NFT approvals after deploy — there is nothing to fill in on this form by design.

Use cases
  • Simple in-app NFT marketplace
  • Royalty-enforced secondary sales
  • Gated community marketplace
NFTMarketplace.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/interfaces/IERC2981.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

// Minimal on-chain NFT listing marketplace with EIP-2981 royalty payout.
contract NFTMarketplace is ReentrancyGuard {
    struct Listing { address seller; uint256 price; }
    mapping(address => mapping(uint256 => Listing)) public listings;

    event Listed(address indexed nft, uint256 indexed id, address seller, uint256 price);
    event Sold(address indexed nft, uint256 indexed id, address buyer, uint256 price);
    event Cancelled(address indexed nft, uint256 indexed id);

    function list(address nft, uint256 id, uint256 price) external {
        require(price > 0, "price=0");
        require(IERC721(nft).ownerOf(id) == msg.sender, "not owner");
        require(IERC721(nft).getApproved(id) == address(this) || IERC721(nft).isApprovedForAll(msg.sender, address(this)), "approve first");
        listings[nft][id] = Listing(msg.sender, price);
        emit Listed(nft, id, msg.sender, price);
    }

    function cancel(address nft, uint256 id) external {
        require(listings[nft][id].seller == msg.sender, "not seller");
        delete listings[nft][id];
        emit Cancelled(nft, id);
    }

    function buy(address nft, uint256 id) external payable nonReentrant {
        Listing memory l = listings[nft][id];
        require(l.seller != address(0), "not listed");
        require(msg.value == l.price, "bad price");
        delete listings[nft][id];

        // pay royalty if supported
        uint256 sellerAmount = msg.value;
        try IERC2981(nft).royaltyInfo(id, msg.value) returns (address rcv, uint256 royalty) {
            if (royalty > 0 && rcv != address(0)) {
                sellerAmount -= royalty;
                payable(rcv).transfer(royalty);
            }
        } catch {}

        payable(l.seller).transfer(sellerAmount);
        IERC721(nft).safeTransferFrom(l.seller, msg.sender, id);
        emit Sold(nft, id, msg.sender, msg.value);
    }
}