diff --git a/test/multisig/MultisigFactory.ts b/test/multisig/MultisigFactory.ts new file mode 100644 index 00000000..249c1eb9 --- /dev/null +++ b/test/multisig/MultisigFactory.ts @@ -0,0 +1,169 @@ +import { expect } from "chai"; +import { ethers, upgrades } from "hardhat"; +import { MultisigFactory, Multisig, MasterMultisig } from "../../typechain-types"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; + +describe("MultisigFactory", function () { + let multisigFactory: MultisigFactory; + let owner: SignerWithAddress; + let addr1: SignerWithAddress; + let addr2: SignerWithAddress; + let ecosystemMaster: SignerWithAddress; + let commonMaster: SignerWithAddress; + + beforeEach(async function () { + [owner, addr1, addr2, ecosystemMaster, commonMaster] = await ethers.getSigners(); + + const MultisigFactoryFactory = await ethers.getContractFactory("MultisigFactory"); + multisigFactory = await upgrades.deployProxy(MultisigFactoryFactory, [ + ecosystemMaster.address, + commonMaster.address + ]) as MultisigFactory; + await multisigFactory.deployed(); + }); + + describe("initialization", function () { + it("should initialize with correct masters", async function () { + await expect( + upgrades.deployProxy(await ethers.getContractFactory("MultisigFactory"), [ + ethers.constants.AddressZero, + commonMaster.address + ]) + ).to.be.revertedWith("Invalid ecosystem master"); + + await expect( + upgrades.deployProxy(await ethers.getContractFactory("MultisigFactory"), [ + ecosystemMaster.address, + ethers.constants.AddressZero + ]) + ).to.be.revertedWith("Invalid common master"); + }); + + it("should set correct roles", async function () { + expect(await multisigFactory.hasRole(await multisigFactory.DEFAULT_ADMIN_ROLE(), owner.address)).to.be.true; + expect(await multisigFactory.hasRole(await multisigFactory.CREATOR_ROLE(), owner.address)).to.be.true; + }); + }); + + describe("createMultisig", function () { + it("should create new multisig with correct parameters", async function () { + const settings = { + signers: [addr1.address, addr2.address], + isInitiatorFlags: [true, false], + threshold: 100, + owner: owner.address + }; + + await expect(multisigFactory.createMultisig(settings)) + .to.emit(multisigFactory, "MultisigCreated"); + + expect(await multisigFactory.getMultisigsCount()).to.equal(1); + + const multisigAddresses = await multisigFactory.getMultisigsAddresses(); + expect(multisigAddresses).to.have.length(1); + + const multisig = await ethers.getContractAt("Multisig", multisigAddresses[0]); + const [signers, flags] = await multisig.getSigners(); + expect(signers).to.deep.equal(settings.signers); + expect(flags).to.deep.equal(settings.isInitiatorFlags); + expect(await multisig.owner()).to.equal(settings.owner); + }); + + it("should fail if caller doesn't have CREATOR_ROLE", async function () { + const settings = { + signers: [addr1.address], + isInitiatorFlags: [true], + threshold: 100, + owner: owner.address + }; + + await expect( + multisigFactory.connect(addr1).createMultisig(settings) + ).to.be.revertedWith( + `AccessControl: account ${addr1.address.toLowerCase()} is missing role ${await multisigFactory.CREATOR_ROLE()}` + ); + }); + }); + + describe("registerMultisigs", function () { + let existingMultisig: Multisig; + + beforeEach(async function () { + const MultisigFactory = await ethers.getContractFactory("Multisig"); + existingMultisig = await MultisigFactory.deploy( + [addr1.address], + [true], + 100, + owner.address + ); + }); + + it("should register existing multisigs", async function () { + await expect(multisigFactory.registerMultisigs([existingMultisig.address])) + .to.emit(multisigFactory, "MultisigRegistered") + .withArgs(existingMultisig.address); + + expect(await multisigFactory.isRegisteredMultisig(existingMultisig.address)).to.be.true; + expect(await multisigFactory.getMultisigsCount()).to.equal(1); + }); + + it("should fail to register zero address", async function () { + await expect( + multisigFactory.registerMultisigs([ethers.constants.AddressZero]) + ).to.be.revertedWith("Invalid multisig address"); + }); + + it("should fail to register same multisig twice", async function () { + await multisigFactory.registerMultisigs([existingMultisig.address]); + await expect( + multisigFactory.registerMultisigs([existingMultisig.address]) + ).to.be.revertedWith("Already registered"); + }); + + it("should fail if caller doesn't have CREATOR_ROLE", async function () { + await expect( + multisigFactory.connect(addr1).registerMultisigs([existingMultisig.address]) + ).to.be.revertedWith( + `AccessControl: account ${addr1.address.toLowerCase()} is missing role ${await multisigFactory.CREATOR_ROLE()}` + ); + }); + }); + + describe("view functions", function () { + it("should return correct counts and addresses", async function () { + expect(await multisigFactory.getMultisigsCount()).to.equal(0); + expect(await multisigFactory.getMultisigsAddresses()).to.deep.equal([]); + + // Create a multisig + const settings = { + signers: [addr1.address], + isInitiatorFlags: [true], + threshold: 100, + owner: owner.address + }; + + await multisigFactory.createMultisig(settings); + + expect(await multisigFactory.getMultisigsCount()).to.equal(1); + const addresses = await multisigFactory.getMultisigsAddresses(); + expect(addresses).to.have.length(1); + expect(await multisigFactory.isRegisteredMultisig(addresses[0])).to.be.true; + }); + }); + + describe("upgrade control", function () { + it("should allow admin to upgrade", async function () { + const MultisigFactoryV2 = await ethers.getContractFactory("MultisigFactory"); + await expect( + upgrades.upgradeProxy(multisigFactory.address, MultisigFactoryV2) + ).to.not.be.reverted; + }); + + it("should not allow non-admin to upgrade", async function () { + const MultisigFactoryV2 = await ethers.getContractFactory("MultisigFactory", addr1); + await expect( + upgrades.upgradeProxy(multisigFactory.address, MultisigFactoryV2) + ).to.be.reverted; + }); + }); +});