// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../core/HasSignature.sol"; import "../utils/TimeChecker.sol"; interface IClaimBox { function mint(address to) external returns (uint256); function balanceOf(address owner) external view returns (uint256); } contract ClaimBoxFactory is HasSignature, TimeChecker { address public executor; mapping(address => bool) public tokenSupported; event BoxClaimed( address indexed nftAddress, address indexed to, uint256 indexed nonce, uint256 tokenId ); constructor() HasSignature("ClaimBoxFactory", "1") {} function addTokenSupport(address nftToken) external onlyOwner { tokenSupported[nftToken] = true; } function removeTokenSupport(address nftToken) external onlyOwner { tokenSupported[nftToken] = false; } /** * @dev update executor */ function updateExecutor(address account) external onlyOwner { require(account != address(0), "ClaimBoxFactory: address can not be zero"); executor = account; } function claim( address nftAddress, uint256 startTime, uint256 saltNonce, bytes calldata signature ) external signatureValid(signature) timeValid(startTime) { require(tokenSupported[nftAddress], "ClaimBoxFactory: unsupported NFT"); address to = _msgSender(); require( IClaimBox(nftAddress).balanceOf(to) == 0, "ClaimBoxFactory: you already have a box" ); bytes32 criteriaMessageHash = getMessageHash( to, nftAddress, startTime, saltNonce ); checkSigner(executor, criteriaMessageHash, signature); uint256 tokenId = IClaimBox(nftAddress).mint(to); _useSignature(signature); emit BoxClaimed(nftAddress, to, saltNonce, tokenId); } function getMessageHash( address _to, address _address, uint256 _startTime, uint256 _saltNonce ) public pure returns (bytes32) { bytes memory encoded = abi.encodePacked( _to, _address, _startTime, _saltNonce ); return keccak256(encoded); } }