mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-09 04:08:01 -05:00
* first pass contracts and makefile cleanup * remove unused 4844 test files * Remove Goerli references * lint fixing * lint fixing * remove more Goerli references * correct folder paths for L2 service tests * fix pathing and hardhat version * reinstate deleted file * correct file pathing
151 lines
5.9 KiB
TypeScript
151 lines
5.9 KiB
TypeScript
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";
|
|
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
|
|
import { expect } from "chai";
|
|
import { ethers } from "hardhat";
|
|
import { RecoverFunds, TestExternalCalls } from "../../typechain-types";
|
|
import {
|
|
ADDRESS_ZERO,
|
|
DEFAULT_ADMIN_ROLE,
|
|
EMPTY_CALLDATA,
|
|
FUNCTION_EXECUTOR_ROLE,
|
|
INITIALIZED_ALREADY_MESSAGE,
|
|
INITIAL_WITHDRAW_LIMIT,
|
|
} from "../common/constants";
|
|
import { deployUpgradableFromFactory } from "../common/deployment";
|
|
import { buildAccessErrorMessage, expectRevertWithCustomError, expectRevertWithReason } from "../common/helpers";
|
|
|
|
describe("RecoverFunds contract", () => {
|
|
let recoverFunds: RecoverFunds;
|
|
let recoverFundsAddress: string;
|
|
let testContract: TestExternalCalls;
|
|
let testContractAddress: string;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
let admin: SignerWithAddress;
|
|
let securityCouncil: SignerWithAddress;
|
|
let executor: SignerWithAddress;
|
|
let nonAuthorizedAccount: SignerWithAddress;
|
|
|
|
async function deployRecoverFundsFixture() {
|
|
const recoverFunds = (await deployUpgradableFromFactory(
|
|
"RecoverFunds",
|
|
[securityCouncil.address, executor.address],
|
|
{
|
|
initializer: "initialize(address,address)",
|
|
unsafeAllow: ["constructor"],
|
|
},
|
|
)) as unknown as RecoverFunds;
|
|
|
|
recoverFundsAddress = await recoverFunds.getAddress();
|
|
return recoverFunds;
|
|
}
|
|
|
|
async function deployTestContractFixture() {
|
|
const testExternalCallsFactory = await ethers.getContractFactory("TestExternalCalls");
|
|
const testExternalCalls = await testExternalCallsFactory.deploy();
|
|
await testExternalCalls.waitForDeployment();
|
|
testContractAddress = await testExternalCalls.getAddress();
|
|
return testExternalCalls;
|
|
}
|
|
|
|
before(async () => {
|
|
[admin, securityCouncil, nonAuthorizedAccount, executor] = await ethers.getSigners();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
recoverFunds = await loadFixture(deployRecoverFundsFixture);
|
|
testContract = await loadFixture(deployTestContractFixture);
|
|
});
|
|
|
|
describe("Fallback/Receive tests", () => {
|
|
const sendEthToContract = async (data: string) => {
|
|
return admin.sendTransaction({ to: await recoverFunds.getAddress(), value: INITIAL_WITHDRAW_LIMIT, data });
|
|
};
|
|
|
|
it("Should fail to send eth to the recoverFunds contract through the fallback", async () => {
|
|
await expect(sendEthToContract(EMPTY_CALLDATA)).to.be.reverted;
|
|
});
|
|
|
|
it("Should fail to send eth to the recoverFunds contract through the receive function", async () => {
|
|
await expect(sendEthToContract("0x1234")).to.be.reverted;
|
|
});
|
|
});
|
|
|
|
describe("Initialisation", () => {
|
|
it("Should revert if security council address is zero address", async () => {
|
|
const deployCall = deployUpgradableFromFactory("RecoverFunds", [ADDRESS_ZERO, executor.address], {
|
|
initializer: "initialize(address,address)",
|
|
unsafeAllow: ["constructor"],
|
|
});
|
|
|
|
await expectRevertWithCustomError(recoverFunds, deployCall, "ZeroAddressNotAllowed");
|
|
});
|
|
|
|
it("Should revert if security council address is zero address", async () => {
|
|
const deployCall = deployUpgradableFromFactory("RecoverFunds", [securityCouncil.address, ADDRESS_ZERO], {
|
|
initializer: "initialize(address,address)",
|
|
unsafeAllow: ["constructor"],
|
|
});
|
|
|
|
await expectRevertWithCustomError(recoverFunds, deployCall, "ZeroAddressNotAllowed");
|
|
});
|
|
|
|
it("Should grant default admin role to security council", async () => {
|
|
expect(await recoverFunds.hasRole(DEFAULT_ADMIN_ROLE, securityCouncil.address)).true;
|
|
});
|
|
|
|
it("Should grant function executor admin role to executor address", async () => {
|
|
expect(await recoverFunds.hasRole(FUNCTION_EXECUTOR_ROLE, executor.address)).true;
|
|
});
|
|
|
|
it("Should revert if the initialize function is called a second time", async () => {
|
|
recoverFunds = await loadFixture(deployRecoverFundsFixture);
|
|
const initializeCall = recoverFunds.initialize(securityCouncil.address, executor.address);
|
|
|
|
await expectRevertWithReason(initializeCall, INITIALIZED_ALREADY_MESSAGE);
|
|
});
|
|
});
|
|
|
|
describe("Executing functions", () => {
|
|
it("Should revert if not security council", async () => {
|
|
const functionCall = recoverFunds
|
|
.connect(nonAuthorizedAccount)
|
|
.executeExternalCall(nonAuthorizedAccount, EMPTY_CALLDATA, 1000n);
|
|
expectRevertWithReason(functionCall, buildAccessErrorMessage(nonAuthorizedAccount, FUNCTION_EXECUTOR_ROLE));
|
|
});
|
|
|
|
it("Should send half of the ETH sent", async () => {
|
|
await recoverFunds
|
|
.connect(executor)
|
|
.executeExternalCall(testContractAddress, EMPTY_CALLDATA, 1000n, { value: 2000n });
|
|
|
|
expect(await ethers.provider.getBalance(recoverFundsAddress)).equal(1000n);
|
|
expect(await ethers.provider.getBalance(testContractAddress)).equal(1000n);
|
|
});
|
|
|
|
it("Should call and set the value on the test contract", async () => {
|
|
const calldata = testContract.interface.encodeFunctionData("setValue", [1000n]);
|
|
|
|
await recoverFunds.connect(executor).executeExternalCall(testContractAddress, calldata, 0n);
|
|
|
|
expect(await testContract.testValue()).equal(1000n);
|
|
});
|
|
|
|
it("Should revert with the destinations custom error", async () => {
|
|
const calldata = testContract.interface.encodeFunctionData("revertWithError");
|
|
|
|
const functionCall = recoverFunds.connect(executor).executeExternalCall(testContractAddress, calldata, 0n);
|
|
|
|
await expectRevertWithCustomError(testContract, functionCall, "TestError");
|
|
});
|
|
|
|
it("Should revert with the recovery contract custom error", async () => {
|
|
const calldata = "0xdeadbeef";
|
|
|
|
const functionCall = recoverFunds.connect(executor).executeExternalCall(testContractAddress, calldata, 0n);
|
|
|
|
await expectRevertWithCustomError(recoverFunds, functionCall, "ExternalCallFailed", [testContractAddress]);
|
|
});
|
|
});
|
|
});
|