// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../core/HasSignature.sol"; import "../utils/TimeChecker.sol"; interface IClaimBox { function batchMint( address to, uint256 count ) external returns (uint256[] memory); } contract ClaimBoxFactory is HasSignature, TimeChecker { address public executor; mapping(address => bool) public tokenSupported; mapping(address => uint256) public claimHistory; 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(claimHistory[to] == 0, "ClaimBoxFactory: claimed"); bytes32 criteriaMessageHash = getMessageHash( to, nftAddress, startTime, saltNonce ); checkSigner(executor, criteriaMessageHash, signature); uint256[] memory tokenIds = IClaimBox(nftAddress).batchMint(to, 1); claimHistory[to] = tokenIds[0]; _useSignature(signature); emit BoxClaimed(nftAddress, to, saltNonce, tokenIds[0]); } 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); } }