diff --git a/helpers/misc-utils.ts b/helpers/misc-utils.ts index c187a40..abbd524 100644 --- a/helpers/misc-utils.ts +++ b/helpers/misc-utils.ts @@ -1,31 +1,69 @@ -import BigNumber from "bignumber.js"; -import BN = require("bn.js"); +import { BigNumber as BigNumberJS } from "bignumber.js"; +import { BigNumber, Wallet, ContractTransaction } from "ethers"; import low from "lowdb"; import FileSync from "lowdb/adapters/FileSync"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; // Updated dependency name import { WAD } from "./constants"; -import { Wallet, ContractTransaction } from "ethers"; -import { BuidlerRuntimeEnvironment } from "@nomiclabs/buidler/types"; import { iParamsPerNetwork, eEthereumNetwork } from "./types"; -export const toWad = (value: string | number) => - new BigNumber(value).times(WAD).toFixed(); +// NOTE: Hardhat/Ethers.js provides its own BigNumber implementation. +// We use BigNumberJS (from bignumber.js) here primarily for arithmetic precision +// before converting back to Ethers BigNumber or string for contract interaction. -export const bnToBigNumber = (amount: BN): BigNumber => - new BigNumber(amount); -export const stringToBigNumber = (amount: string): BigNumber => - new BigNumber(amount); +// --- Configuration and Environment Setup --- +// Default path for contract addresses persistence export const getDb = () => low(new FileSync("./deployed-contracts.json")); -export let BRE: BuidlerRuntimeEnvironment = {} as BuidlerRuntimeEnvironment; -export const setBRE = (_BRE: BuidlerRuntimeEnvironment) => { - BRE = _BRE; +// Using a type alias for the global environment, which should ideally be passed around, +// not stored globally (see comment below). +export type HRE = HardhatRuntimeEnvironment; + +// WARNING: Storing HRE globally is risky. It's better to pass it as an argument +// to functions that need it (e.g., evmSnapshot). +// If absolutely necessary, keep the setter/getter pattern: +export let hre: HRE = {} as HRE; +export const setHRE = (_hre: HRE) => { + hre = _hre; }; -export const getParamPerNetwork = ( +// --- Conversion and Utility Functions --- + +/** + * Converts a standard decimal value (e.g., '1.0' or 1) into a WAD (1e18) string format. + * This is crucial for interacting with Aave/Compound-like protocols. + * @param value The value to convert (e.g., 1.23) + * @returns The WAD representation as a string (e.g., '1230000000000000000') + */ +export const toWad = (value: string | number): string => + new BigNumberJS(value).times(WAD).toFixed(0); // Ensure no decimals in the final integer string + +/** + * Converts an Ethers BigNumber to BigNumberJS for high-precision arithmetic. + * @param amount The Ethers BigNumber object. + * @returns The BigNumberJS object. + */ +export const ethersBnToBigNumberJS = (amount: BigNumber): BigNumberJS => + new BigNumberJS(amount.toString()); + +/** + * Converts a string amount to BigNumberJS for high-precision arithmetic. + * @param amount The amount as a string. + * @returns The BigNumberJS object. + */ +export const stringToBigNumberJS = (amount: string): BigNumberJS => + new BigNumberJS(amount); + +/** + * Retrieves the correct parameter value based on the current Ethereum network environment. + * @param params Object containing network-specific parameters. + * @param network The current network enum. + * @returns The parameter value for the specified network. + */ +export const getParamByNetwork = ( { kovan, ropsten, main, buidlerevm, coverage }: iParamsPerNetwork, network: eEthereumNetwork -) => { +): T => { switch (network) { case eEthereumNetwork.coverage: return coverage; @@ -38,31 +76,70 @@ export const getParamPerNetwork = ( case eEthereumNetwork.main: return main; default: + // Defaulting to 'main' is acceptable if the configuration ensures 'main' always exists. return main; } }; -export const sleep = (milliseconds: number) => { +/** + * Pauses execution for a specified number of milliseconds. + * @param milliseconds Time to sleep. + */ +export const sleep = (milliseconds: number): Promise => { return new Promise((resolve) => setTimeout(resolve, milliseconds)); }; -export const createRandomAddress = () => Wallet.createRandom().address; +/** + * Creates a new randomly generated Ethereum wallet and returns its address. + * @returns A randomly generated Ethereum address. + */ +export const createRandomAddress = (): string => Wallet.createRandom().address; +/** + * Waits for a transaction to be mined and returns the receipt. + * @param tx The contract transaction promise. + * @returns The transaction receipt. + */ export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); -export const evmSnapshot = async () => - await BRE.ethereum.send("evm_snapshot", []); -export const evmRevert = async (id: string) => - BRE.ethereum.send("evm_revert", [id]); +// --- EVM Manipulation Functions (Require HRE/hre to be set) --- + +/** + * Creates a snapshot of the current EVM state. + * @returns The snapshot ID as a string. + */ +export const evmSnapshot = async (): Promise => + await hre.ethers.provider.send("evm_snapshot", []); + +/** + * Reverts the EVM to a previously saved snapshot. + * @param id The ID of the snapshot to revert to. + */ +export const evmRevert = async (id: string): Promise => + await hre.ethers.provider.send("evm_revert", [id]); -export const timeLatest = async () => { - const block = await BRE.ethers.provider.getBlock("latest"); - return new BigNumber(block.timestamp); +/** + * Gets the timestamp of the latest mined block. + * @returns The timestamp as a BigNumberJS object. + */ +export const timeLatest = async (): Promise => { + const block = await hre.ethers.provider.getBlock("latest"); + // Use BigNumberJS for potential large timestamps + return new BigNumberJS(block.timestamp); }; -export const advanceBlock = async (timestamp: number) => - await BRE.ethers.provider.send("evm_mine", [timestamp]); +/** + * Mines a new block with a specific timestamp. + * @param timestamp The Unix timestamp for the new block. + */ +export const advanceBlock = async (timestamp: number): Promise => + await hre.ethers.provider.send("evm_mine", [timestamp]); -export const increaseTime = async (secondsToIncrease: number) => - await BRE.ethers.provider.send("evm_increaseTime", [secondsToIncrease]); +/** + * Increases the EVM's block time by a specified number of seconds. + * Note: A subsequent block mine is needed to activate the time increase. + * @param secondsToIncrease The number of seconds to advance the time by. + */ +export const increaseTime = async (secondsToIncrease: number): Promise => + await hre.ethers.provider.send("evm_increaseTime", [secondsToIncrease]);