82 lines
3.4 KiB
JavaScript
82 lines
3.4 KiB
JavaScript
const { expect } = require("chai");
|
|
const { ethers } = require("hardhat");
|
|
|
|
describe("EdutHumanMembership", function () {
|
|
async function expectRevertWithCustomError(promise, errorName) {
|
|
try {
|
|
await promise;
|
|
expect.fail(`expected revert ${errorName}`);
|
|
} catch (err) {
|
|
expect(String(err)).to.contain(errorName);
|
|
}
|
|
}
|
|
|
|
async function deployFixture() {
|
|
const [deployer, treasury, sponsor, recipient, other] = await ethers.getSigners();
|
|
const factory = await ethers.getContractFactory("EdutHumanMembership", deployer);
|
|
const price = ethers.utils.parseEther("0.002");
|
|
const contract = await factory.deploy(treasury.address, ethers.constants.AddressZero, price);
|
|
await contract.deployed();
|
|
return { contract, deployer, treasury, sponsor, recipient, other, price };
|
|
}
|
|
|
|
it("mints to recipient with sponsor payment", async function () {
|
|
const { contract, treasury, sponsor, recipient, price } = await deployFixture();
|
|
const before = await ethers.provider.getBalance(treasury.address);
|
|
|
|
const tx = await contract.connect(sponsor).mintMembership(recipient.address, { value: price });
|
|
await tx.wait();
|
|
|
|
const after = await ethers.provider.getBalance(treasury.address);
|
|
expect(after.sub(before).eq(price)).to.equal(true);
|
|
expect(await contract.ownerOf(1)).to.equal(recipient.address);
|
|
|
|
const token = await contract.tokenOf(recipient.address);
|
|
expect(token.tokenId.toNumber()).to.equal(1);
|
|
expect(token.status).to.equal(1);
|
|
expect(await contract.hasMembership(recipient.address)).to.equal(true);
|
|
});
|
|
|
|
it("rejects duplicate mint for same human wallet", async function () {
|
|
const { contract, sponsor, recipient, price } = await deployFixture();
|
|
await (await contract.connect(sponsor).mintMembership(recipient.address, { value: price })).wait();
|
|
|
|
await expectRevertWithCustomError(
|
|
contract.connect(sponsor).mintMembership(recipient.address, { value: price }),
|
|
"AlreadyMinted"
|
|
);
|
|
});
|
|
|
|
it("supports owner-configurable price and owner-only admin", async function () {
|
|
const { contract, deployer, other } = await deployFixture();
|
|
const nextPrice = ethers.utils.parseEther("0.003");
|
|
|
|
await expectRevertWithCustomError(
|
|
contract.connect(other).updateMintPrice(ethers.constants.AddressZero, nextPrice),
|
|
"NotOwner"
|
|
);
|
|
|
|
await (await contract.connect(deployer).updateMintPrice(ethers.constants.AddressZero, nextPrice)).wait();
|
|
const price = await contract.currentMintPrice();
|
|
expect(price.amountAtomic.eq(nextPrice)).to.equal(true);
|
|
});
|
|
|
|
it("blocks transfer paths (soulbound)", async function () {
|
|
const { contract, sponsor, recipient, other, price } = await deployFixture();
|
|
await (await contract.connect(sponsor).mintMembership(recipient.address, { value: price })).wait();
|
|
|
|
await expectRevertWithCustomError(
|
|
contract.connect(recipient).transferFrom(recipient.address, other.address, 1),
|
|
"SoulboundNonTransferable"
|
|
);
|
|
});
|
|
|
|
it("allows owner to update status", async function () {
|
|
const { contract, deployer, sponsor, recipient, price } = await deployFixture();
|
|
await (await contract.connect(sponsor).mintMembership(recipient.address, { value: price })).wait();
|
|
await (await contract.connect(deployer).setMembershipStatus(recipient.address, 2)).wait();
|
|
|
|
expect(await contract.membershipStatus(recipient.address)).to.equal(2);
|
|
});
|
|
});
|