From 7c5a35006f34ccd27be0b684ec5076fbdc2cc1fb Mon Sep 17 00:00:00 2001 From: Akshay Date: Mon, 26 Jun 2023 13:41:23 +0200 Subject: [PATCH] [#4] Add test case for protocol mediator, run yarn fmt:ts --- contracts/test/TestModule.sol | 4 + test/SafeProtocolMediator.spec.ts | 165 ++++++++++++++++++------------ test/SafeProtocolRegistry.spec.ts | 7 +- 3 files changed, 108 insertions(+), 68 deletions(-) diff --git a/contracts/test/TestModule.sol b/contracts/test/TestModule.sol index 3a90c937..0e310bc2 100644 --- a/contracts/test/TestModule.sol +++ b/contracts/test/TestModule.sol @@ -12,6 +12,10 @@ abstract contract BaseTestModule is ISafeProtocolModule { bool public requiresRootAccess = false; function metaProvider() external view override returns (uint256 providerType, bytes memory location) {} + + function setRequiresRootAccess(bool _requiresRootAccess) external { + requiresRootAccess = _requiresRootAccess; + } } contract TestModule is BaseTestModule { diff --git a/test/SafeProtocolMediator.spec.ts b/test/SafeProtocolMediator.spec.ts index 67b534ad..4cd7bc3e 100644 --- a/test/SafeProtocolMediator.spec.ts +++ b/test/SafeProtocolMediator.spec.ts @@ -3,31 +3,30 @@ import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { expect } from "chai"; import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import BigNumber from "bignumber.js"; +import { TestModule } from "../typechain-types"; describe("SafeProtocolMediator", async () => { let deployer: SignerWithAddress, owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress; async function deployContractFixture() { - [deployer, owner, user1, user2]= await hre.ethers.getSigners(); + [deployer, owner, user1, user2] = await hre.ethers.getSigners(); const safeProtocolMediator = await (await hre.ethers.getContractFactory("SafeProtocolMediator")).deploy(owner.address); return { safeProtocolMediator }; } - describe("Setup mediator", async()=>{ + describe("Setup mediator", async () => { it("Should set mediator as a module for a safe", async () => { const safe = await hre.ethers.deployContract("TestExecutor"); const { safeProtocolMediator } = await loadFixture(deployContractFixture); await safe.setModule(await safeProtocolMediator.getAddress()); }); - }) - - - describe("Modules", async()=>{ + }); + describe("Modules", async () => { async function deployContractsFixture() { // TODO: Reuse parent fixture - [deployer, owner, user1, user2]= await hre.ethers.getSigners(); + [deployer, owner, user1, user2] = await hre.ethers.getSigners(); const safeProtocolMediator = await (await hre.ethers.getContractFactory("SafeProtocolMediator")).deploy(owner.address); const safe = await hre.ethers.deployContract("TestExecutor"); const module = await (await hre.ethers.getContractFactory("TestModule")).deploy(); @@ -41,38 +40,37 @@ describe("SafeProtocolMediator", async () => { await safe.exec(await safeProtocolMediator.getAddress(), 0, data); // TODO: Check for emitted events and param values expect(await safeProtocolMediator.getModuleInfo(await safe.getAddress(), await module.getAddress())).to.eql([true, false]); - }); - + it("Should fail to enable a module (with non root access) with root access", async () => { - const { safeProtocolMediator, safe, module } = await loadFixture(deployContractsFixture); await safe.setModule(await safeProtocolMediator.getAddress()); const data = safeProtocolMediator.interface.encodeFunctionData("enableModule", [await module.getAddress(), true]); - - await expect(safe.exec(await safeProtocolMediator.getAddress(), 0, data)).to.be.revertedWithCustomError(safeProtocolMediator, "ModuleAccessMismatch"); - expect(await safeProtocolMediator.getModuleInfo(await safe.getAddress(), await module.getAddress())).to.eql([false, false]); + await expect(safe.exec(await safeProtocolMediator.getAddress(), 0, data)).to.be.revertedWithCustomError( + safeProtocolMediator, + "ModuleAccessMismatch", + ); + expect(await safeProtocolMediator.getModuleInfo(await safe.getAddress(), await module.getAddress())).to.eql([false, false]); }); - + it("Should disable a module", async () => { const { safeProtocolMediator, safe, module } = await loadFixture(deployContractsFixture); await safe.setModule(await safeProtocolMediator.getAddress()); const data = safeProtocolMediator.interface.encodeFunctionData("enableModule", [await module.getAddress(), false]); await safe.exec(await safeProtocolMediator.getAddress(), 0, data); expect(await safeProtocolMediator.getModuleInfo(await safe.getAddress(), await module.getAddress())).to.eql([true, false]); - + const data2 = safeProtocolMediator.interface.encodeFunctionData("disableModule", [await module.getAddress()]); await safe.exec(await safeProtocolMediator.getAddress(), 0, data2); // TODO: Check for emitted events and param values expect(await safeProtocolMediator.getModuleInfo(await safe.getAddress(), await module.getAddress())).to.eql([false, false]); }); - }) - - describe("Execute transaction from module", async()=>{ + }); + describe("Execute transaction from module", async () => { async function deployContractsFixture() { - [deployer, owner, user1, user2]= await hre.ethers.getSigners(); + [deployer, owner, user1, user2] = await hre.ethers.getSigners(); const safeProtocolMediator = await (await hre.ethers.getContractFactory("SafeProtocolMediator")).deploy(owner.address); const safe = await hre.ethers.deployContract("TestExecutor"); await safe.setModule(await safeProtocolMediator.getAddress()); @@ -80,24 +78,27 @@ describe("SafeProtocolMediator", async () => { return { safeProtocolMediator, safe }; } - it("Should not allow non-enabled module to execute tx from a safe", async()=>{ + it("Should not allow non-enabled module to execute tx from a safe", async () => { const { safeProtocolMediator, safe } = await loadFixture(deployContractsFixture); const module = await (await hre.ethers.getContractFactory("TestModule")).deploy(); - // TODO: Replace with builder function - const safeTx = { - actions: [ - { - to: user2.address, - value: hre.ethers.parseEther("1"), - data: "0x", - } - ], - nonce: 1, - metaHash: hre.ethers.randomBytes(32), - }; - - await expect(module.executeFromModule(safeProtocolMediator, safe, safeTx)).to.be.revertedWithCustomError(safeProtocolMediator, "MoudleNotEnabled"); - }) + // TODO: Replace with builder function + const safeTx = { + actions: [ + { + to: user2.address, + value: hre.ethers.parseEther("1"), + data: "0x", + }, + ], + nonce: 1, + metaHash: hre.ethers.randomBytes(32), + }; + + await expect(module.executeFromModule(safeProtocolMediator, safe, safeTx)).to.be.revertedWithCustomError( + safeProtocolMediator, + "MoudleNotEnabled", + ); + }); it("Should process a SafeTransaction", async function () { const { safeProtocolMediator, safe } = await loadFixture(deployContractsFixture); @@ -108,22 +109,24 @@ describe("SafeProtocolMediator", async () => { await safe.exec(await safeProtocolMediator.getAddress(), 0, data); const amount = hre.ethers.parseEther("1"); - await(await deployer.sendTransaction({ - to: await safe.getAddress(), - value: amount, - })).wait(); - // TODO: Replace with builder function - const safeTx = { - actions: [ - { - to: user2.address, - value: hre.ethers.parseEther("1"), - data: "0x", - } - ], - nonce: 1, - metaHash: hre.ethers.randomBytes(32), - }; + await ( + await deployer.sendTransaction({ + to: await safe.getAddress(), + value: amount, + }) + ).wait(); + // TODO: Replace with builder function + const safeTx = { + actions: [ + { + to: user2.address, + value: hre.ethers.parseEther("1"), + data: "0x", + }, + ], + nonce: 1, + metaHash: hre.ethers.randomBytes(32), + }; const balanceBefore = (await hre.ethers.provider.getBalance(user2.address)).toString(); const tx = await module.executeFromModule(safeProtocolMediator, safe, safeTx); @@ -133,10 +136,12 @@ describe("SafeProtocolMediator", async () => { expect(BigNumber(balanceAfter)).to.eql(BigNumber(balanceBefore).plus(amount.toString())); expect((await hre.ethers.provider.getBalance(await safe.getAddress())).toString()).to.eql("0"); - await expect(tx).to.emit(safeProtocolMediator, "ActionsExecuted").withArgs(await safe.getAddress(), safeTx.metaHash); - }); + await expect(tx) + .to.emit(safeProtocolMediator, "ActionsExecuted") + .withArgs(await safe.getAddress(), safeTx.metaHash); + }); - it("Should fail to process a SafeTransaction", async function () { + it("Should fail to process a SafeTransaction", async function () { const { safeProtocolMediator, safe } = await loadFixture(deployContractsFixture); // Enable module @@ -146,10 +151,10 @@ describe("SafeProtocolMediator", async () => { const safeTx = { actions: [ { - to: user2.address, - value: hre.ethers.parseEther("1"), - data: "0x", - } + to: user2.address, + value: hre.ethers.parseEther("1"), + data: "0x", + }, ], nonce: 1, metaHash: hre.ethers.randomBytes(32), @@ -160,11 +165,45 @@ describe("SafeProtocolMediator", async () => { const balanceAfter = (await hre.ethers.provider.getBalance(user2.address)).toString(); expect(BigNumber(balanceAfter)).to.eql(BigNumber(balanceBefore)); - console.log(txr); + await expect(tx) + .to.emit(safeProtocolMediator, "ActionExecutionFailed") + .withArgs(await safe.getAddress(), safeTx.metaHash, 0); + }); + + it("Should not process a SafeTransaction when executing non-root access from root access module", async function () { + const { safeProtocolMediator, safe } = await loadFixture(deployContractsFixture); + + // Enable module + const module = await (await hre.ethers.getContractFactory("TestModule")).deploy(); + const data = safeProtocolMediator.interface.encodeFunctionData("enableModule", [await module.getAddress(), false]); + await safe.exec(await safeProtocolMediator.getAddress(), 0, data); + + await module.setRequiresRootAccess(true); + + const amount = hre.ethers.parseEther("1"); + await ( + await deployer.sendTransaction({ + to: await safe.getAddress(), + value: amount, + }) + ).wait(); + // TODO: Replace with builder function + const safeTx = { + actions: [ + { + to: user2.address, + value: hre.ethers.parseEther("1"), + data: "0x", + }, + ], + nonce: 1, + metaHash: hre.ethers.randomBytes(32), + }; - await expect(tx).to.emit(safeProtocolMediator, "ActionExecutionFailed").withArgs(await safe.getAddress(), safeTx.metaHash, 0); - }); - + await expect(module.executeFromModule(safeProtocolMediator, safe, safeTx)).to.be.revertedWithCustomError( + safeProtocolMediator, + "ModuleRequiresRootAccess", + ); }); - + }); }); diff --git a/test/SafeProtocolRegistry.spec.ts b/test/SafeProtocolRegistry.spec.ts index daf061de..b0d9c15f 100644 --- a/test/SafeProtocolRegistry.spec.ts +++ b/test/SafeProtocolRegistry.spec.ts @@ -8,7 +8,7 @@ describe("SafeProtocolRegistry", async () => { let deployer: SignerWithAddress, owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress; async function deployContractFixture() { - [deployer, owner, user1, user2]= await ethers.getSigners(); + [deployer, owner, user1, user2] = await ethers.getSigners(); const safeProtocolRegistry = await ethers.deployContract("SafeProtocolRegistry", [owner.address]); return { safeProtocolRegistry }; } @@ -34,15 +34,12 @@ describe("SafeProtocolRegistry", async () => { const { safeProtocolRegistry } = await loadFixture(deployContractFixture); await safeProtocolRegistry.connect(owner).addComponent(AddressZero); - await expect(safeProtocolRegistry.connect(user1).flagComponent(AddressZero)).to.be.revertedWith( - "Ownable: caller is not the owner" - ); + await expect(safeProtocolRegistry.connect(user1).flagComponent(AddressZero)).to.be.revertedWith("Ownable: caller is not the owner"); expect(await safeProtocolRegistry.connect(owner).flagComponent(AddressZero)); const [listedAt, flaggedAt] = await safeProtocolRegistry.check(AddressZero); expect(flaggedAt).to.be.gt(0); - }); it("Should return (0,0) for non-listed component", async () => {