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

Nadir/deploy refactor #790

Open
wants to merge 35 commits into
base: alex/deploy-refactor
Choose a base branch
from

Conversation

nadir-akhtar
Copy link

@nadir-akhtar nadir-akhtar commented Oct 2, 2024

The PR adds script/Release_Template.sol, a template file providing abstract contracts for a variety of scripting use cases. A release script can inherit and override relevant functions with lightweight and straightforward syntax. Below are the contexts for using each script:

  • EOABuilder: An EOA performing a deploy, returning a Deployment object.
  • MultisigBuilder: A multisig performing some direct action (e.g. sending tokens, acting as a role on a contract), returning a Safe MetaTransactionData object.
    • Note that every MultisigBuilder script transforms calls into MultiSendCallOnly calls, meaning any number of calls (not accounting for gas) can be batched into one transaction by a multisig.
  • OpsTimelockBuilder: A specialized nested multisig action performing a queue() and execute()
    • queue() refers to queueing a transaction in the Timelock and execute() refers to forwarding that transaction after some delay to the Executor Multisig. You can see more details on the EigenLayer admin structure here.

Furthermore, script/releases/v0.1-eigenpod/ contains an example set of scripts inheriting and implementing functions for each aforementioned abstract contract. These scripts are purely for demonstration.

  • DeployEigenPod.s.sol: Deploys a single contract, EigenPod.
  • UpgradeEigenPod.s.sol: Sends a dummy call to the Timelock, plus an upgrade to the eigenPod to some pending implementation.
  • UpgradeViaTimelock.s.sol: Queues up a transaction in the Timelock, then later allows for the same transaction to be executed.

=======================================

To run this locally, try the following commands.

Deploy

forge script DeployEigenPodAndManager -s "deploy(string memory)" "script/configs/zipzoop.json"

Example Output

$ forge script DeployEigenPodAndManager -s "deploy(string memory)" "script/configs/zipzoop.json"
[⠊] Compiling...
No files changed, compilation skipped
Script ran successfully.
Gas used: 12901634

== Return ==
0: struct Deployment[] [Deployment({ name: "EigenPodManager", deployedTo: 0x90193C961A926261B756D1E5bb255e67ff9498A1 }), Deployment({ name: "EigenPod", deployedTo: 0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496 })]

== Logs ==
  Reading from config file: script/configs/zipzoop.json

Execute

forge script UpgradeEigenPod.s.sol -s "execute(string memory)" "script/configs/zipzoop.json"

Example Output

$ forge script UpgradeEigenPod.s.sol -s "execute(string memory)" 
"script/configs/zipzoop.json"
[⠊] Compiling...
[⠘] Compiling 1 files with Solc 0.8.12
[⠃] Solc 0.8.12 finished in 4.92s
...
Script ran successfully.
Gas used: 6812603

== Return ==
0: struct Transaction Transaction({ to: 0x40A2aCCbd92BCA938b02010E17A5b8929b49130D, value: 0, data: 0x8d80ff0a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000212000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e40825f38f0000000000000000000000001bef05c7303d44e0e2fcd2a19d993eded4c51b5b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bef05c7303d44e0e2fcd2a19d993eded4c51b5b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008499a88ec4000000000000000000000000b8d8952f572e67b11e43bc21250967772fa883ff00000000000000000000000010eba780ccd9e5e9ffbe529c25046c076be91048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, op: 1 })

Queue

forge script UpgradeEigenPodAndManager -s "queue(string memory)" "script/configs/zipzoop.json"

Example Output

$ forge script UpgradeEigenPodAndManager -s "queue(string memory)" "script/configs/zipzoop.json"
[⠊] Compiling...
No files changed, compilation skipped
Script ran successfully.
Gas used: 6870245

== Return ==
0: struct Transaction Transaction({ to: 0x0000000000000000000000000000000000000000, value: 0, data: 0x3a66f901000000000000000000000000da29bb71669f46f2a779b4b62f03644a84ee3479000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004246a76120200000000000000000000000040a2accbd92bca938b02010e17a5b8929b49130d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000002248d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d2001bef05c7303d44e0e2fcd2a19d993eded4c51b5b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001049623609d000000000000000000000000b8d8952f572e67b11e43bc21250967772fa883ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000641794bb3c000000000000000000000000da29bb71669f46f2a779b4b62f03644a84ee34790000000000000000000000009ab2feaf0465f0ed51fc2b663ef228b418c9dad10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000092cc4a800a1513e85c481dddf3a06c6921211eac000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243659cfe60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, op: 1 })

== Logs ==
  Reading from config file: script/configs/zipzoop.json

Execute after Queue

forge script UpgradeEigenPodAndManager -s "execute(string memory)" "script/configs/zipzoop.json"

Example Output

$ forge script UpgradeEigenPodAndManager -s "execute(string memory)" "script/configs/zipzoop.json"
[⠊] Compiling...
No files changed, compilation skipped
Script ran successfully.
Gas used: 7531664

== Return ==
0: struct Transaction Transaction({ to: 0x40A2aCCbd92BCA938b02010E17A5b8929b49130D, value: 0, data: 0x8d80ff0a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000532000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004840825f38f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004246a76120200000000000000000000000040a2accbd92bca938b02010e17a5b8929b49130d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000002248d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d2001bef05c7303d44e0e2fcd2a19d993eded4c51b5b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001049623609d000000000000000000000000b8d8952f572e67b11e43bc21250967772fa883ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000641794bb3c000000000000000000000000da29bb71669f46f2a779b4b62f03644a84ee34790000000000000000000000009ab2feaf0465f0ed51fc2b663ef228b418c9dad10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000092cc4a800a1513e85c481dddf3a06c6921211eac000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243659cfe6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b8d8952f572e67b11e43bc21250967772fa883ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004715018a60000000000000000000000000000, op: 1 })

== Logs ==
  Reading from config file: script/configs/zipzoop.json

@nadir-akhtar nadir-akhtar changed the base branch from dev to alex/deploy-refactor October 2, 2024 19:59
Copy link

github-actions bot commented Oct 3, 2024

Reading tracefile ./lcov.info.pruned
                                             |Lines      |Functions|Branches  
Filename                                       |Rate    Num|Rate  Num|Rate   Num
================================================================================
[src/contracts/]
core/AVSDirectory.sol                          |85.2%    27|88.9%   9|    -    0
core/DelegationManager.sol                     |96.5%   198|92.3%  39|    -    0
core/RewardsCoordinator.sol                    |93.0%   128|84.8%  33|    -    0
core/StrategyManager.sol                       |97.6%    83| 100%  24|    -    0
libraries/BeaconChainProofs.sol                | 100%    22| 100%  11|    -    0
libraries/BytesLib.sol                         | 0.0%   156| 0.0%  14|    -    0
libraries/EIP1271SignatureUtils.sol            | 100%     3| 100%   1|    -    0
libraries/Endian.sol                           | 100%     2| 100%   1|    -    0
libraries/Merkle.sol                           | 100%    38| 100%   5|    -    0
libraries/StructuredLinkedList.sol             | 0.0%    45| 0.0%  19|    -    0
permissions/Pausable.sol                       |95.7%    23|90.9%  11|    -    0
permissions/PauserRegistry.sol                 | 100%    12| 100%   6|    -    0
pods/EigenPod.sol                              | 100%   122|96.2%  26|    -    0
pods/EigenPodManager.sol                       | 100%    75|92.9%  14|    -    0
strategies/EigenStrategy.sol                   | 0.0%    10| 0.0%   5|    -    0
strategies/StrategyBase.sol                    |90.9%    44|78.9%  19|    -    0
strategies/StrategyBaseTVLLimits.sol           | 100%    12| 100%   6|    -    0
strategies/StrategyFactory.sol                 | 100%    35| 100%   9|    -    0
token/BackingEigen.sol                         |83.3%    30|69.2%  13|    -    0
token/Eigen.sol                                |45.0%    40|61.5%  13|    -    0
utils/UpgradeableSignatureCheckingUtils.sol    | 0.0%     6| 0.0%   4|    -    0
================================================================================
                                       Total:|75.6%  1111|76.2% 282|    -    0

@nadir-akhtar nadir-akhtar marked this pull request as ready for review October 4, 2024 18:22
Copy link

Reading tracefile ./lcov.info.pruned
                                             |Lines      |Functions|Branches  
Filename                                       |Rate    Num|Rate  Num|Rate   Num
================================================================================
[src/contracts/]
core/AVSDirectory.sol                          |85.2%    27|88.9%   9|    -    0
core/DelegationManager.sol                     |96.5%   198|92.3%  39|    -    0
core/RewardsCoordinator.sol                    |93.0%   128|84.8%  33|    -    0
core/StrategyManager.sol                       |97.6%    83| 100%  24|    -    0
libraries/BeaconChainProofs.sol                | 100%    22| 100%  11|    -    0
libraries/BytesLib.sol                         | 0.0%   156| 0.0%  14|    -    0
libraries/EIP1271SignatureUtils.sol            | 100%     3| 100%   1|    -    0
libraries/Endian.sol                           | 100%     2| 100%   1|    -    0
libraries/Merkle.sol                           | 100%    38| 100%   5|    -    0
libraries/StructuredLinkedList.sol             | 0.0%    45| 0.0%  19|    -    0
permissions/Pausable.sol                       |95.7%    23|90.9%  11|    -    0
permissions/PauserRegistry.sol                 | 100%    12| 100%   6|    -    0
pods/EigenPod.sol                              | 100%   122|96.2%  26|    -    0
pods/EigenPodManager.sol                       | 100%    75|92.9%  14|    -    0
strategies/EigenStrategy.sol                   | 0.0%    10| 0.0%   5|    -    0
strategies/StrategyBase.sol                    |90.9%    44|78.9%  19|    -    0
strategies/StrategyBaseTVLLimits.sol           | 100%    12| 100%   6|    -    0
strategies/StrategyFactory.sol                 | 100%    35| 100%   9|    -    0
token/BackingEigen.sol                         |83.3%    30|69.2%  13|    -    0
token/Eigen.sol                                |45.0%    40|61.5%  13|    -    0
utils/UpgradeableSignatureCheckingUtils.sol    | 0.0%     6| 0.0%   4|    -    0
================================================================================
                                       Total:|75.6%  1111|76.2% 282|    -    0

IEigenPodManager(newEigenPodManager), // update EigenPodManager address
params.EIGENPOD_GENESIS_TIME
)),
envToUpdate: "eigenPod.pendingImpl"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Interesting -- this seems like it's leaking a bit of complexity. I figured zeus would take care of this given the name field?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If zeus isn't able to handle this for us, we should have constants defined or something that makes it harder to supply the wrong value here.

And I guess I'd question whether the name field is relevant

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, I think a better way to do this is to have that envToUpdate field be a boolean, either to update the name reserved config value's pending impl or not. Good callout

Copy link
Collaborator

Choose a reason for hiding this comment

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

Discussion:

  • Unclear whether we're passing deployments between scripts via env variables or as updated values in JSON config. Should clarify with Justin what he expects/has been building - Nadir/I are fine with either.
  • Regardless of whether we're using env variables or updating JSON, the script writer should not have to pass in raw strings to reference storage locations.
    • If using env variables, we will need a library mapping strings to env variables
    • If using JSON, we should be able to discern the location in the JSON by referencing the field getting updated (e.g. by passing in addrs.eigenPod.pendingImpl and the abstraction resolves this to the correct JSON key)

Other observations:

  • Moving solely to env variables might be the play eventually - possibly less brittle.
    • Backwards-compatibility issues will probably exist regardless of using JSON or ENV variables, so different versions may require different env/json schemas


vm.stopBroadcast();

return _deployments;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to return this if it's in a state variable the parent method has access to?

Copy link
Author

Choose a reason for hiding this comment

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

  1. I prefer explicitly returning up values rather than implicitly modifying state variables.
  2. I actually meant to have this not be in the parent contract 😅 and instead have every contract inheriting EOADeployer define their own _deployments array local to their own contract to avoid 1).

Will update this in the templates branch and this PR

Comment on lines +52 to +55
function setUp() public {
(Addresses memory addrs, Environment memory env, Params memory params) = _readConfigFile("script/configs/zipzoop.json");
_deploy(addrs, env, params);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this for testing purposes? (if so, that's fine - just wondering!)

Copy link
Author

Choose a reason for hiding this comment

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

Yep. Though one big concern with this is that it actually modifies the state variable to call _deploy() twice even when not running the tests specifically -- wondering if it makes more sense to separate out tests into a different file, or to simply not use setUp()


MultisigCall[] internal _executorCalls;

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

Choose a reason for hiding this comment

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

Weird that this method in particular is public rather than the internal pattern the other two scripts use

Copy link
Collaborator

Choose a reason for hiding this comment

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

ah, i see now why it's public, used in script 3.

eesh, that feels like a weird pattern!

Copy link
Collaborator

Choose a reason for hiding this comment

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

2 main reasons:

  1. this is the only time we do this pattern (deploy a script and call it from another script)
  2. deploys/calls like this should be minimized because then you have to be careful how/when you use start/stop broadcast

Copy link
Collaborator

Choose a reason for hiding this comment

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

would much rather make this an inheritance relationship somehow

Comment on lines +30 to +48
_multisigCalls.append({
to: addrs.timelock,
value: 0,
data: abi.encodeWithSelector(
ITimelock.executeTransaction.selector,
executorCalldata
)
});

// after queued transaction, renounce ownership from eigenPodManager
_multisigCalls.append({
to: addrs.eigenPodManager.proxy,
value: 0,
data: abi.encodeWithSelector(
EigenPodManager(addrs.eigenPodManager.proxy).renounceOwnership.selector
)
});

return _multisigCalls;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Kind of a strange mix:

  • when we write the queue script, we don't worry about the ops flow and the fact that we'll be calling queueTransaction is abstracted away
  • when we write the execute, we do worry about the ops flow and explicitly call executeTransaction

This distinction doesn't feel apparent given the structure of the code/templates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants