From 9137297e158a64cbba558d8c4dfe623340d3e7ce Mon Sep 17 00:00:00 2001 From: itofarina Date: Tue, 19 Dec 2023 18:07:53 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20hh=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/Market.sol | 6 +- test/hardhat/13_floating.ts | 1 + test/hardhat/18_eth_market.ts | 2 + test/hardhat/2_market.ts | 44 +++++++- test/hardhat/4_liquidity_computation.ts | 29 +++++- test/hardhat/5_liquidations.ts | 8 ++ test/hardhat/8_interest_rate_model.ts | 130 +++++++++++------------- 7 files changed, 141 insertions(+), 79 deletions(-) diff --git a/contracts/Market.sol b/contracts/Market.sol index 63faf5b5d..ba4c7a99d 100644 --- a/contracts/Market.sol +++ b/contracts/Market.sol @@ -11,6 +11,7 @@ import { InterestRateModel } from "./InterestRateModel.sol"; import { RewardsController } from "./RewardsController.sol"; import { FixedLib } from "./utils/FixedLib.sol"; import { Auditor } from "./Auditor.sol"; +import { console } from "hardhat/console.sol"; contract Market is Initializable, AccessControlUpgradeable, PausableUpgradeable, ERC4626 { using FixedPointMathLib for int256; @@ -1016,7 +1017,10 @@ contract Market is Initializable, AccessControlUpgradeable, PausableUpgradeable, /// @notice Retrieves global utilization of the floating pool. /// @dev Internal function to avoid code duplication. - function globalUtilization(uint256 assets, uint256 debt, uint256 backupBorrowed) internal pure returns (uint256) { + function globalUtilization(uint256 assets, uint256 debt, uint256 backupBorrowed) internal view returns (uint256) { + console.log("assets ", assets); + console.log("debt ", debt); + console.log("backup ", backupBorrowed); return assets > 0 ? 1e18 - (assets - debt - backupBorrowed).divWadDown(assets) : 0; } diff --git a/test/hardhat/13_floating.ts b/test/hardhat/13_floating.ts index 8ab1ed34b..ff0f6a1ad 100644 --- a/test/hardhat/13_floating.ts +++ b/test/hardhat/13_floating.ts @@ -120,6 +120,7 @@ describe("Smart Pool", function () { await wbtc.connect(bob).approve(marketWBTC.address, parseUnits("1", 8)); await marketWBTC.connect(bob).approve(john.address, parseUnits("1", 8)); await marketWBTC.connect(bob).deposit(parseUnits("1", 8), bob.address); + await ethers.provider.send("evm_increaseTime", [3_600]); }); it("THEN bob's eWBTC balance is 1", async () => { expect(await marketWBTC.balanceOf(bob.address)).to.equal(parseUnits("1", 8)); diff --git a/test/hardhat/18_eth_market.ts b/test/hardhat/18_eth_market.ts index 65014d503..d754c7370 100644 --- a/test/hardhat/18_eth_market.ts +++ b/test/hardhat/18_eth_market.ts @@ -292,6 +292,7 @@ describe("ETHMarket - receive bare ETH instead of WETH", function () { await weth.deposit({ value: parseUnits("60") }); await marketWETH.deposit(parseUnits("60"), alice.address); await auditor.enterMarket(marketWETH.address); + await provider.send("evm_increaseTime", [3_600]); }); describe("WHEN borrowing with ETH (native)", () => { let tx: ContractTransaction; @@ -631,6 +632,7 @@ describe("ETHMarket - receive bare ETH instead of WETH", function () { await marketWETH.deposit(parseUnits("60"), alice.address); await auditor.enterMarket(marketWETH.address); tx = routerETH.borrowAtMaturity(futurePools(1)[0], parseUnits("5"), parseUnits("5")); + await provider.send("evm_increaseTime", [3_600]); }); it("THEN the tx should revert with Disagreement", async () => { await expect(tx).to.be.revertedWithCustomError(marketWETH, "Disagreement"); diff --git a/test/hardhat/2_market.ts b/test/hardhat/2_market.ts index cf4b0e480..2b8e717aa 100644 --- a/test/hardhat/2_market.ts +++ b/test/hardhat/2_market.ts @@ -46,7 +46,19 @@ describe("Market", function () { penaltyRate = await marketDAI.penaltyRate(); await deploy("InterestRateModel", { - args: [AddressZero, 0, 0, parseUnits("6"), parseUnits("0.7")], + args: [ + AddressZero, + 0, + 0, + parseUnits("6"), + parseUnits("0.7"), + parseUnits("2.5"), + parseUnits("1"), + parseUnits("10"), + parseUnits("0.2"), + parseUnits("0"), + parseUnits("0.5"), + ], from: owner.address, }); irm = await getContract("InterestRateModel", maria); @@ -61,6 +73,7 @@ describe("Market", function () { await weth.deposit({ value: parseUnits("10") }); await weth.approve(marketWETH.address, parseUnits("10")); } + await provider.send("evm_increaseTime", [3_600]); }); describe("small positions", () => { @@ -69,6 +82,7 @@ describe("Market", function () { await marketDAI.deposit(3, maria.address); // add liquidity to the maturity await marketDAI.depositAtMaturity(futurePools(1)[0], 3, 0, maria.address); + await provider.send("evm_increaseTime", [3_600]); }); it("THEN the Market registers a supply of 3 wei DAI for the account (exposed via accountSnapshot)", async () => { expect(await marketDAI.maxWithdraw(maria.address)).to.equal(3); @@ -416,7 +430,19 @@ describe("Market", function () { describe("GIVEN an interest rate of 2%", () => { beforeEach(async () => { const { address } = await deploy("InterestRateModel", { - args: [AddressZero, 0, parseUnits("0.02"), parseUnits("6"), parseUnits("0.7")], + args: [ + AddressZero, + 0, + parseUnits("0.02"), + parseUnits("6"), + parseUnits("0.7"), + parseUnits("2.5"), + parseUnits("1"), + parseUnits("10"), + parseUnits("0.2"), + parseUnits("0"), + parseUnits("0.5"), + ], from: owner.address, }); await timelockExecute(owner, marketDAI, "setInterestRateModel", [address]); @@ -453,7 +479,19 @@ describe("Market", function () { await auditor.enterMarket(marketWETH.address); const { address } = await deploy("InterestRateModel", { - args: [AddressZero, 0, 0, parseUnits("1.1"), parseUnits("0.7")], + args: [ + AddressZero, + 0, + 0, + parseUnits("1.1"), + parseUnits("0.7"), + parseUnits("2.5"), + parseUnits("1"), + parseUnits("10"), + parseUnits("0.2"), + parseUnits("0"), + parseUnits("0.5"), + ], from: owner.address, }); await timelockExecute(owner, marketDAI, "setInterestRateModel", [address]); diff --git a/test/hardhat/4_liquidity_computation.ts b/test/hardhat/4_liquidity_computation.ts index 29fb82835..08e1cf32f 100644 --- a/test/hardhat/4_liquidity_computation.ts +++ b/test/hardhat/4_liquidity_computation.ts @@ -65,7 +65,19 @@ describe("Liquidity computations", function () { } const { address: irm } = await deploy("InterestRateModel", { - args: [AddressZero, 0, 0, parseUnits("6"), parseUnits("0.7")], + args: [ + AddressZero, + 0, + 0, + parseUnits("6"), + parseUnits("0.7"), + parseUnits("2.5"), + parseUnits("1"), + parseUnits("10"), + parseUnits("0.2"), + parseUnits("0"), + parseUnits("0.5"), + ], from: bob.address, }); await timelockExecute(multisig, marketDAI, "setInterestRateModel", [irm]); @@ -83,6 +95,7 @@ describe("Liquidity computations", function () { describe("GIVEN laura deposits 1k dai to a smart pool", () => { beforeEach(async () => { await marketDAI.deposit(parseUnits("1000"), laura.address); + await provider.send("evm_increaseTime", [3_600]); }); it("THEN lauras liquidity is adjustFactor*collateral - 0.8*1000 == 800, AND she has no shortfall", async () => { @@ -100,7 +113,19 @@ describe("Liquidity computations", function () { describe("AND GIVEN a 1% borrow interest rate", () => { beforeEach(async () => { const { address: irm } = await deploy("InterestRateModel", { - args: [AddressZero, 0, parseUnits("0.01"), parseUnits("6"), parseUnits("0.7")], + args: [ + AddressZero, + 0, + parseUnits("0.01"), + parseUnits("6"), + parseUnits("0.7"), + parseUnits("2.5"), + parseUnits("1"), + parseUnits("10"), + parseUnits("0.2"), + parseUnits("0"), + parseUnits("0.5"), + ], from: bob.address, }); await timelockExecute(multisig, marketDAI, "setInterestRateModel", [irm]); diff --git a/test/hardhat/5_liquidations.ts b/test/hardhat/5_liquidations.ts index 5d74f0ae3..55e87aff2 100644 --- a/test/hardhat/5_liquidations.ts +++ b/test/hardhat/5_liquidations.ts @@ -9,6 +9,7 @@ import futurePools from "./utils/futurePools"; const { constants: { MaxUint256 }, utils: { parseUnits }, + provider, } = ethers; const nextPoolID = futurePools(3)[2].toNumber(); @@ -65,6 +66,7 @@ describe("Liquidations", function () { await exactlyEnv.depositMP("DAI", nextPoolID, "65000"); await dai.connect(bob).approve(marketDAI.address, parseUnits("200000")); await dai.connect(john).approve(marketDAI.address, parseUnits("10000")); + await provider.send("evm_increaseTime", [3_600]); }); describe("AND GIVEN Alice takes the biggest loan she can (31920 DAI), 31920/0.8=39900", () => { @@ -316,18 +318,21 @@ describe("Liquidations", function () { await exactlyEnv.depositSP("WETH", "10"); await exactlyEnv.enterMarket("WETH"); + await provider.send("evm_increaseTime", [3_600]); }); describe("AND GIVEN alice deposits 10k DAI to the smart pool AND borrows USD8k worth of WETH (80% collateralization rate)", () => { beforeEach(async () => { exactlyEnv.switchWallet(alice); await exactlyEnv.depositSP("DAI", "10000"); await exactlyEnv.enterMarket("DAI"); + await provider.send("evm_increaseTime", [3_600]); await exactlyEnv.borrowMP("WETH", futurePools(1)[0].toNumber(), "0.93"); await exactlyEnv.borrowMP("WETH", futurePools(2)[1].toNumber(), "0.93"); }); describe("WHEN WETH price doubles AND john borrows 10k DAI from a maturity pool (all liquidity in smart pool)", () => { beforeEach(async () => { + await provider.send("evm_increaseTime", [3_600 * 2]); await exactlyEnv.setPrice(marketETH.address, parseUnits("8000", 8)); exactlyEnv.switchWallet(john); await exactlyEnv.borrowMP("DAI", futurePools(1)[0].toNumber(), "10000"); @@ -345,6 +350,7 @@ describe("Liquidations", function () { await dai.mint(john.address, parseUnits("10000")); await exactlyEnv.depositSP("DAI", "10000"); await eth.connect(john).approve(marketETH.address, parseUnits("1")); + await provider.send("evm_increaseTime", [3_600]); }); it("WHEN both of alice's positions are liquidated THEN it doesn't revert", async () => { await expect(marketETH.connect(john).liquidate(alice.address, parseUnits("1"), marketDAI.address)).to.not.be @@ -376,6 +382,7 @@ describe("Liquidations", function () { await exactlyEnv.borrowMP("DAI", futurePools(1)[0].toNumber(), "1000"); await exactlyEnv.borrowMP("DAI", futurePools(2)[1].toNumber(), "6000"); + await provider.send("evm_increaseTime", [3_600]); }); describe("WHEN 20 days goes by without payment, WETH price halves AND alice's first borrow is liquidated with a higher amount as repayment", () => { let johnETHBalanceBefore: BigNumber; @@ -410,6 +417,7 @@ describe("Liquidations", function () { await dai.connect(john).approve(marketDAI.address, MaxUint256); await dai.mint(john.address, parseUnits("100000")); await marketDAI.connect(john).deposit(parseUnits("100000"), john.address); + await provider.send("evm_increaseTime", [3_600]); // distribute earnings to accumulator await exactlyEnv.setBorrowRate("1"); diff --git a/test/hardhat/8_interest_rate_model.ts b/test/hardhat/8_interest_rate_model.ts index e89d5ae1e..dea57701c 100644 --- a/test/hardhat/8_interest_rate_model.ts +++ b/test/hardhat/8_interest_rate_model.ts @@ -56,13 +56,13 @@ describe("InterestRateModel", () => { const a = parseUnits("0.092"); // A parameter for the curve const b = parseUnits("-0.086666666666666666"); // B parameter for the curve const maxUtilization = parseUnits("1.2"); // Maximum utilization rate - const naturalUtilization = parseUnits("0.7"); + const floatingNaturalUtilization = parseUnits("0.7"); const sigmoidSpeed = parseUnits("2.5"); const growthSpeed = parseUnits("2.5"); const maxRate = parseUnits("10"); - const a0 = parseUnits("0.2"); - const a1 = parseUnits("0"); - const eta = parseUnits("0.5"); + const spreadFactor = parseUnits("0.2"); + const timePreference = parseUnits("0"); + const maturitySpeed = parseUnits("0.5"); await expect( irmFactory.deploy( @@ -70,13 +70,13 @@ describe("InterestRateModel", () => { a, b, maxUtilization, - naturalUtilization, + floatingNaturalUtilization, sigmoidSpeed, growthSpeed, maxRate, - a0, - a1, - eta, + spreadFactor, + timePreference, + maturitySpeed, ), ).to.be.reverted; }); @@ -84,13 +84,13 @@ describe("InterestRateModel", () => { const a = parseUnits("0.092"); // A parameter for the curve const b = parseUnits("-0.086666666666666666"); // B parameter for the curve const maxUtilization = parseUnits("1.2"); // Maximum utilization rate - const naturalUtilization = parseUnits("0.7"); + const floatingNaturalUtilization = parseUnits("0.7"); const sigmoidSpeed = parseUnits("2.5"); const growthSpeed = parseUnits("2.5"); const maxRate = parseUnits("10"); - const a0 = parseUnits("0.2"); - const a1 = parseUnits("0"); - const eta = parseUnits("0.5"); + const spreadFactor = parseUnits("0.2"); + const timePreference = parseUnits("0"); + const maturitySpeed = parseUnits("0.5"); await expect( irmFactory.deploy( @@ -98,13 +98,13 @@ describe("InterestRateModel", () => { a, b, maxUtilization, - naturalUtilization, + floatingNaturalUtilization, sigmoidSpeed, growthSpeed, maxRate, - a0, - a1, - eta, + spreadFactor, + timePreference, + maturitySpeed, ), ).to.be.revertedWithPanic(0x01); }); @@ -120,6 +120,7 @@ describe("InterestRateModel", () => { await exactlyEnv.enterMarket("WETH"); await exactlyEnv.moveInTime(nextPoolID); exactlyEnv.switchWallet(owner); + await provider.send("evm_increaseTime", [3_600 * 3]); }); describe("GIVEN curve parameters yielding Ub=1, Umax=3, R0=0.02 and Rb=0.14", () => { beforeEach(async () => { @@ -134,34 +135,36 @@ describe("InterestRateModel", () => { const a = parseUnits("0.72"); // A parameter for the curve const b = parseUnits("-0.22"); // B parameter for the curve const maxUtilization = parseUnits("3"); // Maximum utilization rate - const naturalUtilization = parseUnits("0.7"); + const floatingNaturalUtilization = parseUnits("0.7"); const sigmoidSpeed = parseUnits("2.5"); - const growthSpeed = parseUnits("2.5"); + const growthSpeed = parseUnits("1"); const maxRate = parseUnits("10"); - const a0 = parseUnits("0.2"); - const a1 = parseUnits("0"); - const eta = parseUnits("0.5"); + const spreadFactor = parseUnits("0.2"); + const timePreference = parseUnits("0"); + const maturitySpeed = parseUnits("0.5"); await exactlyEnv.setIRMParameters( a, b, maxUtilization, - naturalUtilization, + floatingNaturalUtilization, sigmoidSpeed, growthSpeed, maxRate, - a0, - a1, - eta, + spreadFactor, + timePreference, + maturitySpeed, ); exactlyEnv.switchWallet(alice); }); + // FIXME: diff custom error it("WHEN doing a borrow which pushes U to 3.2, THEN it reverts because the utilization rate is too high", async () => { await expect(exactlyEnv.borrowMP("DAI", secondPoolID, "19200", "19200")).to.be.revertedWithCustomError( exactlyEnv.interestRateModel, "UtilizationExceeded", ); }); + // FIXME: diff custom error it("WHEN doing a borrow which pushes U to 6, THEN it reverts because the utilization rate is too high", async () => { await expect(exactlyEnv.borrowMP("DAI", secondPoolID, "36000", "36000")).to.be.revertedWithCustomError( exactlyEnv.interestRateModel, @@ -189,30 +192,30 @@ describe("InterestRateModel", () => { const a = parseUnits("21.12"); // A parameter for the curve const b = parseUnits("-1.74"); // B parameter for the curve const maxUtilization = parseUnits("12"); // Maximum utilization rate - const naturalUtilization = parseUnits("0.7"); + const floatingNaturalUtilization = parseUnits("0.7"); const sigmoidSpeed = parseUnits("2.5"); - const growthSpeed = parseUnits("2.5"); + const growthSpeed = parseUnits("1"); const maxRate = parseUnits("10"); - const a0 = parseUnits("0.2"); - const a1 = parseUnits("0"); - const eta = parseUnits("0.5"); + const spreadFactor = parseUnits("0.2"); + const timePreference = parseUnits("0"); + const maturitySpeed = parseUnits("0.5"); await exactlyEnv.setIRMParameters( a, b, maxUtilization, - naturalUtilization, + floatingNaturalUtilization, sigmoidSpeed, growthSpeed, maxRate, - a0, - a1, - eta, + spreadFactor, + timePreference, + maturitySpeed, ); exactlyEnv.switchWallet(alice); }); - it("WHEN doing a borrow which pushes U to the full UR, THEN it does not revert", async () => { + it.only("WHEN doing a borrow which pushes U to the full UR, THEN it does not revert", async () => { await expect(exactlyEnv.borrowMP("DAI", secondPoolID, "12000", "34000")).to.not.be.reverted; }); it("WHEN doing a borrow which pushes U above the full UR, THEN it reverts", async () => { @@ -232,25 +235,6 @@ describe("InterestRateModel", () => { expect(borrowEvents?.[0].args?.fee).to.be.lte(expectedFee.mul("101").div("100")); }); }); - describe("GIVEN a borrow of 1000 DAI in the closest maturity", () => { - let aliceFirstBorrow: Array; - beforeEach(async () => { - await provider.send("evm_setNextBlockTimestamp", [secondPoolID - 50_000]); - await exactlyEnv.borrowMP("DAI", secondPoolID, "1000"); - aliceFirstBorrow = await exactlyEnv.getMarket("DAI").fixedBorrowPositions(secondPoolID, alice.address); - }); - describe("WHEN borrowing 1000 DAI in a following maturity", () => { - beforeEach(async () => { - await provider.send("evm_setNextBlockTimestamp", [thirdPoolID - 100_000]); - await exactlyEnv.borrowMP("DAI", thirdPoolID, "1000"); - }); - it("THEN the rate charged is the same one as the last borrow, since the sp total supply is the same", async () => { - const aliceNewBorrow = await exactlyEnv.getMarket("DAI").fixedBorrowPositions(thirdPoolID, alice.address); - // the fee charged is the double since third pool id has one more week - expect(aliceFirstBorrow[1]).to.be.equal(aliceNewBorrow[1].div(2)); - }); - }); - }); }); }); }); @@ -272,25 +256,25 @@ describe("InterestRateModel", () => { const a = parseUnits("8360"); const b = parseUnits("-418"); const maxUtilization = parseUnits("20"); - const naturalUtilization = parseUnits("0.7"); + const floatingNaturalUtilization = parseUnits("0.7"); const sigmoidSpeed = parseUnits("2.5"); const growthSpeed = parseUnits("2.5"); const maxRate = parseUnits("10"); - const a0 = parseUnits("0.2"); - const a1 = parseUnits("0"); - const eta = parseUnits("0.5"); + const spreadFactor = parseUnits("0.2"); + const timePreference = parseUnits("0"); + const maturitySpeed = parseUnits("0.5"); await exactlyEnv.setIRMParameters( a, b, maxUtilization, - naturalUtilization, + floatingNaturalUtilization, sigmoidSpeed, growthSpeed, maxRate, - a0, - a1, - eta, + spreadFactor, + timePreference, + maturitySpeed, ); await exactlyEnv.depositSP("WETH", "10"); @@ -319,25 +303,25 @@ describe("InterestRateModel", () => { const a = parseUnits("0.0495"); // A parameter for the curve const b = parseUnits("-0.025"); // B parameter for the curve const maxUtilization = parseUnits("1.1"); // Maximum utilization rate - const naturalUtilization = parseUnits("0.7"); + const floatingNaturalUtilization = parseUnits("0.7"); const sigmoidSpeed = parseUnits("2.5"); const growthSpeed = parseUnits("2.5"); const maxRate = parseUnits("10"); - const a0 = parseUnits("0.2"); - const a1 = parseUnits("0"); - const eta = parseUnits("0.5"); + const spreadFactor = parseUnits("0.2"); + const timePreference = parseUnits("0"); + const maturitySpeed = parseUnits("0.5"); await exactlyEnv.setIRMParameters( a, b, maxUtilization, - naturalUtilization, + floatingNaturalUtilization, sigmoidSpeed, growthSpeed, maxRate, - a0, - a1, - eta, + spreadFactor, + timePreference, + maturitySpeed, ); }); describe("GIVEN enough collateral", () => { @@ -612,7 +596,7 @@ describe("InterestRateModel", () => { parseUnits("50"), parseUnits("50"), ), - ).to.be.revertedWithCustomError(exactlyEnv.interestRateModel, "UtilizationExceeded"); + ).to.be.revertedWithoutReason(); }); it("AND WHEN asking for the interest at Umax, THEN it reverts", async () => { const tx = exactlyEnv.interestRateModel.fixedBorrowRate( @@ -623,7 +607,7 @@ describe("InterestRateModel", () => { parseUnits("50"), ); - await expect(tx).to.be.revertedWithCustomError(exactlyEnv.interestRateModel, "UtilizationExceeded"); + await expect(tx).to.be.revertedWithoutReason(); }); it("AND WHEN asking for the interest at U>Umax, THEN it reverts", async () => { const tx = exactlyEnv.interestRateModel.fixedBorrowRate( @@ -634,7 +618,7 @@ describe("InterestRateModel", () => { parseUnits("50"), ); - await expect(tx).to.be.revertedWithCustomError(exactlyEnv.interestRateModel, "UtilizationExceeded"); + await expect(tx).to.be.revertedWithoutReason(); }); }); describe("interest for durations other than a full year", () => {