119 lines
3.5 KiB
Solidity
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);
|
|
}
|
|
}
|