diff --git a/test/core/IndexFund.ts b/test/core/IndexFund.ts index a9354b1e1..f357a6a38 100644 --- a/test/core/IndexFund.ts +++ b/test/core/IndexFund.ts @@ -1,5 +1,11 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; -import {impersonateAccount, setBalance, time} from "@nomicfoundation/hardhat-network-helpers"; +import { + SnapshotRestorer, + impersonateAccount, + setBalance, + takeSnapshot, + time, +} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; import {Signer} from "ethers"; import hre from "hardhat"; @@ -31,11 +37,11 @@ describe("IndexFund", function () { let proxyAdmin: Signer; let user: Signer; + let accountsDepositWithdrawEndowments: AccountsDepositWithdrawEndowments; let registrar: FakeContract; let wmatic: FakeContract; let token: FakeContract; - let accountsDepositWithdrawEndowments: AccountsDepositWithdrawEndowments; let state: TestFacetProxyContract; let facet: IndexFund; @@ -134,9 +140,7 @@ describe("IndexFund", function () { reentrancyGuardLocked: false, }) ); - }); - beforeEach(async () => { const proxy = await deployIndexFundAsProxy(); facet = IndexFund__factory.connect(proxy.address, owner); @@ -152,6 +156,16 @@ describe("IndexFund", function () { registrar.isTokenAccepted.whenCalledWith(token.address).returns(true); }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + describe("Deploying the contract", function () { it("Deploying the contract as an upgradable proxy", async function () { const proxy = await deployIndexFundAsProxy(); @@ -289,7 +303,11 @@ describe("IndexFund", function () { }); describe("Updating an existing Fund's endowment members", function () { - beforeEach(async function () { + let rootSnapshot: SnapshotRestorer; + + before(async function () { + rootSnapshot = await takeSnapshot(); + // create 2 funds (1 active and 1 expired) let currTime = await time.latest(); await wait(facet.createIndexFund("Test Fund #1", "Test fund", [2, 3], true, 50, 0)); @@ -299,6 +317,10 @@ describe("IndexFund", function () { await time.increase(42069); // move time forward so Fund #2 is @ expiry }); + after(async () => { + await rootSnapshot.restore(); + }); + it("reverts when the message sender is not the owner", async function () { await expect(facet.connect(user).updateFundMembers(1, [1, 2], [])).to.be.revertedWith( "Ownable: caller is not the owner" @@ -333,7 +355,11 @@ describe("IndexFund", function () { }); describe("Removing an existing Fund", function () { - beforeEach(async function () { + let rootSnapshot: SnapshotRestorer; + + before(async function () { + rootSnapshot = await takeSnapshot(); + // create 2 funds (1 active and 1 expired) let currTime = await time.latest(); await wait(facet.createIndexFund("Test Fund #1", "Test fund", [2, 3], true, 50, 0)); @@ -343,6 +369,10 @@ describe("IndexFund", function () { await time.increase(42069); // move time forward so Fund #2 is @ expiry }); + after(async () => { + await rootSnapshot.restore(); + }); + it("reverts when the message sender is not the owner", async function () { await expect(facet.connect(user).removeIndexFund(1)).to.be.revertedWith( "Ownable: caller is not the owner" @@ -359,7 +389,11 @@ describe("IndexFund", function () { }); describe("Removing an endowment from all involved Funds", function () { - beforeEach(async function () { + let rootSnapshot: SnapshotRestorer; + + before(async function () { + rootSnapshot = await takeSnapshot(); + // create 2 funds (1 active and 1 expired) let currTime = await time.latest(); await wait(facet.createIndexFund("Test Fund #1", "Test fund", [2, 3], true, 50, 0)); @@ -369,6 +403,10 @@ describe("IndexFund", function () { await time.increase(42069); // move time forward so Fund #2 is @ expiry }); + after(async () => { + await rootSnapshot.restore(); + }); + it("reverts when the message sender is not the accounts contract", async function () { await expect(facet.removeMember(1)).to.be.revertedWith("Unauthorized"); }); @@ -394,7 +432,11 @@ describe("IndexFund", function () { }); describe("When a user deposits tokens to a Fund", function () { - beforeEach(async function () { + let rootSnapshot: SnapshotRestorer; + + before(async function () { + rootSnapshot = await takeSnapshot(); + let currTime = await time.latest(); // create 1 active, non-rotating fund await wait(facet.createIndexFund("Test Fund #1", "Test fund", [2, 3], false, 50, 0)); @@ -405,6 +447,10 @@ describe("IndexFund", function () { await time.increase(42069); // move time forward so Fund #2 is @ expiry }); + after(async () => { + await rootSnapshot.restore(); + }); + it("reverts when amount is zero", async function () { await expect(facet.depositERC20(1, token.address, 0)).to.be.revertedWith( "Amount to donate must be greater than zero" @@ -416,6 +462,8 @@ describe("IndexFund", function () { await expect(facet.depositERC20(1, token.address, 100)).to.be.revertedWith( "Unaccepted Token" ); + // reset isTokenAccepted behavior + registrar.isTokenAccepted.whenCalledWith(token.address).returns(true); }); it("reverts when fund passed is expired", async function () { @@ -509,7 +557,7 @@ describe("IndexFund", function () { // test with a LARGER donation amount for gas-usage and rotation stress-tests await expect( facet.depositERC20(0, token.address, 1000000, { - gasPrice: 100000, + // gasPrice: 100000, @Nenad: Just wondering, why is manual gas price needed? gasLimit: 10000000, }) ) diff --git a/test/core/accounts/AccountsAllowance.ts b/test/core/accounts/AccountsAllowance.ts index d2982f320..7cc4887b1 100644 --- a/test/core/accounts/AccountsAllowance.ts +++ b/test/core/accounts/AccountsAllowance.ts @@ -1,5 +1,5 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; -import {time} from "@nomicfoundation/hardhat-network-helpers"; +import {SnapshotRestorer, takeSnapshot, time} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; import {Signer} from "ethers"; import hre from "hardhat"; @@ -36,9 +36,7 @@ describe("AccountsAllowance", function () { user = signers.apTeam2; proxyAdmin = await getProxyAdminOwner(hre); - }); - beforeEach(async function () { tokenFake = await smock.fake(IERC20__factory.createInterface()); const Facet = new AccountsAllowance__factory(accOwner); @@ -72,6 +70,16 @@ describe("AccountsAllowance", function () { await wait(state.setAllowlist(ACCOUNT_ID, 2, [await user.getAddress()])); // maturity }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + describe("Test cases for `manageAllowances`", function () { it("reverts when the endowment is closed", async function () { await wait( @@ -124,12 +132,21 @@ describe("AccountsAllowance", function () { 10 ) ).to.be.revertedWith("Invalid Token"); + }); + it("reverts when the token dne", async function () { await expect( facet.manageAllowances(ACCOUNT_ID, await user.getAddress(), genWallet().address, 10) ).to.be.revertedWith("Invalid Token"); }); + it("reverts when the token liquid balance is 0", async function () { + await wait(state.setEndowmentTokenBalance(ACCOUNT_ID, tokenFake.address, 100, 0)); + await expect( + facet.manageAllowances(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10) + ).to.be.revertedWith("Invalid Token"); + }); + it("reverts when the spender is not in allowlistedBeneficiaries of a non-mature endowment", async function () { await expect( facet.manageAllowances(ACCOUNT_ID, await proxyAdmin.getAddress(), tokenFake.address, 10) @@ -181,22 +198,22 @@ describe("AccountsAllowance", function () { [true, false].forEach((isMature) => { const maturityStatus = isMature ? "mature" : "non-mature"; - beforeEach(async () => { - if (!isMature) { - return; + async function setMaturityTimeIfNecessary() { + if (isMature) { + let currTime = await time.latest(); + const endow = await state.getEndowmentDetails(ACCOUNT_ID); + await wait( + state.setEndowmentDetails(ACCOUNT_ID, { + ...endow, + maturityTime: currTime, + }) + ); } - - let currTime = await time.latest(); - const endow = await state.getEndowmentDetails(ACCOUNT_ID); - await wait( - state.setEndowmentDetails(ACCOUNT_ID, { - ...endow, - maturityTime: currTime, - }) - ); - }); + } it(`passes when try to increase a valid token's allowance within range of liquid balance available for a ${maturityStatus} endowment`, async function () { + await setMaturityTimeIfNecessary(); + await expect( facet.manageAllowances(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10) ) @@ -222,6 +239,8 @@ describe("AccountsAllowance", function () { }); it(`passes when try to decrease an existing spender's allowance for a ${maturityStatus} endowment`, async function () { + await setMaturityTimeIfNecessary(); + // now we allocate some token allowance to the user address to spend from await wait( state.setTokenAllowance(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10, 10) @@ -255,24 +274,32 @@ describe("AccountsAllowance", function () { }); describe("Test cases for `spendAllowance`", function () { - it("reverts when try to spend token that is invalid(zero address) or dne in allowances", async function () { - // try to spend an allowance that is invalid (Zero Address) + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); + await wait( + state.setTokenAllowance(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10, 10) + ); + }); + + after(async () => { + await rootSnapshot.restore(); + }); + + it("reverts when try to spend token that is invalid (zero address)", async function () { await expect( facet.spendAllowance(ACCOUNT_ID, ethers.constants.AddressZero, 10, await user.getAddress()) ).to.be.revertedWith("Invalid Token"); + }); - // try to spend an allowance for a token that dne + it("reverts when try to spend token that dne in allowances", async function () { await expect( facet.spendAllowance(ACCOUNT_ID, genWallet().address, 10, await user.getAddress()) ).to.be.revertedWith("Invalid Token"); }); it("reverts when try to spend zero amount of allowance", async function () { - // now we allocate some token allowance to the user address to spend from - await wait( - state.setTokenAllowance(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10, 10) - ); - // try to spend zero allowance await expect( facet.spendAllowance(ACCOUNT_ID, tokenFake.address, 0, await user.getAddress()) @@ -280,11 +307,6 @@ describe("AccountsAllowance", function () { }); it("reverts when try to spend more allowance than is available for token", async function () { - // now we allocate some token allowance to the user address to spend from - await wait( - state.setTokenAllowance(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10, 10) - ); - // try to spend more allowance than user was allocated await expect( facet @@ -294,11 +316,6 @@ describe("AccountsAllowance", function () { }); it("passes when spend less than or equal to the allowance available for token", async function () { - // now we allocate some token allowance to the user address to spend from - await wait( - state.setTokenAllowance(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10, 10) - ); - // mint tokens so that the contract can transfer them to recipient tokenFake.transfer.returns(true); @@ -328,12 +345,19 @@ describe("AccountsAllowance", function () { }); describe("upon queryAllowance", function () { - beforeEach(async () => { + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); await wait( state.setTokenAllowance(ACCOUNT_ID, await user.getAddress(), tokenFake.address, 10, 10) ); }); + after(async () => { + await rootSnapshot.restore(); + }); + it("returns 0 (zero) for non-existent endowment", async () => { const nonExistentEndowId = 200; expect( diff --git a/test/core/accounts/AccountsCreateEndowment.ts b/test/core/accounts/AccountsCreateEndowment.ts index 640437508..5dfa640ee 100644 --- a/test/core/accounts/AccountsCreateEndowment.ts +++ b/test/core/accounts/AccountsCreateEndowment.ts @@ -1,4 +1,5 @@ -import {FakeContract, smock} from "@defi-wonderland/smock"; +import {smock} from "@defi-wonderland/smock"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; import {BigNumber, Signer} from "ethers"; import hre from "hardhat"; @@ -33,9 +34,8 @@ describe("AccountsCreateEndowment", function () { let charityApplications: Signer; let facet: AccountsCreateEndowment; let state: TestFacetProxyContract; + let createEndowmentRequest: AccountMessages.CreateEndowmentRequestStruct; - let registrarFake: FakeContract; - let gasFwdFactoryFake: FakeContract; before(async function () { const signers = await getSigners(hre); @@ -114,10 +114,10 @@ describe("AccountsCreateEndowment", function () { ); endowmentFactoryFake.create.returns(endowmentOwner); - gasFwdFactoryFake = await smock.fake(new GasFwdFactory__factory()); + const gasFwdFactoryFake = await smock.fake(new GasFwdFactory__factory()); gasFwdFactoryFake.create.returns(ethers.constants.AddressZero); - registrarFake = await smock.fake(new Registrar__factory(), { + const registrarFake = await smock.fake(new Registrar__factory(), { address: genWallet().address, }); const config: RegistrarStorage.ConfigStruct = { @@ -127,9 +127,7 @@ describe("AccountsCreateEndowment", function () { gasFwdFactory: gasFwdFactoryFake.address, }; registrarFake.queryConfig.returns(config); - }); - beforeEach(async function () { let Facet = new AccountsCreateEndowment__factory(owner); let facetImpl = await Facet.deploy(); state = await deployFacetAsProxy(hre, owner, proxyAdmin, facetImpl.address); @@ -148,6 +146,16 @@ describe("AccountsCreateEndowment", function () { facet = AccountsCreateEndowment__factory.connect(state.address, owner); }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + it("should revert if the caller is not authorized to create a charity endowment", async () => { const details: AccountMessages.CreateEndowmentRequestStruct = { ...createEndowmentRequest, diff --git a/test/core/accounts/AccountsDepositWithdrawEndowments.ts b/test/core/accounts/AccountsDepositWithdrawEndowments.ts index 311ec3b6c..0c957964c 100644 --- a/test/core/accounts/AccountsDepositWithdrawEndowments.ts +++ b/test/core/accounts/AccountsDepositWithdrawEndowments.ts @@ -1,5 +1,11 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; -import {impersonateAccount, setBalance, time} from "@nomicfoundation/hardhat-network-helpers"; +import { + SnapshotRestorer, + impersonateAccount, + setBalance, + takeSnapshot, + time, +} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; import {BigNumber, Signer} from "ethers"; import hre from "hardhat"; @@ -44,12 +50,6 @@ describe("AccountsDepositWithdrawEndowments", function () { lockedPercentage: 40, donationMatch: ethers.constants.AddressZero, }; - const depositToDafEndow: AccountMessages.DepositRequestStruct = { - id: dafEndowId, - liquidPercentage: 60, - lockedPercentage: 40, - donationMatch: ethers.constants.AddressZero, - }; let accOwner: Signer; let proxyAdmin: Signer; @@ -94,9 +94,7 @@ describe("AccountsDepositWithdrawEndowments", function () { }; treasury = genWallet().address; - }); - beforeEach(async () => { const Facet = new AccountsDepositWithdrawEndowments__factory(accOwner); const facetImpl = await Facet.deploy(); state = await deployFacetAsProxy(hre, accOwner, proxyAdmin, facetImpl.address); @@ -107,21 +105,6 @@ describe("AccountsDepositWithdrawEndowments", function () { tokenFake = await smock.fake(IERC20__factory.createInterface()); wmaticFake = await smock.fake(new DummyWMATIC__factory()); - tokenFake.transferFrom.returns(true); - tokenFake.transfer.returns(true); - wmaticFake.transferFrom.returns(true); - wmaticFake.transfer.returns(true); - - const registrarConfig: RegistrarStorage.ConfigStruct = { - ...DEFAULT_REGISTRAR_CONFIG, - haloToken: genWallet().address, - indexFundContract: await indexFund.getAddress(), - wMaticAddress: wmaticFake.address, - treasury: treasury, - }; - registrarFake.queryConfig.returns(registrarConfig); - registrarFake.isTokenAccepted.whenCalledWith(tokenFake.address).returns(true); - await wait(state.setEndowmentDetails(charityId, charity)); await wait(state.setEndowmentDetails(normalEndowId, normalEndow)); await wait(state.setEndowmentDetails(dafEndowId, dafEndow)); @@ -138,6 +121,37 @@ describe("AccountsDepositWithdrawEndowments", function () { ); }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + + const registrarConfig: RegistrarStorage.ConfigStruct = { + ...DEFAULT_REGISTRAR_CONFIG, + haloToken: genWallet().address, + indexFundContract: await indexFund.getAddress(), + wMaticAddress: wmaticFake.address, + treasury: treasury, + }; + registrarFake.queryConfig.returns(registrarConfig); + registrarFake.isTokenAccepted.whenCalledWith(tokenFake.address).returns(true); + registrarFake.getFeeSettingsByFeeType.returns({ + payoutAddress: ethers.constants.AddressZero, + bps: 0, + }); + + tokenFake.transferFrom.returns(true); + tokenFake.transfer.returns(true); + + wmaticFake.transferFrom.returns(true); + wmaticFake.transfer.returns(true); + wmaticFake.deposit.returns(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + describe("upon deposit", () => { describe("of Matic", () => { let maticValue = BigNumber.from(depositAmt); @@ -654,7 +668,11 @@ describe("AccountsDepositWithdrawEndowments", function () { const lockBal = BigNumber.from(9000); const beneficiaryAddress = genWallet().address; - beforeEach(async () => { + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); + await wait(state.setEndowmentTokenBalance(charityId, tokenFake.address, lockBal, liqBal)); await wait(state.setEndowmentTokenBalance(charityId, wmaticFake.address, lockBal, liqBal)); await wait(state.setEndowmentTokenBalance(normalEndowId, tokenFake.address, lockBal, liqBal)); @@ -665,6 +683,10 @@ describe("AccountsDepositWithdrawEndowments", function () { await wait(state.setEndowmentTokenBalance(dafEndowId, wmaticFake.address, lockBal, liqBal)); }); + after(async () => { + await rootSnapshot.restore(); + }); + it("reverts if the endowment is closed", async () => { await wait( state.setClosingEndowmentState(charityId, true, { diff --git a/test/core/accounts/AccountsGasManager.ts b/test/core/accounts/AccountsGasManager.ts index 74fe7ddca..b40968a38 100644 --- a/test/core/accounts/AccountsGasManager.ts +++ b/test/core/accounts/AccountsGasManager.ts @@ -1,6 +1,7 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; import {expect, use} from "chai"; import {Signer} from "ethers"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import hre from "hardhat"; import { DEFAULT_ACCOUNTS_CONFIG, @@ -25,14 +26,19 @@ import {deployFacetAsProxy} from "./utils"; use(smock.matchers); describe("AccountsGasManager", function () { + const ACCOUNT_ID = 1; + const BALANCE = 1000; + const GAS_COST = 400; + let owner: Signer; let proxyAdmin: Signer; let user: Signer; - let impl: AccountsGasManager; + + let facet: AccountsGasManager; + let state: TestFacetProxyContract; + let token: FakeContract; let gasFwd: FakeContract; - const ACCOUNT_ID = 1; - const BALANCE = 1000; before(async function () { const signers = await getSigners(hre); @@ -41,34 +47,45 @@ describe("AccountsGasManager", function () { proxyAdmin = await getProxyAdminOwner(hre); - let Facet = new AccountsGasManager__factory(owner); - impl = await Facet.deploy(); - }); + const Facet = new AccountsGasManager__factory(owner); + const facetImpl = await Facet.deploy(); + state = await deployFacetAsProxy(hre, owner, proxyAdmin, facetImpl.address); + + facet = AccountsGasManager__factory.connect(state.address, owner); - beforeEach(async () => { token = await smock.fake(IERC20__factory.createInterface()); gasFwd = await smock.fake(new GasFwd__factory()); + let config = { + ...DEFAULT_ACCOUNTS_CONFIG, + owner: await owner.getAddress(), + }; + await wait(state.setConfig(config)); + + let endowment = { + ...DEFAULT_CHARITY_ENDOWMENT, + owner: await user.getAddress(), + gasFwd: gasFwd.address, + }; + await wait(state.setEndowmentDetails(ACCOUNT_ID, endowment)); + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + token.transfer.returns(true); token.transferFrom.returns(true); + gasFwd.sweep.returns(BALANCE); }); - describe("upon `sweepForClosure`", async function () { - let facet: AccountsGasManager; - let state: TestFacetProxyContract; - - beforeEach(async function () { - state = await deployFacetAsProxy(hre, owner, proxyAdmin, impl.address); - facet = AccountsGasManager__factory.connect(state.address, owner); - - let endowment = { - ...DEFAULT_CHARITY_ENDOWMENT, - gasFwd: gasFwd.address, - }; - await wait(state.setEndowmentDetails(ACCOUNT_ID, endowment)); - }); + afterEach(async () => { + await snapshot.restore(); + }); + describe("upon `sweepForClosure`", async function () { it("reverts if not called by self", async function () { await expect(facet.sweepForClosure(ACCOUNT_ID, token.address)).to.be.revertedWithCustomError( facet, @@ -88,27 +105,6 @@ describe("AccountsGasManager", function () { }); describe("upon `sweepForEndowment`", async function () { - let facet: AccountsGasManager; - let state: TestFacetProxyContract; - - beforeEach(async function () { - state = await deployFacetAsProxy(hre, owner, proxyAdmin, impl.address); - facet = AccountsGasManager__factory.connect(state.address, owner); - - let config = { - ...DEFAULT_ACCOUNTS_CONFIG, - owner: await owner.getAddress(), - }; - await wait(state.setConfig(config)); - - let endowment = { - ...DEFAULT_CHARITY_ENDOWMENT, - owner: await user.getAddress(), - gasFwd: gasFwd.address, - }; - await wait(state.setEndowmentDetails(ACCOUNT_ID, endowment)); - }); - it("reverts if not called by admin", async function () { await expect( facet.connect(user).sweepForEndowment(ACCOUNT_ID, VaultType.LOCKED, token.address) @@ -129,16 +125,6 @@ describe("AccountsGasManager", function () { }); describe("upon `addGas`", async function () { - let facet: AccountsGasManager; - let state: TestFacetProxyContract; - const BALANCE = 1000; - const GAS_COST = 400; - - beforeEach(async function () { - state = await deployFacetAsProxy(hre, owner, proxyAdmin, impl.address); - facet = AccountsGasManager__factory.connect(state.address, owner); - }); - it("reverts if not called by an approved caller", async function () { await expect( facet.connect(owner).addGas(ACCOUNT_ID, VaultType.LOCKED, token.address, GAS_COST) diff --git a/test/core/accounts/AccountsStrategy.ts b/test/core/accounts/AccountsStrategy.ts index 33817cf07..a36733011 100644 --- a/test/core/accounts/AccountsStrategy.ts +++ b/test/core/accounts/AccountsStrategy.ts @@ -1,4 +1,5 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; import {BigNumber, Signer} from "ethers"; import hre from "hardhat"; @@ -73,7 +74,6 @@ describe("AccountsStrategy", function () { let token: FakeContract; let vault: FakeContract; - let facetImpl: AccountsStrategy; let state: TestFacetProxyContract; let facet: AccountsStrategy; @@ -92,25 +92,17 @@ describe("AccountsStrategy", function () { gasService = await smock.fake(IAxelarGasService__factory.createInterface()); gateway = await smock.fake(IAxelarGateway__factory.createInterface()); vault = await smock.fake(IVault__factory.createInterface()); - - const Facet = new AccountsStrategy__factory(owner); - facetImpl = await Facet.deploy(); - await facetImpl.deployed(); - }); - - beforeEach(async function () { gasFwd = await smock.fake(new GasFwd__factory()); registrar = await smock.fake(new Registrar__factory()); router = await smock.fake(new Router__factory()); token = await smock.fake(ERC20__factory.createInterface()); + const Facet = new AccountsStrategy__factory(owner); + const facetImpl = await Facet.deploy(); + await facetImpl.deployed(); state = await deployFacetAsProxy(hre, owner, admin, facetImpl.address); facet = AccountsStrategy__factory.connect(state.address, owner); - token.approve.returns(true); - token.symbol.returns("TKN"); - token.transfer.returns(true); - const config: AccountStorage.ConfigStruct = { ...DEFAULT_ACCOUNTS_CONFIG, networkName: NET_NAME_THIS, @@ -158,6 +150,17 @@ describe("AccountsStrategy", function () { chainId: 42, router: genWallet().address, }; + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async function () { + snapshot = await takeSnapshot(); + + token.approve.returns(true); + token.symbol.returns("TKN"); + token.transfer.returns(true); + registrar.queryNetworkConnection.whenCalledWith(NET_NAME_THIS).returns(netInfoThis); registrar.queryNetworkConnection.whenCalledWith(NET_NAME_THAT).returns(netInfoThat); @@ -170,14 +173,29 @@ describe("AccountsStrategy", function () { registrar.isTokenAccepted.returns(true); + gasFwd.payForGas.returns(0); + gateway.tokenAddresses.returns(token.address); + gateway.validateContractCall.returns(false); + gateway.validateContractCallAndMint.returns(false); + }); + + afterEach(async () => { + await snapshot.restore(); }); describe("upon strategyInvest", function () { - beforeEach(async () => { + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); await wait(state.setActiveStrategyEndowmentState(ACCOUNT_ID, DEFAULT_STRATEGY_ID, false)); }); + after(async () => { + await rootSnapshot.restore(); + }); + describe("reverts when", function () { it("neither locked nor liquid funds are set to be invested", async function () { await expect( @@ -358,6 +376,7 @@ describe("AccountsStrategy", function () { }); describe("and calls axelar GMP", function () { + // nothing to snapshot, only mock's behavior is changing beforeEach(async function () { const stratParams: LocalRegistrarLib.StrategyParamsStruct = { ...DEFAULT_STRATEGY_PARAMS, @@ -587,10 +606,17 @@ describe("AccountsStrategy", function () { }); describe("upon strategyRedeem", function () { - beforeEach(async () => { + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); await wait(state.setActiveStrategyEndowmentState(ACCOUNT_ID, DEFAULT_STRATEGY_ID, true)); }); + after(async () => { + await rootSnapshot.restore(); + }); + describe("reverts when", function () { it("neither locked nor liquid funds are set to be redeemed", async function () { await expect( @@ -750,6 +776,7 @@ describe("AccountsStrategy", function () { }); describe("and calls axelar GMP", function () { + // nothing to snapshot, only mock's behavior is changing beforeEach(async function () { const stratParams: LocalRegistrarLib.StrategyParamsStruct = { ...DEFAULT_STRATEGY_PARAMS, @@ -949,10 +976,17 @@ describe("AccountsStrategy", function () { }); describe("upon strategyRedeemAll", function () { - beforeEach(async () => { + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); await wait(state.setActiveStrategyEndowmentState(ACCOUNT_ID, DEFAULT_STRATEGY_ID, true)); }); + after(async () => { + await rootSnapshot.restore(); + }); + describe("reverts when", function () { it("neither locked nor liquid funds are set to be redeemed", async function () { await expect( @@ -1107,6 +1141,7 @@ describe("AccountsStrategy", function () { }); describe("and calls axelar GMP", function () { + // nothing to snapshot, only mock's behavior is changing beforeEach(async function () { const stratParams: LocalRegistrarLib.StrategyParamsStruct = { ...DEFAULT_STRATEGY_PARAMS, @@ -1404,11 +1439,21 @@ describe("AccountsStrategy", function () { }); describe("upon axelar callback", function () { + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); + await wait(state.setActiveStrategyEndowmentState(ACCOUNT_ID, DEFAULT_STRATEGY_ID, true)); + }); + + // nothing to snapshot, only mock's behavior is changing beforeEach(async () => { gateway.validateContractCall.returns(true); gateway.validateContractCallAndMint.returns(true); + }); - await wait(state.setActiveStrategyEndowmentState(ACCOUNT_ID, DEFAULT_STRATEGY_ID, true)); + after(async () => { + await rootSnapshot.restore(); }); describe("into _execute", () => { diff --git a/test/core/accounts/AccountsSwapRouter.ts b/test/core/accounts/AccountsSwapRouter.ts index debe93732..2f0553b76 100644 --- a/test/core/accounts/AccountsSwapRouter.ts +++ b/test/core/accounts/AccountsSwapRouter.ts @@ -1,7 +1,7 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; -import {time} from "@nomicfoundation/hardhat-network-helpers"; -import {Signer} from "ethers"; +import {SnapshotRestorer, takeSnapshot, time} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; +import {Signer} from "ethers"; import hre from "hardhat"; import {deployDummyERC20} from "tasks/helpers"; import { @@ -33,17 +33,21 @@ use(smock.matchers); describe("AccountsSwapRouter", function () { const {ethers} = hre; + + const ACCOUNT_ID = 1; + let owner: Signer; let proxyAdmin: Signer; let user: Signer; + let facet: AccountsSwapRouter; - let facetImpl: AccountsSwapRouter; let state: TestFacetProxyContract; - let registrar: FakeContract; + let uniswapRouter: DummySwapRouter; let uniswapFactory: DummyUniswapV3Factory; + + let registrar: FakeContract; let chainlink: FakeContract; - const ACCOUNT_ID = 1; before(async function () { const signers = await getSigners(hre); @@ -53,10 +57,8 @@ describe("AccountsSwapRouter", function () { proxyAdmin = await getProxyAdminOwner(hre); let Facet = new AccountsSwapRouter__factory(owner); - facetImpl = await Facet.deploy(); - }); + const facetImpl = await Facet.deploy(); - beforeEach(async function () { registrar = await smock.fake(new Registrar__factory(), { address: genWallet().address, }); @@ -72,19 +74,41 @@ describe("AccountsSwapRouter", function () { uniswapFactory = await UniswapFactory.deploy(); state = await deployFacetAsProxy(hre, owner, proxyAdmin, facetImpl.address); + facet = AccountsSwapRouter__factory.connect(state.address, owner); const config = { ...DEFAULT_ACCOUNTS_CONFIG, registrarContract: registrar.address, }; await wait(state.setConfig(config)); + }); - facet = AccountsSwapRouter__factory.connect(state.address, owner); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + + const ANSWER = 1; + let currTime = await time.latest(); + chainlink.latestRoundData.returns([0, ANSWER, 0, currTime, 0]); + + registrar.queryConfig.returns({ + ...DEFAULT_REGISTRAR_CONFIG, + uniswapRouter: uniswapRouter.address, + uniswapFactory: uniswapFactory.address, + }); + registrar.isTokenAccepted.returns(true); + registrar.queryTokenPriceFeed.returns(chainlink.address); + }); + + afterEach(async () => { + await snapshot.restore(); }); describe("upon swapToken", async function () { describe("revert cases", async function () { it("reverts if the uniswapRouter isn't set", async function () { + registrar.queryConfig.returns(DEFAULT_REGISTRAR_CONFIG); await expect( facet.swapToken( ACCOUNT_ID, @@ -115,11 +139,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if the amountIn is zero", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); await expect( facet.swapToken( ACCOUNT_ID, @@ -133,11 +152,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if the tokenIn is the zero address", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); await expect( facet.swapToken( ACCOUNT_ID, @@ -151,11 +165,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if tokenIn is the same as tokenOut", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); let token = genWallet().address; await expect( facet.swapToken(ACCOUNT_ID, VaultType.LOCKED, token, 1, token, 0) @@ -163,11 +172,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if the tokenOut is the zero address", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); await expect( facet.swapToken( ACCOUNT_ID, @@ -181,11 +185,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if the slippage is too high", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); await expect( facet.swapToken( ACCOUNT_ID, @@ -199,11 +198,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if the token isn't accepted", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); registrar.isTokenAccepted.returns(false); await expect( @@ -219,13 +213,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if locked vault mgmt isnt allowed", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); - registrar.isTokenAccepted.returns(true); - await expect( facet.swapToken( ACCOUNT_ID, @@ -239,13 +226,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if liquid vault mgmt isnt allowed", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); - registrar.isTokenAccepted.returns(true); - await expect( facet.swapToken( ACCOUNT_ID, @@ -259,12 +239,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if locked token balance is insufficient", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); - registrar.isTokenAccepted.returns(true); const endow = DEFAULT_CHARITY_ENDOWMENT; endow.settingsController.lockedInvestmentManagement = { ...DEFAULT_PERMISSIONS_STRUCT, @@ -282,12 +256,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if liquid token balance is insufficient", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); - registrar.isTokenAccepted.returns(true); const endow = DEFAULT_CHARITY_ENDOWMENT; endow.settingsController.liquidInvestmentManagement = { ...DEFAULT_PERMISSIONS_STRUCT, @@ -306,12 +274,6 @@ describe("AccountsSwapRouter", function () { }); it("reverts if the chainlink price oracle contract is not set in the registrar nor in state PriceFeeds", async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); - registrar.isTokenAccepted.returns(true); const endow = { ...DEFAULT_CHARITY_ENDOWMENT, owner: await owner.getAddress(), @@ -331,18 +293,12 @@ describe("AccountsSwapRouter", function () { it("reverts if the token approval fails", async function () { let token = await deployDummyERC20(owner); await token.setApproveAllowed(false); - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); - registrar.isTokenAccepted.returns(true); + const endow = { ...DEFAULT_CHARITY_ENDOWMENT, owner: await owner.getAddress(), }; await wait(state.setEndowmentDetails(ACCOUNT_ID, endow)); - registrar.queryTokenPriceFeed.returns(chainlink.address); await wait(state.setEndowmentTokenBalance(ACCOUNT_ID, token.address, 100, 100)); await expect( @@ -355,29 +311,39 @@ describe("AccountsSwapRouter", function () { let token1: DummyERC20; let token2: DummyERC20; const AMT1 = 1000; - beforeEach(async function () { - registrar.queryConfig.returns({ - ...DEFAULT_REGISTRAR_CONFIG, - uniswapRouter: uniswapRouter.address, - uniswapFactory: uniswapFactory.address, - }); - registrar.isTokenAccepted.returns(true); - registrar.queryTokenPriceFeed.returns(chainlink.address); + + let rootSnapshot: SnapshotRestorer; + + before(async () => { + rootSnapshot = await takeSnapshot(); + + token1 = await deployDummyERC20(owner); + token2 = await deployDummyERC20(owner); const endow = { ...DEFAULT_CHARITY_ENDOWMENT, owner: await owner.getAddress(), }; - token1 = await deployDummyERC20(owner); - token2 = await deployDummyERC20(owner); await wait(state.setEndowmentDetails(ACCOUNT_ID, endow)); await wait(state.setEndowmentTokenBalance(ACCOUNT_ID, token1.address, AMT1, 0)); }); + after(async () => { + await rootSnapshot.restore(); + }); + describe("revert cases", async function () { - beforeEach(async function () { + let parentSnapshot: SnapshotRestorer; + + before(async () => { + parentSnapshot = await takeSnapshot(); await wait(token1.mint(facet.address, AMT1)); }); + + after(async () => { + await parentSnapshot.restore(); + }); + it("reverts if the price feed response is invalid", async function () { const ANSWER = 0; chainlink.latestRoundData.returns([0, ANSWER, 0, 0, 0]); @@ -387,18 +353,12 @@ describe("AccountsSwapRouter", function () { }); it("reverts if the factory cant find a pool", async function () { - const ANSWER = 1; - let currTime = await time.latest(); - chainlink.latestRoundData.returns([0, ANSWER, 0, currTime, 0]); await expect( facet.swapToken(ACCOUNT_ID, VaultType.LOCKED, token1.address, AMT1, token2.address, 1) ).to.be.revertedWith("No pool found to swap"); }); it("reverts if output is less than expected", async function () { - const ANSWER = 1; - let currTime = await time.latest(); - chainlink.latestRoundData.returns([0, ANSWER, 0, currTime, 0]); await wait(uniswapFactory.setPool(genWallet().address)); await wait(uniswapRouter.setOutputValue(0)); await expect( @@ -410,19 +370,26 @@ describe("AccountsSwapRouter", function () { describe("successfully swaps", async function () { const AMT1 = 1000; const AMT2 = 1000; - beforeEach(async function () { - const ANSWER = 1; - let currTime = await time.latest(); - chainlink.latestRoundData.returns([0, ANSWER, 0, currTime, 0]); + + let parentSnapshot: SnapshotRestorer; + + before(async () => { + parentSnapshot = await takeSnapshot(); + await wait(uniswapFactory.setPool(genWallet().address)); await wait(uniswapRouter.setOutputValue(AMT2)); - }); - it("swaps and updates the locked balance successfully", async function () { await wait(token1.mint(facet.address, AMT1)); await wait(token2.mint(uniswapRouter.address, AMT2)); - await wait(uniswapRouter.setOutputValue(AMT2)); + }); + + after(async () => { + await parentSnapshot.restore(); + }); + + it("swaps and updates the locked balance successfully", async function () { await wait(state.setEndowmentTokenBalance(ACCOUNT_ID, token1.address, AMT1, 0)); + await expect( facet.swapToken(ACCOUNT_ID, VaultType.LOCKED, token1.address, AMT1, token2.address, 1) ) @@ -444,9 +411,8 @@ describe("AccountsSwapRouter", function () { }); it("swaps and updates the liquid balance successfully", async function () { - await wait(token1.mint(facet.address, AMT1)); - await wait(token2.mint(uniswapRouter.address, AMT2)); await wait(state.setEndowmentTokenBalance(ACCOUNT_ID, token1.address, 0, AMT1)); + await expect( facet.swapToken(ACCOUNT_ID, VaultType.LIQUID, token1.address, AMT1, token2.address, 1) ) diff --git a/test/core/accounts/AccountsUpdate.ts b/test/core/accounts/AccountsUpdate.ts index 8507b3004..96ad0673f 100644 --- a/test/core/accounts/AccountsUpdate.ts +++ b/test/core/accounts/AccountsUpdate.ts @@ -7,6 +7,7 @@ import {AccountStorage} from "typechain-types/contracts/test/accounts/TestFacetP import {EndowmentType} from "types"; import {getProxyAdminOwner, getSigners} from "utils"; import {deployFacetAsProxy} from "./utils"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; describe("AccountsUpdate", function () { const {ethers} = hre; @@ -30,9 +31,7 @@ describe("AccountsUpdate", function () { newRegistrar = await signers.apTeam1.getAddress(); endowment = {...DEFAULT_CHARITY_ENDOWMENT, owner: await owner.getAddress()}; - }); - beforeEach(async function () { let Facet = new AccountsUpdate__factory(owner); let facetImpl = await Facet.deploy(); state = await deployFacetAsProxy(hre, owner, proxyAdmin, facetImpl.address); @@ -55,6 +54,16 @@ describe("AccountsUpdate", function () { facet = AccountsUpdate__factory.connect(state.address, owner); }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + describe("updateOwner", () => { it("should update the owner when called by the current owner", async () => { await expect(facet.updateOwner(await user.getAddress())) diff --git a/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts b/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts index 73bb40579..6b4bc63bd 100644 --- a/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts +++ b/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts @@ -1,7 +1,7 @@ import {smock} from "@defi-wonderland/smock"; -import {Signer} from "ethers"; -import {time} from "@nomicfoundation/hardhat-network-helpers"; +import {SnapshotRestorer, takeSnapshot, time} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; +import {Signer} from "ethers"; import hre from "hardhat"; import {DEFAULT_CHARITY_ENDOWMENT, wait} from "test/utils"; import { @@ -51,9 +51,7 @@ describe("AccountsUpdateEndowmentSettingsController", function () { ...charity, endowType: 1, }; - }); - beforeEach(async () => { let Facet = new AccountsUpdateEndowmentSettingsController__factory(owner); let facetImpl = await Facet.deploy(); state = await deployFacetAsProxy(hre, owner, proxyAdmin, facetImpl.address); @@ -75,6 +73,16 @@ describe("AccountsUpdateEndowmentSettingsController", function () { await wait(state.setEndowmentDetails(normalEndowId, normalEndow)); }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + describe("updateEndowmentSettings", () => { let charityReq: AccountMessages.UpdateEndowmentSettingsRequestStruct; let normalEndowReq: AccountMessages.UpdateEndowmentSettingsRequestStruct; diff --git a/test/core/accounts/AccountsUpdateEndowments.ts b/test/core/accounts/AccountsUpdateEndowments.ts index 448ad064a..a0cfb8df7 100644 --- a/test/core/accounts/AccountsUpdateEndowments.ts +++ b/test/core/accounts/AccountsUpdateEndowments.ts @@ -1,4 +1,4 @@ -import {smock} from "@defi-wonderland/smock"; +import {FakeContract, smock} from "@defi-wonderland/smock"; import {expect, use} from "chai"; import {BigNumberish, Signer} from "ethers"; import hre from "hardhat"; @@ -19,6 +19,7 @@ import { import {ControllerSettingOption} from "types"; import {genWallet, getProxyAdminOwner, getSigners} from "utils"; import {deployFacetAsProxy, updateAllSettings, updateSettings} from "./utils"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; use(smock.matchers); @@ -39,6 +40,8 @@ describe("AccountsUpdateEndowments", function () { let oldNormalEndow: AccountStorage.EndowmentStruct; let oldCharity: AccountStorage.EndowmentStruct; + let registrarFake: FakeContract; + before(async function () { const signers = await getSigners(hre); accOwner = signers.apTeam1; @@ -58,9 +61,11 @@ describe("AccountsUpdateEndowments", function () { ...oldCharity, endowType: 1, }; - }); - beforeEach(async () => { + registrarFake = await smock.fake(new Registrar__factory(), { + address: genWallet().address, + }); + const Facet = new AccountsUpdateEndowments__factory(accOwner); const facetImpl = await Facet.deploy(); state = await deployFacetAsProxy(hre, accOwner, proxyAdmin, facetImpl.address); @@ -69,6 +74,28 @@ describe("AccountsUpdateEndowments", function () { await wait(state.setEndowmentDetails(charityId, oldCharity)); await wait(state.setEndowmentDetails(normalEndowId, oldNormalEndow)); + + await wait( + state.setConfig({ + networkName: "test", + owner: await accOwner.getAddress(), + version: "1", + registrarContract: registrarFake.address, + nextAccountId: 1, + reentrancyGuardLocked: false, + }) + ); + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + registrarFake.isTokenAccepted.returns(false); + }); + + afterEach(async () => { + await snapshot.restore(); }); describe("updateEndowmentDetails", () => { @@ -560,7 +587,6 @@ describe("AccountsUpdateEndowments", function () { }); it("reverts if the token is a member of the protocol-level accepted tokens list in the Registrar", async () => { - const registrarFake = await deployFakeRegistrar(); registrarFake.isTokenAccepted.returns(true); await expect( facet.updateAcceptedToken(normalEndowId, tokenAddr, priceFeedAddr, true) @@ -568,8 +594,6 @@ describe("AccountsUpdateEndowments", function () { }); it("reverts if the price feed passed to the function does not support ERC-165", async () => { - const registrarFake = await deployFakeRegistrar(); - registrarFake.isTokenAccepted.returns(false); await expect( facet.updateAcceptedToken(normalEndowId, tokenAddr, priceFeedAddr, true) ).to.be.revertedWith("Price Feed contract is not a valid ERC-165 interface"); @@ -579,9 +603,6 @@ describe("AccountsUpdateEndowments", function () { it(`adds token's price feed and sets token's status as ${ tokenStatus ? "" : "*not* " }accepted`, async () => { - const registrarFake = await deployFakeRegistrar(); - registrarFake.isTokenAccepted.returns(false); - const FakePriceFeed = new DummyERC165CompatibleContract__factory(proxyAdmin); const fakePriceFeed = await FakePriceFeed.deploy(); await fakePriceFeed.deployed(); @@ -596,22 +617,5 @@ describe("AccountsUpdateEndowments", function () { await expect(await state.getTokenAccepted(normalEndowId, tokenAddr)).to.equal(tokenStatus); }); }); - - async function deployFakeRegistrar() { - const registrarFake = await smock.fake(new Registrar__factory(), { - address: genWallet().address, - }); - await wait( - state.setConfig({ - networkName: "test", - owner: await accOwner.getAddress(), - version: "1", - registrarContract: registrarFake.address, - nextAccountId: 1, - reentrancyGuardLocked: false, - }) - ); - return registrarFake; - } }); }); diff --git a/test/core/accounts/AccountsUpdateStatusEndowments.ts b/test/core/accounts/AccountsUpdateStatusEndowments.ts index eac873608..27566678b 100644 --- a/test/core/accounts/AccountsUpdateStatusEndowments.ts +++ b/test/core/accounts/AccountsUpdateStatusEndowments.ts @@ -1,6 +1,7 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; -import {Signer} from "ethers"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; +import {Signer} from "ethers"; import hre from "hardhat"; import { DEFAULT_CHARITY_ENDOWMENT, @@ -77,12 +78,6 @@ describe("AccountsUpdateStatusEndowments", function () { endowType: EndowmentType.Daf, owner: await endowOwner.getAddress(), }; - }); - - beforeEach(async function () { - let Facet = new AccountsUpdateStatusEndowments__factory(accOwner); - let facetImpl = await Facet.deploy(); - state = await deployFacetAsProxy(hre, accOwner, proxyAdmin, facetImpl.address); indexFundFake = await smock.fake(new IndexFund__factory(), { address: genWallet().address, @@ -91,14 +86,9 @@ describe("AccountsUpdateStatusEndowments", function () { address: genWallet().address, }); - const config: RegistrarStorage.ConfigStruct = { - ...DEFAULT_REGISTRAR_CONFIG, - indexFundContract: indexFundFake.address, - treasury: treasuryAddress, - haloToken: genWallet().address, - }; - registrarFake.queryConfig.returns(config); - registrarFake.queryAllStrategies.returns(strategies); + let Facet = new AccountsUpdateStatusEndowments__factory(accOwner); + let facetImpl = await Facet.deploy(); + state = await deployFacetAsProxy(hre, accOwner, proxyAdmin, facetImpl.address); await wait(state.setEndowmentDetails(accountId, ast_endowment)); await wait(state.setEndowmentDetails(charityId, charity_endowment)); @@ -119,6 +109,25 @@ describe("AccountsUpdateStatusEndowments", function () { facet = AccountsUpdateStatusEndowments__factory.connect(state.address, endowOwner); }); + let snapshot: SnapshotRestorer; + + beforeEach(async function () { + snapshot = await takeSnapshot(); + + const config: RegistrarStorage.ConfigStruct = { + ...DEFAULT_REGISTRAR_CONFIG, + indexFundContract: indexFundFake.address, + treasury: treasuryAddress, + haloToken: genWallet().address, + }; + registrarFake.queryConfig.returns(config); + registrarFake.queryAllStrategies.returns(strategies); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + describe("upon closeEndowmment", async function () { it("reverts if the caller is not the owner of the endowment", async () => { await expect( diff --git a/test/core/gasFwd/GasFwd.ts b/test/core/gasFwd/GasFwd.ts index 7aa64081e..51452e0b1 100644 --- a/test/core/gasFwd/GasFwd.ts +++ b/test/core/gasFwd/GasFwd.ts @@ -1,6 +1,7 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; -import {Signer} from "ethers"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; +import {Signer} from "ethers"; import hre from "hardhat"; import { GasFwd, @@ -23,38 +24,32 @@ describe("GasFwd", function () { let token: FakeContract; let gasFwd: GasFwd; - async function deployGasFwdAsProxy( - owner: Signer, - admin: Signer, - accounts: Signer - ): Promise { - let GasFwd = new GasFwd__factory(admin); - let gasFwdImpl = await GasFwd.deploy(); - await gasFwdImpl.deployed(); - const data = gasFwdImpl.interface.encodeFunctionData("initialize", [ - accounts ? await accounts.getAddress() : await owner.getAddress(), - ]); - let proxyFactory = new ProxyContract__factory(owner); - let proxy = await proxyFactory.deploy(gasFwdImpl.address, await admin.getAddress(), data); - await proxy.deployed(); - return GasFwd__factory.connect(proxy.address, accounts); - } - before(async function () { const {deployer, apTeam1} = await getSigners(hre); owner = deployer; accounts = apTeam1; admin = await getProxyAdminOwner(hre); - }); - beforeEach(async function () { token = await smock.fake(IERC20__factory.createInterface()); + gasFwd = await deployGasFwdAsProxy(owner, admin, accounts); + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async function () { + snapshot = await takeSnapshot(); + token.balanceOf.returns(BALANCE); + token.transfer.reset(); token.transfer.returns(true); }); + afterEach(async () => { + await snapshot.restore(); + }); + describe("upon payForGas", async function () { it("reverts if called by non-accounts contract", async function () { await expect(gasFwd.connect(owner).payForGas(token.address, 1)).to.be.revertedWithCustomError( @@ -105,7 +100,6 @@ describe("GasFwd", function () { expect(token.transfer).to.not.be.called; }); it("transfers the token balance", async function () { - token.transfer.returns(true); await expect(gasFwd.sweep(token.address)) .to.emit(gasFwd, "Sweep") .withArgs(token.address, BALANCE); @@ -113,3 +107,20 @@ describe("GasFwd", function () { }); }); }); + +async function deployGasFwdAsProxy( + owner: Signer, + admin: Signer, + accounts: Signer +): Promise { + let GasFwd = new GasFwd__factory(admin); + let gasFwdImpl = await GasFwd.deploy(); + await gasFwdImpl.deployed(); + const data = gasFwdImpl.interface.encodeFunctionData("initialize", [ + accounts ? await accounts.getAddress() : await owner.getAddress(), + ]); + let proxyFactory = new ProxyContract__factory(owner); + let proxy = await proxyFactory.deploy(gasFwdImpl.address, await admin.getAddress(), data); + await proxy.deployed(); + return GasFwd__factory.connect(proxy.address, accounts); +} diff --git a/test/core/gasFwd/GasFwdFactory.ts b/test/core/gasFwd/GasFwdFactory.ts index c393a99fa..d537f97ee 100644 --- a/test/core/gasFwd/GasFwdFactory.ts +++ b/test/core/gasFwd/GasFwdFactory.ts @@ -16,82 +16,107 @@ use(smock.matchers); describe("GasFwdFactory", function () { const {ethers} = hre; - let owner: Signer; + + let deployer: Signer; let admin: Signer; let user: Signer; - let registrarFake: FakeContract; - async function deployGasFwdFactory( - owner: Signer, - admin: Signer, - registrar: string - ): Promise { - let GasFwd = new GasFwd__factory(admin); - let gasFwdImpl = await GasFwd.deploy(); - await gasFwdImpl.deployed(); - let GFF = new GasFwdFactory__factory(owner); - let gff = await GFF.deploy(gasFwdImpl.address, await admin.getAddress(), registrar); - await gff.deployed(); - return gff; - } + let gasFwdFactory: GasFwdFactory; + + let registrarFake: FakeContract; before(async function () { - const {deployer, apTeam1} = await getSigners(hre); - owner = deployer; - user = apTeam1; + const signers = await getSigners(hre); + deployer = signers.deployer; + user = signers.apTeam1; admin = await getProxyAdminOwner(hre); - }); - beforeEach(async function () { registrarFake = await smock.fake(new Registrar__factory(), { address: genWallet().address, }); + const config = { ...DEFAULT_REGISTRAR_CONFIG, accountsContract: genWallet().address, }; registrarFake.queryConfig.returns(config); + + const GasFwd = new GasFwd__factory(deployer); + const gasFwd = await GasFwd.deploy(); + gasFwdFactory = await deploy( + gasFwd.address, + await admin.getAddress(), + registrarFake.address, + deployer + ); }); describe("upon deployement", async function () { - it("reverts if the registrar address is invalid", async function () { - await expect(deployGasFwdFactory(owner, admin, ethers.constants.AddressZero)).to.be.reverted; - }); + const gffInterface = GasFwdFactory__factory.createInterface(); - it("successfully deploys", async function () { - expect(await deployGasFwdFactory(owner, admin, registrarFake.address)); + it("reverts if the implementation address is invalid", async function () { + await expect( + deploy( + ethers.constants.AddressZero, + await admin.getAddress(), + registrarFake.address, + deployer + ) + ) + .to.be.revertedWithCustomError({interface: gffInterface}, "InvalidAddress") + .withArgs("_impl"); + }); + it("reverts if the admin address is invalid", async function () { + await expect( + deploy(genWallet().address, ethers.constants.AddressZero, registrarFake.address, deployer) + ) + .to.be.revertedWithCustomError({interface: gffInterface}, "InvalidAddress") + .withArgs("_admin"); + }); + it("reverts if the registrar address is invalid", async function () { + await expect( + deploy( + genWallet().address, + await admin.getAddress(), + ethers.constants.AddressZero, + deployer + ) + ) + .to.be.revertedWithCustomError({interface: gffInterface}, "InvalidAddress") + .withArgs("_registrar"); }); }); describe("upon create", async function () { - let gff: GasFwdFactory; - beforeEach(async function () { - gff = await deployGasFwdFactory(owner, admin, registrarFake.address); - }); - it("deploys a new proxy of the GasFwd contract", async function () { - expect(gff.address); - expect(await gff.create()).to.emit(gff, "GasFwdCreated"); + await expect(gasFwdFactory.create()).to.emit(gasFwdFactory, "GasFwdCreated"); }); }); describe("upon updateImplementation", async function () { - let gff: GasFwdFactory; - beforeEach(async function () { - gff = await deployGasFwdFactory(owner, admin, registrarFake.address); - }); - it("reverts if called by a non-owner ", async function () { await expect( - gff.connect(admin).updateImplementation(ethers.constants.AddressZero) + gasFwdFactory.connect(admin).updateImplementation(ethers.constants.AddressZero) ).to.be.revertedWith("Ownable: caller is not the owner"); }); it("reverts if the new impl address is invalid", async function () { await expect( - gff.updateImplementation(ethers.constants.AddressZero) - ).to.be.revertedWithCustomError(gff, "InvalidAddress"); + gasFwdFactory.updateImplementation(ethers.constants.AddressZero) + ).to.be.revertedWithCustomError(gasFwdFactory, "InvalidAddress"); }); }); }); + +async function deploy( + impl: string, + admin: string, + registrar: string, + deployer: Signer +): Promise { + let GFF = new GasFwdFactory__factory(deployer); + let gff = await GFF.deploy(impl, admin, registrar); + await gff.deployed(); + return gff; +} diff --git a/test/core/registrar/LocalRegistrar.ts b/test/core/registrar/LocalRegistrar.ts index 0f4f54e68..ee961d375 100644 --- a/test/core/registrar/LocalRegistrar.ts +++ b/test/core/registrar/LocalRegistrar.ts @@ -1,3 +1,4 @@ +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; import {BigNumber, Signer} from "ethers"; import hre from "hardhat"; @@ -7,13 +8,16 @@ import {LocalRegistrarLib} from "typechain-types/contracts/core/registrar/LocalR import {FeeTypes, StrategyApprovalState} from "types"; import {getSigners} from "utils"; -describe("Local Registrar", function () { +describe("LocalRegistrar", function () { const {ethers, upgrades} = hre; let owner: Signer; let user: Signer; + let Registrar: LocalRegistrar__factory; + let registrar: LocalRegistrar; + let defaultRebalParams = { rebalanceLiquidProfits: false, lockedRebalanceToLiquid: 75, @@ -23,11 +27,6 @@ describe("Local Registrar", function () { basis: 100, }; - let defaultApParams = { - routerAddr: ethers.constants.AddressZero, - refundAddr: ethers.constants.AddressZero, - }; - let mockUniswapAddresses = { router: "0x0000000000000000000000000000000000111111", factory: "0x0000000000000000000000000000000002222222", @@ -36,29 +35,28 @@ describe("Local Registrar", function () { let originatingChain = "polygon"; let accountsContract = "0x000000000000000000000000000000000000dead"; - async function deployRegistrarAsProxy(): Promise { + before(async function () { const signers = await getSigners(hre); user = signers.apTeam1; owner = signers.apTeam2; - Registrar = (await ethers.getContractFactory( - "LocalRegistrar", - owner - )) as LocalRegistrar__factory; - const registrar = (await upgrades.deployProxy(Registrar, [originatingChain])) as LocalRegistrar; - await registrar.deployed(); - return registrar; - } + Registrar = new LocalRegistrar__factory(owner); + registrar = (await upgrades.deployProxy(Registrar, [originatingChain])) as LocalRegistrar; + }); - describe("Deployment", function () { - let registrar: LocalRegistrar; - beforeEach(async function () { - registrar = await deployRegistrarAsProxy(); - }); + let snapshot: SnapshotRestorer; + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + + describe("Deployment", function () { it("Should successfully deploy the contract as an upgradable proxy", async function () { - expect(registrar.address); - expect(await upgrades.upgradeProxy(registrar.address, Registrar)); + await expect(upgrades.upgradeProxy(registrar.address, Registrar)).to.not.be.reverted; }); it("Should set the right owner", async function () { @@ -81,20 +79,12 @@ describe("Local Registrar", function () { }); it("Should not allow a non-owner to run an upgrade", async function () { - const UserRegistrar = (await ethers.getContractFactory( - "LocalRegistrar", - user - )) as LocalRegistrar__factory; - await expect(upgrades.upgradeProxy(registrar.address, UserRegistrar)).to.be.reverted; + await expect(upgrades.upgradeProxy(registrar.address, Registrar.connect(user))).to.be + .reverted; }); }); describe("Setters and Getters", function () { - let registrar: LocalRegistrar; - beforeEach(async function () { - registrar = await deployRegistrarAsProxy(); - }); - describe("setRebalanceParams and getRebalanceParams", async function () { it("Should be an owner restricted method", async function () { await expect(registrar.connect(user).setRebalanceParams(defaultRebalParams)).to.be.reverted; @@ -369,10 +359,6 @@ describe("Local Registrar", function () { }); describe("Events", function () { - let registrar: LocalRegistrar; - beforeEach(async function () { - registrar = await deployRegistrarAsProxy(); - }); let strategyId = "0xffffffff"; // random 4-byte hash let strategyParams: LocalRegistrarLib.StrategyParamsStruct = { approvalState: StrategyApprovalState.APPROVED, diff --git a/test/core/router/Router.ts b/test/core/router/Router.ts index 83f16b52f..ec81940ea 100644 --- a/test/core/router/Router.ts +++ b/test/core/router/Router.ts @@ -1,6 +1,7 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; -import {Signer} from "ethers"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; +import {Signer} from "ethers"; import hre from "hardhat"; import { DEFAULT_ACTION_DATA, @@ -76,33 +77,44 @@ describe("Router", function () { RouterProxy.upgradeTo(RouterImpl.address); } - describe("Deployment", function () { - let registrar: FakeContract; - let router: Router; - beforeEach(async function () { - registrar = await smock.fake(new Registrar__factory()); - router = await deployRouterAsProxy(registrar.address); - }); + let router: Router; + + let liquidVault: FakeContract; + let lockedVault: FakeContract; + let gasService: FakeContract; + let gateway: FakeContract; + let registrar: FakeContract; + let token: FakeContract; + + before(async () => { + liquidVault = await smock.fake(new DummyVault__factory()); + lockedVault = await smock.fake(new DummyVault__factory()); + gasService = await smock.fake(new DummyGasService__factory()); + gateway = await smock.fake(new DummyGateway__factory()); + registrar = await smock.fake(new Registrar__factory()); + token = await smock.fake(new DummyERC20__factory()); + + router = await deployRouterAsProxy(registrar.address); + }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + + describe("Deployment", function () { it("Should successfully deploy the contract as an upgradable proxy", async function () { - expect(router.address); - expect(await upgradeProxy(admin, router.address)); + await expect(upgradeProxy(admin, router.address)).to.not.be.reverted; }); }); describe("Protected methods", function () { - let registrar: FakeContract; - let gateway: FakeContract; - let gasService: FakeContract; - let token: FakeContract; - let router: Router; - beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - gasService = await smock.fake(new DummyGasService__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -121,7 +133,6 @@ describe("Router", function () { .whenCalledWith(localChain) .returns(await owner.getAddress()); registrar.thisChain.returns(localChain); - router = await deployRouterAsProxy(registrar.address); }); it("Does not allow a non-accounts contract address on another chain to call executeWithToken via GMP", async function () { @@ -200,17 +211,11 @@ describe("Router", function () { }); describe("Correctly triggers the refund process on failed Deposit", function () { - let liquidVault: FakeContract; - let registrar: FakeContract; - let gateway: FakeContract; - let gasService: FakeContract; - let token: FakeContract; - let router: Router; - const LOCK_AMT = 111; const LIQ_AMT = 222; const GAS_COST = 5; const TOTAL_AMT = LOCK_AMT + LIQ_AMT; + const getDefaultActionData = () => ({ ...DEFAULT_ACTION_DATA, accountId: 1, @@ -219,12 +224,6 @@ describe("Router", function () { }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - gasService = await smock.fake(new DummyGasService__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -250,7 +249,6 @@ describe("Router", function () { token.approve.returns(true); token.approveFor.returns(true); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); describe("and the refund call is successful back through axelar", function () { @@ -377,16 +375,11 @@ describe("Router", function () { }); describe("and the refund call fails through axelar and falls back to the refund collector", async function () { - let liquidVault: FakeContract; - let registrar: FakeContract; - let gateway: FakeContract; - let gasService: FakeContract; - let token: FakeContract; - let router: Router; const LOCK_AMT = 111; const LIQ_AMT = 222; const GAS_COST = 5; const TOTAL_AMT = LOCK_AMT + LIQ_AMT; + const getDefaultActionData = () => ({ ...DEFAULT_ACTION_DATA, accountId: 1, @@ -395,12 +388,6 @@ describe("Router", function () { }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - gasService = await smock.fake(new DummyGasService__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -426,7 +413,6 @@ describe("Router", function () { token.approve.returns(false); token.approveFor.returns(false); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); it("when an action other than deposit is called", async function () { @@ -549,17 +535,11 @@ describe("Router", function () { }); describe("Routes messages according to payload instructions", function () { - let lockedVault: FakeContract; - let liquidVault: FakeContract; - let registrar: FakeContract; - let gateway: FakeContract; - let gasService: FakeContract; - let token: FakeContract; - let router: Router; const LOCK_AMT = 111; const LIQ_AMT = 222; const GAS_COST = 5; const TOTAL_AMT = LOCK_AMT + LIQ_AMT; + const getDefaultActionData = () => ({ ...DEFAULT_ACTION_DATA, accountId: 1, @@ -568,13 +548,6 @@ describe("Router", function () { }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - gasService = await smock.fake(new DummyGasService__factory()); - lockedVault = await smock.fake(new DummyVault__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -609,7 +582,6 @@ describe("Router", function () { token.approve.returns(true); token.approveFor.returns(true); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); it("correctly calls depost", async function () { @@ -687,17 +659,11 @@ describe("Router", function () { }); describe("Deposit", function () { - let lockedVault: FakeContract; - let liquidVault: FakeContract; - let registrar: FakeContract; - let gateway: FakeContract; - let gasService: FakeContract; - let token: FakeContract; - let router: Router; const LOCK_AMT = 111; const LIQ_AMT = 222; const GAS_COST = 5; const TOTAL_AMT = LOCK_AMT + LIQ_AMT; + const getDefaultActionData = () => ({ ...DEFAULT_ACTION_DATA, accountId: 1, @@ -706,13 +672,6 @@ describe("Router", function () { }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - gasService = await smock.fake(new DummyGasService__factory()); - lockedVault = await smock.fake(new DummyVault__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -745,7 +704,6 @@ describe("Router", function () { token.approve.returns(true); token.approveFor.returns(true); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); it("deposits the specified amounts to the specified vaults", async function () { @@ -767,13 +725,6 @@ describe("Router", function () { }); describe("Redeem", function () { - let lockedVault: FakeContract; - let liquidVault: FakeContract; - let registrar: FakeContract; - let gateway: FakeContract; - let gasService: FakeContract; - let token: FakeContract; - let router: Router; const LOCK_AMT = 111; const LIQ_AMT = 222; const GAS_COST = 5; @@ -786,13 +737,6 @@ describe("Router", function () { }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - gasService = await smock.fake(new DummyGasService__factory()); - lockedVault = await smock.fake(new DummyVault__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -830,7 +774,6 @@ describe("Router", function () { token.approve.returns(true); token.approveFor.returns(true); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); it("Redeems the amounts specified back to the router", async function () { @@ -921,17 +864,11 @@ describe("Router", function () { }); describe("RedeemAll", function () { - let lockedVault: FakeContract; - let liquidVault: FakeContract; - let registrar: FakeContract; - let gateway: FakeContract; - let gasService: FakeContract; - let token: FakeContract; - let router: Router; const LOCK_AMT = 111; const LIQ_AMT = 222; const GAS_COST = 5; const TOTAL_AMT = LOCK_AMT + LIQ_AMT; + const getDefaultActionData = () => ({ ...DEFAULT_ACTION_DATA, accountId: 1, @@ -940,13 +877,6 @@ describe("Router", function () { }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - gasService = await smock.fake(new DummyGasService__factory()); - lockedVault = await smock.fake(new DummyVault__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -984,7 +914,6 @@ describe("Router", function () { token.approve.returns(true); token.approveFor.returns(true); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); it("Redeems the amounts specified back to the router", async function () { @@ -1075,27 +1004,16 @@ describe("Router", function () { }); describe("Harvest cross-chain", function () { - let lockedVault: FakeContract; - let liquidVault: FakeContract; - let registrar: FakeContract; - let gateway: FakeContract; - let token: FakeContract; - let router: Router; const LOCK_AMT = 111; const LIQ_AMT = 222; const TOTAL_AMT = LOCK_AMT + LIQ_AMT; + const getDefaultHarvestRequest = () => ({ ...DEFAULT_HARVEST_REQUEST, accountIds: [1], }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - gateway = await smock.fake(new DummyGateway__factory()); - lockedVault = await smock.fake(new DummyVault__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, axelarGateway: gateway.address, @@ -1132,7 +1050,6 @@ describe("Router", function () { token.approve.returns(true); token.approveFor.returns(true); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); it("Harvests the targeted accounts and forwards tokens cross-chain", async function () { @@ -1157,25 +1074,16 @@ describe("Router", function () { }); describe("Harvest locally", function () { - let lockedVault: FakeContract; - let liquidVault: FakeContract; - let registrar: FakeContract; - let token: FakeContract; - let router: Router; const LOCK_AMT = 111; const LIQ_AMT = 222; const TOTAL_AMT = LOCK_AMT + LIQ_AMT; + const getDefaultHarvestRequest = () => ({ ...DEFAULT_HARVEST_REQUEST, accountIds: [1], }); beforeEach(async function () { - token = await smock.fake(new DummyERC20__factory()); - registrar = await smock.fake(new Registrar__factory()); - lockedVault = await smock.fake(new DummyVault__factory()); - liquidVault = await smock.fake(new DummyVault__factory()); - const networkParams = { ...DEFAULT_NETWORK_INFO, }; @@ -1204,7 +1112,6 @@ describe("Router", function () { token.approve.returns(true); token.approveFor.returns(true); token.symbol.returns("TKN"); - router = await deployRouterAsProxy(registrar.address); }); it("Reverts if the caller is not a valid operator", async function () { diff --git a/test/core/vault/Vault.ts b/test/core/vault/Vault.ts index 37d314c1b..f17c8067c 100644 --- a/test/core/vault/Vault.ts +++ b/test/core/vault/Vault.ts @@ -1,4 +1,5 @@ import {FakeContract, smock} from "@defi-wonderland/smock"; +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect, use} from "chai"; import {BigNumber, Signer} from "ethers"; import hre from "hardhat"; @@ -28,7 +29,7 @@ import { } from "typechain-types"; import {LocalRegistrarLib} from "typechain-types/contracts/core/registrar/LocalRegistrar"; import {StrategyApprovalState} from "types"; -import {getProxyAdminOwner, getSigners} from "utils"; +import {getSigners} from "utils"; use(smock.matchers); @@ -39,7 +40,6 @@ describe("Vault", function () { let owner: Signer; let user: Signer; - let admin: Signer; let collector: Signer; async function deployVault( @@ -88,8 +88,6 @@ describe("Vault", function () { user = apTeam1; collector = apTeam2; - admin = await getProxyAdminOwner(hre); - vaultEmitterFake = await smock.fake(IVaultEmitter__factory.createInterface()); }); @@ -98,7 +96,7 @@ describe("Vault", function () { let token: FakeContract; const DECIMALS = 18; - beforeEach(async function () { + before(async function () { token = await smock.fake(new DummyERC20__factory()); token.decimals.returns(DECIMALS); vault = await deployVault( @@ -110,6 +108,17 @@ describe("Vault", function () { vaultEmitterFake.address ); }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + it("Should successfully deploy the vault", async function () { expect(await vault.address); }); @@ -136,7 +145,7 @@ describe("Vault", function () { let vault: APVault_V1; let token: FakeContract; - beforeEach(async function () { + before(async function () { token = await smock.fake(new DummyERC20__factory()); vault = await deployVault( { @@ -147,6 +156,17 @@ describe("Vault", function () { vaultEmitterFake.address ); }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + it("should set the config as specified on deployment", async function () { let config = await vault.getVaultConfig(); let admin = await vault.owner(); @@ -185,9 +205,25 @@ describe("Vault", function () { let yieldToken: FakeContract; let strategy: FakeContract; - beforeEach(async function () { + before(async () => { baseToken = await smock.fake(new DummyERC20__factory()); yieldToken = await smock.fake(new DummyERC20__factory()); + strategy = await smock.fake(new DummyStrategy__factory()); + registrarFake = await smock.fake(new LocalRegistrar__factory()); + vault = await deployVault( + { + vaultType: 1, // Liquid + admin: await owner.getAddress(), + baseToken: baseToken.address, + yieldToken: yieldToken.address, + strategy: strategy.address, + registrar: registrarFake.address, + }, + vaultEmitterFake.address + ); + }); + + beforeEach(async function () { baseToken.transfer.returns(true); baseToken.transferFrom.returns(true); baseToken.approve.returns(true); @@ -196,26 +232,15 @@ describe("Vault", function () { yieldToken.transferFrom.returns(true); yieldToken.approve.returns(true); yieldToken.approveFor.returns(true); - strategy = await smock.fake(new DummyStrategy__factory()); strategy.getStrategyConfig.returns({ strategyId: DEFAULT_STRATEGY_ID, baseToken: baseToken.address, yieldToken: yieldToken.address, admin: await owner.getAddress(), }); - registrarFake = await smock.fake(new LocalRegistrar__factory()); + strategy.paused.returns(false); registrarFake.getVaultOperatorApproved.whenCalledWith(await owner.getAddress()).returns(true); - vault = await deployVault( - { - vaultType: 1, // Liquid - admin: await owner.getAddress(), - baseToken: baseToken.address, - yieldToken: yieldToken.address, - strategy: strategy.address, - registrar: registrarFake.address, - }, - vaultEmitterFake.address - ); + registrarFake.getStrategyApprovalState.whenCalledWith(DEFAULT_STRATEGY_ID).returns(true); registrarFake.thisChain.returns(DEFAULT_NETWORK); registrarFake.queryNetworkConnection.whenCalledWith(DEFAULT_NETWORK).returns({ @@ -224,6 +249,16 @@ describe("Vault", function () { }); }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + it("reverts if the operator isn't approved as an operator, sibling vault, or approved router", async function () { registrarFake.getVaultOperatorApproved .whenCalledWith(await owner.getAddress()) @@ -308,9 +343,7 @@ describe("Vault", function () { const TAX_RATE = 100; // bps const PRECISION = BigNumber.from(10).pow(24); - beforeEach(async function () { - baseToken = await smock.fake(new DummyERC20__factory()); - yieldToken = await smock.fake(new DummyERC20__factory()); + async function setup() { baseToken.transfer.returns(true); baseToken.transferFrom.returns(true); baseToken.approve.returns(true); @@ -319,19 +352,17 @@ describe("Vault", function () { yieldToken.transferFrom.returns(true); yieldToken.approve.returns(true); yieldToken.approveFor.returns(true); - router = await smock.fake(new DummyRouter__factory()); - strategy = await smock.fake(new DummyStrategy__factory()); strategy.getStrategyConfig.returns({ strategyId: DEFAULT_STRATEGY_ID, baseToken: baseToken.address, yieldToken: yieldToken.address, admin: await owner.getAddress(), }); + strategy.paused.returns(false); const networkParams = { ...DEFAULT_NETWORK_INFO, router: router.address, }; - registrarFake = await smock.fake(new LocalRegistrar__factory()); registrarFake.thisChain.returns(DEFAULT_NETWORK); registrarFake.queryNetworkConnection.returns(networkParams); registrarFake.getVaultOperatorApproved.whenCalledWith(await owner.getAddress()).returns(true); @@ -339,6 +370,16 @@ describe("Vault", function () { payoutAddress: await collector.getAddress(), bps: TAX_RATE, }); + strategy.deposit.returns(DEPOSIT); + yieldToken.balanceOf.returns(DEPOSIT); + } + + before(async () => { + baseToken = await smock.fake(new DummyERC20__factory()); + yieldToken = await smock.fake(new DummyERC20__factory()); + router = await smock.fake(new DummyRouter__factory()); + strategy = await smock.fake(new DummyStrategy__factory()); + registrarFake = await smock.fake(new LocalRegistrar__factory()); vault = await deployVault( { @@ -351,12 +392,25 @@ describe("Vault", function () { }, vaultEmitterFake.address ); - - strategy.deposit.returns(DEPOSIT); - yieldToken.balanceOf.returns(DEPOSIT); + // need to setup fake contracts for the deposit to succeed + await setup(); await wait(vault.deposit(0, baseToken.address, DEPOSIT)); }); + beforeEach(async function () { + await setup(); + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + it("reverts if the strategy is paused", async function () { strategy.paused.returns(true); await expect(vault.redeem(0, DEPOSIT / 2)).to.be.revertedWithCustomError( @@ -445,9 +499,7 @@ describe("Vault", function () { const TAX_RATE = 100; // bps const PRECISION = BigNumber.from(10).pow(24); - beforeEach(async function () { - baseToken = await smock.fake(new DummyERC20__factory()); - yieldToken = await smock.fake(new DummyERC20__factory()); + async function setup() { baseToken.transfer.returns(true); baseToken.transferFrom.returns(true); baseToken.approve.returns(true); @@ -456,19 +508,17 @@ describe("Vault", function () { yieldToken.transferFrom.returns(true); yieldToken.approve.returns(true); yieldToken.approveFor.returns(true); - router = await smock.fake(new DummyRouter__factory()); - strategy = await smock.fake(new DummyStrategy__factory()); strategy.getStrategyConfig.returns({ strategyId: DEFAULT_STRATEGY_ID, baseToken: baseToken.address, yieldToken: yieldToken.address, admin: await owner.getAddress(), }); + strategy.paused.returns(false); const networkParams = { ...DEFAULT_NETWORK_INFO, router: router.address, }; - registrarFake = await smock.fake(new LocalRegistrar__factory()); registrarFake.thisChain.returns(DEFAULT_NETWORK); registrarFake.queryNetworkConnection.returns(networkParams); registrarFake.getVaultOperatorApproved.whenCalledWith(await owner.getAddress()).returns(true); @@ -476,6 +526,16 @@ describe("Vault", function () { payoutAddress: await collector.getAddress(), bps: TAX_RATE, }); + strategy.deposit.returns(DEPOSIT); + yieldToken.balanceOf.returns(DEPOSIT); + } + + before(async () => { + baseToken = await smock.fake(new DummyERC20__factory()); + yieldToken = await smock.fake(new DummyERC20__factory()); + router = await smock.fake(new DummyRouter__factory()); + strategy = await smock.fake(new DummyStrategy__factory()); + registrarFake = await smock.fake(new LocalRegistrar__factory()); vault = await deployVault( { @@ -488,12 +548,25 @@ describe("Vault", function () { }, vaultEmitterFake.address ); - - strategy.deposit.returns(DEPOSIT); - yieldToken.balanceOf.returns(DEPOSIT); + // need to setup fake contracts for the deposit to succeed + await setup(); await wait(vault.deposit(0, baseToken.address, DEPOSIT)); }); + beforeEach(async function () { + await setup(); + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + it("reverts if the strategy is paused", async function () { strategy.paused.returns(true); await expect(vault.redeemAll(0)).to.be.revertedWithCustomError(vault, "OnlyNotPaused"); @@ -557,9 +630,7 @@ describe("Vault", function () { const TAX_RATE = 100; // bps const PRECISION = BigNumber.from(10).pow(24); - beforeEach(async function () { - baseToken = await smock.fake(new DummyERC20__factory()); - yieldToken = await smock.fake(new DummyERC20__factory()); + async function setup() { baseToken.transfer.returns(true); baseToken.transferFrom.returns(true); baseToken.approve.returns(true); @@ -568,15 +639,13 @@ describe("Vault", function () { yieldToken.transferFrom.returns(true); yieldToken.approve.returns(true); yieldToken.approveFor.returns(true); - router = await smock.fake(new DummyRouter__factory()); - strategy = await smock.fake(new DummyStrategy__factory()); strategy.getStrategyConfig.returns({ strategyId: DEFAULT_STRATEGY_ID, baseToken: baseToken.address, yieldToken: yieldToken.address, admin: await owner.getAddress(), }); - registrarFake = await smock.fake(new LocalRegistrar__factory()); + strategy.paused.returns(false); registrarFake.getVaultOperatorApproved.whenCalledWith(await owner.getAddress()).returns(true); registrarFake.getFeeSettingsByFeeType .whenCalledWith(1) @@ -586,11 +655,37 @@ describe("Vault", function () { ...DEFAULT_NETWORK_INFO, router: router.address, }); + } + + before(async () => { + baseToken = await smock.fake(new DummyERC20__factory()); + yieldToken = await smock.fake(new DummyERC20__factory()); + router = await smock.fake(new DummyRouter__factory()); + strategy = await smock.fake(new DummyStrategy__factory()); + registrarFake = await smock.fake(new LocalRegistrar__factory()); + await setup(); + }); + + beforeEach(async function () { + await setup(); + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); }); describe("For liquid vaults", async function () { let vault: APVault_V1; - beforeEach(async function () { + let rootSnapshot: SnapshotRestorer; + + before(async function () { + rootSnapshot = await takeSnapshot(); vault = await deployVault( { vaultType: 1, // Locked @@ -607,6 +702,15 @@ describe("Vault", function () { await wait(vault.deposit(0, baseToken.address, DEPOSIT)); }); + beforeEach(() => { + strategy.deposit.returns(DEPOSIT); + yieldToken.balanceOf.returns(DEPOSIT); + }); + + after(async () => { + await rootSnapshot.restore(); + }); + it("reverts if the strategy is paused", async function () { strategy.paused.returns(true); await expect(vault.harvest([0])).to.be.revertedWithCustomError(vault, "OnlyNotPaused"); @@ -657,37 +761,16 @@ describe("Vault", function () { let liquidStrategy: FakeContract; const REBAL_RATE = 5000; // 5% const BASIS = 10000; - beforeEach(async function () { - // establish second strategy for liquid vault responses - liquidStrategy = await smock.fake(new DummyStrategy__factory()); + let rootSnapshot: SnapshotRestorer; + + async function nestedSetup() { liquidStrategy.getStrategyConfig.returns({ strategyId: DEFAULT_STRATEGY_ID, baseToken: baseToken.address, yieldToken: yieldToken.address, admin: await owner.getAddress(), }); - liquidVault = await deployVault( - { - vaultType: 1, // Liquid - admin: await owner.getAddress(), - baseToken: baseToken.address, - yieldToken: yieldToken.address, - strategy: liquidStrategy.address, - registrar: registrarFake.address, - }, - vaultEmitterFake.address - ); - lockedVault = await deployVault( - { - vaultType: 0, // Locked - admin: await owner.getAddress(), - baseToken: baseToken.address, - yieldToken: yieldToken.address, - strategy: strategy.address, - registrar: registrarFake.address, - }, - vaultEmitterFake.address - ); + liquidStrategy.paused.returns(false); const stratParams: LocalRegistrarLib.StrategyParamsStruct = { ...DEFAULT_STRATEGY_PARAMS, network: DEFAULT_NETWORK, @@ -712,9 +795,47 @@ describe("Vault", function () { registrarFake.getVaultOperatorApproved.whenCalledWith(lockedVault.address).returns(true); strategy.deposit.returns(DEPOSIT); yieldToken.balanceOf.returns(DEPOSIT); + } + before(async function () { + rootSnapshot = await takeSnapshot(); + // establish second strategy for liquid vault responses + liquidStrategy = await smock.fake(new DummyStrategy__factory()); + + liquidVault = await deployVault( + { + vaultType: 1, // Liquid + admin: await owner.getAddress(), + baseToken: baseToken.address, + yieldToken: yieldToken.address, + strategy: liquidStrategy.address, + registrar: registrarFake.address, + }, + vaultEmitterFake.address + ); + lockedVault = await deployVault( + { + vaultType: 0, // Locked + admin: await owner.getAddress(), + baseToken: baseToken.address, + yieldToken: yieldToken.address, + strategy: strategy.address, + registrar: registrarFake.address, + }, + vaultEmitterFake.address + ); + // need to setup fake contracts for the deposit to succeed + await nestedSetup(); await wait(lockedVault.deposit(0, baseToken.address, DEPOSIT)); }); + beforeEach(async () => { + await nestedSetup(); + }); + + after(async () => { + await rootSnapshot.restore(); + }); + it("reverts if the baseToken transfer fails", async function () { strategy.previewWithdraw.returns(DEPOSIT * 2); let expectedTaxAmt = (DEPOSIT * TAX_RATE) / BASIS; // DEPOSIT = position in yield, apply tax diff --git a/test/halo/Halo.ts b/test/halo/Halo.ts index 825087fdb..3051fc68a 100644 --- a/test/halo/Halo.ts +++ b/test/halo/Halo.ts @@ -1,31 +1,41 @@ +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; import {BigNumber, Signer} from "ethers"; import hre from "hardhat"; import {Halo, Halo__factory} from "typechain-types"; import {getProxyAdminOwner, getSigners} from "utils"; -describe("Halo token", function () { - let Halo: Halo__factory; +describe("Halo", function () { + const INITIALSUPPLY = BigNumber.from(10).pow(27); // 1 billion tokens with 18 decimals let deployer: Signer; let proxyAdmin: Signer; let user: Signer; - describe("upon Deployment", async function () { - let halo: Halo; - let INITIALSUPPLY = BigNumber.from(10).pow(27); // 1 billion tokens with 18 decimals - - beforeEach(async function () { - const signers = await getSigners(hre); - deployer = signers.deployer; - proxyAdmin = await getProxyAdminOwner(hre); - user = signers.apTeam1; - - Halo = (await hre.ethers.getContractFactory("Halo", deployer)) as Halo__factory; - halo = await Halo.deploy(); - await halo.deployed(); - }); + let halo: Halo; + + before(async function () { + const signers = await getSigners(hre); + deployer = signers.deployer; + user = signers.apTeam1; + + proxyAdmin = await getProxyAdminOwner(hre); + + const Halo = new Halo__factory(deployer); + halo = await Halo.deploy(); + }); + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + + describe("upon Deployment", async function () { it("Sends the specified amount to the specified recipient", async function () { expect(await halo.balanceOf(await deployer.getAddress())).to.equal(INITIALSUPPLY); }); @@ -37,7 +47,9 @@ describe("Halo token", function () { }); it("Token holder can burn tokens", async function () { const burnAmount = BigNumber.from(100000); - expect(await halo.burn(burnAmount)).to.emit(halo, "Burn"); + await expect(halo.burn(burnAmount)) + .to.emit(halo, "Transfer") + .withArgs(await halo.signer.getAddress(), hre.ethers.constants.AddressZero, burnAmount); expect(await halo.totalSupply()).to.equal(INITIALSUPPLY.sub(burnAmount)); }); }); diff --git a/test/integrations/flux/FluxStrategy.ts b/test/integrations/flux/FluxStrategy.ts index d9f86fec1..6d72a0750 100644 --- a/test/integrations/flux/FluxStrategy.ts +++ b/test/integrations/flux/FluxStrategy.ts @@ -1,3 +1,4 @@ +import {SnapshotRestorer, takeSnapshot} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; import {BigNumber, Signer} from "ethers"; import hre from "hardhat"; @@ -15,7 +16,10 @@ describe("FluxStrategy", function () { let owner: Signer; let user: Signer; - let collector: Signer; + + let flux: FluxStrategy; + let baseToken: DummyERC20; + let yieldToken: DummyFUSDC; async function deployFluxStrategy({ baseToken, @@ -40,42 +44,40 @@ describe("FluxStrategy", function () { return flux; } - describe("during deployment", async function () { - let flux: FluxStrategy; - before(async function () { - [owner, user, collector] = await ethers.getSigners(); - }); - it("deploys", async function () { - flux = await deployFluxStrategy({ - baseToken: await user.getAddress(), - yieldToken: await user.getAddress(), - admin: await owner.getAddress(), - }); - expect(flux); + before(async function () { + [owner, user] = await ethers.getSigners(); + + baseToken = await deployDummyERC20(owner, 6); + yieldToken = await deployDummyFUSDC(owner, baseToken.address); + + flux = await deployFluxStrategy({ + baseToken: baseToken.address, + yieldToken: yieldToken.address, + admin: await owner.getAddress(), }); + }); + + let snapshot: SnapshotRestorer; + + beforeEach(async () => { + snapshot = await takeSnapshot(); + }); + + afterEach(async () => { + await snapshot.restore(); + }); + + describe("during deployment", async function () { it("sets the config according to the input params", async function () { - flux = await deployFluxStrategy({ - baseToken: await user.getAddress(), - yieldToken: await collector.getAddress(), - admin: await owner.getAddress(), - }); let config = await flux.getStrategyConfig(); - expect(config.baseToken).to.equal(await user.getAddress()); - expect(config.yieldToken).to.equal(await collector.getAddress()); + expect(config.baseToken).to.equal(baseToken.address); + expect(config.yieldToken).to.equal(yieldToken.address); expect(config.strategyId).to.equal(DEFAULT_STRATEGY_ID); expect(config.admin).to.equal(await owner.getAddress()); }); }); describe("pause extension", async function () { - let flux: FluxStrategy; - beforeEach(async function () { - flux = await deployFluxStrategy({ - baseToken: await user.getAddress(), - yieldToken: await user.getAddress(), - admin: await owner.getAddress(), - }); - }); it("reverts if a non-admin calls the `pause` method", async function () { await expect(flux.connect(user).pause()).to.be.revertedWithCustomError(flux, "AdminOnly"); }); @@ -93,14 +95,6 @@ describe("FluxStrategy", function () { }); }); describe("upon get and set config", async function () { - let flux: FluxStrategy; - beforeEach(async function () { - flux = await deployFluxStrategy({ - baseToken: await user.getAddress(), - yieldToken: await user.getAddress(), - admin: await owner.getAddress(), - }); - }); it("reverts if set is called by a non-admin", async function () { await expect( flux.connect(user).setStrategyConfig({ @@ -128,20 +122,6 @@ describe("FluxStrategy", function () { }); }); describe("upon Deposit", async function () { - let flux: FluxStrategy; - let baseToken: DummyERC20; - let yieldToken: DummyFUSDC; - before(async function () { - baseToken = await deployDummyERC20(owner, 6); - yieldToken = await deployDummyFUSDC(owner, baseToken.address); - }); - beforeEach(async function () { - flux = await deployFluxStrategy({ - baseToken: baseToken.address, - yieldToken: yieldToken.address, - admin: await owner.getAddress(), - }); - }); it("reverts when paused", async function () { await expect(flux.pause()).to.not.be.reverted; await expect(flux.deposit(1)).to.revertedWith("Pausable: paused"); @@ -192,26 +172,19 @@ describe("FluxStrategy", function () { }); }); describe("upon Withdrawal", async function () { - let flux: FluxStrategy; - let baseToken: DummyERC20; - let yieldToken: DummyFUSDC; const DEPOSIT_AMT = 10; - before(async function () { - baseToken = await deployDummyERC20(owner, 6); - yieldToken = await deployDummyFUSDC(owner, baseToken.address); - }); - beforeEach(async function () { - flux = await deployFluxStrategy({ - baseToken: baseToken.address, - yieldToken: yieldToken.address, - admin: await owner.getAddress(), - }); + let rootSnapshot: SnapshotRestorer; + before(async () => { + rootSnapshot = await takeSnapshot(); await wait(baseToken.mint(await owner.getAddress(), DEPOSIT_AMT)); await wait(baseToken.approve(flux.address, DEPOSIT_AMT)); await wait(yieldToken.setResponseAmt(DEPOSIT_AMT)); await wait(flux.deposit(DEPOSIT_AMT)); await wait(yieldToken.transferFrom(flux.address, await owner.getAddress(), DEPOSIT_AMT)); }); + after(async () => { + await rootSnapshot.restore(); + }); it("reverts when paused", async function () { await expect(flux.pause()).to.not.be.reverted; await expect(flux.withdraw(1)).to.revertedWith("Pausable: paused"); @@ -256,23 +229,9 @@ describe("FluxStrategy", function () { }); }); describe("upon previewDeposit and previewWithdraw", async function () { - let flux: FluxStrategy; - let baseToken: DummyERC20; - let yieldToken: DummyFUSDC; const DECIMAL_MAG = 100; // fUSDC: 8, USDC: 6 const EXP_SCALE = BigNumber.from(10).pow(18); // 10**18 = expScale in fUSDC contract const ONE_THOUSAND = BigNumber.from("1000000000"); // 1,000,000,000 = $1000 - before(async function () { - baseToken = await deployDummyERC20(owner, 6); - yieldToken = await deployDummyFUSDC(owner, baseToken.address); - }); - beforeEach(async function () { - flux = await deployFluxStrategy({ - baseToken: baseToken.address, - yieldToken: yieldToken.address, - admin: await owner.getAddress(), - }); - }); it("correctly applies the exchange rate for previewDeposit", async function () { await expect(yieldToken.setExRate(EXP_SCALE.div(DECIMAL_MAG))).to.not.be.reverted; // test 1:1 let previewedDeposit = await flux.previewDeposit(ONE_THOUSAND);