Skip to content

Commit

Permalink
add test stubs
Browse files Browse the repository at this point in the history
  • Loading branch information
auryn-macmillan committed Jul 22, 2024
1 parent ac89dfe commit dc64a12
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 29 deletions.
4 changes: 2 additions & 2 deletions contracts/OSXAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract OSXAdapter is Modifier {
event TransactionUnwrapperSet(address multisendAddress, ITransactionUnwrapper transactionUnwrapper);

error DelegateCallNotAllowed();
error MultisendAddressNotAllowed();
error UnwrapperNotAllowed();
error TransactionUnwrapperAlreadySet();

constructor(address _owner, address _avatar, address _target) {
Expand Down Expand Up @@ -102,7 +102,7 @@ contract OSXAdapter is Modifier {
) private view returns (Action[] memory) {
if (operation == Enum.Operation.DelegateCall) {
ITransactionUnwrapper transactionUnwrapper = transactionUnwrappers[to];
require(transactionUnwrapper != ITransactionUnwrapper(address(0)), MultisendAddressNotAllowed());
require(transactionUnwrapper != ITransactionUnwrapper(address(0)), UnwrapperNotAllowed());

UnwrappedTransaction[] memory unwrappedTransactions = transactionUnwrapper.unwrap(
to,
Expand Down
2 changes: 1 addition & 1 deletion contracts/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity >=0.8.26 <0.9.0;

import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol";

interface IMultiSend {
interface IMultisend {
function multiSend(bytes memory transactions) external payable;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.26 <0.9.0;

import "./Types.sol";
import "../Types.sol";

contract MultiSendUnwrapper is ITransactionUnwrapper {
contract MultisendUnwrapper is ITransactionUnwrapper {
uint256 private constant OFFSET_START = 68;

error UnsupportedMode();
Expand All @@ -29,7 +29,7 @@ contract MultiSendUnwrapper is ITransactionUnwrapper {

function _validateHeader(bytes calldata data) private pure {
// first 4 bytes are the selector for multiSend(bytes)
if (bytes4(data) != IMultiSend.multiSend.selector) {
if (bytes4(data) != IMultisend.multiSend.selector) {
revert MalformedHeader();
}

Expand Down
4 changes: 4 additions & 0 deletions deploy/02_test_dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const deploy: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
from: deployerAddress,
})

const multisendUnwrapperDeployment = await deploy("MultisendUnwrapper", {
from: deployerAddress,
})

// Make the MockOSXDAO the owner of the button
const buttonContract = await ethers.getContractAt("Button", buttonDeployment.address, deployer)
const currentOwner = await buttonContract.owner()
Expand Down
25 changes: 25 additions & 0 deletions test/MultisendUnwrapper.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect } from "chai"
import { ethers, deployments, getNamedAccounts } from "hardhat"

const setup = async () => {
await deployments.fixture(["moduleProxy"])
const { deployer, tester } = await getNamedAccounts()
const multisendUnwrapperDeployment = await deployments.get("MultisendUnwrapper")
const multisendUnwrapper = await ethers.getContractAt("MultisendUnwrapper", multisendUnwrapperDeployment.address)
return { multisendUnwrapper, multisendUnwrapperDeployment, deployer, tester }
}

describe.only("MultisendUnwrapper", function () {
describe("constructor", function () {
it("Deploys successfully", async function () {
const { multisendUnwrapperDeployment } = await setup()
expect(multisendUnwrapperDeployment.address).to.not.be.equal(ethers.ZeroAddress)
})
})

describe("unwrap()", function () {
it("Should revert revert with `UnsupportedMode` if value is non-zero")
it("Shoudl revert with UnsupportedMode if operation is not `DelegateCall`")
it("Should correctly unwrap the multisend call")
})
})
97 changes: 74 additions & 23 deletions test/OSXAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,86 @@ const setup = async () => {
}

describe("OSXAdapter", function () {
it("Should be possible to 'press the button' through OSXAdapter", async function () {
const { buttonContract, OSXAdapterProxyContract, deployer } = await setup()
expect(await buttonContract.pushes()).to.equal(0)
describe("constructor / setup", function () {
it("Should set owner, avatar, and target correctly")
})

expect(await OSXAdapterProxyContract.enableModule(deployer))
describe("exec()", function () {
it("Should revert if called by an account that is not enabled as a module")
it("Should revert if included calls fail")
it("Should return true if all included calls execute successfully")
it("Should trigger OSx to make external calls", async function () {
const { buttonContract, OSXAdapterProxyContract, deployer } = await setup()
expect(await buttonContract.pushes()).to.equal(0)

const enabledModules = await OSXAdapterProxyContract.getModulesPaginated(
"0x0000000000000000000000000000000000000001",
10,
)
expect(await OSXAdapterProxyContract.enableModule(deployer))

const enabledModules = await OSXAdapterProxyContract.getModulesPaginated(
"0x0000000000000000000000000000000000000001",
10,
)

const data = buttonContract.interface.encodeFunctionData("pushButton")

const txData = {
to: await buttonContract.getAddress(),
value: 0,
data: data,
operation: 0,
}

const tx = OSXAdapterProxyContract.interface.encodeFunctionData("execTransactionFromModule", [
txData.to,
txData.value,
txData.data,
txData.operation,
])

const result = await (
await OSXAdapterProxyContract.execTransactionFromModule(txData.to, txData.value, txData.data, txData.operation)
).wait()

expect(await buttonContract.pushes()).to.equal(1)
})
it("Should emit `ExecutionFromModuleSuccess` with correct args")
})

describe("execAndReturnData()", function () {
it("Should revert if called by an account that is not enabled as a module")
it("Should revert if any included calls fail")
it("Should return true if all included calls execute successfully")
it("Should return any data returned by the executed calls")
it("Should emit `ExecutionFromModuleSuccess` with correct args")
})

const data = buttonContract.interface.encodeFunctionData("pushButton")
describe("execTransactionFromModule()", function () {
it("Should call exec()")
it("Should return true if exec() call is successful")
})

const txData = {
to: await buttonContract.getAddress(),
value: 0,
data: data,
operation: 0,
}
describe("execTransactionFromModuleReturnData()", function () {
it("Should call execAndReturnData()")
it("Should return true if execAndReturnData() call is successful")
it("Should return returnData from successful execAndReturnData() call")
})

const tx = OSXAdapterProxyContract.interface.encodeFunctionData("execTransactionFromModule", [
txData.to,
txData.value,
txData.data,
txData.operation,
])
describe("setTransactionUnwrapper()", function () {
it("Should revert if called by account other than `owner`")
it("Should revert with TransactionUnwrapperAlreadySet() if duplicate address is given")
it("Should correctly set the give transaction unwrapper address")
it("Should emit `TransactionUnwaperSet` with correct args")
})

await OSXAdapterProxyContract.execTransactionFromModule(txData.to, txData.value, txData.data, txData.operation)
describe("Convert()", function () {
it("Should revert with `DelegateCallNotAllowed` if operation is delegate call")
it("Should encode call params in into Action struct")
})

expect(await buttonContract.pushes()).to.equal(1)
describe("ConvertTransaction()", function () {
it(
"Should revert with `UnwrapperNotAllowed` if operation is delegate call and target is not enabled as a transaction unwrapper",
)
it("Should convert a single encoded call")
it("Should convert multiple encoded calls")
})
})

0 comments on commit dc64a12

Please sign in to comment.