Ethers cheatsheet

        
// get 0.001 ETH
ethers.utils.parseEther("0.001")

// zero address
ethers.constants.AddressZero

// max uint256 value
ethers.constants.MaxUint256

// wei per ether
ethers.constants.WeiPerEther

// get signers
// you can get upto 5 signers if I remember correctly
const [signer1, signer2] = await ethers.getSigners();

// deploying a contract TestContract.sol
// by default signer1 will be the deployer of the contract
const TestContract = await ethers.getContractFactory(
    "TestContract"
);
const testContract = await TestContract.deploy();
await testContract.deployed();

// if the contract has constructor arguments
const TestContract = await ethers.getContractFactory(
    "TestContract"
);
const testContract = await TestContract.deploy(argument1, argument2);
await testContract.deployed();

// if you need to send ether to the contract on deploy
const TestContract = await ethers.getContractFactory(
    "TestContract"
);
const testContract = await TestContract.deploy(
    argument1,
    {
    value: ethers.constants.WeiPerEther,
    }
);
await testContract.deployed();

// sending ether to a address
await signer1.sendTransaction({
    to: someAddress,
    value: ethers.utils.parseEther("1.0"),
});

// sending ether to a address while calling a method of a contract
await signer1.sendTransaction({
    to: someAddress,
    value: ethers.utils.parseEther("1.0"),
    data: someContract.interface.encodeFunctionData(
    "someMethod"
    ),
});

// writing a fixture
async function fixture() {
    const [deployer] = await ethers.getSigners();

    const TestContract = await ethers.getContractFactory(
    "TestContract"
    );
    const testContract = await TestContract.deploy();
    await testContract.deployed();

    return { deployer, testContract };
}

// loading above fixture
const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");
const { deployer, testContract } = await loadFixture(fixture);

// check if a contract function returns a particular value
const { expect } = require("chai");
expect(await testContract.isSomeCondition()).to.equal(true);

// call a contract as a different signer
await testContract.connect(signer2).someFunction();

// get ether balance of a address
await provider.getBalance(someAddress);

// attach a contract interface to a deployed address
const TestContract = await ethers.getContractFactory(
    "TestContract"
);
const testContract = TestContract.attach(alreadyDeployedTestContractAddress);

// check if revert happens
await expect(
    testContract.someMethod()
).to.be.revertedWith(revertReasonString);

// check if revert happens with custom error
await expect(
    testContract.someMethod()
).to.be.revertedWithCustomError(testContract, "CustomError");

// check if revert happens with custom error with args
await expect(
    testContract.someMethod()
).to.be.revertedWithCustomError(testContract, "CustomError")
.withArgs(arg1, arg2);

// check if an event is emitted 
await expect(testContract.someMethod())
    .to.emit(testContract, "Event");

// check if an event with args is emitted
await expect(testContract.someMethod())
    .to.emit(testContract, "Event")
    .withArgs(arg1, arg2);

// get revert message for role missing 
// (if using OpenZeppelin AccessControl)
function getRoleKeccakFromRoleName(roleName: string) {
    return ethers.utils.keccak256(utils.toUtf8Bytes(roleName));
}
function getAccessControlRevertMessage(
    roleName: string,
    address: string
) {
    const role = getRoleKeccakFromRoleName(roleName);
    return `AccessControl: account ${address.toLowerCase()} is missing role ${role}`;
}

// Expect a transaction to throw
await expect(
    testContract.someVeryExpensiveCall({ gasLimit: 50_000 })
).to.be.rejected;

// Expect a transaction to throw with error message
await expect(
    testContract.someVeryExpensiveCall({ gasLimit: 50_000 })
).to.be.rejectedWith("Transaction ran out of gas");

// read from a particular storage slot
async function readSlot(address: string, slot: any): Promise {
    const value = await ethers.provider.getStorageAt(address, slot);
    return value;
}

// get slot for a mapping
function getMappingSlot(address: string, slot: any, key: any): string {
    const paddedSlot = ethers.utils.hexZeroPad(slot, 32);
    const paddedKey = ethers.utils.hexZeroPad(key, 32);
    const itemSlot = ethers.utils.keccak256(paddedKey + paddedSlot.slice(2));
    return itemSlot;
}

// get slot for a nested mapping
function getNestedMappingSlot(
    address: string,
    slot: any,
    parentKey: any,
    childKey: any
): string {
    const parentSlot = getMappingSlot(address, slot, parentKey);
    const childSlot = getMappingSlot(address, parentSlot, childKey);
    return childSlot;
}

// parse a hex string to string
function parseString(hex: string): string {
    const len = parseInt(hex.slice(-2), 16);
    hex = hex.replace(/^0x/, "");
    return Buffer.from(hex.slice(0, len), "hex").toString("utf8");
}

// parse a hex string to BigNumber
import { BigNumber } from "ethers";
function parseUInt(hex: string): BigNumber {
    return BigNumber.from(hex);
}

// mine 256 blocks
const { mine } = require("@nomicfoundation/hardhat-network-helpers");
await mine(256);

// increase time by 86,400 seconds
const { time } = require("@nomicfoundation/hardhat-network-helpers");
await time.increase(86400)
    
// abi.encodeWithSignature("initializeV2()")
const abi = ["function initializeV2()"];
const interface = new ethers.utils.Interface(abi);
interface.encodeFunctionData("initializeV2", []);