const { expect } = require("chai"); const { ethers } = require("hardhat"); describe("AereBestExReceipt", () => { let foundation, casp1, casp2, outsider; let reg; const LICENCE_REF = ethers.keccak256(ethers.toUtf8Bytes("MICA-XYZ-12345||DE-BAFIN||LEI-1234")); beforeEach(async () => { [foundation, casp1, casp2, outsider] = await ethers.getSigners(); const F = await ethers.getContractFactory("AereBestExReceipt"); reg = await F.deploy(foundation.address); await reg.waitForDeployment(); }); function blankReceipt(caspAddr, overrides = {}) { return { casp: caspAddr, clientHash: ethers.keccak256(ethers.toUtf8Bytes("client-42")), clientClass: 0, // Retail orderId: ethers.keccak256(ethers.toUtf8Bytes("order-1")), orderType: 0, // Market instrumentSymbol: ethers.keccak256(ethers.toUtf8Bytes("BTC/EUR")), requestedQty: ethers.parseUnits("1", 18), executedQty: ethers.parseUnits("1", 18), executedPrice: ethers.parseUnits("63000", 18), executedVenue: ethers.keccak256(ethers.toUtf8Bytes("Binance.com")), alternativesRoot: ethers.keccak256(ethers.toUtf8Bytes("merkle-root-alts")), algorithmRef: ethers.keccak256(ethers.toUtf8Bytes("SOR-v3.1||abc123")), decisionTsMs: 1717880000000n, executionTsMs: 1717880000420n, evidenceUri: "ipfs://bafy...alts.json", ...overrides, }; } it("registers a CASP only by the Foundation", async () => { await expect( reg.connect(outsider).registerCasp(casp1.address, LICENCE_REF) ).to.be.revertedWithCustomError(reg, "NotFoundation"); await reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF); expect((await reg.caspOf(casp1.address)).exists).to.equal(true); }); it("rejects double-registration + zero licence", async () => { await reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF); await expect( reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF) ).to.be.revertedWithCustomError(reg, "CaspExists"); await expect( reg.connect(foundation).registerCasp(casp2.address, ethers.ZeroHash) ).to.be.revertedWithCustomError(reg, "ZeroLicence"); }); it("issues a receipt, increments nonce, emits the full event", async () => { await reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF); const r = blankReceipt(casp1.address); const expectedId = await reg.nextReceiptId(casp1.address); await expect(reg.connect(casp1).issueReceipt(r)) .to.emit(reg, "ReceiptIssued") .withArgs( casp1.address, expectedId, r.clientHash, r.instrumentSymbol, r.executedVenue, r.alternativesRoot, r.executedQty, r.executedPrice, r.decisionTsMs, r.executionTsMs, r.algorithmRef, r.evidenceUri ); expect(await reg.issuedCount(casp1.address)).to.equal(1n); expect(await reg.receiptNonce(casp1.address)).to.equal(1n); const stored = await reg.getReceipt(expectedId); expect(stored.executedPrice).to.equal(r.executedPrice); expect(await reg.executionLatencyMs(expectedId)).to.equal(420n); expect(await reg.caspIsActive(casp1.address)).to.equal(true); }); it("rejects unregistered, paused, and mismatched-casp issuance", async () => { const r = blankReceipt(casp1.address); // unregistered await expect(reg.connect(casp1).issueReceipt(r)).to.be.revertedWithCustomError(reg, "CaspUnknown"); await reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF); // r.casp != msg.sender await expect( reg.connect(casp1).issueReceipt(blankReceipt(casp2.address)) ).to.be.revertedWithCustomError(reg, "CaspUnknown"); // pause then attempt await reg.connect(foundation).setCaspPaused(casp1.address, true); await expect(reg.connect(casp1).issueReceipt(r)).to.be.revertedWithCustomError(reg, "CaspIsPaused"); // unpause + succeed await reg.connect(foundation).setCaspPaused(casp1.address, false); await reg.connect(casp1).issueReceipt(r); }); it("rejects malformed receipts (timestamps, qty, alts root)", async () => { await reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF); // execution before decision await expect( reg.connect(casp1).issueReceipt( blankReceipt(casp1.address, { decisionTsMs: 1000n, executionTsMs: 500n }) ) ).to.be.revertedWithCustomError(reg, "BadTimestamps"); // zero qty await expect( reg.connect(casp1).issueReceipt(blankReceipt(casp1.address, { executedQty: 0 })) ).to.be.revertedWithCustomError(reg, "BadQuantities"); // over-execution await expect( reg.connect(casp1).issueReceipt( blankReceipt(casp1.address, { requestedQty: ethers.parseUnits("1", 18), executedQty: ethers.parseUnits("2", 18), }) ) ).to.be.revertedWithCustomError(reg, "BadQuantities"); // zero alts root await expect( reg.connect(casp1).issueReceipt( blankReceipt(casp1.address, { alternativesRoot: ethers.ZeroHash }) ) ).to.be.revertedWithCustomError(reg, "BadAlternatives"); // zero venue await expect( reg.connect(casp1).issueReceipt( blankReceipt(casp1.address, { executedVenue: ethers.ZeroHash }) ) ).to.be.revertedWithCustomError(reg, "BadAlternatives"); }); it("caspIsActive false until first receipt issued", async () => { await reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF); expect(await reg.caspIsActive(casp1.address)).to.equal(false); await reg.connect(casp1).issueReceipt(blankReceipt(casp1.address)); expect(await reg.caspIsActive(casp1.address)).to.equal(true); }); it("receiptIds for distinct CASPs do not collide", async () => { await reg.connect(foundation).registerCasp(casp1.address, LICENCE_REF); await reg.connect(foundation).registerCasp(casp2.address, LICENCE_REF); const id1 = await reg.nextReceiptId(casp1.address); const id2 = await reg.nextReceiptId(casp2.address); expect(id1).to.not.equal(id2); }); });