A decentralized NFT marketplace with off-chain EIP-712 signed listings, ERC-2981 royalty support, and comprehensive security features. Built with Foundry.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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 β β
β ββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββ
- 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
- 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
EIP712Domain {
string name = "NFTMarketplace"
string version = "1"
uint256 chainId
address verifyingContract
}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 {
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
}- Foundry
- Git
# 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 testCreate a .env file:
PRIVATE_KEY=your_private_key_here
BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
BASESCAN_API_KEY=your_basescan_api_key# 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| 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 |
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# 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| 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 |
- Sellers must approve marketplace before listing
- Signatures are created off-chain and stored securely
- Price is denominated in native token (ETH)
- Royalty receiver is trusted to accept payments
- Platform fee recipient is a valid payable address
- NFT can only have one owner at any time
- Fulfilled listings cannot be fulfilled again
- Cancelled listings cannot be fulfilled
- Platform fee never exceeds 5%
- Total funds distributed equals sale price
| Function | Gas (approx) |
|---|---|
mint() |
~95,000 |
fulfillListing() |
~120,000 |
cancelListing() |
~45,000 |
setApprovalForAll() |
~46,000 |
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
MIT License - see LICENSE for details.
- OpenZeppelin Contracts
- Foundry
- Cyfrin - Template patterns and best practices
- EIP-712 - Typed structured data hashing
- ERC-2981 - NFT Royalty Standard