Skip to content

Commit

Permalink
GuardableModifier tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cristovaoth committed Oct 7, 2023
1 parent a82c0b6 commit dd1fd41
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 0 deletions.
87 changes: 87 additions & 0 deletions contracts/test/TestGuardableModifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;

import "../core/GuardableModifier.sol";

contract TestGuardableModifier is GuardableModifier {
event executed(
address to,
uint256 value,
bytes data,
Enum.Operation operation,
bool success
);

event executedAndReturnedData(
address to,
uint256 value,
bytes data,
Enum.Operation operation,
bytes returnData,
bool success
);

constructor(address _avatar, address _target) {
bytes memory initParams = abi.encode(_avatar, _target);
setUp(initParams);
}

/// @dev Passes a transaction to the modifier.
/// @param to Destination address of module transaction
/// @param value Ether value of module transaction
/// @param data Data payload of module transaction
/// @param operation Operation type of module transaction
/// @notice Can only be called by enabled modules
function execTransactionFromModule(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
) public override moduleOnly returns (bool success) {
success = exec(to, value, data, operation);
emit executed(to, value, data, operation, success);
}

/// @dev Passes a transaction to the modifier, expects return data.
/// @param to Destination address of module transaction
/// @param value Ether value of module transaction
/// @param data Data payload of module transaction
/// @param operation Operation type of module transaction
/// @notice Can only be called by enabled modules
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
)
public
override
moduleOnly
returns (bool success, bytes memory returnData)
{
(success, returnData) = execAndReturnData(to, value, data, operation);
emit executedAndReturnedData(
to,
value,
data,
operation,
returnData,
success
);
}

function setUp(bytes memory initializeParams) public override initializer {
setupModules();
__Ownable_init();
(address _avatar, address _target) = abi.decode(
initializeParams,
(address, address)
);
avatar = _avatar;
target = _target;
}

function attemptToSetupModules() public {
setupModules();
}
}
180 changes: 180 additions & 0 deletions test/07_GuardableModifier.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import hre from "hardhat";
import { expect } from "chai";
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";

import {
TestAvatar__factory,
TestGuard__factory,
TestGuardableModifier__factory,
} from "../typechain-types";

describe("GuardableModifier", async () => {
async function setupTests() {
const [signer, someone, executor] = await hre.ethers.getSigners();

const Avatar = await hre.ethers.getContractFactory("TestAvatar");
const avatar = TestAvatar__factory.connect(
(await Avatar.deploy()).address,
signer
);

const Modifier = await hre.ethers.getContractFactory(
"TestGuardableModifier"
);
const modifier = TestGuardableModifier__factory.connect(
(await Modifier.connect(signer).deploy(avatar.address, avatar.address))
.address,
signer
);
const Guard = await hre.ethers.getContractFactory("TestGuard");
const guard = TestGuard__factory.connect(
(await Guard.deploy(modifier.address)).address,
hre.ethers.provider
);

await avatar.enableModule(modifier.address);
await modifier.enableModule(executor.address);

return {
avatar,
someone,
executor,
guard,
modifier,
};
}

describe("exec", async () => {
it("skips guard pre-check if no guard is set", async () => {
const { avatar, modifier, executor } = await loadFixture(setupTests);

await expect(
modifier
.connect(executor)
.execTransactionFromModule(avatar.address, 0, "0x", 0)
).to.not.be.reverted;
});

it("pre-checks transaction if guard is set", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);
await modifier.setGuard(guard.address);

await expect(
modifier
.connect(executor)
.execTransactionFromModule(avatar.address, 0, "0x", 0)
)
.to.emit(guard, "PreChecked")
.withArgs(true);
});

it("pre-checks and reverts transaction if guard is set", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);
await modifier.setGuard(guard.address);

await expect(
modifier
.connect(executor)
.execTransactionFromModule(avatar.address, 1337, "0x", 0)
).to.be.revertedWith("Cannot send 1337");
});

it("skips post-check if no guard is enabled", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);

await expect(
modifier
.connect(executor)
.execTransactionFromModule(avatar.address, 0, "0x", 0)
).not.to.emit(guard, "PostChecked");
});

it("post-checks transaction if guard is set", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);
await modifier.setGuard(guard.address);

await expect(
modifier
.connect(executor)
.execTransactionFromModule(avatar.address, 0, "0x", 0)
)
.to.emit(guard, "PostChecked")
.withArgs(true);
});
});

describe("execAndReturnData", async () => {
it("skips guard pre-check if no guard is set", async () => {
const { avatar, modifier, executor } = await loadFixture(setupTests);

await expect(
modifier
.connect(executor)
.execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0)
).to.not.be.reverted;
});

it("pre-checks transaction if guard is set", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);
await modifier.setGuard(guard.address);

await expect(
modifier
.connect(executor)
.execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0)
)
.to.emit(guard, "PreChecked")
.withArgs(true);
});

it("pre-checks and reverts transaction if guard is set", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);
await modifier.setGuard(guard.address);

await expect(
modifier
.connect(executor)
.execTransactionFromModuleReturnData(avatar.address, 1337, "0x", 0)
).to.be.revertedWith("Cannot send 1337");
});

it("skips post-check if no guard is enabled", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);

await expect(
modifier
.connect(executor)
.execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0)
).not.to.emit(guard, "PostChecked");
});

it("post-checks transaction if guard is set", async () => {
const { avatar, executor, modifier, guard } = await loadFixture(
setupTests
);
await modifier.setGuard(guard.address);

await expect(
modifier
.connect(executor)
.execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0)
)
.to.emit(guard, "PostChecked")
.withArgs(true);
});
});
});

0 comments on commit dd1fd41

Please sign in to comment.