Phrase Trade NFT Marketplace
Overview
The PhraseTradeNFTMarketplace is a Solidity smart contract that implements a decentralized marketplace for trading Non-Fungible Tokens (NFTs). This contract allows users to list their NFTs for sale, buy listed NFTs, and delist their own NFTs. It supports payments in both Ether (ETH) and ERC-20 tokens.
Contract Details
License: BSUL
Solidity Version: ^0.8.0
Inherits From:
Ownable: Provides basic authorization control functionsIPhraseTradeNFTMarketplace: Interface defining the contract's structure
Key Structures
Listing
struct Listing {
address seller;
address paymentToken;
uint256 price;
}seller: Address of the NFT sellerpaymentToken: Address of the token to be used for payment (0x0 for ETH)price: Price of the NFT in the specified payment token
State Variables
listings
mapping(address => mapping(uint256 => Listing)) public listings;A nested mapping that stores NFT listings. The first key is the NFT contract address, the second key is the token ID, and the value is the Listing struct.
Functions
listNFT
function listNFT(
address nftContract,
uint256 tokenId,
address paymentToken,
uint256 price
) externalLists an NFT for sale.
Parameters:
nftContract: Address of the NFT contracttokenId: ID of the NFTpaymentToken: Address of the token to be used for payment (0x0 for ETH)price: Price of the NFT in the specified payment token
Functionality:
Transfers the NFT from the seller to the contract
Creates a new
Listingand stores it in thelistingsmappingEmits an
NFTListedevent
Security Considerations:
Ensure that the contract has approval to transfer the NFT before calling this function
buyNFT
function buyNFT(address nftContract, uint256 tokenId) external payableAllows a user to purchase a listed NFT.
Parameters:
nftContract: Address of the NFT contracttokenId: ID of the NFT
Functionality:
Retrieves the listing information
Handles payment in ETH or ERC-20 tokens
Transfers the NFT to the buyer
Deletes the listing
Emits an
NFTSoldevent
Security Considerations:
Checks if the NFT is listed for sale
Ensures sufficient payment is sent for ETH transactions
Uses the
transferFromfunction for ERC-20 payments, requiring prior approval
delistNFT
function delistNFT(address nftContract, uint256 tokenId) externalAllows the seller to remove their NFT from the marketplace.
Parameters:
nftContract: Address of the NFT contracttokenId: ID of the NFT
Functionality:
Verifies that the caller is the seller
Transfers the NFT back to the seller
Deletes the listing
Emits an
NFTDelistedevent
Security Considerations:
Only the original seller can delist the NFT
withdrawETH
function withdrawETH(uint256 amount) external onlyOwnerAllows the contract owner to withdraw ETH from the contract.
Parameters:
amount: Amount of ETH to withdraw
Security Considerations:
Only the contract owner can call this function
Checks if the contract has sufficient balance before withdrawal
withdrawERC20
function withdrawERC20(address token, uint256 amount) external onlyOwnerAllows the contract owner to withdraw ERC-20 tokens from the contract.
Parameters:
token: Address of the ERC-20 tokenamount: Amount of tokens to withdraw
Security Considerations:
Only the contract owner can call this function
Assumes the contract has sufficient token balance
Events
The contract emits the following events:
NFTListed: When an NFT is listed for saleNFTSold: When an NFT is soldNFTDelisted: When an NFT is delisted
Usage Examples
Listing an NFT for sale
// Assume 'nftContract' is the address of your NFT contract
// and 'tokenId' is the ID of your NFT
// First, approve the marketplace contract to transfer your NFT
IERC721(nftContract).approve(marketplaceAddress, tokenId);
// Then, list the NFT for sale
marketplaceContract.listNFT(nftContract, tokenId, address(0), 1 ether);Buying an NFT with ETH
// Assume 'nftContract' and 'tokenId' identify the NFT you want to buy
// Send ETH with the transaction
marketplaceContract.buyNFT{value: 1 ether}(nftContract, tokenId);Buying an NFT with an ERC-20 token
// Assume 'nftContract' and 'tokenId' identify the NFT you want to buy
// and 'erc20TokenAddress' is the address of the payment token
// First, approve the marketplace contract to spend your tokens
IERC20(erc20TokenAddress).approve(marketplaceAddress, 1000);
// Then, buy the NFT
marketplaceContract.buyNFT(nftContract, tokenId);Security Considerations
Reentrancy: The contract uses the "checks-effects-interactions" pattern to prevent reentrancy attacks.
Access Control: The
Ownablecontract is used to restrict access to sensitive functions.Input Validation: The contract checks for valid inputs and sufficient payments.
Token Approvals: Users must approve the contract to transfer their NFTs and ERC-20 tokens before listing or buying.
ETH Handling: The contract uses
transferfor sending ETH, which has a gas stipend and can fail silently.
Gas Optimization
The contract uses
deleteto remove listings, which can save gas by clearing storage.It uses
_msgSender()instead ofmsg.sender, which is more flexible for potential future upgrades.
Best Practices
The contract follows the Checks-Effects-Interactions pattern for better security.
It uses OpenZeppelin's
Ownablecontract for standardized ownership management.The contract emits events for important state changes, allowing for off-chain tracking.
It supports both ETH and ERC-20 token payments, increasing flexibility for users.
Potential Improvements
Implement a fee system for the marketplace.
Add functionality to update listing prices.
Implement batch listing and buying functions for gas efficiency.
Add a mechanism to pause the contract in case of emergencies.
Last updated