Skip to content

Instantly share code, notes, and snippets.

@aLIEzsss4
Created September 6, 2022 04:44
Show Gist options
  • Save aLIEzsss4/7d81ae3bc81f1a0e10f0457472710c93 to your computer and use it in GitHub Desktop.
Save aLIEzsss4/7d81ae3bc81f1a0e10f0457472710c93 to your computer and use it in GitHub Desktop.
market
// 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