contracts/test/EdutOfferEntitlement.test.js

138 lines
5.5 KiB
JavaScript

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("EdutOfferEntitlement", function () {
const PRICE = ethers.BigNumber.from("1000000000"); // 1000 USDC (6 decimals)
const OFFER_WORKSPACE_CORE = "edut.workspace.core";
const OFFER_WORKSPACE_LANE24 = "edut.workspace.lane24";
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, ownerWallet, payer, other] = await ethers.getSigners();
const tokenFactory = await ethers.getContractFactory("MockERC20");
const usdc = await tokenFactory.connect(deployer).deploy("Mock USDC", "USDC", 6);
await usdc.deployed();
const membershipFactory = await ethers.getContractFactory("MockMembershipStatus");
const membership = await membershipFactory.connect(deployer).deploy();
await membership.deployed();
const registryFactory = await ethers.getContractFactory("EdutOfferEntitlement");
const registry = await registryFactory
.connect(deployer)
.deploy(treasury.address, usdc.address, membership.address);
await registry.deployed();
return { deployer, treasury, ownerWallet, payer, other, usdc, membership, registry };
}
it("requires owner role to configure offers", async function () {
const { registry, other } = await deployFixture();
await expectRevertWithCustomError(
registry.connect(other).upsertOffer(OFFER_WORKSPACE_CORE, PRICE, true, true),
"NotOwner",
);
});
it("blocks purchase when membership-required offer has no active membership", async function () {
const { registry, ownerWallet, payer, usdc } = await deployFixture();
await (await registry.upsertOffer(OFFER_WORKSPACE_CORE, PRICE, true, true)).wait();
await (await usdc.mint(payer.address, PRICE)).wait();
await (await usdc.connect(payer).approve(registry.address, PRICE)).wait();
await expectRevertWithCustomError(
registry.connect(payer).purchaseEntitlement(
OFFER_WORKSPACE_CORE,
ownerWallet.address,
ethers.utils.formatBytes32String("org_root_a"),
ethers.utils.formatBytes32String("workspace_a"),
),
"MembershipRequired",
);
});
it("mints entitlement and settles USDC to treasury", async function () {
const { registry, membership, ownerWallet, payer, treasury, usdc } = await deployFixture();
await (await registry.upsertOffer(OFFER_WORKSPACE_CORE, PRICE, true, true)).wait();
await (await membership.setMembership(ownerWallet.address, true)).wait();
await (await usdc.mint(payer.address, PRICE)).wait();
await (await usdc.connect(payer).approve(registry.address, PRICE)).wait();
const tx = await registry.connect(payer).purchaseEntitlement(
OFFER_WORKSPACE_CORE,
ownerWallet.address,
ethers.utils.formatBytes32String("org_root_a"),
ethers.utils.formatBytes32String("workspace_a"),
);
await tx.wait();
expect((await usdc.balanceOf(treasury.address)).eq(PRICE)).to.equal(true);
const entitlement = await registry.entitlementById(1);
expect(entitlement.ownerWallet).to.equal(ownerWallet.address);
expect(entitlement.payerWallet).to.equal(payer.address);
expect(Number(entitlement.state)).to.equal(1);
});
it("supports repeated lane purchases with deterministic incremental ids", async function () {
const { registry, membership, ownerWallet, payer, usdc } = await deployFixture();
await (await registry.upsertOffer(OFFER_WORKSPACE_LANE24, PRICE, true, true)).wait();
await (await membership.setMembership(ownerWallet.address, true)).wait();
const total = PRICE.mul(2);
await (await usdc.mint(payer.address, total)).wait();
await (await usdc.connect(payer).approve(registry.address, total)).wait();
await (
await registry.connect(payer).purchaseEntitlement(
OFFER_WORKSPACE_LANE24,
ownerWallet.address,
ethers.utils.formatBytes32String("org_root_a"),
ethers.utils.formatBytes32String("workspace_a"),
)
).wait();
await (
await registry.connect(payer).purchaseEntitlement(
OFFER_WORKSPACE_LANE24,
ownerWallet.address,
ethers.utils.formatBytes32String("org_root_a"),
ethers.utils.formatBytes32String("workspace_a"),
)
).wait();
const first = await registry.entitlementById(1);
const second = await registry.entitlementById(2);
expect(Number(first.state)).to.equal(1);
expect(Number(second.state)).to.equal(1);
expect((await registry.nextEntitlementId()).eq(3)).to.equal(true);
});
it("allows owner to update entitlement state", async function () {
const { registry, membership, ownerWallet, payer, usdc } = await deployFixture();
await (await registry.upsertOffer(OFFER_WORKSPACE_CORE, PRICE, true, true)).wait();
await (await membership.setMembership(ownerWallet.address, true)).wait();
await (await usdc.mint(payer.address, PRICE)).wait();
await (await usdc.connect(payer).approve(registry.address, PRICE)).wait();
await (
await registry.connect(payer).purchaseEntitlement(
OFFER_WORKSPACE_CORE,
ownerWallet.address,
ethers.utils.formatBytes32String("org_root_a"),
ethers.utils.formatBytes32String("workspace_a"),
)
).wait();
await (await registry.setEntitlementState(1, 2)).wait();
const entitlement = await registry.entitlementById(1);
expect(Number(entitlement.state)).to.equal(2);
});
});