becrypto/contracts/market/BENftMarket.sol
2023-01-10 17:08:05 +08:00

300 lines
8.4 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract BENFTMarket is Ownable, ReentrancyGuard, ERC1155Holder,ERC721Holder {
using SafeERC20 for IERC20;
struct OrderInfo {
uint256 orderId;
uint256 tokenId;
uint256 amount;
address owner;
uint256 price;
address nftToken;
address currency;
}
mapping(address => bool) public erc721Supported;
mapping(address => bool) public erc1155Supported;
mapping(address => bool) public erc20Supported;
mapping(uint256 => OrderInfo) public orderInfos;
mapping(address => uint256) public nftPriceMaxLimit;
mapping(address => uint256) public nftPriceMinLimit;
event SellOrder(
uint256 indexed tokenId,
address indexed owner,
address indexed nftToken,
uint256 amount,
uint256 orderId,
address currency,
uint256 price
);
event CancelOrder(
uint256 indexed orderId,
address indexed nftToken,
uint256 indexed tokenId
);
event PriceUpdate(
uint256 indexed orderId,
address indexed nftToken,
uint256 indexed tokenId,
uint256 priceOld,
uint256 price
);
event BuyOrder(
uint256 indexed tokenId,
uint256 orderId,
address nftToken,
uint256 amount,
address seller,
address buyer,
address erc20,
uint256 price
);
event AddNFTSuppout(address nftToken);
event RemoveNFTSuppout(address nftToken);
event AddERC20Suppout(address erc20);
event RemoveERC20Suppout(address erc20);
uint256 public tranFeeTotal;
uint256 constant ROUND = 1000000;
uint256 public transactionFee = (3 * ROUND) / 100;
// min transaction fee is: 0.5%
uint256 public constant MIN_TRANSACTION_FEE = (5 * ROUND) / 1000;
// max transaction fee is: 10%
uint256 public constant MAX_TRANSACTION_FEE = (10 * ROUND) / 100;
address public feeToAddress;
uint256 public incrId;
function sell(
address nftToken,
address currency,
uint256 tokenId,
uint256 price,
uint256 amount
) external {
require(tokenId != 0, "NFTMarket: tokenId can not be 0!");
require(
erc721Supported[nftToken] || erc1155Supported[nftToken],
"NFTMarket: Unsupported NFT"
);
require(erc20Supported[currency], "NFTMarket: Unsupported tokens");
require(
price <= nftPriceMaxLimit[nftToken] || nftPriceMaxLimit[nftToken] == 0,
"NFTMarket: Maximum price limit exceeded"
);
require(
price >= nftPriceMinLimit[nftToken] && price != 0,
"NFTMarket: Below the minimum price limit"
);
incrId += 1;
OrderInfo storage orderInfo = orderInfos[incrId];
orderInfo.orderId = incrId;
orderInfo.tokenId = tokenId;
orderInfo.amount = amount;
orderInfo.nftToken = nftToken;
orderInfo.owner = msg.sender;
orderInfo.price = price;
orderInfo.currency = currency;
if (erc721Supported[nftToken]) {
require(amount == 1, "NFTMarket: ERC721 amount must be 1 ");
IERC721(nftToken).safeTransferFrom(msg.sender, address(this), tokenId);
} else if (erc1155Supported[nftToken]) {
IERC1155(nftToken).safeTransferFrom(
msg.sender,
address(this),
tokenId,
amount,
""
);
}
emit SellOrder(
tokenId,
msg.sender,
nftToken,
amount,
incrId,
currency,
price
);
}
function buy(uint256 orderId) external nonReentrant {
OrderInfo memory orderInfo = orderInfos[orderId];
require(orderInfo.tokenId != 0, "NFTMarket: NFT does not exist");
uint256 _transactionFee = (orderInfo.price * transactionFee) / ROUND;
tranFeeTotal = tranFeeTotal + _transactionFee;
uint256 _amount = orderInfo.price - _transactionFee;
IERC20(orderInfo.currency).safeTransferFrom(
msg.sender,
orderInfo.owner,
_amount
);
IERC20(orderInfo.currency).safeTransferFrom(
msg.sender,
feeToAddress,
_transactionFee
);
if (erc721Supported[orderInfo.nftToken]) {
IERC721(orderInfo.nftToken).safeTransferFrom(
address(this),
msg.sender,
orderInfo.tokenId
);
} else if (erc1155Supported[orderInfo.nftToken]) {
IERC1155(orderInfo.nftToken).safeTransferFrom(
address(this),
msg.sender,
orderInfo.tokenId,
orderInfo.amount,
""
);
}
emit BuyOrder(
orderInfo.tokenId,
orderId,
orderInfo.nftToken,
orderInfo.amount,
orderInfo.owner,
msg.sender,
orderInfo.currency,
orderInfo.price
);
delete orderInfos[orderId];
}
function cancelOrder(uint256 orderId) external nonReentrant {
require(
orderInfos[orderId].owner == msg.sender,
"NFTMarket: cancel caller is not owner"
);
OrderInfo memory orderInfo = orderInfos[orderId];
if (erc721Supported[orderInfo.nftToken]) {
IERC721(orderInfo.nftToken).safeTransferFrom(
address(this),
msg.sender,
orderInfo.tokenId
);
} else if (erc1155Supported[orderInfo.nftToken]) {
IERC1155(orderInfo.nftToken).safeTransferFrom(
address(this),
msg.sender,
orderInfo.tokenId,
orderInfo.amount,
""
);
}
delete orderInfos[orderId];
emit CancelOrder(orderId, orderInfo.nftToken, orderInfo.tokenId);
}
function updatePrice(uint256 orderId, uint256 price) external {
OrderInfo memory orderInfo = orderInfos[orderId];
require(orderInfo.tokenId != 0, "NFTMarket: NFT does not exist");
require(orderInfo.owner == msg.sender, "NFTMarket: caller is not owner");
require(
price <= nftPriceMaxLimit[orderInfo.nftToken] || nftPriceMaxLimit[orderInfo.nftToken] == 0,
"NFTMarket: Maximum price limit exceeded"
);
require(
price >= nftPriceMinLimit[orderInfo.nftToken] && price != 0,
"NFTMarket: Below the minimum price limit"
);
uint256 priceOld = orderInfo.price;
orderInfo.price = price;
emit PriceUpdate(orderId, orderInfo.nftToken, orderInfo.tokenId, priceOld, price);
}
function addERC721Support(address nftToken) external onlyOwner {
erc721Supported[nftToken] = true;
emit AddNFTSuppout(nftToken);
}
function removeERC721Support(address nftToken) external onlyOwner {
erc721Supported[nftToken] = false;
emit RemoveNFTSuppout(nftToken);
}
function addERC1155Support(address nftToken) external onlyOwner {
erc1155Supported[nftToken] = true;
emit AddNFTSuppout(nftToken);
}
function removeERC1155Support(address nftToken) external onlyOwner {
erc1155Supported[nftToken] = false;
emit RemoveNFTSuppout(nftToken);
}
function addERC20Support(address erc20) external onlyOwner {
require(erc20 != address(0), "NFTMarket: ERC20 address is zero");
erc20Supported[erc20] = true;
emit AddERC20Suppout(erc20);
}
function removeERC20Support(address erc20) external onlyOwner {
erc20Supported[erc20] = false;
emit RemoveERC20Suppout(erc20);
}
function setNFTPriceMaxLimit(address nftToken, uint256 maxLimit)
external
onlyOwner
{
require(
maxLimit >= nftPriceMinLimit[nftToken],
"NFTMarket: maxLimit can not be less than min limit!"
);
nftPriceMaxLimit[nftToken] = maxLimit;
}
function setNFTPriceMinLimit(address nftToken, uint256 minLimit)
external
onlyOwner
{
if (nftPriceMaxLimit[nftToken] != 0) {
require(
minLimit <= nftPriceMaxLimit[nftToken],
"NFTMarket: minLimit can not be larger than max limit!"
);
}
nftPriceMinLimit[nftToken] = minLimit;
}
function setTransactionFee(uint256 _transactionFee) external onlyOwner {
require(
_transactionFee >= MIN_TRANSACTION_FEE &&
_transactionFee <= MAX_TRANSACTION_FEE,
"NFTMarket: _transactionFee must >= 0.5% and <= 10%"
);
transactionFee = _transactionFee;
}
function setFeeToAddress(address _feeToAddress) external onlyOwner {
require(_feeToAddress != address(0), "NFTMarket: fee received address can not be zero");
feeToAddress = _feeToAddress;
}
}