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

feat: introduce zeus templates #790

Merged
merged 58 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
fd8c2e1
feat: wip refactor of deploy scripts
wadealexc Aug 14, 2024
402caea
wip
wadealexc Oct 1, 2024
7a014cb
wip2
wadealexc Oct 1, 2024
b2d9d43
Cleanup to get compiling
nadir-akhtar Oct 2, 2024
d1381bd
Clean up template and create deploy script
nadir-akhtar Oct 2, 2024
26861fc
Mild refactoring + adding in utils file + commenting out code
nadir-akhtar Oct 3, 2024
8461668
Craft transactions producing a bytestring
nadir-akhtar Oct 3, 2024
7f46c77
wip: ops timelock script
wadealexc Oct 3, 2024
5b6829c
Reorder contracts
nadir-akhtar Oct 3, 2024
12e2d10
Move around code and rename variables
nadir-akhtar Oct 3, 2024
c604d45
Finish up upgrade script
nadir-akhtar Oct 3, 2024
4978dc5
Get queueing working
nadir-akhtar Oct 4, 2024
0fb7e8f
Clean up unused files
nadir-akhtar Oct 4, 2024
bd5030f
Fix UpgradeViaTimelock name
nadir-akhtar Oct 4, 2024
8a9f466
Complete execute and queue flow
nadir-akhtar Oct 4, 2024
58a6183
Add timelock as parameter to executor encoding
nadir-akhtar Oct 7, 2024
8bc1085
Finish deploy and upgrade scripts
nadir-akhtar Oct 7, 2024
bc9ae19
Rename deploy script
nadir-akhtar Oct 7, 2024
85249e7
Set up example tests
nadir-akhtar Oct 8, 2024
ddbeff3
Add new base contract separating queueing and execution
nadir-akhtar Oct 8, 2024
a80fba0
Break out MultisigCallUtils into separate file
nadir-akhtar Oct 9, 2024
c315b8b
Break out SafeTxUtils into separate file
nadir-akhtar Oct 9, 2024
a410e0e
Move out all abstract contracts into template directory
nadir-akhtar Oct 9, 2024
cd3b528
Remove virtual test functions
nadir-akhtar Oct 9, 2024
9e89fd0
Add boilerplate for Zeus
nadir-akhtar Oct 9, 2024
b8f75b5
Fix outdated comment
nadir-akhtar Oct 9, 2024
43ae726
Amend incorrect contract names
nadir-akhtar Oct 9, 2024
3394433
Document template files and make inheritance more explicit
nadir-akhtar Oct 10, 2024
a11ea7f
add /var/folder access to foundry for zoooos
jbrower95 Oct 10, 2024
10fdf54
Remove unnecessary imports and mildly refactor ConfigParser
nadir-akhtar Oct 12, 2024
a21e293
Refactor to updated Zeus specification
nadir-akhtar Oct 12, 2024
a2c46cd
forge install: zeus-templates
nadir-akhtar Oct 16, 2024
e6f63d9
Cleanup and rename example scripts
nadir-akhtar Oct 17, 2024
12b7a2e
Remove file
nadir-akhtar Oct 17, 2024
00b5092
forge install: zeus-templates
nadir-akhtar Oct 17, 2024
7c561c3
Use zeus-templates for dependency
nadir-akhtar Oct 17, 2024
98d7cb9
fix: remove files in zeus-templates, and move interfaces and utils wh…
nadir-akhtar Oct 22, 2024
8a23fb3
Update README and example path
nadir-akhtar Oct 23, 2024
1aea7a1
refactor: remove template dir
nadir-akhtar Oct 28, 2024
0d5b8b2
refactor: update deployment struct and example
nadir-akhtar Oct 28, 2024
431a501
refactor: remove tests
nadir-akhtar Oct 28, 2024
0803bd3
refactor: use envvars instead of config parsing
nadir-akhtar Oct 30, 2024
baee221
Lays Labs lmfao
jbrower95 Oct 30, 2024
016e71c
feat: add templates back into directory
nadir-akhtar Oct 30, 2024
964a47c
refactor: use helper deployment functions + forge fmt
nadir-akhtar Oct 31, 2024
d6fac5f
fix: update env and zeus-templates
nadir-akhtar Oct 31, 2024
7194883
Add zuesTest stubs
nadir-akhtar Oct 31, 2024
9081275
chore: update zeus-templates
nadir-akhtar Oct 31, 2024
85b58ad
refactor: use helper functions for getting envvars
nadir-akhtar Oct 31, 2024
640bfa5
chore: add basic test example for deploy
nadir-akhtar Oct 31, 2024
fe4eff6
Merge branch 'dev' into nadir/deploy-refactor
nadir-akhtar Nov 1, 2024
4bc77da
chore: retrigger checks
nadir-akhtar Nov 1, 2024
72e8fd7
chore: forge fmt
nadir-akhtar Nov 1, 2024
b329059
chore: update zeus-templates for file capitalization change
nadir-akhtar Nov 1, 2024
6e3648a
chore: restore files for tests
nadir-akhtar Nov 1, 2024
75a09c7
chore: restore more files for tests
nadir-akhtar Nov 1, 2024
5ea4dba
chore: restore even _more_ files for integration tests
nadir-akhtar Nov 1, 2024
50a14b0
chore: remove unnecessary Certora script
nadir-akhtar Nov 1, 2024
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
[submodule "lib/openzeppelin-contracts-upgradeable-v4.9.0"]
path = lib/openzeppelin-contracts-upgradeable-v4.9.0
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/zeus-templates"]
path = lib/zeus-templates
url = https://github.com/Lays-labs/zeus-templates
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
src = 'src'
out = 'out'
libs = ['lib']
fs_permissions = [{ access = "read-write", path = "./"}]
fs_permissions = [{ access = "read-write", path = "./"}, { access = "read-write", path = "/var/folders"}]
gas_reports = ["*"]
# ignore upgrade testing in scripts by default
no_match_test = "queueUpgrade"
Expand Down
1 change: 1 addition & 0 deletions lib/zeus-templates
Submodule zeus-templates added at 322ad2
197 changes: 197 additions & 0 deletions script/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# Release Scripts

This directory contains the following subdirectories:

* `configs`: to store configuration data related to a given network.
* `interfaces`: to store interfaces relevant to your scripts.
* `releases`: to set up more subdirectories corresponding to your release, and the most important `script/` subdirectory.
* `utils`: to define any utility contracts for performing common actions.

It is intended to be driven by [Zeus](https://github.com/Layr-Labs/zeus), which will run `forge` commands under the hood and track the status of upgrades.

## Using Zeus Templates

The [zeus-templates](https://github.com/Layr-Labs/zeus-templates) repository provides two base contract classes to facilitate deployment and multisig scripts.

### EOADeployer

`EOADeployer` is the base contract for performing EOA deploys, providing a `Deployment` struct. The entry function is `deploy()` and requires adding `-s "deploy(string memory)" "<path_to_config>"` as a `forge script` flag. Any inheriting contract is expected to inherit the `_deploy()` internal function and return a `Deployment[]` array, containing all deployed contract details.

The `Deployment` struct contains 3 fields:
* `name`: the name of the contract published
* `address`: the address to which the contract was published
* `envToUpdate`: the environment variable in the config file to update if relevant.
* Leave this as an empty string if deploying an instance of a contract that doesn't need to be tracked long-term.

If you need to do something with an EOA other than deploy, the base `ConfigParser` provided by `zeus-templates` is the appropriate base contract.

### MultisigBuilder

`MultisigBuilder` is the base class for any action to be taken by a Safe Multisig. The entry function is `execute()` and requires adding `-s "execute(string memory)" "<path_to_config>"` as a `forge script` flag. Any inheriting contract is expected to inherit the `_execute()` internal function and return a `MultisigCall[]` object, containing all intended multisig calls.

The `MultisigCall` struct contains 3 fields:
* `to`: the address to call with the multisig
* `value`: the amount of ETH to send as part of the transaction.
* `data`: the calldata associated with the multisig call.

Once the `_execute()` function is implemented, the base MultisigBuilder contract will combine these calls into one `SafeTx` object, which is intended to pass all calls into the [MultiSendCallOnly](https://github.com/safe-global/safe-smart-account/blob/6fde75d29c8b52d5ac0c93a6fb7631d434b64119/contracts/libraries/MultiSendCallOnly.sol) contract.

## Setting up a Release Directory

### Naming

Every file must be named either `#-eoa.s.sol` or `#-multisig.s.sol`, where `#` represents the script's order in the release process and the choice of `(eoa|multisig)` represents the relevant signing strategy.

## Example: How to write a Deploy-Queue-Upgrade

Before diving into how to do this, a quick context blurb for those unfamiliar. If you are familiar, feel free to jump to the next subsection, [Deploy](#deploy).

### Context

A deploy-queue-execute flow is common given EigenLayer's [multisig governance](https://docs.eigenlayer.xyz/eigenlayer/security/multisig-governance) structure. For context, the Executor Multisig (a 1-of-2 multisig) owns many critical privileges on EigenLayer, such as the ability to upgrade core contracts. An EigenLayer upgrade will often originate from the Operations Multisig, controlled by Eigen Labs, which is 1 of the 2 signers. Well, in spirit at least.

Technically, there is an intermediate contract between the Ops Multisig and Executor known as the Timelock into which actions must be queued for a waiting period (~10 days). After the delay, the Operations Multsig must then poke the Timelock to forward the transaction to the Executor, which will finally take action.

### Deploy

Deploy scripts are expected to inherit the `EOADeployer` script and produce a `Deployment[]` array containing all deployed contract names, addresses, and overridden config values.

An example deploy script looks as follows:

```solidity
pragma solidity ^0.8.12;

import "zeus-templates/templates/EOADeployer.sol";

... // imagine imports here

contract DeployEigenPodManager is EOADeployer {

function _deploy(Addresses memory, Environment memory, Params memory params) internal override returns (Deployment[] memory) {

vm.startBroadcast();

address newEigenPodManager = new EigenPodManager(
... // imagine params here
);

_deployments.push(Deployment({
name: type(EigenPodManager).name,
deployedTo: newEigenPodManager,
envToUpdate: "eigenPodManager.pendingImpl"
}));

vm.stopBroadcast();

return _deployments;
}
}
```

Here, the script inherits the `EOADeployer` and implements the `_deploy()` function, creating a new `EigenPodManager` with relevant details and requesting for Zeus to set the `pendingImpl` field of the `eigenPodManager` in the config to the given address. It would be pending because a transaction must be issued to upgrade the EigenPodManager to this new implementation.

### Queue

Once the above `eigenPodManager` is deployed, a `queueTransaction` operation must be taken in the Timelock if upgrading via the Ops Multisig. This could look like something below:

```solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import "zeus-templates/templates/OpsTimelockBuilder.sol";

import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {IUpgradeableBeacon} from "script/interfaces/IUpgradeableBeacon.sol";
import "src/contracts/pods/EigenPodManager.sol";

contract QueueEigenPodAndManager is OpsTimelockBuilder {

using MultisigCallUtils for MultisigCall[];
using SafeTxUtils for SafeTx;

MultisigCall[] internal _executorCalls;

function queue(Addresses memory addrs, Environment memory env, Params memory params) public override returns (MultisigCall[] memory) {

// construct initialization data for eigenPodManager
bytes memory eigenPodManagerData = abi.encodeWithSelector(
EigenPodManager(addrs.eigenPodManager.pendingImpl).initialize.selector,
... // imagine initialization data
);

// upgrade eigenPodManager
_executorCalls.append({
to: addrs.proxyAdmin,
data: abi.encodeWithSelector(
ProxyAdmin.upgradeAndCall.selector,
addrs.eigenPodManager.proxy,
addrs.eigenPodManager.pendingImpl,
eigenPodManagerData // initialize impl here
)
});

// upgrade eigenPod beacon implementation
_executorCalls.append({
to: addrs.eigenPod.beacon,
data: abi.encodeWithSelector(
IUpgradeableBeacon.upgradeTo.selector,
addrs.eigenPod.pendingImpl
)
});

return _executorCalls;
}
}
```

After inheriting the `OpsTimelockBuilder` contract (which is an extension of `MultisigBuilder`), we implement the `queue()` function from the perspective of the Executor Multisig. All calls are eventually encoded as a `SafeTx` from the Ops Multisig to the Timelock.

### Upgrade

Once the delay has passed, `executeTransaction` can be called on the timelock with the appropriate calldata. As an example:

```solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import "zeus-templates/templates/OpsTimelockBuilder.sol";

import "src/contracts/pods/EigenPodManager.sol";

import "./2-multisig.s.sol"; // using previous script to avoid rewriting

contract ExecuteEigenPodManager is MultisigBuilder {

using MultisigCallUtils for MultisigCall[];
using SafeTxUtils for *;

function _execute(Addresses memory addrs, Environment memory env, Params memory params) internal override returns (MultisigCall[] memory) {

QueueEigenPodManager queue = new QueueEigenPodManager();

MultisigCall[] memory _executorCalls = queue.queue(addrs, env, params);

// steals logic from queue() to perform execute()
// likely the first step of any _execute() after a _queue()
bytes memory executorCalldata = queue.makeExecutorCalldata(
_executorCalls,
params.multiSendCallOnly,
addrs.timelock
);

// execute queued transaction upgrading eigenPodManager
_multisigCalls.append({
to: addrs.timelock,
value: 0,
data: abi.encodeWithSelector(
ITimelock.executeTransaction.selector,
executorCalldata
)
});

return _multisigCalls;
}
}
```

After reusing the previous script's `queue()` function to recreate the calldata, we wrap it up in an `executeTransaction` encoded data blob and return the `MultisigCall`, which will then be crafted as a `SafeTx` by the parent contract.
71 changes: 0 additions & 71 deletions script/admin/mainnet/Mainnet_Unpause_Deposits.s.sol

This file was deleted.

Loading
Loading