Skip to content

Latest commit

 

History

History
110 lines (80 loc) · 7.24 KB

NESTED-VALIDATION.md

File metadata and controls

110 lines (80 loc) · 7.24 KB

Validation - Nested Safe

This document describes the generic validation steps for running a Mainnet or Sepolia tasks for any nested 2/2 Safe involving either the Security Council & Foundation Upgrade Safe or the Base and Foundation Operations Safe.

State Overrides

The following state overrides related to the nested Safe execution must be seen:

GnosisSafeProxy - the 2/2 ProxyAdminOwner Safe

The ProxyAdminOwner has the following address:

The Superchain addresses are attested to in the Optimism Docs.

Enables the simulation by setting the threshold to 1:

  • Key: 0x0000000000000000000000000000000000000000000000000000000000000004
    Value: 0x0000000000000000000000000000000000000000000000000000000000000001 Meaning: The threshold is set to 1.

Safe Signer

Depending on which role the task was simulated for, you must see the following overrides for the following address:

The simulated role will also be called the Safe Signer in the remaining document.

These addresses can be verified as the owners of the 2/2 ProxyAdminOwner Safe described above.

The Safe Signer will have the following overrides which will set the Multicall contract as the sole owner of the signing Safe. This allows simulating both the approve hash and the final tx in a single Tenderly tx.

  • Key: 0x0000000000000000000000000000000000000000000000000000000000000003
    Value: 0x0000000000000000000000000000000000000000000000000000000000000001
    Meaning: The number of owners is set to 1.

  • Key: 0x0000000000000000000000000000000000000000000000000000000000000004
    Value: 0x0000000000000000000000000000000000000000000000000000000000000001
    Meaning: The threshold is set to 1.

The following two overrides are modifications to the owners mapping. For the purpose of calculating the storage, note that this mapping is in slot 2. This mapping implements a linked list for iterating through the list of owners. Since we'll only have one owner, Multicall3 (0xca11bde05977b3631167028862be2a173976ca11 on Mainnet and Sepolia), and the 0x01 address is used as the first and last entry in the linked list, we will see the following overrides:

  • owners[1] -> 0xca11bde05977b3631167028862be2a173976ca11
  • owners[0xca11bde05977b3631167028862be2a173976ca11] -> 1

And we do indeed see these entries:

  • Key: 0x316a0aac0d94f5824f0b66f5bbe94a8c360a17699a1d3a233aafcf7146e9f11c
    Value: 0x0000000000000000000000000000000000000000000000000000000000000001
    Meaning: This is owners[0xca11bde05977b3631167028862be2a173976ca11] -> 1, so the key can be derived from cast index address 0xca11bde05977b3631167028862be2a173976ca11 2.

  • Key: 0xe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0
    Value: 0x000000000000000000000000ca11bde05977b3631167028862be2a173976ca11
    Meaning: This is owners[1] -> 0xca11bde05977b3631167028862be2a173976ca11, so the key can be derived from cast index address 0x0000000000000000000000000000000000000001 2.

State Changes

The following state changes related to the nested Safe execution must be seen, either for the Security Council, or the Foundation Safe, depending on which role the simulation was run for:

GnosisSafeProxy - approvedHashes mapping update

  • Key: Needs to be computed.
    Before: 0x0000000000000000000000000000000000000000000000000000000000000000
    After: 0x0000000000000000000000000000000000000000000000000000000000000001

Key Computation

The GnosisSafe approvedHashes mapping is updated to indicate approval of this transaction by the Safe Signer. The correctness of this slot can be verified as follows:

  • Since this is a nested mapping, we need to use cast index twice to confirm that this is the correct slot. The inputs needed are:
    • The location (8) of the approvedHashes mapping in the GnosisSafe storage layout
    • The address of the Safe Signer, stored at the env var $SAFE_SIGNER in the following cast script command.
    • The safe hash to approve, stored at the env var $SAFE_HASH in the following cast script command. It's the value after "Nested hash:" in the simulation output logs.
  • Then using cast index, we can compute the key with
      $ cast index bytes32 $SAFE_HASH $(cast index address $SAFE_SIGNER 8)
    The output of this command must match the key of the state change.

Liveness Guard (Security Council only)

When the Security Council executes a transaction, the liveness timestamps are updated for each owner that signed the task. This is updating at the moment when the transaction is submitted (block.timestamp) into the lastLive mapping located at the slot 0.

Nonce increments

The only other state changes related to the nested execution are three nonce increments:

  • One increment of the ProxyAdminOwner Safe nonce, located as storage slot 0x0000000000000000000000000000000000000000000000000000000000000005 on a GnosisSafeProxy.
  • One increment of the Safe Signer nonce, located as storage slot 0x0000000000000000000000000000000000000000000000000000000000000005 on a GnosisSafeProxy.
  • One increment of the nonce of the EOA that is the first entry in the owner set of the Safe Signer.