// 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 "../core/HasSignature.sol"; import "../utils/TimeChecker.sol"; /** * @title ClaimToken * @dev for user to claim token */ contract ClaimToken is HasSignature, TimeChecker { using SafeERC20 for IERC20; uint256 private immutable _CACHED_CHAIN_ID; address private immutable _CACHED_THIS; address private verifier; address private paymentAddress; mapping(address => bool) public tokenSupported; mapping(address => uint256) public claimHistory; struct TestStuct { address user; address nft; uint256 tokenId; uint64 start; uint64 stakeTime; } event TestEvent ( address indexed user, TestStuct info ); event TokenClaimed( address indexed tokenAddress, address indexed to, uint256 indexed nonce, uint256 amount ); event TokenSupportUpdated(address indexed tokenAddress, bool support); event VerifierUpdated(address indexed verifier); event PaymentAddressUpdated(address indexed paymentAddress); constructor() { _CACHED_CHAIN_ID = block.chainid; _CACHED_THIS = address(this); } function updateTokenSupport(address _token, bool _support) external onlyOwner { tokenSupported[_token] = _support; emit TokenSupportUpdated(_token, _support); } /** * @dev update verifier address */ function updateVerifier(address _verifier) external onlyOwner { require(_verifier != address(0), "ClaimToken: address can not be zero"); verifier = _verifier; emit VerifierUpdated(_verifier); } /** * @dev update payment address */ function updatePaymentAddress(address _paymentAddress) external onlyOwner { require( _paymentAddress != address(0), "ClaimToken: payment address can not be zero" ); paymentAddress = _paymentAddress; emit PaymentAddressUpdated(_paymentAddress); } function claim( address _token, uint256 _amount, uint256 _startTime, uint256 _saltNonce, bytes calldata _signature ) external signatureValid(_signature) timeValid(_startTime) { require(tokenSupported[_token], "ClaimToken: unsupported token"); address to = _msgSender(); bytes32 criteriaMessageHash = getMessageHash( to, _token, _CACHED_THIS, _CACHED_CHAIN_ID, _amount, _startTime, _saltNonce ); checkSigner(verifier, criteriaMessageHash, _signature); IERC20(_token).safeTransferFrom(paymentAddress, to, _amount); claimHistory[to] = _amount; _useSignature(_signature); emit TokenClaimed(_token, to, _saltNonce, _amount); } function getMessageHash( address _to, address _address, address _contract, uint256 _chainId, uint256 _amount, uint256 _startTime, uint256 _saltNonce ) public pure returns (bytes32) { bytes memory encoded = abi.encodePacked( _to, _address, _contract, _chainId, _amount, _startTime, _saltNonce ); return keccak256(encoded); } }