From e458b02cbbb7a7fa2f7312637c826bac86698f26 Mon Sep 17 00:00:00 2001 From: Nenad Date: Wed, 19 Jul 2023 09:41:09 +0200 Subject: [PATCH] Add setupDonationMatch test cases --- test/core/accounts/AccountsDonationMatch.ts | 168 +++++++++++++++++++- test/utils/helpers/types.ts | 5 + 2 files changed, 172 insertions(+), 1 deletion(-) diff --git a/test/core/accounts/AccountsDonationMatch.ts b/test/core/accounts/AccountsDonationMatch.ts index da9f39198..07ecd5637 100644 --- a/test/core/accounts/AccountsDonationMatch.ts +++ b/test/core/accounts/AccountsDonationMatch.ts @@ -7,10 +7,15 @@ import { DEFAULT_CHARITY_ENDOWMENT, DEFAULT_REGISTRAR_CONFIG, DEFAULT_STRATEGY_SELECTOR, + DonationMatchEnum, } from "test/utils"; import { AccountsDonationMatch, AccountsDonationMatch__factory, + DonationMatch, + DonationMatchEmitter, + DonationMatchEmitter__factory, + DonationMatch__factory, DummyERC20, DummyERC20__factory, Registrar, @@ -21,6 +26,8 @@ import {RegistrarStorage} from "typechain-types/contracts/core/registrar/Registr import {AccountStorage} from "typechain-types/contracts/test/accounts/TestFacetProxyContract"; import {genWallet, getSigners} from "utils"; import {deployFacetAsProxy} from "./utils/deployTestFacet"; +import {AccountMessages} from "typechain-types/contracts/core/accounts/facets/AccountsDonationMatch"; +import {DonationMatchStorage} from "typechain-types/contracts/normalized_endowment/donation-match/DonationMatchEmitter"; use(smock.matchers); @@ -29,6 +36,8 @@ describe("AccountsDonationMatch", function () { const endowId = 1; + const usdcAddress = genWallet().address; + let accOwner: SignerWithAddress; let proxyAdmin: SignerWithAddress; let endowOwner: SignerWithAddress; @@ -38,6 +47,8 @@ describe("AccountsDonationMatch", function () { let state: TestFacetProxyContract; let daoTokenFake: FakeContract; + let donationMatchFake: FakeContract; + let donationMatchEmitterFake: FakeContract; let haloTokenFake: FakeContract; let registrarFake: FakeContract; @@ -56,13 +67,21 @@ describe("AccountsDonationMatch", function () { facet = AccountsDonationMatch__factory.connect(state.address, endowOwner); - registrarFake = await smock.fake(new Registrar__factory()); daoTokenFake = await smock.fake(new DummyERC20__factory()); + donationMatchFake = await smock.fake(new DonationMatch__factory()); + donationMatchEmitterFake = await smock.fake( + new DonationMatchEmitter__factory() + ); haloTokenFake = await smock.fake(new DummyERC20__factory()); + registrarFake = await smock.fake(new Registrar__factory()); const config: RegistrarStorage.ConfigStruct = { ...DEFAULT_REGISTRAR_CONFIG, + donationMatchContract: donationMatchFake.address, + donationMatchEmitter: donationMatchEmitterFake.address, haloToken: haloTokenFake.address, + proxyAdmin: proxyAdmin.address, + usdcAddress, }; registrarFake.queryConfig.returns(config); @@ -169,4 +188,151 @@ describe("AccountsDonationMatch", function () { expect(await state.getDaoTokenBalance(endowId)).to.equal(1); }); }); + + describe("upon setupDonationMatch", () => { + let details: AccountMessages.DonationMatchStruct; + + beforeEach(() => { + details = { + enumData: DonationMatchEnum.HaloTokenReserve, + data: { + poolFee: 5, + reserveToken: ethers.constants.AddressZero, + uniswapFactory: genWallet().address, + }, + }; + }); + + it("reverts if sender is not the endowment owner", async () => { + await expect(facet.connect(user).setupDonationMatch(endowId, details)).to.be.revertedWith( + "Unauthorized" + ); + }); + + it("reverts if a donation match contract has already been created for an endowment", async () => { + const prevEndow = await state.getEndowmentDetails(endowId); + const endowWithDonMatch: AccountStorage.EndowmentStruct = { + ...prevEndow, + donationMatchContract: genWallet().address, + }; + await state.setEndowmentDetails(endowId, endowWithDonMatch); + + await expect(facet.setupDonationMatch(endowId, details)).to.be.revertedWith( + "A Donation Match contract already exists for this Endowment" + ); + }); + + it("reverts if the passed uniswapFactory address is a zero address", async () => { + details.data.uniswapFactory = ethers.constants.AddressZero; + + await expect(facet.setupDonationMatch(endowId, details)).to.be.revertedWith( + "Invalid UniswapFactory address" + ); + }); + + it("reverts if the passed pool fee is 0 (zero)", async () => { + details.data.poolFee = 0; + + await expect(facet.setupDonationMatch(endowId, details)).to.be.revertedWith( + "Invalid pool fee" + ); + }); + + it("reverts if there is no donation matching contract implementation in the Registrar", async () => { + const prevConfig = await registrarFake.queryConfig(); + const config: RegistrarStorage.ConfigStruct = { + ...prevConfig, + donationMatchContract: ethers.constants.AddressZero, + }; + registrarFake.queryConfig.returns(config); + + await expect(facet.setupDonationMatch(endowId, details)).to.be.revertedWith( + "Missing implementation for donation matching contract" + ); + }); + + it("reverts if there is no USDC address in the Registrar", async () => { + const prevConfig = await registrarFake.queryConfig(); + const config: RegistrarStorage.ConfigStruct = { + ...prevConfig, + usdcAddress: ethers.constants.AddressZero, + }; + registrarFake.queryConfig.returns(config); + + await expect(facet.setupDonationMatch(endowId, details)).to.be.revertedWith( + "Invalid USDC address in Registrar" + ); + }); + + it("reverts if there is no HALO address in the Registrar", async () => { + const prevConfig = await registrarFake.queryConfig(); + const config: RegistrarStorage.ConfigStruct = { + ...prevConfig, + haloToken: ethers.constants.AddressZero, + }; + registrarFake.queryConfig.returns(config); + + await expect(facet.setupDonationMatch(endowId, details)).to.be.revertedWith( + "Invalid HALO address in Registrar" + ); + }); + + it("reverts if the passed reserveToken address is a zero address", async () => { + details.enumData = DonationMatchEnum.Cw20TokenReserve; + details.data.reserveToken = ethers.constants.AddressZero; + + await expect(facet.setupDonationMatch(endowId, details)).to.be.revertedWith( + "Invalid reserve token address" + ); + }); + + it("passes when setting up HALO as the reserve token", async () => { + await expect(facet.setupDonationMatch(endowId, details)).to.emit( + facet, + "DonationMatchCreated" + ); + + const endow = await state.getEndowmentDetails(endowId); + expect(endow.donationMatchContract).to.not.equal(ethers.constants.AddressZero); + + const expectedConfig: DonationMatchStorage.ConfigStruct = { + poolFee: details.data.poolFee, + uniswapFactory: details.data.uniswapFactory, + registrarContract: registrarFake.address, + reserveToken: haloTokenFake.address, + usdcAddress, + }; + expect(donationMatchEmitterFake.initializeDonationMatch).to.have.been.calledWith( + endowId, + endow.donationMatchContract, + expectedConfig + ); + }); + + it("passes when setting up some custom reserve token", async () => { + details.enumData = DonationMatchEnum.Cw20TokenReserve; + details.data.reserveToken = genWallet().address; + + await expect(facet.setupDonationMatch(endowId, details)).to.emit( + facet, + "DonationMatchCreated" + ); + + const endow = await state.getEndowmentDetails(endowId); + expect(endow.donationMatchContract).to.not.equal(ethers.constants.AddressZero); + + const expectedConfig: DonationMatchStorage.ConfigStruct = { + poolFee: details.data.poolFee, + uniswapFactory: details.data.uniswapFactory, + registrarContract: registrarFake.address, + reserveToken: details.data.reserveToken, + usdcAddress, + }; + expect(donationMatchEmitterFake.initializeDonationMatch).to.have.been.calledWith( + endowId, + endow.donationMatchContract, + expectedConfig + ); + }); + }); }); diff --git a/test/utils/helpers/types.ts b/test/utils/helpers/types.ts index 706e12dde..e93803ed4 100644 --- a/test/utils/helpers/types.ts +++ b/test/utils/helpers/types.ts @@ -47,3 +47,8 @@ export enum DelegateAction { Set, Revoke, } + +export enum DonationMatchEnum { + HaloTokenReserve, + Cw20TokenReserve, +}