260 lines
12 KiB
TypeScript
260 lines
12 KiB
TypeScript
import { expect } from 'chai'
|
|
import hre from "hardhat";
|
|
import {
|
|
getBytes,
|
|
solidityPackedKeccak256,
|
|
} from 'ethers'
|
|
import {
|
|
loadFixture,
|
|
} from "@nomicfoundation/hardhat-toolbox/network-helpers";
|
|
|
|
describe('NFTClaimStage2', function() {
|
|
async function deployOneContract() {
|
|
// Contracts are deployed using the first signer/account by default
|
|
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 CFFT = await hre.ethers.getContractFactory("ImmutableERC20MinterBurnerPermit");
|
|
const ft = await CFFT.deploy(owner.address, owner.address, owner.address, "test usdc", "usdc", '100000000000000000000000000');
|
|
await ft.grantMinterRole(owner.address);
|
|
await ft.mint(otherAccount.address, '1000');
|
|
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 NFTClaimStage2 = await hre.ethers.getContractFactory("NFTClaimStage2");
|
|
const mintConfig = [
|
|
1000,
|
|
2000,
|
|
ft.target,
|
|
100,
|
|
owner.address
|
|
]
|
|
const nftClaimer = await NFTClaimStage2.deploy( nftAddress, verifier, mintConfig);
|
|
await nft.grantMinterRole(nftClaimer.target)
|
|
const chainId = hre.network.config.chainId
|
|
return { nftClaimer, owner, otherAccount, verifier, nftAddress, ft, nft, chainId };
|
|
}
|
|
describe("Deployment", function () {
|
|
it('should deploy NFTClaimStage2', async function() {
|
|
const { nftClaimer } = await loadFixture(deployOneContract);
|
|
expect((await nftClaimer.mintConfig()).mintPrice).to.equal(100);
|
|
});
|
|
it('should deploy NFTClaimStage2 with the correct verifier', async function() {
|
|
const { nftClaimer, verifier } = await loadFixture(deployOneContract);
|
|
expect(await nftClaimer.verifier()).to.equal(verifier);
|
|
});
|
|
it('should deploy NFTClaimStage2 with the correct NFT address', async function() {
|
|
const { nftClaimer, nftAddress } = await loadFixture(deployOneContract);
|
|
expect(await nftClaimer.nftAddress()).to.equal(nftAddress);
|
|
});
|
|
})
|
|
|
|
describe("update settings", function () {
|
|
it('should update mintConfig', async function() {
|
|
const { nftClaimer } = await loadFixture(deployOneContract);
|
|
const mintConfig = [
|
|
1000,
|
|
2000,
|
|
'0xaa34B79A0Ab433eaC900fB3CB9f191F5Cd27501D',
|
|
200,
|
|
'0x5Ab03Aa79Ab91B7420b5CFF134a4188388888888'
|
|
]
|
|
await nftClaimer.updateMintConfig(mintConfig);
|
|
expect((await nftClaimer.mintConfig()).mintPrice).to.equal(200);
|
|
});
|
|
it('should update verifier', async function() {
|
|
const { nftClaimer, otherAccount } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateVerifier(otherAccount.address);
|
|
expect(await nftClaimer.verifier()).to.equal(otherAccount.address);
|
|
});
|
|
it('should update parse', async function() {
|
|
const { nftClaimer } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
expect(await nftClaimer.mintParse()).to.equal(1);
|
|
});
|
|
});
|
|
describe("claim", function () {
|
|
it('should claim NFT', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
const price = 100
|
|
//use ft.connect() to send a transaction from another account
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
const ids = ['1002']
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price, nftClaimer.target, chainId, nonce, ...ids]);
|
|
|
|
const contractMsgHash = await nftClaimer.getMessageHash(
|
|
otherAccount.address, nft.target, ids, price, nftClaimer.target, chainId, nonce
|
|
)
|
|
expect(localMsgHash).equal(contractMsgHash);
|
|
|
|
expect(await nftClaimer.verifier()).equal(owner.address);
|
|
expect(await nftClaimer.nftAddress()).equal(nft.target);
|
|
const signature = await owner.signMessage(getBytes(contractMsgHash));
|
|
// @ts-ignore
|
|
await nftClaimer.connect(otherAccount).claim(ids, price, nonce, signature);
|
|
expect(await nft.balanceOf(otherAccount.address)).to.equal(1);
|
|
expect(await nftClaimer.totalCount()).to.equal(1);
|
|
});
|
|
it('should claim NFTS', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
const price = 100
|
|
const ids = ['1002', '1003', '1004']
|
|
const tokenAmount = price * ids.length
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, tokenAmount)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, tokenAmount, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
// @ts-ignore
|
|
await nftClaimer.connect(otherAccount).claim(ids, tokenAmount, nonce, signature);
|
|
expect(await nft.balanceOf(otherAccount.address)).to.equal(ids.length);
|
|
expect(await ft.balanceOf(owner.address)).to.equal(tokenAmount)
|
|
});
|
|
it('should revert claim NFT if the signature error', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
const price = 100
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
const ids = ['1002']
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
const nonce2 = (Math.random() * 1000) | 0;
|
|
// @ts-ignore
|
|
await expect(nftClaimer.connect(otherAccount).claim(ids, price, nonce2, signature)).to.be.revertedWith(
|
|
"invalid signature"
|
|
);
|
|
});
|
|
it('should revert claim NFT if the balance not enough', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
const price = 1001
|
|
const mintConfig = [
|
|
1000,
|
|
2000,
|
|
ft.target,
|
|
price,
|
|
owner.address
|
|
]
|
|
await nftClaimer.updateMintConfig(mintConfig);
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
const ids = ['1002']
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
// @ts-ignore
|
|
await expect(nftClaimer.connect(otherAccount).claim(ids, price, nonce, signature)).to.be.revertedWith(
|
|
"ERC20: transfer amount exceeds balance"
|
|
);
|
|
});
|
|
it('should revert claim NFT if allowance not enough', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
const price = 100
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price - 1)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
const ids = ['1002']
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
// @ts-ignore
|
|
await expect(nftClaimer.connect(otherAccount).claim(ids, price, nonce, signature)).to.be.revertedWith(
|
|
"ERC20: insufficient allowance"
|
|
);
|
|
});
|
|
it('should revert claim NFT if the price not correct', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
const price = 99
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
const ids = ['1002']
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
// @ts-ignore
|
|
await expect(nftClaimer.connect(otherAccount).claim(ids, price, nonce, signature)).to.be.revertedWith(
|
|
"NFTClaimer: insufficient token amount"
|
|
);
|
|
});
|
|
it('should revert claim NFT if the activity not open', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(0);
|
|
const price = 100
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
const ids = ['1002']
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
// @ts-ignore
|
|
await expect(nftClaimer.connect(otherAccount).claim(ids, price, nonce, signature)).to.be.revertedWith(
|
|
"NFTClaimer: not begin or ended"
|
|
);
|
|
});
|
|
it('should revert claim NFT if the exceed parse1 max num', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(1);
|
|
const price = 100
|
|
const mintConfig = [
|
|
1,
|
|
2000,
|
|
ft.target,
|
|
price,
|
|
owner.address
|
|
]
|
|
await nftClaimer.updateMintConfig(mintConfig);
|
|
const ids = ['1002', '1003']
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price * ids.length)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price * ids.length, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
// @ts-ignore
|
|
await expect(nftClaimer.connect(otherAccount).claim(ids, price, nonce, signature)).to.be.revertedWith(
|
|
"NFTClaimer: exceed parse 1 max supply"
|
|
);
|
|
});
|
|
it('should revert claim NFT if the exceed total num', async function() {
|
|
const { nftClaimer, owner, otherAccount, ft, nft, chainId } = await loadFixture(deployOneContract);
|
|
await nftClaimer.updateMintParse(2);
|
|
const price = 100
|
|
const mintConfig = [
|
|
1000,
|
|
1,
|
|
ft.target,
|
|
price,
|
|
owner.address
|
|
]
|
|
await nftClaimer.updateMintConfig(mintConfig);
|
|
const ids = ['1002', '1003']
|
|
// @ts-ignore
|
|
await ft.connect(otherAccount).approve(nftClaimer.target, price * ids.length)
|
|
const nonce = (Math.random() * 1000) | 0;
|
|
|
|
let localMsgHash = solidityPackedKeccak256(["address", "address", "uint256", "address", "uint256", "uint256", ...ids.map(() => "uint256")],
|
|
[otherAccount.address, nft.target, price * ids.length, nftClaimer.target, chainId, nonce, ...ids]);
|
|
const signature = await owner.signMessage(getBytes(localMsgHash));
|
|
// @ts-ignore
|
|
await expect(nftClaimer.connect(otherAccount).claim(ids, price, nonce, signature)).to.be.revertedWith(
|
|
"NFTClaimer: exceed max supply"
|
|
);
|
|
});
|
|
});
|
|
}) |