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<string> {
  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", []);