const { expect } = require("chai"); const { ethers } = require("hardhat"); describe("AereComputeMarket (DePIN)", function () { async function deploy() { const [foundation, provider, requester, other] = await ethers.getSigners(); const M = await ethers.getContractFactory("AereComputeMarket"); const m = await M.deploy(foundation.address); await m.waitForDeployment(); return { m, foundation, provider, requester, other }; } const STAKE = ethers.parseEther("10"); const PAY = ethers.parseEther("1"); const spec = ethers.id("train-model-x"); it("full happy path: register → post → claim → submit → confirm → paid", async function () { const { m, provider, requester } = await deploy(); await m.connect(provider).registerProvider(1000, "https://p.example", { value: STAKE }); await m.connect(requester).postJob(spec, { value: PAY }); await m.connect(provider).claimJob(0); await m.connect(provider).submitResult(0, ethers.id("result")); const before = await ethers.provider.getBalance(provider.address); await m.connect(requester).confirmJob(0); const after = await ethers.provider.getBalance(provider.address); expect(after - before).to.be.closeTo(PAY, ethers.parseEther("0.001")); expect((await m.jobs(0)).status).to.equal(4); // Paid }); it("rejects under-stake provider + non-provider claim", async function () { const { m, provider, requester, other } = await deploy(); await expect(m.connect(provider).registerProvider(1, "x", { value: ethers.parseEther("9") })) .to.be.revertedWithCustomError(m, "BadStake"); await m.connect(requester).postJob(spec, { value: PAY }); await expect(m.connect(other).claimJob(0)).to.be.revertedWithCustomError(m, "NotProvider"); }); it("cancel unclaimed job refunds requester", async function () { const { m, requester } = await deploy(); await m.connect(requester).postJob(spec, { value: PAY }); await m.connect(requester).cancelJob(0); expect((await m.jobs(0)).status).to.equal(5); // Refunded }); it("autoConfirm after window pays provider; not before", async function () { const { m, provider, requester } = await deploy(); await m.connect(provider).registerProvider(1, "x", { value: STAKE }); await m.connect(requester).postJob(spec, { value: PAY }); await m.connect(provider).claimJob(0); await m.connect(provider).submitResult(0, ethers.id("r")); await expect(m.autoConfirm(0)).to.be.revertedWithCustomError(m, "WindowOpen"); await ethers.provider.send("evm_increaseTime", [3 * 24 * 3600 + 1]); await ethers.provider.send("evm_mine", []); await m.autoConfirm(0); expect((await m.jobs(0)).status).to.equal(4); // Paid }); it("dispute → Foundation slashes provider, refunds requester", async function () { const { m, foundation, provider, requester } = await deploy(); await m.connect(provider).registerProvider(1, "x", { value: STAKE }); await m.connect(requester).postJob(spec, { value: PAY }); await m.connect(provider).claimJob(0); await m.connect(provider).submitResult(0, ethers.id("bad")); await m.connect(requester).disputeJob(0); await m.connect(foundation).resolveDispute(0, false); // provider loses expect((await m.jobs(0)).status).to.equal(6); // Slashed const p = await m.providers(provider.address); expect(p.stake).to.equal(ethers.parseEther("5")); // 50% slashed expect(await m.slashPool()).to.equal(ethers.parseEther("5")); }); it("provider cannot deregister with active jobs", async function () { const { m, provider, requester } = await deploy(); await m.connect(provider).registerProvider(1, "x", { value: STAKE }); await m.connect(requester).postJob(spec, { value: PAY }); await m.connect(provider).claimJob(0); await expect(m.connect(provider).deregisterProvider()).to.be.revertedWithCustomError(m, "HasActiveJobs"); }); });