becrypto/contracts/market/BENftMall.sol
2023-06-16 12:51:00 +08:00

119 lines
3.5 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../core/HasSignature.sol";
import "../interfaces/IBEERC721.sol";
import "../utils/TimeChecker.sol";
import "./MallBase.sol";
contract BENftMall is MallBase, ReentrancyGuard, HasSignature, TimeChecker {
using SafeERC20 for IERC20;
constructor() HasSignature("NftMall", "1") {}
mapping(address => bool) public nftTokenSupported;
// Events
event BuyTransaction(
address indexed buyer,
uint256 indexed nonce,
uint256 tokenId,
address[3] addresses,
uint256 price
);
function addNFTTokenSupport(address nftToken) external onlyOwner {
nftTokenSupported[nftToken] = true;
}
function removeNFTTokenSupport(address nftToken) external onlyOwner {
nftTokenSupported[nftToken] = false;
}
function ignoreSignature(
address[4] calldata addresses,
uint256[] calldata signArray,
bytes calldata signature
) external signatureValid(signature) {
// address[4] [seller_address,nft_address,payment_token_address, buyer_address]
// uint256[4] [token_id,price,salt_nonce,startTime]
bytes32 criteriaMessageHash = getMessageHash(
addresses[1],
addresses[2],
addresses[3],
signArray
);
checkSigner(_msgSender(), criteriaMessageHash, signature);
_useSignature(signature);
}
/**
* @dev Function matched transaction with user signatures
*/
function buyNFT(
address[3] calldata addresses,
uint256[4] calldata values,
bytes calldata signature
) external nonReentrant signatureValid(signature) timeValid(values[3]) {
// address[3] [seller_address,nft_address,payment_token_address]
// uint256[4] [token_id,price,salt_nonce,startTime]
// bytes seller_signature
require(nftTokenSupported[addresses[1]], "BENftMall: Unsupported NFT");
require(erc20Supported[addresses[2]], "BENftMall: invalid payment method");
address to = _msgSender();
uint256[] memory signArray = new uint256[](values.length);
for (uint256 i = 0; i < values.length; ++i) {
signArray[i] = values[i];
}
bytes32 criteriaMessageHash = getMessageHash(
addresses[1],
addresses[2],
to,
signArray
);
checkSigner(addresses[0], criteriaMessageHash, signature);
// Check payment approval and buyer balance
IERC20 paymentContract = IERC20(addresses[2]);
require(
paymentContract.balanceOf(to) >= values[1],
"BENftMall: buyer doesn't have enough token to buy this item"
);
require(
paymentContract.allowance(to, address(this)) >= values[1],
"BENftMall: buyer doesn't approve marketplace to spend payment amount"
);
paymentContract.safeTransferFrom(to, feeToAddress, values[1]);
// mint item to user
IBEERC721 nft = IBEERC721(addresses[1]);
nft.mint(to, values[0]);
_useSignature(signature);
// emit sale event
emit BuyTransaction(to, values[2], values[0], addresses, values[1]);
}
function getMessageHash(
address _nftAddress,
address _tokenAddress,
address _buyerAddress,
uint256[] memory _datas
) public pure returns (bytes32) {
bytes memory encoded = abi.encodePacked(
_nftAddress,
_tokenAddress,
_buyerAddress
);
uint256 len = _datas.length;
for (uint256 i = 0; i < len; ++i) {
encoded = bytes.concat(encoded, abi.encodePacked(_datas[i]));
}
return keccak256(encoded);
}
}