Created
September 6, 2022 04:44
-
-
Save aLIEzsss4/7d81ae3bc81f1a0e10f0457472710c93 to your computer and use it in GitHub Desktop.
market
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.7; | |
import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | |
import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; | |
error PriceNotMet(address nftAddress, uint256 tokenId, uint256 price); | |
error ItemNotForSale(address nftAddress, uint256 tokenId); | |
error NotListed(address nftAddress, uint256 tokenId); | |
error AlreadyListed(address nftAddress, uint256 tokenId); | |
error NoProceeds(); | |
error NotOwner(); | |
error NotApprovedForMarketplace(); | |
error PriceMustBeAboveZero(); | |
contract NftMarketplace is ReentrancyGuard { | |
struct Listing { | |
uint256 price; | |
address seller; | |
} | |
event ItemListed( | |
address indexed seller, | |
address indexed nftAddress, | |
uint256 indexed tokenId, | |
uint256 price | |
); | |
event ItemCanceled( | |
address indexed seller, | |
address indexed nftAddress, | |
uint256 indexed tokenId | |
); | |
event ItemBought( | |
address indexed buyer, | |
address indexed nftAddress, | |
uint256 indexed tokenId, | |
uint256 price | |
); | |
mapping(address => mapping(uint256 => Listing)) public s_listings; | |
mapping(address => mapping(uint256 => uint256)) public allList; | |
modifier notListed( | |
address nftAddress, | |
uint256 tokenId, | |
address owner | |
) { | |
Listing memory listing = s_listings[nftAddress][tokenId]; | |
if (listing.price > 0) { | |
revert AlreadyListed(nftAddress, tokenId); | |
} | |
_; | |
} | |
modifier isListed(address nftAddress, uint256 tokenId) { | |
Listing memory listing = s_listings[nftAddress][tokenId]; | |
if (listing.price <= 0) { | |
revert NotListed(nftAddress, tokenId); | |
} | |
_; | |
} | |
modifier isOwner( | |
address nftAddress, | |
uint256 tokenId, | |
address spender | |
) { | |
IERC721 nft = IERC721(nftAddress); | |
address owner = nft.ownerOf(tokenId); | |
if (spender != owner) { | |
revert NotOwner(); | |
} | |
_; | |
} | |
///////////////////// | |
// Main Functions // | |
///////////////////// | |
/* | |
* @notice Method for listing NFT | |
* @param nftAddress Address of NFT contract | |
* @param tokenId Token ID of NFT | |
* @param price sale price for each item | |
*/ | |
function listItem( | |
address nftAddress, | |
uint256 tokenId, | |
uint256 price | |
) | |
external | |
notListed(nftAddress, tokenId, msg.sender) | |
isOwner(nftAddress, tokenId, msg.sender) | |
{ | |
if (price <= 0) { | |
revert PriceMustBeAboveZero(); | |
} | |
IERC721 nft = IERC721(nftAddress); | |
if(nft.isApprovedForAll(msg.sender,nftAddress)){ | |
revert NotApprovedForMarketplace(); | |
} | |
s_listings[nftAddress][tokenId] = Listing(price, msg.sender); | |
allList[nftAddress][tokenId]=price; | |
emit ItemListed(msg.sender, nftAddress, tokenId, price); | |
} | |
/* | |
* @notice Method for cancelling listing | |
* @param nftAddress Address of NFT contract | |
* @param tokenId Token ID of NFT | |
*/ | |
function cancelListing(address nftAddress, uint256 tokenId) | |
external | |
isOwner(nftAddress, tokenId, msg.sender) | |
isListed(nftAddress, tokenId) | |
{ | |
delete (s_listings[nftAddress][tokenId]); | |
delete (allList[nftAddress][tokenId]); | |
emit ItemCanceled(msg.sender, nftAddress, tokenId); | |
} | |
/* | |
* @notice Method for buying listing | |
* @notice The owner of an NFT could unapprove the marketplace, | |
* which would cause this function to fail | |
* Ideally you'd also have a `createOffer` functionality. | |
* @param nftAddress Address of NFT contract | |
* @param tokenId Token ID of NFT | |
*/ | |
function buyItem(address nftAddress, uint256 tokenId) | |
external | |
payable | |
isListed(nftAddress, tokenId) | |
nonReentrant | |
{ | |
Listing memory listedItem = s_listings[nftAddress][tokenId]; | |
if (msg.value < listedItem.price) { | |
revert PriceNotMet(nftAddress, tokenId, listedItem.price); | |
} | |
address seller = listedItem.seller; | |
delete (s_listings[nftAddress][tokenId]); | |
delete (allList[nftAddress][tokenId]); | |
IERC721(nftAddress).safeTransferFrom(listedItem.seller, msg.sender, tokenId); | |
payable(seller).transfer(msg.value); | |
emit ItemBought(msg.sender, nftAddress, tokenId, listedItem.price); | |
} | |
/* | |
* @notice Method for updating listing | |
* @param nftAddress Address of NFT contract | |
* @param tokenId Token ID of NFT | |
* @param newPrice Price in Wei of the item | |
*/ | |
function updateListing( | |
address nftAddress, | |
uint256 tokenId, | |
uint256 newPrice | |
) | |
external | |
isListed(nftAddress, tokenId) | |
nonReentrant | |
isOwner(nftAddress, tokenId, msg.sender) | |
{ | |
//We should check the value of `newPrice` and revert if it's below zero (like we also check in `listItem()`) | |
if (newPrice <= 0) { | |
revert PriceMustBeAboveZero(); | |
} | |
s_listings[nftAddress][tokenId].price = newPrice; | |
allList[nftAddress][tokenId] = newPrice; | |
emit ItemListed(msg.sender, nftAddress, tokenId, newPrice); | |
} | |
///////////////////// | |
// Getter Functions // | |
///////////////////// | |
function getListing(address nftAddress, uint256 tokenId) | |
external | |
view | |
returns (Listing memory) | |
{ | |
return s_listings[nftAddress][tokenId]; | |
} | |
// function getAllListing(address nftAddress) | |
// external | |
// view | |
// returns () | |
// { | |
// return allList[nftAddress]; | |
// } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment