Skip to content

Commit

Permalink
Load the DisputeGameFactory address and OwnerSafe via a curl to the s…
Browse files Browse the repository at this point in the history
…uperchain-registry.

Dynamically load the safe owners.
Add revert reasons to pre checks.
  • Loading branch information
ajsutton committed Oct 30, 2024
1 parent 3d3c16e commit b73271f
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 30 deletions.
1 change: 0 additions & 1 deletion tasks/sep/fp-recovery/005-set-game-implementation/.env
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
ETH_RPC_URL="https://ethereum-sepolia.publicnode.com"
COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977
FOUNDATION_SAFE=0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B
OWNER_SAFE=0x1Eb2fFc903729a0F03966B917003800b145F56E2
SAFE_NONCE=""
L1_CHAIN_NAME="sepolia"
L2_CHAIN_NAME="op"
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ contract NestedSignFromJson is OriginalNestedSignFromJson {
string l2ChainName = vm.envString("L2_CHAIN_NAME");

// Safe contract for this task.
GnosisSafe securityCouncilSafe = GnosisSafe(payable(vm.envAddress("COUNCIL_SAFE")));
GnosisSafe fndSafe = GnosisSafe(payable(vm.envAddress("FOUNDATION_SAFE")));
GnosisSafe ownerSafe = GnosisSafe(payable(vm.envAddress("OWNER_SAFE")));
address livenessGuard = 0xc26977310bC89DAee5823C2e2a73195E85382cC7;

Expand Down Expand Up @@ -67,25 +65,41 @@ contract NestedSignFromJson is OriginalNestedSignFromJson {
}

function getCodeExceptions() internal view override returns (address[] memory) {
// Safe owners will appear in storage in the LivenessGuard when added, and they are allowed
// Owners of the nested safes will appear in storage in the LivenessGuard when added, and they are allowed
// to have code AND to have no code.
address[] memory securityCouncilSafeOwners = securityCouncilSafe.getOwners();
address[] memory nestedSafes = ownerSafe.getOwners();
// First count the total owners from the nested safes
uint256 totalNumberOfSigners;
for (uint256 a = 0; a < nestedSafes.length; a++) {
GnosisSafe safe = GnosisSafe(payable(nestedSafes[a]));
totalNumberOfSigners += safe.getOwners().length;
}
address[] memory safeOwners = new address[](totalNumberOfSigners);
uint256 addedSigners;
for (uint256 a = 0; a < nestedSafes.length; a++) {
GnosisSafe safe = GnosisSafe(payable(nestedSafes[a]));
address[] memory nestedSafeOwners = safe.getOwners();
for (uint256 i = 0; i < nestedSafeOwners.length; i++) {
safeOwners[addedSigners] = nestedSafeOwners[i];
addedSigners++;
}
}

// To make sure we probably handle all signers whether or not they have code, first we count
// the number of signers that have no code.
uint256 numberOfSafeSignersWithNoCode;
for (uint256 i = 0; i < securityCouncilSafeOwners.length; i++) {
if (securityCouncilSafeOwners[i].code.length == 0) {
for (uint256 i = 0; i < safeOwners.length; i++) {
if (safeOwners[i].code.length == 0) {
numberOfSafeSignersWithNoCode++;
}
}

// Then we extract those EOA addresses into a dedicated array.
uint256 trackedSignersWithNoCode;
address[] memory safeSignersWithNoCode = new address[](numberOfSafeSignersWithNoCode);
for (uint256 i = 0; i < securityCouncilSafeOwners.length; i++) {
if (securityCouncilSafeOwners[i].code.length == 0) {
safeSignersWithNoCode[trackedSignersWithNoCode] = securityCouncilSafeOwners[i];
for (uint256 i = 0; i < safeOwners.length; i++) {
if (safeOwners[i].code.length == 0) {
safeSignersWithNoCode[trackedSignersWithNoCode] = safeOwners[i];
trackedSignersWithNoCode++;
}
}
Expand All @@ -112,30 +126,32 @@ contract NestedSignFromJson is OriginalNestedSignFromJson {
if (address(currentImpl) == address(0)) {
return;
}
require(address(currentImpl.vm()) == address(faultDisputeGame.vm()));
require(address(currentImpl.weth()) == address(faultDisputeGame.weth()));
require(address(currentImpl.anchorStateRegistry()) == address(faultDisputeGame.anchorStateRegistry()));
require(currentImpl.l2ChainId() == faultDisputeGame.l2ChainId());
require(currentImpl.splitDepth() == faultDisputeGame.splitDepth());
require(currentImpl.maxGameDepth() == faultDisputeGame.maxGameDepth());
require(uint64(Duration.unwrap(currentImpl.maxClockDuration())) == uint64(Duration.unwrap(faultDisputeGame.maxClockDuration())));
require(uint64(Duration.unwrap(currentImpl.clockExtension())) == uint64(Duration.unwrap(faultDisputeGame.clockExtension())));
require(address(currentImpl.vm()) == address(faultDisputeGame.vm()), "10");
require(address(currentImpl.weth()) == address(faultDisputeGame.weth()), "20");
require(address(currentImpl.anchorStateRegistry()) == address(faultDisputeGame.anchorStateRegistry()), "30");
require(currentImpl.l2ChainId() == faultDisputeGame.l2ChainId(), "40");
require(currentImpl.splitDepth() == faultDisputeGame.splitDepth(), "50");
require(currentImpl.maxGameDepth() == faultDisputeGame.maxGameDepth(), "60");
require(uint64(Duration.unwrap(currentImpl.maxClockDuration())) == uint64(Duration.unwrap(faultDisputeGame.maxClockDuration())), "70");
require(uint64(Duration.unwrap(currentImpl.clockExtension())) == uint64(Duration.unwrap(faultDisputeGame.clockExtension())), "80");

if (targetGameType.raw() == GameTypes.PERMISSIONED_CANNON.raw()) {
PermissionedDisputeGame currentPDG = PermissionedDisputeGame(address(currentImpl));
PermissionedDisputeGame permissionedDisputeGame = PermissionedDisputeGame(address(faultDisputeGame));
require(address(currentPDG.proposer()) == address(permissionedDisputeGame.proposer()));
require(address(currentPDG.challenger()) == address(permissionedDisputeGame.challenger()));
require(address(currentPDG.proposer()) == address(permissionedDisputeGame.proposer()), "90");
require(address(currentPDG.challenger()) == address(permissionedDisputeGame.challenger()), "100");
}
}

function getAllowedStorageAccess() internal view override returns (address[] memory allowed) {
allowed = new address[](5);
address[] memory nestedSafes = ownerSafe.getOwners();
allowed = new address[](3 + nestedSafes.length);
allowed[0] = address(dgfProxy);
allowed[1] = address(ownerSafe);
allowed[2] = address(securityCouncilSafe);
allowed[3] = address(fndSafe);
allowed[4] = livenessGuard;
allowed[2] = livenessGuard;
for (uint256 i = 0; i < nestedSafes.length; i++) {
allowed[3 + i] = nestedSafes[i];
}
}

/// @notice Checks the correctness of the deployment
Expand Down Expand Up @@ -173,8 +189,6 @@ contract NestedSignFromJson is OriginalNestedSignFromJson {
}

// Read the known EOAs out of the config toml file
l2OutputOracleProposer = stdToml.readAddress(chainConfig, "$.addresses.Proposer");
l2OutputOracleChallenger = stdToml.readAddress(chainConfig, "$.addresses.Challenger");
systemConfigOwner = stdToml.readAddress(chainConfig, "$.addresses.SystemConfigOwner");
batchSenderAddress = stdToml.readAddress(chainConfig, "$.addresses.BatchSubmitter");
p2pSequencerAddress = stdToml.readAddress(chainConfig, "$.addresses.UnsafeBlockSigner");
Expand Down
6 changes: 4 additions & 2 deletions tasks/sep/fp-recovery/005-set-game-implementation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ Sets the game type implementation contract.

1. Copy this directory to the appropriate final task location.

2. Update the path in `NestedSignFromJson.s.sol` `setUp` function to the new location
2. Review the assertions in `NestedSignFromJson.s.sol` `_precheckDisputeGameImplementation` function.
The template assertions check that properties of the new implementation match the old one if it exists.
No checks are performed if there is no prior implementation, in which case it is recommended to implement custom checks.

3. Update the relative path to lib/superchain-registry in `justfile` if needed.

4. Set the `L1_CHAIN_NAME` and `L2_CHAIN_NAME` configuration to the appropriate chain in the `.env` file.
4. Set the `L1_CHAIN_NAME` and `L2_CHAIN_NAME` configuration to the appropriate chain in the `.env` file.

5. Generate the batch with `just generate-input <gameType> <newImplAddr>`.

Expand Down
9 changes: 7 additions & 2 deletions tasks/sep/fp-recovery/005-set-game-implementation/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ generate-input gameType='' implAddr='':
SET_GAME_TYPE_SIG="setImplementation(uint32,address)"
ENCODED_CALL=$(cast calldata "${SET_GAME_TYPE_SIG}" "{{gameType}}" "{{implAddr}}")
REGISTRY_DIR="../../../../lib/superchain-registry"
DGF_ADDR=$(yq .addresses.DisputeGameFactoryProxy "${REGISTRY_DIR}/superchain/configs/${L1_CHAIN_NAME}/${L2_CHAIN_NAME}.toml")
CONFIG_URL="https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/refs/heads/main/superchain/configs/${L1_CHAIN_NAME}/${L2_CHAIN_NAME}.toml"
CONFIG_TOML=$(curl -s --show-error --fail "${CONFIG_URL}")
SC_CONFIG_ADDR=$(echo "${CONFIG_TOML}" | yq -p toml .addresses.SystemConfigProxy)
PROXY_ADMIN_OWNER_ADDR=$(echo "${CONFIG_TOML}" | yq -p toml .addresses.ProxyAdminOwner)

DGF_ADDR=$(cast call "${SC_CONFIG_ADDR}" "disputeGameFactory()(address)")
echo "OWNER_SAFE=${PROXY_ADMIN_OWNER_ADDR}" >> .env

cp ./input-template.json ./input.json
jq "(.transactions[0].data = \"$ENCODED_CALL\") |
Expand Down

0 comments on commit b73271f

Please sign in to comment.