Skip to content

Instantly share code, notes, and snippets.

@tunnckoCore
Last active August 29, 2022 23:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tunnckoCore/c1704dcd04c695802b7ee084bd74452f to your computer and use it in GitHub Desktop.
Save tunnckoCore/c1704dcd04c695802b7ee084bd74452f to your computer and use it in GitHub Desktop.
Perpetual NFT Marketplace, with increasing token price - cannot list it for less than the last sale + 20% (configurable)

Fancy Perpetual Non-Custodial Marketplace

  • NFT token is always listed, even after sale (just the owner is changed)
  • the marketplace contract IS NOT holding/owning the listed NFT token
  • after sale, the price of the token is increased by sale price + 20%, so the new owner doesn't need to list it
  • if the new owner doesn't want that behavior, it should cancel the order
  • the new owner cannot update the price to be lower than the sale price +20%
  • the new owner can update the price to be higher than the sale price +20%
  • only a new owner of the token can update the price to be lower
  • listing price cannot be lower than general floor price which increases after each sale
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
interface IERC721 {
function ownerOf(uint256 tokenId) external view returns (address owner);
function transferFrom(address from, address to, uint256 tokenId) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
contract Marketplace {
mapping(IERC721 => mapping(uint256 => uint256)) public orders;
mapping(IERC721 => mapping(uint256 => address)) public sellers;
function createOrder(IERC721 nftContract, uint256 tokenId, uint256 price) public {
require(IERC721(nftContract).ownerOf(tokenId) == msg.sender, "BasicMarketplace: not owner of token");
require(IERC721(nftContract).isApprovedForAll(msg.sender, address(this)), "approve the marketplace contract first");
if (price != 0) {
require(price > orders[nftContract][tokenId], "new price must be higher than current order price");
}
orders[nftContract][tokenId] = price;
sellers[nftContract][tokenId] = msg.sender;
}
function bulkList(IERC721 nftContract, uint256[] memory tokenIds, uint256[] memory prices) public {
require(IERC721(nftContract).isApprovedForAll(msg.sender, address(this)), "approve the marketplace contract first");
for(uint i=0; i< tokenIds.length; i++) {
uint256 id = tokenIds[i];
uint256 price = prices[i];
require(IERC721(nftContract).ownerOf(id) == msg.sender, "BasicMarketplace: not owner of token");
if (price != 0) {
require(price > orders[nftContract][id], "new price must be higher than current order price");
}
orders[nftContract][id] = price;
sellers[nftContract][id] = msg.sender;
}
}
function fulfillOrder(IERC721 nftContract, uint256 tokenId) external payable {
require(IERC721(nftContract).ownerOf(tokenId) != msg.sender, "owner of token");
uint256 price = orders[nftContract][tokenId];
address seller = sellers[nftContract][tokenId];
require(price != 0, "no opened order for this token");
require(seller != address(0), "no seller for this token");
require(seller != msg.sender, "cannot sell to yourself");
require(price == msg.value, "invalid ask price");
orders[nftContract][tokenId] = price + (price / 4);
sellers[nftContract][tokenId] = msg.sender;
// transfer the nft to the buyer
IERC721(nftContract).transferFrom(seller, msg.sender, tokenId);
// transfer ETH from the sender/contract to the seller
payable(seller).transfer(price);
}
function sweepOrders(IERC721 nftContract, uint256[] memory tokenIds) external payable {
uint256 sweepPrice = 0;
for(uint i=0; i< tokenIds.length; i++) {
sweepPrice += orders[nftContract][tokenIds[i]];
}
require(sweepPrice == msg.value, "not enough funds for sweep");
for(uint i=0; i< tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
require(IERC721(nftContract).ownerOf(tokenId) != msg.sender, "owner of token");
uint256 price = orders[nftContract][tokenId];
address seller = sellers[nftContract][tokenId];
require(price != 0, "no opened order for this token");
require(seller != address(0), "no seller for this token");
require(seller != msg.sender, "cannot sell to yourself");
// require(price == msg.value, "invalid ask price");
orders[nftContract][tokenId] = price + (price / 4);
sellers[nftContract][tokenId] = msg.sender;
// transfer the nft to the buyer
IERC721(nftContract).transferFrom(seller, msg.sender, tokenId);
payable(seller).transfer(price);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment