一个常规NFT市场合约代码,支持上架、下架NFT艺术作品,设定价格,购买NFT,配置NFT白名单功能。
一个常规NFT市场合约代码,支持上架、下架NFT艺术作品,设定价格,购买NFT,配置NFT白名单功能。
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
library SafeTransferLib {
// ERC721 & ERC1155 support
function safeTransferFrom (address contractAddress, address from, address to, uint256 tokenID, uint256 amount) internal returns (bool) {
try IERC721(contractAddress).safeTransferFrom(from, to, tokenID) {
return true;
} catch (bytes memory) {
try IERC1155(contractAddress).safeTransferFrom(from, to, tokenID, amount, "0x0") {
return true;
} catch (bytes memory) {
return false;
}
}
}
}
contract LandNFTMarket is ERC721Holder, ERC1155Holder {
using SafeMath for uint;
using SafeERC20 for IERC20;
using Address for address;
struct OnSaleNFT {
uint idx;
address nftAddress;
uint256 tokenId;
address seller;
uint256 price;
uint256 amount;
}
address public creator;
string public logoUrl; // 市场的logo图
string public bannerUrl; // 市场的banner图
address public settleToken; // 用于结算的token
mapping(address => bool) public whitelist; // 只有白名单内的NFT地址可以上架
bool public enableExternal = false;
mapping(address => mapping(uint256 => uint256)) public nftList; // nftAddress => tokenId => idx
mapping(uint256 => OnSaleNFT) public nftBriefList; // idx => tokenData
uint256 public nftCount; // idx 从1开始,只加不减
address private feeTo; // 费用接收地址
event OnSale(address indexed market, address indexed nftAddress, uint, uint);
event OffSale(address indexed market, address indexed nftAddress, uint);
event Buy(address indexed market, address indexed nftAddress, uint, uint);
constructor() {
creator = msg.sender;
}
function setSettleToken(address _settleToken) external returns(bool){
require(msg.sender == creator, 'Error: 9101');
settleToken = _settleToken;
return true;
}
// 设置费用接收地址
function setFeeTo(address _feeTo) external virtual returns(bool){
require(msg.sender == creator, 'Error: 0011');
feeTo = _feeTo;
return true;
}
// 设置市场的banner
function setLogo(string memory _logoUrl) external returns (bool) {
require(msg.sender == creator, 'Error: 9003');
logoUrl = _logoUrl;
return true;
}
// 设置市场的logo
function setBanner(string memory _bannerUrl) external returns (bool) {
require(msg.sender == creator, 'Error: 9004');
bannerUrl = _bannerUrl;
return true;
}
// 允许普通用户上架作品
function enable(bool _flag) external returns (bool) {
require(msg.sender == creator, 'Error: 9005');
enableExternal = _flag;
return true;
}
// 上架作品
function onSale(address _nftAddress, uint256 _tokenId, uint256 _price, uint256 _amount) external returns (bool) {
require(whitelist[_nftAddress] == true, 'Error: 9100');
if(msg.sender != creator){
require(enableExternal, 'Error: 9006');
}
require(nftList[_nftAddress][_tokenId] == 0, 'Error: 9007');
require(_price > 0, 'Error: 9008');
// to market
if(SafeTransferLib.safeTransferFrom(_nftAddress, msg.sender, address(this), _tokenId, _amount)){
// add to onsales
nftCount++;
nftList[_nftAddress][_tokenId] = nftCount;
OnSaleNFT memory nftBrief = OnSaleNFT(nftCount, _nftAddress, _tokenId, msg.sender, _price, _amount);
nftBriefList[nftCount] = nftBrief;
emit OnSale(address(this), _nftAddress, _tokenId, _price);
return true;
}
return false;
}
function _verify(address _nftAddress, uint256 _tokenId) internal view returns(address seller,uint256 price,uint256 amount){
( seller, price, amount) = _getBrief(_nftAddress, _tokenId);
require(nftList[_nftAddress][_tokenId] > 0, 'Error: 9010');
require(price > 0, 'Error: 9011');
require(seller != address(0), 'Error: 9012');
}
// 下架作品
function offSale(uint idx) external returns (bool) {
OnSaleNFT memory nftBrief = nftBriefList[idx];
require(msg.sender == nftBrief.seller || msg.sender == creator, 'Error: 9014');
require(nftBrief.nftAddress != address(0), 'Error: 9015');
require(nftBrief.tokenId > 0, 'Error: 9016');
require(nftBrief.amount > 0, 'Error: 9017');
// to seller
if(SafeTransferLib.safeTransferFrom(nftBrief.nftAddress, address(this), nftBrief.seller, nftBrief.tokenId, nftBrief.amount)){
delete nftBriefList[idx];
delete nftList[nftBrief.nftAddress][nftBrief.tokenId];
emit OffSale(address(this), nftBrief.nftAddress, nftBrief.tokenId);
return true;
}
return false;
}
function _getBrief(address _nftAddress, uint256 _tokenId) private view returns(address seller, uint256 price, uint256 amount){
uint256 idx = nftList[_nftAddress][_tokenId];
OnSaleNFT memory nftBrief = nftBriefList[idx];
(seller, price, amount) = (nftBrief.seller, nftBrief.price, nftBrief.amount);
}
function getBrief(address _nftAddress, uint256 _tokenId) external view returns(address seller, uint256 price, uint256 amount){
return _getBrief(_nftAddress, _tokenId);
}
// 购买作品
function buy(uint idx, uint256 _amount) external returns (bool) {
OnSaleNFT memory nftBrief = nftBriefList[idx];
// check amount
require(nftBrief.amount >= _amount, 'Error: 9015');
require(nftBrief.price > 0, 'Error: 9016');
require(nftBrief.seller != address(0), 'Error: 9012');
require(nftBrief.nftAddress != address(0), 'Error: 9015');
require(nftBrief.tokenId > 0, 'Error: 9016');
uint256 totalPrice = uint(nftBrief.price).mul(_amount);
// to seller
IERC20(settleToken).safeTransferFrom(msg.sender, nftBrief.seller, totalPrice);
// to buyer
if(SafeTransferLib.safeTransferFrom(nftBrief.nftAddress, address(this), msg.sender, nftBrief.tokenId, 1)){
// remove from onsales
// NFT
delete nftBriefList[idx];
delete nftList[nftBrief.nftAddress][nftBrief.tokenId];
emit Buy(address(this), nftBrief.nftAddress, nftBrief.tokenId, totalPrice);
return true;
}
return false;
}
// 分页获取在售作品,每页10个
function getNftList(uint startIdx) external view returns (OnSaleNFT[] memory) {
uint256 counter = 0;
for(uint256 i = 1; i <= nftCount; i++){
if(nftBriefList[i].tokenId > 0){
counter++;
}
}
OnSaleNFT[] memory _lists = new OnSaleNFT[](counter);
if (counter != 0) {
uint256 itemCounter = 0;
for(uint256 i = startIdx + 1; i <= nftCount; i++){
if(nftBriefList[i].tokenId > 0){
_lists[itemCounter] = nftBriefList[i];
itemCounter++;
if(itemCounter >= 10){
break;
}
}
}
}
return _lists;
}
// 获取指定用户出售中的作品
function getNftListBySeller(address seller) external view returns (OnSaleNFT[] memory) {
uint256 counter = 0;
for(uint256 i = 1; i <= nftCount; i++){
if(nftBriefList[i].seller == seller){
counter++;
}
}
OnSaleNFT[] memory _lists = new OnSaleNFT[](counter);
if (counter != 0) {
uint256 itemCounter = 0;
for(uint256 i = 1; i <= nftCount; i++){
if(nftBriefList[i].seller == seller){
_lists[itemCounter] = nftBriefList[i];
itemCounter++;
}
}
}
return _lists;
}
function setNFTWhitelist(address _address, bool _status) external returns(bool){
require(msg.sender == creator, 'Error: 1009');
whitelist[_address] = _status;
return true;
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!