增加用于主网的nftlocker
This commit is contained in:
parent
92cd4db0d8
commit
a832a127d1
20819
build/contracts/BEBadgeV2.json
Normal file
20819
build/contracts/BEBadgeV2.json
Normal file
File diff suppressed because one or more lines are too long
58
config/config_sepolia_test.js
Normal file
58
config/config_sepolia_test.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
const market = {
|
||||||
|
feeToAddress: "0x50A8e60041A206AcaA5F844a1104896224be6F39",
|
||||||
|
mallFeeAddress: "0x50A8e60041A206AcaA5F844a1104896224be6F39",
|
||||||
|
paymentTokens: [
|
||||||
|
"0x514609B71340E149Cb81A80A953D07A7Fe41bd4F", // USDT
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const admins = {
|
||||||
|
admin: "0x50A8e60041A206AcaA5F844a1104896224be6F39",
|
||||||
|
proposers: [
|
||||||
|
"0x50A8e60041A206AcaA5F844a1104896224be6F39",
|
||||||
|
"0x746338765a8FbDD1c5aB61bfb92CD6D960C3C662",
|
||||||
|
],
|
||||||
|
confirmers: ["0x50A8e60041A206AcaA5F844a1104896224be6F39"],
|
||||||
|
executors: [
|
||||||
|
"0x50A8e60041A206AcaA5F844a1104896224be6F39",
|
||||||
|
"0x746338765a8FbDD1c5aB61bfb92CD6D960C3C662",
|
||||||
|
"0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b",
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const token = {
|
||||||
|
baseTokenURIHero: "https://nft-test.kingsome.cn/hero/meta/13473/",
|
||||||
|
contractURIHero: 'https://nft-test.kingsome.cn/hero/home_meta/13473',
|
||||||
|
royaltyReceiver: '0x5Ab03Aa79Ab91B7420b5CFF134a4188388888888',
|
||||||
|
baseTokenURIGold: "https://nft-test.kingsome.cn/gold_bullion/meta/13473/",
|
||||||
|
contractURIGold: 'https://nft-test.kingsome.cn/gold_bullion/home_meta/13473',
|
||||||
|
royaltyFee: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
const imtbl = {
|
||||||
|
operatorAllowlist: '0x6b969FD89dE634d8DE3271EbE97734FEFfcd58eE',
|
||||||
|
}
|
||||||
|
const mint = {
|
||||||
|
// 2期mint支付的代币
|
||||||
|
mintCurrency: '0xFd42bfb03212dA7e1A4608a44d7658641D99CF34',
|
||||||
|
// 2期mint, 单个nft价格
|
||||||
|
mintPrice: '75000000000000000',
|
||||||
|
// 2期mint接收代币的钱包地址
|
||||||
|
mintFeeAddress: '0x50A8e60041A206AcaA5F844a1104896224be6F39',
|
||||||
|
// 2期mint nftid 开始
|
||||||
|
mintStartNftId: '6240603010010301',
|
||||||
|
// 2期mint 最大可mint数量
|
||||||
|
maxSupply: 2000,
|
||||||
|
// 2期mint airdrop数量
|
||||||
|
airdropCount: 500,
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
market,
|
||||||
|
admins,
|
||||||
|
token,
|
||||||
|
imtbl,
|
||||||
|
mint
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
153
contracts/game/NFTLockMain.sol
Normal file
153
contracts/game/NFTLockMain.sol
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.19;
|
||||||
|
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
contract NFTLockMain is ERC721Holder, 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 => mapping(uint256 tokenId => address user)) public addressOriginal;
|
||||||
|
mapping(address nft => mapping(address user => EnumerableSet.UintSet tokenIdSet)) private lockedRecords;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* lock NFT
|
||||||
|
* from eoa only
|
||||||
|
* @param nft nft address
|
||||||
|
* @param to passport address for game
|
||||||
|
* @param tokenIds nft token id list
|
||||||
|
*/
|
||||||
|
function lock(address nft, address to, uint256[] calldata tokenIds) external whenNotPaused{
|
||||||
|
require(tokenIds.length <= maxBatch, "tokenIds too many");
|
||||||
|
require(to != address(0), "passport can't be zero");
|
||||||
|
require(supportNftList[nft], "not support nft");
|
||||||
|
address _sender = _msgSender();
|
||||||
|
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||||
|
addressOriginal[nft][tokenIds[i]] = _sender;
|
||||||
|
lockedRecords[nft][_sender].add(tokenIds[i]);
|
||||||
|
INFT(nft).transferFrom(_sender, address(this), tokenIds[i]);
|
||||||
|
}
|
||||||
|
emit Lock(nft, _sender, to, tokenIds);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @dev unlock or mint nft
|
||||||
|
* from passport only
|
||||||
|
* if tokenId not exists, mint it
|
||||||
|
* if exists and user is owner, unlock it
|
||||||
|
*/
|
||||||
|
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++) {
|
||||||
|
if (nftList[i].isMint) {
|
||||||
|
INFT(nft).mint(nftList[i].to, nftList[i].tokenId);
|
||||||
|
} else {
|
||||||
|
require(addressOriginal[nft][nftList[i].tokenId] == _sender, "not owner");
|
||||||
|
delete addressOriginal[nft][nftList[i].tokenId];
|
||||||
|
lockedRecords[nft][_sender].remove(nftList[i].tokenId);
|
||||||
|
INFT(nft).transferFrom(address(this), nftList[i].to, nftList[i].tokenId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit UnLock(nft, _sender, saltNonce, nftList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev unlock nft
|
||||||
|
* from game svr only
|
||||||
|
*/
|
||||||
|
function unlockWithSvr(address nft, uint256[] calldata tokenIds) external onlyOwner{
|
||||||
|
require(tokenIds.length <= maxBatch, "tokenIds too many");
|
||||||
|
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||||
|
address _sender = addressOriginal[nft][tokenIds[i]];
|
||||||
|
delete addressOriginal[nft][tokenIds[i]];
|
||||||
|
lockedRecords[nft][_sender].remove(tokenIds[i]);
|
||||||
|
INFT(nft).transferFrom(address(this), _sender, tokenIds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ------get------- **/
|
||||||
|
function lockedNum(address token, address user) public view returns (uint256) {
|
||||||
|
return lockedRecords[token][user].length();
|
||||||
|
}
|
||||||
|
|
||||||
|
function lockedNft(address token, address user) public view returns (uint256[] memory) {
|
||||||
|
return lockedRecords[token][user].values();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBatch(uint256 _maxBatch) external onlyOwner {
|
||||||
|
maxBatch = _maxBatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
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), "NFTClaimer: 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);
|
||||||
|
}
|
||||||
|
}
|
29
deploy/4_1_deploy_nftlocker_main.ts
Normal file
29
deploy/4_1_deploy_nftlocker_main.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { HardhatRuntimeEnvironment } from "hardhat/types";
|
||||||
|
import { DeployFunction } from "hardhat-deploy/types";
|
||||||
|
import { updateArray } from "../scripts/utils"
|
||||||
|
|
||||||
|
|
||||||
|
const deployNFTClaim: DeployFunction =
|
||||||
|
async function (hre: HardhatRuntimeEnvironment) {
|
||||||
|
const provider = hre.ethers.provider;
|
||||||
|
const from = await (await provider.getSigner()).getAddress();
|
||||||
|
const config = require(`../config/config_${hre.network.name}`);
|
||||||
|
const verifier = config.admins.admin
|
||||||
|
const ret = await hre.deployments.deploy("NFTLockMain", {
|
||||||
|
from,
|
||||||
|
args: [3600, verifier],
|
||||||
|
log: true,
|
||||||
|
});
|
||||||
|
console.log("==NFTLock addr=", ret.address);
|
||||||
|
updateArray({
|
||||||
|
name: "NFTLock",
|
||||||
|
type: "logic",
|
||||||
|
json: "assets/contracts/NFTLock.json",
|
||||||
|
address: ret.address,
|
||||||
|
network: hre.network.name,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
deployNFTClaim.tags = ["NFTLockMain"];
|
||||||
|
|
||||||
|
export default deployNFTClaim;
|
1
deployments/sepolia_test/.chainId
Normal file
1
deployments/sepolia_test/.chainId
Normal file
@ -0,0 +1 @@
|
|||||||
|
11155111
|
969
deployments/sepolia_test/NFTLockMain.json
Normal file
969
deployments/sepolia_test/NFTLockMain.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -56,6 +56,10 @@ const config: HardhatUserConfig = {
|
|||||||
url: process.env.IMTBL_TEST_URL || "",
|
url: process.env.IMTBL_TEST_URL || "",
|
||||||
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
|
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
|
||||||
},
|
},
|
||||||
|
sepolia_test: {
|
||||||
|
url: process.env.SEPOLIA_URL || "",
|
||||||
|
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
14
out/sepolia_test_dev.json
Normal file
14
out/sepolia_test_dev.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "NFTLock",
|
||||||
|
"type": "logic",
|
||||||
|
"json": "assets/contracts/NFTLock.json",
|
||||||
|
"address": "0x7F2b4DB626d878778e178B4F0C7bA3a2870C6dd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "BEBadgeV2",
|
||||||
|
"type": "erc721",
|
||||||
|
"json": "assets/contracts/BEBadgeV2.json",
|
||||||
|
"address": "0x1304E6AA241eE3C9ea44Db9e593e85Ae76eC41F1"
|
||||||
|
}
|
||||||
|
]
|
@ -12,6 +12,7 @@
|
|||||||
"deploy:nftclaimwl": "hardhat deploy --tags NFTClaimStage2WL --network imtbl_test --reset",
|
"deploy:nftclaimwl": "hardhat deploy --tags NFTClaimStage2WL --network imtbl_test --reset",
|
||||||
"deploy:nft": "hardhat deploy --tags CFNFTGame --network imtbl_test --reset",
|
"deploy:nft": "hardhat deploy --tags CFNFTGame --network imtbl_test --reset",
|
||||||
"deploy:nftlock": "hardhat deploy --tags NFTLock --network imtbl_test --reset",
|
"deploy:nftlock": "hardhat deploy --tags NFTLock --network imtbl_test --reset",
|
||||||
|
"deploy:nftlock:main": "hardhat deploy --tags NFTLockMain --network sepolia_test --reset",
|
||||||
"deploy:testtoken": "hardhat deploy --tags TestToken --network imtbl_test --reset",
|
"deploy:testtoken": "hardhat deploy --tags TestToken --network imtbl_test --reset",
|
||||||
"deploy:airdrop": "hardhat deploy --tags AirdropToken --network imtbl_test --reset",
|
"deploy:airdrop": "hardhat deploy --tags AirdropToken --network imtbl_test --reset",
|
||||||
"solhint": "solhint --config ./.solhint.json"
|
"solhint": "solhint --config ./.solhint.json"
|
||||||
|
126
test/testNFTLockerMain.ts
Normal file
126
test/testNFTLockerMain.ts
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import { expect } from 'chai'
|
||||||
|
import hre from "hardhat";
|
||||||
|
import {
|
||||||
|
getBytes,
|
||||||
|
solidityPackedKeccak256,
|
||||||
|
} from 'ethers'
|
||||||
|
import {
|
||||||
|
loadFixture,
|
||||||
|
} from "@nomicfoundation/hardhat-toolbox/network-helpers";
|
||||||
|
|
||||||
|
describe('NFTLock', function() {
|
||||||
|
async function deployOneContract() {
|
||||||
|
const [owner, otherAccount] = await hre.ethers.getSigners();
|
||||||
|
const verifier = owner.address;
|
||||||
|
const OperatorAllowlist = await hre.ethers.getContractFactory("OperatorAllowlist");
|
||||||
|
const operatorAllowlist = await OperatorAllowlist.deploy(owner.address);
|
||||||
|
|
||||||
|
const CFNFTGame = await hre.ethers.getContractFactory("CFNFTGame");
|
||||||
|
const nft = await CFNFTGame.deploy(owner.address, 'name', 'symbol', 'baseURI', 'contractURI', operatorAllowlist.target, owner.address, 5);
|
||||||
|
const nftAddress = nft.target;
|
||||||
|
const NFTLock = await hre.ethers.getContractFactory("NFTLockMain");
|
||||||
|
|
||||||
|
const nftLock = await NFTLock.deploy( 3600, verifier );
|
||||||
|
await nft.grantMinterRole(nftLock.target)
|
||||||
|
await nft.grantMinterRole(owner.address)
|
||||||
|
await nftLock.addSupportNftList([nftAddress]);
|
||||||
|
await nft.mint(otherAccount.address, "1001");
|
||||||
|
const chainId = hre.network.config.chainId
|
||||||
|
await operatorAllowlist.grantRegistrarRole(owner.address)
|
||||||
|
await operatorAllowlist.addAddressToAllowlist([nftLock.target])
|
||||||
|
return { nftLock, owner, otherAccount, verifier, nftAddress, nft, chainId };
|
||||||
|
}
|
||||||
|
describe("Deployment", function () {
|
||||||
|
it('should deploy NFTLock with the correct verifier', async function() {
|
||||||
|
const { nftLock, verifier } = await loadFixture(deployOneContract);
|
||||||
|
expect(await nftLock.verifier()).to.equal(verifier);
|
||||||
|
});
|
||||||
|
it('should deploy NFTLock with the correct NFT address', async function() {
|
||||||
|
const { nftLock, nftAddress } = await loadFixture(deployOneContract);
|
||||||
|
expect(await nftLock.supportNftList(nftAddress)).to.equal(true);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Lock", function () {
|
||||||
|
it('should lock NFT', async function() {
|
||||||
|
const { nftLock, nft, otherAccount, owner } = await loadFixture(deployOneContract);
|
||||||
|
const tokenId = "1001"
|
||||||
|
// @ts-ignore
|
||||||
|
await nft.connect(otherAccount).approve(nftLock.target, tokenId);
|
||||||
|
//@ts-ignore
|
||||||
|
await nftLock.connect(otherAccount).lock(nft.target, owner.address, [tokenId]);
|
||||||
|
expect(await nft.balanceOf(nftLock.target)).to.equal(1);
|
||||||
|
expect(await nftLock.addressOriginal(nft.target, tokenId)).to.equal(otherAccount.address);
|
||||||
|
expect(await nft.ownerOf(tokenId)).to.equal(nftLock.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("UnLock", function () {
|
||||||
|
it('should unlock NFT from lock', async function() {
|
||||||
|
const { nftLock, nft, otherAccount, chainId, owner } = await loadFixture(deployOneContract);
|
||||||
|
const tokenId = '1001'
|
||||||
|
// @ts-ignore
|
||||||
|
await nft.connect(otherAccount).approve(nftLock.target, tokenId);
|
||||||
|
//@ts-ignore
|
||||||
|
await nftLock.connect(otherAccount).lock(nft.target, owner.address, [tokenId]);
|
||||||
|
const nonce = (Math.random() * 1000) | 0;
|
||||||
|
const now = Date.now() / 1000 | 0;
|
||||||
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "address", "uint256", "uint256", "uint256", "uint256", "address", "bool"],
|
||||||
|
[otherAccount.address, nft.target, nftLock.target, chainId, now, nonce, tokenId, owner.address, false]);
|
||||||
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
||||||
|
//@ts-ignore
|
||||||
|
await nftLock.connect(otherAccount).unlockOrMint(nft.target, [[tokenId, owner.address, false]], now, nonce, signature);
|
||||||
|
// await nftLock.connect(otherAccount).unlockOrMint(nft.target, [[tokenId, false]], now, nonce, signature);
|
||||||
|
expect(await nft.ownerOf(tokenId)).to.equal(owner.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mint NFT from lock', async function() {
|
||||||
|
const { nftLock, nft, otherAccount, chainId, owner } = await loadFixture(deployOneContract);
|
||||||
|
const tokenId = '1002'
|
||||||
|
const isMint = true
|
||||||
|
|
||||||
|
const nonce = (Math.random() * 1000) | 0;
|
||||||
|
const now = Date.now() / 1000 | 0;
|
||||||
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "address", "uint256", "uint256", "uint256", "uint256", "address", "bool"],
|
||||||
|
[otherAccount.address, nft.target, nftLock.target, chainId, now, nonce, tokenId, otherAccount.address, isMint]);
|
||||||
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
||||||
|
//@ts-ignore
|
||||||
|
await nftLock.connect(otherAccount).unlockOrMint(nft.target, [[tokenId, otherAccount.address, isMint]], now, nonce, signature);
|
||||||
|
expect(await nft.ownerOf(tokenId)).to.equal(otherAccount.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should revert NFT mint for nft already minted', async function() {
|
||||||
|
const { nftLock, nft, otherAccount, chainId, owner } = await loadFixture(deployOneContract);
|
||||||
|
const tokenId = '1001'
|
||||||
|
const isMint = true
|
||||||
|
|
||||||
|
const nonce = (Math.random() * 1000) | 0;
|
||||||
|
const now = Date.now() / 1000 | 0;
|
||||||
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "address", "uint256", "uint256", "uint256", "uint256", "address", "bool"],
|
||||||
|
[otherAccount.address, nft.target, nftLock.target, chainId, now, nonce, tokenId, otherAccount.address, isMint]);
|
||||||
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
||||||
|
//@ts-ignore
|
||||||
|
await expect(nftLock.connect(otherAccount).unlockOrMint(nft.target, [[tokenId, otherAccount.address, isMint]], now, nonce, signature)).to.be.revertedWith(
|
||||||
|
"ERC721: token already minted"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should unlock NFT with svr', async function() {
|
||||||
|
const { nftLock, nft, otherAccount, chainId, owner } = await loadFixture(deployOneContract);
|
||||||
|
const tokenId = '1001'
|
||||||
|
// @ts-ignore
|
||||||
|
await nft.connect(otherAccount).approve(nftLock.target, tokenId);
|
||||||
|
//@ts-ignore
|
||||||
|
await nftLock.connect(otherAccount).lock(nft.target, owner.address, [tokenId]);
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
await nftLock.unlockWithSvr(nft.target, [tokenId]);
|
||||||
|
// await nftLock.connect(otherAccount).unlockOrMint(nft.target, [[tokenId, false]], now, nonce, signature);
|
||||||
|
expect(await nft.ownerOf(tokenId)).to.equal(otherAccount.address);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
})
|
Loading…
x
Reference in New Issue
Block a user