-
Notifications
You must be signed in to change notification settings - Fork 370
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
**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
Showing
10 changed files
with
336 additions
and
31 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
] | ||
} |