A decentralized marketplace for ERC-721 NFTs built with Solidity, OpenZeppelin, and Foundry.
The marketplace enables NFT owners to list their assets for sale, buyers to purchase listed NFTs, and sellers to cancel active listings in a secure, trustless manner.
- ERC-721 Marketplace
- List NFTs for sale
- Buy listed NFTs
- Cancel active listings
- Ownership validation
- Marketplace approval verification
- Secure NFT transfers
- Event emission for marketplace actions
- Comprehensive unit testing with Foundry
┌─────────────────────────┐
│ NFT Owner │
└──────────┬──────────────┘
│ approve()
▼
┌─────────────────────────┐
│ ERC721 Collection │
└──────────┬──────────────┘
│
│ transferFrom()
▼
┌────────────────────────────────┐
│ NFT Marketplace │
│────────────────────────────────│
│ │
│ Listing[] │
│ │
│ • seller │
│ • nftAddress │
│ • tokenId │
│ • price │
│ │
└───────┬─────────────┬──────────┘
│ │
listNFT() │ │ buyNFT()
│ │
▼ ▼
Listing Stored ETH Payment
│ │
└──────┬──────┘
▼
NFT transferred to buyer
Seller
│
│
├── Mint NFT
│
├── Approve Marketplace
│
├── List NFT
│
▼
Marketplace
│
├── Validate owner
├── Validate approval
├── Store listing
│
▼
Buyer
│
├── Buy NFT
│
▼
Marketplace
│
├── Validate payment
├── Transfer NFT
├── Transfer ETH
├── Remove listing
│
▼
Transaction Completed
.
├── src/
│ ├── NFTMarketplace.sol
├── test/
│ └── NFTMarketplace.t.sol
├── lib/
├── foundry.toml
└── README.md
- Solidity
- Foundry
- Forge
- Anvil
- Cast
- OpenZeppelin ERC721
struct Listing {
address seller;
address nftAddress;
uint256 tokenId;
uint256 price;
}The marketplace stores all active NFT listings using this structure.
Lists an NFT for sale.
Requirements
- Caller must own the NFT
- Marketplace must be approved
- Price must be greater than zero
- NFT cannot already be listed
Example
listNFT(
nftAddress,
tokenId,
price
);Purchases a listed NFT.
Requirements
- Listing must exist
- Buyer must send enough ETH
- NFT ownership is transferred
- Seller receives payment
- Listing is removed
Example
buyNFT{value: 1 ether}(
nftAddress,
tokenId
);Removes an NFT from sale.
Requirements
- Only the seller can cancel
- Listing must exist
Example
cancelListing(
nftAddress,
tokenId
);event NFTListed(
address indexed seller,
address indexed nftAddress,
uint256 indexed tokenId,
uint256 price
);
event NFTSold(
address indexed buyer,
address indexed nftAddress,
uint256 indexed tokenId,
uint256 price
);
event ListingCancelled(
address indexed seller,
address indexed nftAddress,
uint256 indexed tokenId
);Clone the repository
git clone https://github.com/<username>/nft-marketplace.git
cd nft-marketplaceInstall dependencies
forge installCompile
forge buildRun every test
forge testVerbose output
forge test -vvvvGas report
forge test --gas-reportCoverage
forge coverageStart a local blockchain
anvilDeploy
forge script script/DeployNFTMarketplace.s.sol \
--rpc-url http://127.0.0.1:8545 \
--private-key <PRIVATE_KEY> \
--broadcastThe project includes unit tests for:
- Contract deployment
- NFT listing
- Duplicate listings
- Invalid price
- Owner validation
- Marketplace approval
- Successful purchase
- Incorrect payment
- Seller payment
- NFT ownership transfer
- Cancel listing
- Unauthorized cancellation
- Revert conditions
- Event emission
The marketplace validates:
- NFT ownership
- Marketplace approval
- Existing listings
- Correct payment amount
- Authorized cancellation
- Secure ERC721 transfers
- State updates before external interactions
- Marketplace fees
- Royalties (ERC-2981)
- Offers & bidding
- Auctions
- Collection whitelisting
- Batch listings
- Purchase with ERC20
- Signature-based listings
- Upgradeable contracts
- EIP-712 support
- Off-chain order book
Build
forge buildRun tests
forge testGas report
forge test --gas-reportCoverage
forge coverageFormat
forge fmtClean artifacts
forge cleanStart local node
anvilInteract with contracts
castDistributed under the MIT License.
- OpenZeppelin Contracts
- Foundry
- Ethereum Foundation