Skip to content

Commit

Permalink
feat: alm upgrade script (#1103)
Browse files Browse the repository at this point in the history
**Motivation:**

Registrar interface needs to be upgraded to unblock integration quickly
as possible

**Modifications:**

Upgrade script for the AllocationManager

**Result:**

Upgrade to testnet Holesky environment will take place
  • Loading branch information
8sunyuan authored Feb 14, 2025
1 parent 0d6b926 commit 917e8af
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 31 deletions.
4 changes: 2 additions & 2 deletions pkg/bindings/AllocationManager/binding.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/bindings/AllocationManagerStorage/binding.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/bindings/DelegationManager/binding.go

Large diffs are not rendered by default.

81 changes: 56 additions & 25 deletions pkg/bindings/IAVSRegistrar/binding.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/bindings/IAllocationManager/binding.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/bindings/RewardsCoordinator/binding.go

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions script/releases/v1.1.1-slashing/1-eoa.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {EOADeployer} from "zeus-templates/templates/EOADeployer.sol";
import "../Env.sol";

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

contract Deploy is EOADeployer {
using Env for *;

function _runAsEOA() internal override {
vm.startBroadcast();

// Deploy Allocation Manager
deployImpl({
name: type(AllocationManager).name,
deployedTo: address(
new AllocationManager({
_delegation: Env.proxy.delegationManager(),
_pauserRegistry: Env.impl.pauserRegistry(),
_permissionController: Env.proxy.permissionController(),
_DEALLOCATION_DELAY: Env.MIN_WITHDRAWAL_DELAY(),
_ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY()
})
)
});

vm.stopBroadcast();
}

function testDeploy() public virtual {
_runAsEOA();
_validateNewImplAddresses(false);
_validateImplConstructors();
_validateImplsInitialized();
}

/// @dev Validate that the `Env.impl` addresses are updated to be distinct from what the proxy
/// admin reports as the current implementation address.
///
/// Note: The upgrade script can call this with `areMatching == true` to check that these impl
/// addresses _are_ matches.
function _validateNewImplAddresses(
bool areMatching
) internal view {
function(address, address, string memory)
internal
pure assertion = areMatching ? _assertMatch : _assertNotMatch;

assertion(
_getProxyImpl(address(Env.proxy.allocationManager())),
address(Env.impl.allocationManager()),
"allocationManager impl failed"
);
}

/// @dev Validate the immutables set in the new implementation constructors
function _validateImplConstructors() internal view {
AllocationManager allocationManager = Env.impl.allocationManager();
assertTrue(allocationManager.delegation() == Env.proxy.delegationManager(), "dm invalid");
assertTrue(allocationManager.pauserRegistry() == Env.impl.pauserRegistry(), "pR invalid");
assertTrue(allocationManager.permissionController() == Env.proxy.permissionController(), "pc invalid");
assertTrue(allocationManager.DEALLOCATION_DELAY() == Env.MIN_WITHDRAWAL_DELAY(), "deallocationDelay invalid");
assertTrue(
allocationManager.ALLOCATION_CONFIGURATION_DELAY() == Env.ALLOCATION_CONFIGURATION_DELAY(),
"allocationConfigurationDelay invalid"
);
}

/// @dev Call initialize on all deployed implementations to ensure initializers are disabled
function _validateImplsInitialized() internal {
bytes memory errInit = "Initializable: contract is already initialized";

AllocationManager allocationManager = Env.impl.allocationManager();
vm.expectRevert(errInit);
allocationManager.initialize(address(0), 0);
}

/// @dev Query and return `proxyAdmin.getProxyImplementation(proxy)`
function _getProxyImpl(
address proxy
) internal view returns (address) {
return ProxyAdmin(Env.proxyAdmin()).getProxyImplementation(ITransparentUpgradeableProxy(proxy));
}

/// @dev Query and return `proxyAdmin.getProxyAdmin(proxy)`
function _getProxyAdmin(
address proxy
) internal view returns (address) {
return ProxyAdmin(Env.proxyAdmin()).getProxyAdmin(ITransparentUpgradeableProxy(proxy));
}

function _assertMatch(address a, address b, string memory err) private pure {
assertEq(a, b, err);
}

function _assertNotMatch(address a, address b, string memory err) private pure {
assertNotEq(a, b, err);
}
}
69 changes: 69 additions & 0 deletions script/releases/v1.1.1-slashing/2-multisig.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {Deploy} from "./1-eoa.s.sol";
import "../Env.sol";

import {MultisigBuilder} from "zeus-templates/templates/MultisigBuilder.sol";
import "zeus-templates/utils/Encode.sol";

import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";

contract Queue is MultisigBuilder, Deploy {
using Env for *;
using Encode for *;

function _runAsMultisig() internal virtual override prank(Env.opsMultisig()) {
bytes memory calldata_to_executor = _getCalldataToExecutor();

TimelockController timelock = Env.timelockController();
timelock.schedule({
target: Env.executorMultisig(),
value: 0,
data: calldata_to_executor,
predecessor: 0,
salt: 0,
delay: timelock.getMinDelay()
});
}

/// @dev Get the calldata to be sent from the timelock to the executor
function _getCalldataToExecutor() internal returns (bytes memory) {
MultisigCall[] storage executorCalls = Encode.newMultisigCalls().append({
to: Env.proxyAdmin(),
data: Encode.proxyAdmin.upgrade({
proxy: address(Env.proxy.allocationManager()),
impl: address(Env.impl.allocationManager())
})
});

return Encode.gnosisSafe.execTransaction({
from: address(Env.timelockController()),
to: address(Env.multiSendCallOnly()),
op: Encode.Operation.DelegateCall,
data: Encode.multiSend(executorCalls)
});
}

function testScript() public virtual {
runAsEOA();

TimelockController timelock = Env.timelockController();
bytes memory calldata_to_executor = _getCalldataToExecutor();
bytes32 txHash = timelock.hashOperation({
target: Env.executorMultisig(),
value: 0,
data: calldata_to_executor,
predecessor: 0,
salt: 0
});

// Check that the upgrade does not exist in the timelock
assertFalse(timelock.isOperationPending(txHash), "Transaction should NOT be queued.");

execute();

// Check that the upgrade has been added to the timelock
assertTrue(timelock.isOperationPending(txHash), "Transaction should be queued.");
}
}
82 changes: 82 additions & 0 deletions script/releases/v1.1.1-slashing/3-execute.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import "../Env.sol";
import {Queue} from "./2-multisig.s.sol";

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

contract Execute is Queue {
using Env for *;

function _runAsMultisig() internal override(Queue) prank(Env.protocolCouncilMultisig()) {
bytes memory calldata_to_executor = _getCalldataToExecutor();

TimelockController timelock = Env.timelockController();
timelock.execute({
target: Env.executorMultisig(),
value: 0,
payload: calldata_to_executor,
predecessor: 0,
salt: 0
});
}

function testScript() public virtual override(Queue) {
// 0. Deploy Impls
runAsEOA();

TimelockController timelock = Env.timelockController();
bytes memory calldata_to_executor = _getCalldataToExecutor();
bytes32 txHash = timelock.hashOperation({
target: Env.executorMultisig(),
value: 0,
data: calldata_to_executor,
predecessor: 0,
salt: 0
});
assertFalse(timelock.isOperationPending(txHash), "Transaction should NOT be queued.");

// 1. Queue Upgrade
Queue._runAsMultisig();
_unsafeResetHasPranked(); // reset hasPranked so we can use it again

// 2. Warp past delay
vm.warp(block.timestamp + timelock.getMinDelay()); // 1 tick after ETA
assertEq(timelock.isOperationReady(txHash), true, "Transaction should be executable.");

// 3- execute
execute();

assertTrue(timelock.isOperationDone(txHash), "Transaction should be complete.");

// 4. Validate
_validateNewImplAddresses(true);
_validateProxyConstructors();
_validateProxyInitialized();
}

function _validateProxyConstructors() internal view {
AllocationManager allocationManager = Env.proxy.allocationManager();
assertTrue(allocationManager.delegation() == Env.proxy.delegationManager(), "alm.dm invalid");
assertTrue(allocationManager.pauserRegistry() == Env.impl.pauserRegistry(), "alm.pR invalid");
assertTrue(allocationManager.permissionController() == Env.proxy.permissionController(), "alm.pc invalid");
assertTrue(
allocationManager.DEALLOCATION_DELAY() == Env.MIN_WITHDRAWAL_DELAY(), "alm.deallocationDelay invalid"
);
assertTrue(
allocationManager.ALLOCATION_CONFIGURATION_DELAY() == Env.ALLOCATION_CONFIGURATION_DELAY(),
"alm.allocationConfigurationDelay invalid"
);
}

/// @dev Call initialize on all deployed proxies to ensure initializers are disabled
function _validateProxyInitialized() internal {
bytes memory errInit = "Initializable: contract is already initialized";

AllocationManager allocationManager = Env.proxy.allocationManager();
vm.expectRevert(errInit);
allocationManager.initialize(address(0), 0);
}
}
19 changes: 19 additions & 0 deletions script/releases/v1.1.1-slashing/upgrade.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "slashing-registrar-hotfix",
"from": "1.1.0",
"to": "1.1.1",
"phases": [
{
"type": "eoa",
"filename": "1-eoa.s.sol"
},
{
"type": "multisig",
"filename": "2-multisig.s.sol"
},
{
"type": "multisig",
"filename": "3-execute.s.sol"
}
]
}

0 comments on commit 917e8af

Please sign in to comment.