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("NFTLockV2"); 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(owner.address)).to.equal(0); }); it('should revert lock NFT for not owner', async function() { const { nftLock, nft, otherAccount, owner } = await loadFixture(deployOneContract); const tokenId = "1001" // @ts-ignore await nft.connect(otherAccount).approve(nftLock.target, tokenId); await expect(nftLock.lock(nft.target, owner.address, [tokenId])).to.be.revertedWith("not owner"); }); it('should revert lock NFT for not approved', async function() { const { nftLock, nft, otherAccount, owner } = await loadFixture(deployOneContract); const tokenId = "1001" // @ts-ignore await expect(nftLock.connect(otherAccount).lock(nft.target, owner.address, [tokenId])).to.be.revertedWith("ERC721: caller is not token owner or approved"); }); it('should revert lock NFT for invalid token id', async function() { const { nftLock, nft, otherAccount, owner } = await loadFixture(deployOneContract); const tokenId = "1002" // @ts-ignore await expect(nft.connect(otherAccount).approve(nftLock.target, tokenId)).to.be.revertedWith("ERC721: invalid token ID"); }); }) describe("UnLock", function () { 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 unlock', async function() { const { nftLock, nft, otherAccount, chainId, owner } = await loadFixture(deployOneContract); const tokenId = '1001' const isMint = false 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( "mint only" ); }); it('should revert NFT unlock for alreay burned', 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 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.revertedWithCustomError( nft, "IImmutableERC721TokenAlreadyBurned" ).withArgs(tokenId); }); }); })