const { expect } = require("chai"); const { ethers } = require("hardhat"); describe("Meridian Protocol", function () { let meridianToken, compliance, reserveAggregator; let owner, addr1, addr2; let custodianId; beforeEach(async function () { [owner, addr1, addr2] = await ethers.getSigners(); // Deploy Compliance const Compliance = await ethers.getContractFactory("Compliance"); compliance = await Compliance.deploy(owner.address); await compliance.deployed(); // Deploy ReserveAggregator const ReserveAggregator = await ethers.getContractFactory("ReserveAggregator"); reserveAggregator = await ReserveAggregator.deploy(owner.address); await reserveAggregator.deployed(); // Deploy MeridianToken const MeridianToken = await ethers.getContractFactory("MeridianToken"); meridianToken = await MeridianToken.deploy( "Meridian GBP", "MGBP", "GBP", "Meridian LLC", reserveAggregator.address, compliance.address, owner.address ); await meridianToken.deployed(); // Add test custodian custodianId = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("test-custodian")); await reserveAggregator.addCustodian( custodianId, "Test Custodian", owner.address, // Use owner as oracle for testing 3600, // 1 hour heartbeat 2 // fund admin type ); }); describe("Deployment", function () { it("Should deploy with correct parameters", async function () { expect(await meridianToken.name()).to.equal("Meridian GBP"); expect(await meridianToken.symbol()).to.equal("MGBP"); expect(await meridianToken.currency()).to.equal("GBP"); expect(await meridianToken.issuerName()).to.equal("Meridian LLC"); expect(await meridianToken.minimumCollateralRatio()).to.equal(10200); }); it("Should have correct access roles", async function () { const MINTER_ROLE = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("MINTER_ROLE")); expect(await meridianToken.hasRole(MINTER_ROLE, owner.address)).to.be.true; }); }); describe("Compliance", function () { it("Should whitelist addresses correctly", async function () { await compliance.whitelistAddress(addr1.address, 2, "UK", 0); expect(await compliance.isWhitelisted(addr1.address)).to.be.true; expect(await compliance.isSanctioned(addr1.address)).to.be.false; }); it("Should set velocity limits based on KYC level", async function () { await compliance.whitelistAddress(addr1.address, 1, "UK", 0); const limits = await compliance.getVelocityLimits(addr1.address); expect(limits.dailyLimit).to.equal(ethers.utils.parseEther("1000")); }); }); describe("Reserve Aggregator", function () { it("Should add custodians correctly", async function () { const custodianInfo = await reserveAggregator.getCustodianInfo(custodianId); expect(custodianInfo.name).to.equal("Test Custodian"); expect(custodianInfo.isActive).to.be.true; expect(custodianInfo.custodianType).to.equal(2); }); it("Should attest reserves", async function () { const reserveAmount = ethers.utils.parseEther("1020000"); const documentHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("reserve-doc")); await reserveAggregator.attestReserves( custodianId, reserveAmount, documentHash ); const attestation = await reserveAggregator.getLatestAttestation(custodianId); expect(attestation.balance).to.equal(reserveAmount); expect(attestation.isValid).to.be.true; }); }); describe("Token Operations", function () { beforeEach(async function () { // Whitelist recipient await compliance.whitelistAddress(addr1.address, 2, "UK", 0); // Attest reserves const reserveAmount = ethers.utils.parseEther("1020000"); // £1.02M const documentHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("reserve-doc")); await reserveAggregator.attestReserves(custodianId, reserveAmount, documentHash); }); it("Should mint tokens with sufficient reserves", async function () { const mintAmount = ethers.utils.parseEther("1000000"); // £1M const attestationHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("mint-attestation")); await meridianToken.mint(addr1.address, mintAmount, attestationHash); expect(await meridianToken.balanceOf(addr1.address)).to.equal(mintAmount); expect(await meridianToken.totalSupply()).to.equal(mintAmount); }); it("Should reject mint with insufficient reserves", async function () { const mintAmount = ethers.utils.parseEther("1100000"); // £1.1M (exceeds 102% ratio) const attestationHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("mint-attestation")); await expect( meridianToken.mint(addr1.address, mintAmount, attestationHash) ).to.be.revertedWith("Insufficient reserves for mint"); }); it("Should reject mint to non-whitelisted address", async function () { const mintAmount = ethers.utils.parseEther("1000"); const attestationHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("mint-attestation")); await expect( meridianToken.mint(addr2.address, mintAmount, attestationHash) ).to.be.revertedWith("Recipient not whitelisted"); }); it("Should calculate collateralization ratio correctly", async function () { const mintAmount = ethers.utils.parseEther("1000000"); const attestationHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("mint-attestation")); await meridianToken.mint(addr1.address, mintAmount, attestationHash); const [ratio, isValid] = await meridianToken.getCurrentCollateralizationRatio(); expect(isValid).to.be.true; expect(ratio).to.equal(10200); // 102% }); }); describe("Transfer Restrictions", function () { beforeEach(async function () { // Setup: mint tokens to addr1 await compliance.whitelistAddress(addr1.address, 2, "UK", 0); await compliance.whitelistAddress(addr2.address, 2, "US", 0); const reserveAmount = ethers.utils.parseEther("1020000"); const documentHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("reserve-doc")); await reserveAggregator.attestReserves(custodianId, reserveAmount, documentHash); const mintAmount = ethers.utils.parseEther("1000"); const attestationHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("mint-attestation")); await meridianToken.mint(addr1.address, mintAmount, attestationHash); }); it("Should allow transfer between whitelisted addresses", async function () { const transferAmount = ethers.utils.parseEther("100"); await meridianToken.connect(addr1).transfer(addr2.address, transferAmount); expect(await meridianToken.balanceOf(addr2.address)).to.equal(transferAmount); }); it("Should reject transfer to non-whitelisted address", async function () { const transferAmount = ethers.utils.parseEther("100"); const addr3 = ethers.Wallet.createRandom(); await expect( meridianToken.connect(addr1).transfer(addr3.address, transferAmount) ).to.be.revertedWith("Recipient not whitelisted"); }); }); });