138 lines
5.5 KiB
JavaScript
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);
|
|
});
|
|
});
|