114 lines
3.9 KiB
Solidity
114 lines
3.9 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.19;
|
|
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
|
|
import {HasSignature} from "../core/HasSignature.sol";
|
|
import {TimeChecker} from "../utils/TimeChecker.sol";
|
|
|
|
interface INFT {
|
|
function mint(address to, uint256 tokenID) external;
|
|
function transferFrom(address from, address to, uint256 tokenId) external;
|
|
function burn(uint256 tokenId) external;
|
|
function ownerOf(uint256 tokenId) external view returns (address);
|
|
}
|
|
|
|
contract NFTLockV2 is HasSignature, TimeChecker, Pausable {
|
|
using EnumerableSet for EnumerableSet.UintSet;
|
|
|
|
uint256 public immutable _CACHED_CHAIN_ID;
|
|
address public immutable _CACHED_THIS;
|
|
address public verifier;
|
|
uint256 public maxBatch = 100;
|
|
|
|
struct NFTInfo {
|
|
uint256 tokenId;
|
|
address to;
|
|
bool isMint;
|
|
}
|
|
mapping(address nft => bool status) public supportNftList;
|
|
|
|
event UnLock(address indexed nft, address indexed user, uint256 nonce, NFTInfo[] nftList);
|
|
event Lock(address indexed nft, address indexed sender, address indexed to, uint256[] tokenIds);
|
|
event VerifierUpdated(address indexed verifier);
|
|
|
|
constructor(uint256 _duration, address _verifier) TimeChecker(_duration) {
|
|
_CACHED_CHAIN_ID = block.chainid;
|
|
_CACHED_THIS = address(this);
|
|
verifier = _verifier;
|
|
}
|
|
/**
|
|
* from eoa or passport
|
|
*/
|
|
function lock(address nft, address to, uint256[] calldata tokenIds) external whenNotPaused{
|
|
require(tokenIds.length <= maxBatch, "tokenIds too many");
|
|
require(to != address(0), "to can't be zero");
|
|
require(supportNftList[nft], "not support nft");
|
|
address _sender = _msgSender();
|
|
for (uint256 i = 0; i < tokenIds.length; i++) {
|
|
address owner = INFT(nft).ownerOf(tokenIds[i]);
|
|
require(owner == _sender, "not owner");
|
|
INFT(nft).burn(tokenIds[i]);
|
|
}
|
|
emit Lock(nft, _sender, to, tokenIds);
|
|
}
|
|
/**
|
|
* @dev mint nft
|
|
*/
|
|
function unlockOrMint(
|
|
address nft,
|
|
NFTInfo[] calldata nftList,
|
|
uint256 signTime,
|
|
uint256 saltNonce,
|
|
bytes calldata signature
|
|
) external signatureValid(signature) timeValid(signTime) {
|
|
require(nftList.length <= maxBatch, "tokenIds too many");
|
|
address _sender = _msgSender();
|
|
bytes32 messageHash = getMessageHash(_sender, nft, nftList, _CACHED_THIS, _CACHED_CHAIN_ID, signTime, saltNonce);
|
|
checkSigner(verifier, messageHash, signature);
|
|
_useSignature(signature);
|
|
for (uint256 i = 0; i < nftList.length; i++) {
|
|
require(nftList[i].isMint, "mint only");
|
|
INFT(nft).mint(nftList[i].to, nftList[i].tokenId);
|
|
}
|
|
emit UnLock(nft, _sender, saltNonce, nftList);
|
|
}
|
|
|
|
function addSupportNftList(address[] calldata nftList) external onlyOwner {
|
|
for (uint256 i = 0; i < nftList.length; i++) {
|
|
supportNftList[nftList[i]] = true;
|
|
}
|
|
}
|
|
|
|
function removeSupportNft(address nftAddress) external onlyOwner {
|
|
require(supportNftList[nftAddress], "can't remove");
|
|
delete supportNftList[nftAddress];
|
|
}
|
|
|
|
/**
|
|
* @dev update verifier address
|
|
*/
|
|
function updateVerifier(address _verifier) external onlyOwner {
|
|
require(_verifier != address(0), "address can not be zero");
|
|
verifier = _verifier;
|
|
emit VerifierUpdated(_verifier);
|
|
}
|
|
|
|
function getMessageHash(
|
|
address _to,
|
|
address _nft,
|
|
NFTInfo[] memory _ids,
|
|
address _contract,
|
|
uint256 _chainId,
|
|
uint256 _signTime,
|
|
uint256 _saltNonce
|
|
) public pure returns (bytes32) {
|
|
bytes memory encoded = abi.encodePacked(_to, _nft, _contract, _chainId, _signTime, _saltNonce);
|
|
for (uint256 i = 0; i < _ids.length; ++i) {
|
|
encoded = bytes.concat(encoded, abi.encodePacked(_ids[i].tokenId));
|
|
encoded = bytes.concat(encoded, abi.encodePacked(_ids[i].to));
|
|
encoded = bytes.concat(encoded, abi.encodePacked(_ids[i].isMint));
|
|
}
|
|
return keccak256(encoded);
|
|
}
|
|
}
|