|
// 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); |
|
} |
|
} |
|
} |