Skip to content

Kazopl/nft-marketplace-signatures

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

14 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NFT Collection + Marketplace (EIP-712 Orderbook)

License: MIT Solidity

A decentralized NFT marketplace with off-chain EIP-712 signed listings, ERC-2981 royalty support, and comprehensive security features. Built with Foundry.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         ORDER LIFECYCLE                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  SELLER                           OFF-CHAIN                          BUYER
    β”‚                                  β”‚                                β”‚
    β”‚  1. Create Listing               β”‚                                β”‚
    β”‚  ─────────────────►              β”‚                                β”‚
    β”‚                                  β”‚                                β”‚
    β”‚  2. Sign EIP-712 TypedData       β”‚                                β”‚
    β”‚  ◄─────────────────              β”‚                                β”‚
    β”‚                                  β”‚                                β”‚
    β”‚  3. Publish Listing + Signature  β”‚                                β”‚
    β”‚  ─────────────────────────────►  β”‚                                β”‚
    β”‚                                  β”‚                                β”‚
    β”‚                                  β”‚  4. Browse Listings            β”‚
    β”‚                                  β”‚  ◄─────────────────────────────│
    β”‚                                  β”‚                                β”‚
    β”‚                                  β”‚  5. Select Listing             β”‚
    β”‚                                  β”‚  ─────────────────────────────►│
    β”‚                                  β”‚                                β”‚
    β”‚                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                   β”‚
    β”‚                     β”‚      ON-CHAIN           β”‚                   β”‚
    β”‚                     β”‚   fulfillListing()      β”‚                   β”‚
    β”‚                     β”‚                         β”‚                   β”‚
    β”‚                     β”‚  6. Verify Signature    │◄──────────────────│
    β”‚                     β”‚  7. Check Expiration    β”‚                   β”‚
    β”‚                     β”‚  8. Transfer NFT        β”‚                   β”‚
    β”‚                     β”‚  9. Distribute Funds    β”‚                   β”‚
    β”‚                     β”‚     - Platform Fee      β”‚                   β”‚
    β”‚                     β”‚     - Royalty (ERC2981) β”‚                   β”‚
    β”‚                     β”‚     - Seller Proceeds   β”‚                   β”‚
    β”‚                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚
    β”‚                                  β”‚                                β”‚
    β”‚  10. Receive Payment             β”‚                                β”‚
    β”‚  ◄───────────────────────────────│                                β”‚
    β”‚                                  β”‚      11. Receive NFT           β”‚
    β”‚                                  │────────────────────────────────►


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         SYSTEM COMPONENTS                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    NFTCollection     β”‚         β”‚             NFTMarketplace              β”‚
β”‚      (ERC-721)       β”‚         β”‚                                         β”‚
β”‚                      β”‚         β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β€’ Enumerable        │◄───────►│  β”‚       EIP-712 Signatures         β”‚   β”‚
β”‚  β€’ ERC-2981 Royalty  β”‚  NFT    β”‚  β”‚  β€’ Domain Separator              β”‚   β”‚
β”‚  β€’ URI Storage       β”‚ Transferβ”‚  β”‚  β€’ Listing TypeHash              β”‚   β”‚
β”‚  β€’ Mint Controls     β”‚         β”‚  β”‚  β€’ Offer TypeHash                β”‚   β”‚
β”‚  β€’ Owner Functions   β”‚         β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                      β”‚         β”‚                                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
                                 β”‚  β”‚       Fund Distribution          β”‚   β”‚
                                 β”‚  β”‚  β€’ Platform Fee (max 5%)         β”‚   β”‚
                                 β”‚  β”‚  β€’ ERC-2981 Royalty              β”‚   β”‚
                                 β”‚  β”‚  β€’ Seller Proceeds               β”‚   β”‚
                                 β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                                 β”‚                                         β”‚
                                 β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
                                 β”‚  β”‚       Security Features          β”‚   β”‚
                                 β”‚  β”‚  β€’ Nonce replay protection       β”‚   β”‚
                                 β”‚  β”‚  β€’ Expiration timestamps         β”‚   β”‚
                                 β”‚  β”‚  β€’ Cancellation mapping          β”‚   β”‚
                                 β”‚  β”‚  β€’ ReentrancyGuard               β”‚   β”‚
                                 β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Features

NFTCollection (ERC-721)

  • ERC-721 Enumerable: Easy token discovery and iteration
  • ERC-2981 Royalties: On-chain royalty standard support (max 10%)
  • Configurable Minting: Adjustable price and pausable
  • Batch Minting: Gas-efficient multi-mint for owners
  • URI Storage: Flexible metadata management

NFTMarketplace

  • EIP-712 Typed Signatures: Secure off-chain listing creation
  • Gasless Listings: Sellers sign off-chain, buyers pay gas
  • ERC-2981 Integration: Automatic royalty distribution
  • Platform Fees: Configurable fee (max 5%)
  • Order Cancellation: Sellers can cancel anytime
  • Replay Protection: Nonce and expiration checks

EIP-712 Typed Data Specification

Domain Separator

EIP712Domain {
    string name = "NFTMarketplace"
    string version = "1"
    uint256 chainId
    address verifyingContract
}

Listing Type

Listing {
    address seller       // NFT owner
    address nftContract  // ERC-721 contract
    uint256 tokenId      // Token to sell
    uint256 price        // Price in wei
    uint256 expiration   // Unix timestamp
    uint256 nonce        // Replay protection
}

Offer Type

Offer {
    address buyer        // Offer maker
    address nftContract  // ERC-721 contract
    uint256 tokenId      // Token to buy
    uint256 price        // Offer price in wei
    uint256 expiration   // Unix timestamp
    uint256 nonce        // Replay protection
}

Installation

Prerequisites

Setup

# Clone the repository
git clone https://github.com/Kazopl/nft-marketplace-signatures.git
cd nft-marketplace-signatures

# Install dependencies
forge install OpenZeppelin/[email protected]
forge install foundry-rs/forge-std

# Build
forge build

# Run tests
forge test

Environment Setup

Create a .env file:

PRIVATE_KEY=your_private_key_here
BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
BASESCAN_API_KEY=your_basescan_api_key

Testing

# Run all tests
forge test

# Run with verbosity
forge test -vvv

# Run specific test file
forge test --match-path test/unit/NFTMarketplace.t.sol

# Run fuzz tests
forge test --match-path "test/fuzz/*"

# Run invariant tests
forge test --match-path "test/invariant/*"

# Gas report
forge test --gas-report

# Coverage
forge coverage

Test Categories

Category Description Files
Unit Individual function tests test/unit/*.t.sol
Fuzz Random input testing test/fuzz/*.t.sol
Invariant System property verification test/invariant/*.t.sol

Deployment

Deploy to Base Sepolia

source .env

forge script script/DeployAll.s.sol:DeployAll \
  --rpc-url $BASE_SEPOLIA_RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast \
  --verify \
  --etherscan-api-key $BASESCAN_API_KEY

Post-Deployment

# Mint an NFT
NFT_ADDRESS=0x... forge script script/Interactions.s.sol:MintNFT \
  --rpc-url $BASE_SEPOLIA_RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast

# Check status
NFT_ADDRESS=0x... MARKETPLACE_ADDRESS=0x... forge script \
  script/Interactions.s.sol:CheckStatus \
  --rpc-url $BASE_SEPOLIA_RPC_URL

Security

Threat Model

Threat Mitigation
Signature Replay Nonce tracking per user, expiration timestamps
Cross-Chain Replay EIP-712 domain separator includes chainId
Front-Running Listing fulfillment is atomic, signature bound to price
Reentrancy ReentrancyGuard on all external calls
Royalty Bypass On-chain ERC-2981 check, capped at 10%
Fee Manipulation Platform fee capped at 5%, owner-only updates
NFT Not Owned Ownership check before transfer
Expired Orders Block timestamp validation

Security Assumptions

  1. Sellers must approve marketplace before listing
  2. Signatures are created off-chain and stored securely
  3. Price is denominated in native token (ETH)
  4. Royalty receiver is trusted to accept payments
  5. Platform fee recipient is a valid payable address

Invariants Verified

  1. NFT can only have one owner at any time
  2. Fulfilled listings cannot be fulfilled again
  3. Cancelled listings cannot be fulfilled
  4. Platform fee never exceeds 5%
  5. Total funds distributed equals sale price

Gas Optimization

Function Gas (approx)
mint() ~95,000
fulfillListing() ~120,000
cancelListing() ~45,000
setApprovalForAll() ~46,000

Project Structure

nft-marketplace-signatures/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ NFTCollection.sol        # ERC-721 with royalties
β”‚   β”œβ”€β”€ NFTMarketplace.sol       # Marketplace with EIP-712
β”‚   β”œβ”€β”€ interfaces/
β”‚   β”‚   β”œβ”€β”€ INFTCollection.sol
β”‚   β”‚   └── INFTMarketplace.sol
β”‚   └── libraries/
β”‚       └── OrderTypes.sol       # EIP-712 type definitions
β”œβ”€β”€ test/
β”‚   β”œβ”€β”€ BaseTest.sol             # Shared test setup
β”‚   β”œβ”€β”€ unit/
β”‚   β”‚   β”œβ”€β”€ NFTCollection.t.sol
β”‚   β”‚   └── NFTMarketplace.t.sol
β”‚   β”œβ”€β”€ fuzz/
β”‚   β”‚   └── NFTMarketplaceFuzz.t.sol
β”‚   └── invariant/
β”‚       └── NFTMarketplaceInvariant.t.sol
β”œβ”€β”€ script/
β”‚   β”œβ”€β”€ DeployAll.s.sol
β”‚   └── Interactions.s.sol
β”œβ”€β”€ foundry.toml
└── README.md

License

MIT License - see LICENSE for details.

Acknowledgments

Releases

No releases published

Packages

No packages published