From e53d3eeb1a906fc51f0b60f47cc6e34527cde91d Mon Sep 17 00:00:00 2001 From: GitGuru7 <128375421+GitGuru7@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:24:53 +0530 Subject: [PATCH] WIP: refactor borrow & repay test --- hardhat.config.zksync.ts | 3 ++ tests/hardhat/Fork/borrowAndRepayTest.ts | 41 +++++++++++-------- tests/hardhat/Fork/constants.ts | 4 +- tests/hardhat/Fork/utils.ts | 51 ++++++++++++++++++++++-- 4 files changed, 78 insertions(+), 21 deletions(-) diff --git a/hardhat.config.zksync.ts b/hardhat.config.zksync.ts index f13e7c79d..62882229c 100644 --- a/hardhat.config.zksync.ts +++ b/hardhat.config.zksync.ts @@ -140,6 +140,9 @@ const config: HardhatUserConfig = { "hardhat-deploy/solc_0.8/openzeppelin/proxy/transparent/ProxyAdmin.sol", ], }, + mocha: { + timeout: 200000000, + }, }; export default config; diff --git a/tests/hardhat/Fork/borrowAndRepayTest.ts b/tests/hardhat/Fork/borrowAndRepayTest.ts index ae6fe936e..aa75ebbfb 100644 --- a/tests/hardhat/Fork/borrowAndRepayTest.ts +++ b/tests/hardhat/Fork/borrowAndRepayTest.ts @@ -20,7 +20,7 @@ import { WrappedNative, WrappedNative__factory, } from "../../../typechain"; -import { getContractAddresses, initMainnetUser, setForkBlock } from "./utils"; +import { getContractAddresses, initMainnetUser, mineBlocks, mineOnZksync, setForkBlock } from "./utils"; const { expect } = chai; chai.use(smock.matchers); @@ -105,13 +105,17 @@ if (FORK) { feed: token1Config.feed, maxStalePeriod: BigNumber.from(1000000000), }; - const token2NewConfig = { - asset: token2Config.asset, - feed: token2Config.feed, - maxStalePeriod: BigNumber.from(1000000000), - }; await ChainlinkOracle.setTokenConfig(token1NewConfig); - await ChainlinkOracle.setTokenConfig(token2NewConfig); + + // Direct price is set for ZK token + if (FORKED_NETWORK != "zksyncsepolia") { + const token2NewConfig = { + asset: token2Config.asset, + feed: token2Config.feed, + maxStalePeriod: BigNumber.from(1000000000), + }; + await ChainlinkOracle.setTokenConfig(token2NewConfig); + } } token1 = IERC20__factory.connect(TOKEN1, impersonatedTimelock); @@ -146,7 +150,6 @@ if (FORK) { // Allocate reserves to market from ACC3 to the TOKEN2 market await token2.connect(token2Holder).approve(vTOKEN2.address, convertToUnit(10000, 18)); await expect(vTOKEN2.connect(token2Holder).mint(convertToUnit(10000, 18))).to.emit(vTOKEN2, "Mint"); - // Increase collateral for ACC await token1.connect(token1Holder).transfer(ACC1, mintAmount); await token1.connect(acc1Signer).approve(vTOKEN1.address, mintAmount); @@ -159,14 +162,12 @@ if (FORK) { it("Total Borrow Balance with Two Borrowers", async function () { // common factors const vTOKEN1CollateralFactor = await comptroller.markets(VTOKEN1); - await expect(vTOKEN1.connect(acc1Signer).mint(mintAmount)).to.emit(vTOKEN1, "Mint"); let exchangeRateCollateral = await vTOKEN1.exchangeRateStored(); let TOKEN1Price = await priceOracle.getUnderlyingPrice(VTOKEN1); let TOKEN2Price = await priceOracle.getUnderlyingPrice(VTOKEN2); - let vTokenPrice = exchangeRateCollateral.mul(TOKEN1Price).div(convertToUnit(1, 18)); let weightedPriceTOKEN1 = vTokenPrice @@ -197,7 +198,6 @@ if (FORK) { expectedMintAmount = mintAmount.mul(convertToUnit(1, 18)).div(await vTOKEN1.exchangeRateStored()); expectedLiquidityAcc1 = weightedPriceTOKEN1.mul(await vTOKEN1.balanceOf(ACC1)).div(convertToUnit(1, 18)); - [err, liquidity, shortfall] = await comptroller.getBorrowingPower(ACC2); let expectedLiquidityAcc2 = weightedPriceTOKEN1.mul(expectedMintAmount).div(convertToUnit(1, 18)); @@ -225,7 +225,11 @@ if (FORK) { expect(shortfall).equals(0); // ********************************Mine 30000 blocks***********************************/ - await mine(30000); + if (FORKED_NETWORK == "zksyncsepolia") { + await mineOnZksync(30000); + } else { + await mine(30000); + } await vTOKEN2.accrueInterest(); let borrowIndexCurrent = await vTOKEN2.borrowIndex(); @@ -246,8 +250,14 @@ if (FORK) { expect(shortfall).equals(0); // ********************************Mine 300000 blocks***********************************/ - await mine(300000); + if (FORKED_NETWORK == "zksyncsepolia") { + await mineOnZksync(30000); + } else { + await mine(300000); + } + await vTOKEN2.accrueInterest(); + borrowIndexCurrent = await vTOKEN2.borrowIndex(); // Change borrow balance of ACC1 @@ -257,17 +267,14 @@ if (FORK) { // Change borrow balance of ACC2 borrowBalanceStored = await vTOKEN2.borrowBalanceStored(ACC2); expect(borrowIndexCurrent.mul(TOKEN2BorrowAmount).div(borrowIndexAcc2Prev)).equals(borrowBalanceStored); - // *************************Repay ACC2**************************************************/ // Allocate some funds to repay debt await vTOKEN2.accrueInterest(); borrowBalanceStored = await vTOKEN2.borrowBalanceStored(ACC2); - await token2.connect(token2Holder).transfer(ACC2, borrowBalanceStored.add(convertToUnit(1, 20))); await token2.connect(acc2Signer).approve(vTOKEN2.address, borrowBalanceStored.add(convertToUnit(1, 20))); await vTOKEN2.connect(acc2Signer).repayBorrow(borrowBalanceStored.add(convertToUnit(1, 20))); - // Full debt repaid acc2 borrowBalanceStored = await vTOKEN2.borrowBalanceStored(ACC2); expect(borrowBalanceStored).equals(0); @@ -276,7 +283,9 @@ if (FORK) { await vTOKEN2.accrueInterest(); borrowIndexCurrent = await vTOKEN2.borrowIndex(); borrowBalanceStored = await vTOKEN2.borrowBalanceStored(ACC1); + expect(borrowIndexCurrent.mul(TOKEN2BorrowAmount).div(borrowIndexAcc1Prev)).equals(borrowBalanceStored); + console.log("end", borrowIndexCurrent.mul(TOKEN2BorrowAmount).div(borrowIndexAcc1Prev), borrowBalanceStored); }); it("Attempt to borrow over set cap", async function () { diff --git a/tests/hardhat/Fork/constants.ts b/tests/hardhat/Fork/constants.ts index 3767ff501..9baffc5df 100644 --- a/tests/hardhat/Fork/constants.ts +++ b/tests/hardhat/Fork/constants.ts @@ -220,8 +220,8 @@ export const contractAddresses = { CHAINLINK_ORACLE: OracleZksyncsepolia.contracts.ChainlinkOracle.address, TOKEN1: "0x53F7e72C7ac55b44c7cd73cC13D4EF4b121678e6", // WETH TOKEN2: "0x8A2E9048F5d658E88D6eD89DdD1F3B5cA0250B9F", // ZK - TOKEN1_HOLDER: "0xE0B015E54d54fc84a6cB9B666099c46adE9335FF", - TOKEN2_HOLDER: "0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E", + TOKEN1_HOLDER: "0xEF4B807f9442b0EbD8a051C2cAEA81e5e7BAcFBD", + TOKEN2_HOLDER: "0xE8C6Cf867CF962d289305ECE9b139a4116674541", ACC1: "0x32B701d3957fee432664cFA57FB44b0fE8496659", ACC2: "0xB09F16F625B363875e39ADa56C03682088471523", ACC3: "0x4A2339eE9c4fD4c99DE1d3AeB513B53ab42Db5ca", diff --git a/tests/hardhat/Fork/utils.ts b/tests/hardhat/Fork/utils.ts index d52d631bb..a3be27bdf 100644 --- a/tests/hardhat/Fork/utils.ts +++ b/tests/hardhat/Fork/utils.ts @@ -20,7 +20,9 @@ export const forking = (blockNumber: number, fn: () => Promise) => { })(); }; -export async function setForkBlock(blockNumber: number) { +export async function setForkBlock(_blockNumber: number) { + // const _blockNumber = config.networks.hardhat.zksync ? _blockNumber.toString(16) : _blockNumber; + const blockNumber = _blockNumber.toString(16); await network.provider.request({ method: "hardhat_reset", params: [ @@ -35,7 +37,50 @@ export async function setForkBlock(blockNumber: number) { } export const initMainnetUser = async (user: string, balance: NumberLike) => { - await impersonateAccount(user); - await setBalance(user, balance); + await network.provider.send("hardhat_impersonateAccount", [user]); + const balanceHex = toRpcQuantity(balance); + await network.provider.send("hardhat_setBalance", [user, balanceHex]); + return ethers.getSigner(user); }; + +const toRpcQuantity = (x: NumberLike): string => { + let hex: string; + if (typeof x === "number" || typeof x === "bigint") { + // TODO: check that number is safe + hex = `0x${x.toString(16)}`; + } else if (typeof x === "string") { + if (!x.startsWith("0x")) { + throw new Error("Only 0x-prefixed hex-encoded strings are accepted"); + } + hex = x; + } else if ("toHexString" in x) { + hex = x.toHexString(); + } else if ("toString" in x) { + hex = x.toString(16); + } else { + throw new Error(`${x as any} cannot be converted to an RPC quantity`); + } + + if (hex === "0x0") return hex; + + return hex.startsWith("0x") ? hex.replace(/0x0+/, "0x") : `0x${hex}`; +}; + +export const mineOnZksync = async (blocks: number) => { + const blockTimestamp = (await ethers.provider.getBlock("latest")).timestamp; + const targetTimestamp = blockTimestamp + blocks; + await ethers.provider.send("evm_setNextBlockTimestamp", [targetTimestamp]); + await mineBlocks(); +}; + +export async function mineBlocks(blocks: NumberLike = 1, options: { interval?: NumberLike } = {}): Promise { + const interval = options.interval ?? 1; + const blocksHex = toRpcQuantity(blocks); + const intervalHex = toRpcQuantity(interval); + + await network.provider.request({ + method: "hardhat_mine", + params: [blocksHex, intervalHex], + }); +}