Skip to content

Commit

Permalink
Multisigs WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed Nov 8, 2024
1 parent 8bca1d1 commit 52c8e20
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/Multisig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ contract Multisig is IMultisig, PluginUUPSUpgradeable, ProposalUpgradeable {
event MultisigSettingsUpdated(
bool onlyListed,
uint16 indexed minApprovals,
SignerList signerList,
uint64 destinationProposalDuration,
SignerList signerList,
uint64 proposalExpirationPeriod
);

Expand Down
124 changes: 121 additions & 3 deletions test/EmergencyMultisigTree.t.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;

import {Test} from "forge-std/Test.sol";
import {AragonTest} from "./base/AragonTest.sol";
import {Addresslist} from "@aragon/osx/plugins/utils/Addresslist.sol";
import {EmergencyMultisig} from "../src/EmergencyMultisig.sol";
import {SignerList} from "../src/SignerList.sol";
import {DaoBuilder} from "./helpers/DaoBuilder.sol";
import {DAO} from "@aragon/osx/core/dao/DAO.sol";
import {createProxyAndCall} from "../src/helpers/proxy.sol";

uint64 constant EMERGENCY_MULTISIG_PROPOSAL_EXPIRATION_PERIOD = 10 days;

contract EmergencyMultisigTest is AragonTest {
SignerList signerList;
DaoBuilder builder;
DAO dao;
EmergencyMultisig eMultisig;

address immutable SIGNER_LIST_BASE = address(new SignerList());

// Events/errors to be tested here (duplicate)
error DaoUnauthorized(address dao, address where, address who, bytes32 permissionId);
error InvalidAddresslistUpdate(address member);

event MultisigSettingsUpdated(
bool onlyListed, uint16 indexed minApprovals, SignerList signerList, uint64 proposalExpirationPeriod
);

function setUp() public {
vm.startPrank(alice);
vm.warp(1 days);
vm.roll(100);

builder = new DaoBuilder();
(dao,,, eMultisig,, signerList,,) = builder.withMultisigMember(alice).withMultisigMember(bob).withMultisigMember(
carol
).withMultisigMember(david).build();
}

contract EmergencyMultisigTest is Test {
modifier givenANewlyDeployedContract() {
_;
}
Expand All @@ -13,15 +47,99 @@ contract EmergencyMultisigTest is Test {
}

function test_GivenCallingInitialize() external givenANewlyDeployedContract givenCallingInitialize {
EmergencyMultisig.MultisigSettings memory settings = EmergencyMultisig.MultisigSettings({
onlyListed: true,
minApprovals: 3,
signerList: signerList,
proposalExpirationPeriod: EMERGENCY_MULTISIG_PROPOSAL_EXPIRATION_PERIOD
});

// It should initialize the first time
eMultisig = EmergencyMultisig(
createProxyAndCall(
address(EMERGENCY_MULTISIG_BASE), abi.encodeCall(EmergencyMultisig.initialize, (dao, settings))
)
);

// It should refuse to initialize again
vm.expectRevert("Initializable: contract is already initialized");
eMultisig.initialize(dao, settings);

// It should set the DAO address

assertEq((address(eMultisig.dao())), address(dao), "Incorrect dao");

// It should set the minApprovals

(, uint16 minApprovals,,) = eMultisig.multisigSettings();
assertEq(minApprovals, uint16(3), "Incorrect minApprovals");
settings.minApprovals = 1;
eMultisig = EmergencyMultisig(
createProxyAndCall(
address(EMERGENCY_MULTISIG_BASE), abi.encodeCall(EmergencyMultisig.initialize, (dao, settings))
)
);
(, minApprovals,,) = eMultisig.multisigSettings();
assertEq(minApprovals, uint16(1), "Incorrect minApprovals");

// It should set onlyListed

(bool onlyListed,,,) = eMultisig.multisigSettings();
assertEq(onlyListed, true, "Incorrect onlyListed");
settings.onlyListed = false;
eMultisig = EmergencyMultisig(
createProxyAndCall(
address(EMERGENCY_MULTISIG_BASE), abi.encodeCall(EmergencyMultisig.initialize, (dao, settings))
)
);
(onlyListed,,,) = eMultisig.multisigSettings();
assertEq(onlyListed, false, "Incorrect onlyListed");

// It should set signerList

(,, Addresslist givenSignerList,) = eMultisig.multisigSettings();
assertEq(address(givenSignerList), address(signerList), "Incorrect addresslistSource");
(,,,,, signerList,,) = builder.build();
settings.signerList = signerList;
eMultisig = EmergencyMultisig(
createProxyAndCall(
address(EMERGENCY_MULTISIG_BASE), abi.encodeCall(EmergencyMultisig.initialize, (dao, settings))
)
);
(,, signerList,) = eMultisig.multisigSettings();
assertEq(address(signerList), address(settings.signerList), "Incorrect addresslistSource");

// It should set proposalExpirationPeriod

(,,, uint64 expirationPeriod) = eMultisig.multisigSettings();
assertEq(expirationPeriod, EMERGENCY_MULTISIG_PROPOSAL_EXPIRATION_PERIOD, "Incorrect expirationPeriod");
settings.proposalExpirationPeriod = 3 days;
eMultisig = EmergencyMultisig(
createProxyAndCall(
address(EMERGENCY_MULTISIG_BASE), abi.encodeCall(EmergencyMultisig.initialize, (dao, settings))
)
);
(,,, expirationPeriod) = eMultisig.multisigSettings();
assertEq(expirationPeriod, 3 days, "Incorrect expirationPeriod");

// It should emit MultisigSettingsUpdated
vm.skip(true);

(,,,,, SignerList newSignerList,,) = builder.build();

settings = EmergencyMultisig.MultisigSettings({
onlyListed: false,
minApprovals: 2,
signerList: newSignerList,
proposalExpirationPeriod: 15 days
});
vm.expectEmit();
emit MultisigSettingsUpdated(false, uint16(2), newSignerList, 15 days);

eMultisig = EmergencyMultisig(
createProxyAndCall(
address(EMERGENCY_MULTISIG_BASE), abi.encodeCall(EmergencyMultisig.initialize, (dao, settings))
)
);
}

function test_RevertWhen_MinApprovalsIsGreaterThanSignerListLengthOnInitialize()
Expand Down
121 changes: 117 additions & 4 deletions test/MultisigTree.t.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,45 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;

import {Test} from "forge-std/Test.sol";
import {AragonTest} from "./base/AragonTest.sol";
import {Addresslist} from "@aragon/osx/plugins/utils/Addresslist.sol";
import {Multisig} from "../src/Multisig.sol";
import {SignerList} from "../src/SignerList.sol";
import {DaoBuilder} from "./helpers/DaoBuilder.sol";
import {DAO} from "@aragon/osx/core/dao/DAO.sol";
import {createProxyAndCall} from "../src/helpers/proxy.sol";

uint64 constant MULTISIG_PROPOSAL_EXPIRATION_PERIOD = 10 days;

contract MultisigTest is AragonTest {
SignerList signerList;
DaoBuilder builder;
DAO dao;
Multisig multisig;

address immutable SIGNER_LIST_BASE = address(new SignerList());

// Events/errors to be tested here (duplicate)
error DaoUnauthorized(address dao, address where, address who, bytes32 permissionId);
error InvalidAddresslistUpdate(address member);

event MultisigSettingsUpdated(
bool onlyListed,
uint16 indexed minApprovals,
uint64 destinationProposalDuration,
SignerList signerList,
uint64 proposalExpirationPeriod
);

function setUp() public {
vm.startPrank(alice);

builder = new DaoBuilder();
(dao,, multisig,,, signerList,,) = builder.withMultisigMember(alice).withMultisigMember(bob).withMultisigMember(
carol
).withMultisigMember(david).build();
}

contract MultisigTest is Test {
modifier givenANewlyDeployedContract() {
_;
}
Expand All @@ -13,16 +49,93 @@ contract MultisigTest is Test {
}

function test_GivenCallingInitialize() external givenANewlyDeployedContract givenCallingInitialize {
Multisig.MultisigSettings memory settings = Multisig.MultisigSettings({
onlyListed: true,
minApprovals: 3,
destinationProposalDuration: 4 days,
signerList: signerList,
proposalExpirationPeriod: MULTISIG_PROPOSAL_EXPIRATION_PERIOD
});

// It should initialize the first time
multisig =
Multisig(createProxyAndCall(address(MULTISIG_BASE), abi.encodeCall(Multisig.initialize, (dao, settings))));

// It should refuse to initialize again
vm.expectRevert("Initializable: contract is already initialized");
multisig.initialize(dao, settings);

// It should set the DAO address

assertEq((address(multisig.dao())), address(dao), "Incorrect dao");

// It should set the minApprovals

(, uint16 minApprovals,,,) = multisig.multisigSettings();
assertEq(minApprovals, uint16(3), "Incorrect minApprovals");
settings.minApprovals = 1;
multisig =
Multisig(createProxyAndCall(address(MULTISIG_BASE), abi.encodeCall(Multisig.initialize, (dao, settings))));
(, minApprovals,,,) = multisig.multisigSettings();
assertEq(minApprovals, uint16(1), "Incorrect minApprovals");

// It should set onlyListed
// It should set signerList

(bool onlyListed,,,,) = multisig.multisigSettings();
assertEq(onlyListed, true, "Incorrect onlyListed");
settings.onlyListed = false;
multisig =
Multisig(createProxyAndCall(address(MULTISIG_BASE), abi.encodeCall(Multisig.initialize, (dao, settings))));
(onlyListed,,,,) = multisig.multisigSettings();
assertEq(onlyListed, false, "Incorrect onlyListed");

// It should set destinationProposalDuration

(,, uint64 destinationProposalDuration,,) = multisig.multisigSettings();
assertEq(destinationProposalDuration, 4 days, "Incorrect destinationProposalDuration");
settings.destinationProposalDuration = 3 days;
multisig =
Multisig(createProxyAndCall(address(MULTISIG_BASE), abi.encodeCall(Multisig.initialize, (dao, settings))));
(,, destinationProposalDuration,,) = multisig.multisigSettings();
assertEq(destinationProposalDuration, 3 days, "Incorrect destinationProposalDuration");

// It should set signerList

(,,, Addresslist givenSignerList,) = multisig.multisigSettings();
assertEq(address(givenSignerList), address(signerList), "Incorrect addresslistSource");
(,,,,, signerList,,) = builder.build();
settings.signerList = signerList;
multisig =
Multisig(createProxyAndCall(address(MULTISIG_BASE), abi.encodeCall(Multisig.initialize, (dao, settings))));
(,,, signerList,) = multisig.multisigSettings();
assertEq(address(signerList), address(settings.signerList), "Incorrect addresslistSource");

// It should set proposalExpirationPeriod

(,,,, uint64 expirationPeriod) = multisig.multisigSettings();
assertEq(expirationPeriod, MULTISIG_PROPOSAL_EXPIRATION_PERIOD, "Incorrect expirationPeriod");
settings.proposalExpirationPeriod = 3 days;
multisig =
Multisig(createProxyAndCall(address(MULTISIG_BASE), abi.encodeCall(Multisig.initialize, (dao, settings))));
(,,,, expirationPeriod) = multisig.multisigSettings();
assertEq(expirationPeriod, 3 days, "Incorrect expirationPeriod");

// It should emit MultisigSettingsUpdated
vm.skip(true);

(,,,,, SignerList newSignerList,,) = builder.build();

settings = Multisig.MultisigSettings({
onlyListed: false,
minApprovals: 2,
destinationProposalDuration: 4 days,
signerList: newSignerList,
proposalExpirationPeriod: 15 days
});
vm.expectEmit();
emit MultisigSettingsUpdated(false, uint16(2), 4 days, newSignerList, 15 days);

multisig =
Multisig(createProxyAndCall(address(MULTISIG_BASE), abi.encodeCall(Multisig.initialize, (dao, settings))));
}

function test_RevertWhen_MinApprovalsIsGreaterThanSignerListLengthOnInitialize()
Expand Down

0 comments on commit 52c8e20

Please sign in to comment.