Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FPS] multisig task tests #485

Open
wants to merge 78 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
bea1a0a
remove: name and description from task config
ElliotFriedman Jan 22, 2025
ade894d
checkpoint
ElliotFriedman Jan 22, 2025
44dd5fd
remove isNested flag from toml config file
ElliotFriedman Jan 22, 2025
40b6f9e
fmt
ElliotFriedman Jan 23, 2025
43acb05
fix is nested safe logic
prateek105 Jan 23, 2025
c3e4c4b
fix task01
prateek105 Jan 23, 2025
237a015
add Task02
prateek105 Jan 23, 2025
8e94d13
refactor _getDataToSign function
ElliotFriedman Jan 23, 2025
f8aed6d
add: gas template docs
ElliotFriedman Jan 23, 2025
5fe7914
Merge branch 'feat/templates-pt2' of github.com:solidity-labs-io/supe…
ElliotFriedman Jan 23, 2025
15b2f60
add: template examples to run
ElliotFriedman Jan 23, 2025
bd58ec5
add: error handle parsing l2 chain configs
ElliotFriedman Jan 23, 2025
e76e57a
fmt
ElliotFriedman Jan 23, 2025
6a5bda5
remove unused variable name
ElliotFriedman Jan 23, 2025
f15022d
error handle reading in and parsing task config file
ElliotFriedman Jan 23, 2025
a06ef46
Merge branch 'main' into feat/templates-pt2
ElliotFriedman Jan 23, 2025
4391957
add breakdown of calldata difference for signers
ElliotFriedman Jan 23, 2025
cd28019
remove setting scalars to simplify example task
ElliotFriedman Jan 23, 2025
01ff9d7
add duplicate call structure of task 020 in existing tooling
ElliotFriedman Jan 23, 2025
d5fe386
remove setting gas scalars from gas config template
ElliotFriedman Jan 23, 2025
86921e4
Merge branch 'feat/templates-pt2' of github.com:solidity-labs-io/supe…
ElliotFriedman Jan 23, 2025
b81fb94
note on commenting out failing check and link to diffchecker
ElliotFriedman Jan 23, 2025
50717d1
add: task config tests
ElliotFriedman Jan 23, 2025
4a35d70
add forge build before running template
ElliotFriedman Jan 23, 2025
68b518b
update docs to only include gas limits and not gas scalars
ElliotFriedman Jan 23, 2025
1088348
remove template ci runs
ElliotFriedman Jan 23, 2025
27d04c9
Update src/fps/FPS.md
ElliotFriedman Jan 23, 2025
c6c2b50
Update src/fps/FPS.md
ElliotFriedman Jan 23, 2025
d5acbb9
Update src/fps/FPS.md
ElliotFriedman Jan 23, 2025
dd997ca
fps -> new task simulation tooling
ElliotFriedman Jan 23, 2025
9d9b268
Merge branch 'feat/templates-pt2' of github.com:solidity-labs-io/supe…
ElliotFriedman Jan 23, 2025
0fa2661
remove unused template files
ElliotFriedman Jan 23, 2025
80cb410
naming: fps.md -> readme.md
ElliotFriedman Jan 23, 2025
403c040
naming: move away from fps
ElliotFriedman Jan 23, 2025
1c9633c
use op types, remove inlined interfaces
ElliotFriedman Jan 23, 2025
6150e4d
update readme for running tasks
ElliotFriedman Jan 23, 2025
b8bef6e
update: cleanup, make MultisigTask a generic template
ElliotFriedman Jan 23, 2025
803b84a
fix test
ElliotFriedman Jan 24, 2025
8b8c1de
delete: task config
ElliotFriedman Jan 24, 2025
155eae4
update based on PR feedback, remove taskConfig.toml fields, and safeN…
ElliotFriedman Jan 24, 2025
b49165d
remove unused mock network configs
ElliotFriedman Jan 24, 2025
e235404
remove opmainnetConfig.toml
ElliotFriedman Jan 24, 2025
3f8b5fc
add op set gas limit config
ElliotFriedman Jan 24, 2025
0cf2842
update command to use new run function
ElliotFriedman Jan 24, 2025
6027c6b
update command to only have mainnet config toml file
ElliotFriedman Jan 24, 2025
e6c80c2
naming: networkConfigFilePath -> taskConfigFilePath
ElliotFriedman Jan 24, 2025
9d77704
fmt
ElliotFriedman Jan 24, 2025
cf51481
natspec, taskStorageWrites -> _taskStorageWrites
ElliotFriedman Jan 24, 2025
51e74b9
fix test
ElliotFriedman Jan 24, 2025
92c88f4
add additional docs for address registry
ElliotFriedman Jan 24, 2025
e901161
fix: nested multisig issue
ElliotFriedman Jan 24, 2025
0ecdca5
add op gas config command
ElliotFriedman Jan 24, 2025
70ed74f
add task tests
prateek105 Jan 24, 2025
152b2d3
Revert "add task tests"
prateek105 Jan 24, 2025
4ffc20f
add tests
prateek105 Jan 24, 2025
68fe293
fix: nonce for nested safes use their own nonce and not parent
ElliotFriedman Jan 24, 2025
6f58ac7
Merge branch 'feat/templates-pt2' of github.com:solidity-labs-io/supe…
ElliotFriedman Jan 24, 2025
4645579
Merge branch 'main' into feat/templates-pt2
ElliotFriedman Jan 24, 2025
9cc89d6
update natspec proposal -> task
ElliotFriedman Jan 24, 2025
512f631
Merge branch 'main' into feat/templates-pt2
ElliotFriedman Jan 26, 2025
32d5528
fix failing single multisig tests
prateek105 Jan 27, 2025
abf0bda
cleanup debug logs
prateek105 Jan 27, 2025
2230855
fix address registry failing test
prateek105 Jan 27, 2025
089a57d
Merge branch 'feat/templates-pt2' into feat/task-test
prateek105 Jan 27, 2025
daa5186
add test for nested hash to approve
prateek105 Jan 27, 2025
7194585
rename public function
prateek105 Jan 27, 2025
cb196c2
remove build warnings
prateek105 Jan 27, 2025
5cf515f
pr feedback
prateek105 Jan 27, 2025
4e5a5c1
Merge branch 'upstream-main' into feat/task-test
prateek105 Jan 27, 2025
cf29738
Update src/fps/task/MultisigTask.sol
prateek105 Jan 28, 2025
76fda92
pr feedback
prateek105 Jan 29, 2025
c4bbe47
fix: virtual keyword to allow template variants
blmalone Jan 29, 2025
0d10d73
Merge pull request #25 from solidity-labs-io/bm/refactor-virtual-keyw…
blmalone Jan 29, 2025
bcdc5fa
Merge branch 'main' into feat/task-test
ElliotFriedman Jan 29, 2025
de66ddf
address pr feedback: multicall import
ElliotFriedman Jan 29, 2025
05be9d5
delete testnetConfig.toml
ElliotFriedman Jan 29, 2025
d4ecfb6
add: natspec comment on taskConfigFilePath var
ElliotFriedman Jan 29, 2025
656de62
address feedback: add comments
ElliotFriedman Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions src/fps/task/MultisigTask.sol
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,9 @@ abstract contract MultisigTask is Test, Script, ITask {
multisig == addresses.getAddress(config.safeAddressString, chains[i].chainId),
string.concat(
"MultisigTask: safe address mismatch. Caller: ",
vm.getLabel(multisig),
getAddressLabel(multisig),
". Actual address: ",
vm.getLabel(addresses.getAddress(config.safeAddressString, chains[i].chainId))
getAddressLabel(addresses.getAddress(config.safeAddressString, chains[i].chainId))
)
);
}
Expand Down Expand Up @@ -250,7 +250,7 @@ abstract contract MultisigTask is Test, Script, ITask {

/// @notice print the data to sig by EOA for single multisig
function printDataToSign() public view {
console.logBytes(_getDataToSign(multisig, getCalldata()));
console.logBytes(getDataToSign(multisig, getCalldata()));
}

/// @notice print the hash to approve by EOA for single multisig
Expand All @@ -261,7 +261,7 @@ abstract contract MultisigTask is Test, Script, ITask {
/// @notice get the data to sign by EOA for single multisig
/// @param data The calldata to be executed
/// @return The data to sign
function _getDataToSign(address safe, bytes memory data) internal view returns (bytes memory) {
function getDataToSign(address safe, bytes memory data) public view returns (bytes memory) {
uint256 useNonce;

if (safe == multisig) {
Expand Down Expand Up @@ -339,7 +339,7 @@ abstract contract MultisigTask is Test, Script, ITask {
_allowedStorageAccesses.contains(addr),
string(
abi.encodePacked(
"MultisigTask: address ", _getAddressLabel(addr), " not in allowed storage accesses"
"MultisigTask: address ", getAddressLabel(addr), " not in allowed storage accesses"
)
)
);
Expand All @@ -352,7 +352,7 @@ abstract contract MultisigTask is Test, Script, ITask {
_taskStateChangeAddresses.contains(addr),
string(
abi.encodePacked(
"MultisigTask: address ", _getAddressLabel(addr), " not in task state change addresses"
"MultisigTask: address ", getAddressLabel(addr), " not in task state change addresses"
)
)
);
Expand Down Expand Up @@ -429,7 +429,7 @@ abstract contract MultisigTask is Test, Script, ITask {
console.log("\n------------------ Proposal Actions ------------------");
for (uint256 i; i < actions.length; i++) {
console.log("%d). %s", i + 1, actions[i].description);
console.log("target: %s\npayload", _getAddressLabel(actions[i].target));
console.log("target: %s\npayload", getAddressLabel(actions[i].target));
console.logBytes(actions[i].arguments);
console.log("\n");
}
Expand All @@ -441,7 +441,7 @@ abstract contract MultisigTask is Test, Script, ITask {
for (uint256 i; i < _taskTransferFromAddresses.length(); i++) {
address account = _taskTransferFromAddresses.at(i);

console.log("\n\n", string(abi.encodePacked(_getAddressLabel(account), ":")));
console.log("\n\n", string(abi.encodePacked(getAddressLabel(account), ":")));
prateek105 marked this conversation as resolved.
Show resolved Hide resolved

// print token transfers
TransferInfo[] memory transfers = _taskTransfers[account];
Expand All @@ -453,7 +453,7 @@ abstract contract MultisigTask is Test, Script, ITask {
console.log(
string(
abi.encodePacked(
"Sent ", vm.toString(transfers[j].value), " ETH to ", _getAddressLabel(transfers[j].to)
"Sent ", vm.toString(transfers[j].value), " ETH to ", getAddressLabel(transfers[j].to)
)
)
);
Expand All @@ -464,9 +464,9 @@ abstract contract MultisigTask is Test, Script, ITask {
"Sent ",
vm.toString(transfers[j].value),
" ",
_getAddressLabel(transfers[j].tokenAddress),
getAddressLabel(transfers[j].tokenAddress),
" to ",
_getAddressLabel(transfers[j].to)
getAddressLabel(transfers[j].to)
)
)
);
Expand All @@ -480,7 +480,7 @@ abstract contract MultisigTask is Test, Script, ITask {
address account = _taskStateChangeAddresses.at(k);
StateInfo[] memory stateChanges = _stateInfos[account];
if (stateChanges.length > 0) {
console.log("\n State Changes for account:", _getAddressLabel(account));
console.log("\n State Changes for account:", getAddressLabel(account));
}
for (uint256 j; j < stateChanges.length; j++) {
console.log("Slot:", vm.toString(stateChanges[j].slot));
Expand Down Expand Up @@ -508,21 +508,21 @@ abstract contract MultisigTask is Test, Script, ITask {

/// @notice print the data to sign by EOA for nested multisig
function printNestedDataToSign() public view {
bytes memory callData = _generateApproveMulticallData();
bytes memory callData = generateApproveMulticallData();

for (uint256 i; i < startingOwners.length; i++) {
bytes memory dataToSign = _getDataToSign(startingOwners[i], callData);
console.log("Nested multisig: %s", _getAddressLabel(startingOwners[i]));
bytes memory dataToSign = getDataToSign(startingOwners[i], callData);
console.log("Nested multisig: %s", getAddressLabel(startingOwners[i]));
console.logBytes(dataToSign);
}
}

/// @notice print the hash to approve by EOA for nested multisig
function printNestedHashToApprove() public view {
bytes memory callData = _generateApproveMulticallData();
bytes memory callData = generateApproveMulticallData();
for (uint256 i; i < startingOwners.length; i++) {
bytes32 hash = keccak256(_getDataToSign(startingOwners[i], callData));
console.log("Nested multisig: %s", _getAddressLabel(startingOwners[i]));
bytes32 hash = keccak256(getDataToSign(startingOwners[i], callData));
console.log("Nested multisig: %s", getAddressLabel(startingOwners[i]));
console.logBytes32(hash);
}
}
Expand All @@ -535,9 +535,9 @@ abstract contract MultisigTask is Test, Script, ITask {

/// @notice get the hash for this safe transaction
/// can only be called after the build function, otherwise it reverts
function getHash() internal view returns (bytes32) {
function getHash() public view returns (bytes32) {
bytes memory data = getCalldata();
return keccak256(_getDataToSign(multisig, data));
return keccak256(getDataToSign(multisig, data));
}

/// @notice validate actions inclusion
Expand All @@ -561,7 +561,7 @@ abstract contract MultisigTask is Test, Script, ITask {
}

/// @notice helper function to generate the approveHash calldata to be executed by child multisig owner on parent multisig
function _generateApproveMulticallData() internal view returns (bytes memory) {
function generateApproveMulticallData() public view returns (bytes memory) {
bytes32 hash = getHash();
Call3Value memory call = Call3Value({
target: multisig,
Expand Down Expand Up @@ -647,7 +647,7 @@ abstract contract MultisigTask is Test, Script, ITask {
description: string(
abi.encodePacked(
"calling ",
_getAddressLabel(accountAccesses[i].account),
getAddressLabel(accountAccesses[i].account),
" with ",
vm.toString(accountAccesses[i].value),
" eth and ",
Expand Down Expand Up @@ -753,7 +753,7 @@ abstract contract MultisigTask is Test, Script, ITask {
}

/// @notice helper method to get labels for addresses
function _getAddressLabel(address contractAddress) internal view returns (string memory) {
function getAddressLabel(address contractAddress) public view returns (string memory) {
string memory label = vm.getLabel(contractAddress);

bytes memory prefix = bytes("unlabeled:");
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ contract MainnetAddressRegistryTest is Test {
/// Construction failure tests

function testInvalidChainIdInSuperchainsFails() public {
string memory networkConfigFilePath = "test/mock/invalidChainIdNetworkConfig.toml";
string memory networkConfigFilePath = "test/registry/mock/invalidChainIdNetworkConfig.toml";

vm.expectRevert("Invalid chain ID in config");
new AddressRegistry(networkConfigFilePath);
Expand Down
103 changes: 103 additions & 0 deletions test/task/NestedMultisigTask.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {Test} from "forge-std/Test.sol";

import {AddressRegistry as Addresses} from "src/fps/AddressRegistry.sol";
import {MultisigTask} from "src/fps/task/MultisigTask.sol";
import {DisputeGameUpgradeTemplate} from "src/fps/example/template/DisputeGameUpgradeTemplate.sol";
import {IGnosisSafe, Enum} from "@base-contracts/script/universal/IGnosisSafe.sol";
import {MULTICALL3_ADDRESS} from "src/fps/utils/Constants.sol";

contract NestedMultisigTaskTest is Test {
struct Call3Value {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as comment below can we take this from import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol";?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

address target;
bool allowFailure;
uint256 value;
bytes callData;
}

MultisigTask private multisigTask;
Addresses private addresses;
string taskConfigFilePath = "src/fps/example/task-01/mainnetConfig.toml";

function setUp() public {
vm.createSelectFork("mainnet");
multisigTask = new DisputeGameUpgradeTemplate();
blmalone marked this conversation as resolved.
Show resolved Hide resolved
multisigTask.run(taskConfigFilePath);
addresses = multisigTask.addresses();
}

function testSafeNested() public view {
assertEq(multisigTask.isNestedSafe(), true, "Expected isNestedSafe to be false");
}

function testNestedDataToSignAndHashToApprove() public view {
blmalone marked this conversation as resolved.
Show resolved Hide resolved
IGnosisSafe parentMultisig = IGnosisSafe(multisigTask.multisig());
address[] memory childOwnerMultisigs = parentMultisig.getOwners();

bytes32 hashToApproveByChildMultisig = parentMultisig.getTransactionHash(
MULTICALL3_ADDRESS,
0,
multisigTask.getCalldata(),
Enum.Operation.DelegateCall,
0,
0,
0,
address(0),
address(0),
parentMultisig.nonce() - 1
blmalone marked this conversation as resolved.
Show resolved Hide resolved
);

Call3Value memory call = Call3Value({
target: address(parentMultisig),
allowFailure: false,
value: 0,
callData: abi.encodeCall(parentMultisig.approveHash, (hashToApproveByChildMultisig))
});

Call3Value[] memory calls = new Call3Value[](1);
calls[0] = call;

bytes memory callDataToApprove =
abi.encodeWithSignature("aggregate3Value((address,bool,uint256,bytes)[])", calls);
assertEq(callDataToApprove, multisigTask.generateApproveMulticallData(), "Wrong callDataToApprove");

for (uint256 i; i < childOwnerMultisigs.length; i++) {
bytes memory dataToSign = getNestedDataToSign(childOwnerMultisigs[i]);
bytes memory expectedDataToSign = IGnosisSafe(childOwnerMultisigs[i]).encodeTransactionData({
to: MULTICALL3_ADDRESS,
value: 0,
data: callDataToApprove,
operation: Enum.Operation.DelegateCall,
safeTxGas: 0,
baseGas: 0,
gasPrice: 0,
gasToken: address(0),
refundReceiver: address(0),
_nonce: IGnosisSafe(childOwnerMultisigs[i]).nonce()
});
assertEq(dataToSign, expectedDataToSign, "Wrong data to sign");

bytes32 nestedHashToApprove = keccak256(getNestedDataToSign(childOwnerMultisigs[i]));
blmalone marked this conversation as resolved.
Show resolved Hide resolved
bytes32 expectedNestedHashToApprove = IGnosisSafe(childOwnerMultisigs[i]).getTransactionHash(
MULTICALL3_ADDRESS,
0,
callDataToApprove,
Enum.Operation.DelegateCall,
0,
0,
0,
address(0),
address(0),
IGnosisSafe(childOwnerMultisigs[i]).nonce()
);
assertEq(nestedHashToApprove, expectedNestedHashToApprove, "Wrong nested hash to approve");
}
}

function getNestedDataToSign(address owner) public view returns (bytes memory) {
bytes memory callData = multisigTask.generateApproveMulticallData();
return multisigTask.getDataToSign(owner, callData);
}
}
Loading