contracts-imtbl/contracts/activity/NFTClaimStage2.sol

136 lines
4.2 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {HasSignature} from "../core/HasSignature.sol";
/**
* Contract for the activity of NFT claim stage 2.
*/
interface IClaimAbleNFT {
function safeMint(address to, uint256 tokenID) external;
}
contract NFTClaimStage2 is HasSignature, ReentrancyGuard {
using SafeERC20 for IERC20;
struct MintConfig {
uint256 parse1MaxSupply; // max supply for phase1
uint256 maxSupply; // max supply for phase2
address currency; // token address which user must pay to mint
uint256 mintPrice; // in wei
address feeToAddress; // wallet address to receive mint fee
}
// parse: 0: not open or end, 1: phase1, 2: phase2
uint256 public mintParse = 0;
uint256 public immutable _CACHED_CHAIN_ID;
address public immutable _CACHED_THIS;
address public immutable nftAddress;
address public verifier;
MintConfig public mintConfig;
uint256 public parse1Count;
uint256 public totalCount;
event NFTClaimed(address indexed nftAddress, address indexed to, uint256[] ids);
event ParseUpdated(uint256 _parse);
event MintConfigUpdated(MintConfig config);
event VerifierUpdated(address indexed verifier);
constructor(address _nftAddress, address _verifier, MintConfig memory _mintConfig) {
_CACHED_CHAIN_ID = block.chainid;
_CACHED_THIS = address(this);
nftAddress = _nftAddress;
verifier = _verifier;
mintConfig = _mintConfig;
}
modifier whenNotPaused() {
require(mintParse > 0, "NFTClaimer: not begin or ended");
_;
}
function updateMintParse(uint256 _mintParse) external onlyOwner {
mintParse = _mintParse;
emit ParseUpdated(_mintParse);
}
function updateMintConfig(MintConfig calldata config) external onlyOwner {
mintConfig = config;
emit MintConfigUpdated(config);
}
/**
* @dev update verifier address
*/
function updateVerifier(address _verifier) external onlyOwner {
require(_verifier != address(0), "NFTClaimer: address can not be zero");
verifier = _verifier;
emit VerifierUpdated(_verifier);
}
/**
* @dev claim NFT
* Get whitelist signature from a third-party service, then call this method to claim NFT
* @param saltNonce nonce
* @param signature signature
*/
function claim(
uint256[] memory ids,
uint256 tokenAmount,
uint256 saltNonce,
bytes calldata signature
) external nonReentrant whenNotPaused {
// get current parse;
uint256 count = ids.length;
require(count > 0, "NFTClaimer: ids length must be greater than 0");
if (mintParse == 1) {
require(count <= mintConfig.parse1MaxSupply - parse1Count, "NFTClaimer: exceed parse 1 max supply");
} else {
require(count <= mintConfig.maxSupply - totalCount, "NFTClaimer: exceed max supply");
}
require(tokenAmount >= mintConfig.mintPrice * count, "NFTClaimer: insufficient token amount");
address to = _msgSender();
bytes32 criteriaMessageHash = getMessageHash(
to,
nftAddress,
ids,
tokenAmount,
_CACHED_THIS,
_CACHED_CHAIN_ID,
saltNonce
);
checkSigner(verifier, criteriaMessageHash, signature);
IERC20(mintConfig.currency).safeTransferFrom(to, mintConfig.feeToAddress, tokenAmount);
for (uint256 i = 0; i < count; ++i) {
IClaimAbleNFT(nftAddress).safeMint(to, ids[i]);
}
// require(count > 2, "run to here");
totalCount += count;
if (mintParse == 1) {
parse1Count += count;
}
_useSignature(signature);
emit NFTClaimed(nftAddress, to, ids);
}
function getMessageHash(
address _to,
address _address,
uint256[] memory _ids,
uint256 _tokenAmount,
address _contract,
uint256 _chainId,
uint256 _saltNonce
) public pure returns (bytes32) {
bytes memory encoded = abi.encodePacked(_to, _address, _tokenAmount, _contract, _chainId, _saltNonce);
for (uint256 i = 0; i < _ids.length; ++i) {
encoded = bytes.concat(encoded, abi.encodePacked(_ids[i]));
}
return keccak256(encoded);
}
}