Skip to content

Commit

Permalink
fix: patch rewards v2 (#940)
Browse files Browse the repository at this point in the history
* fix: patch rewards v2

* test: assert 1 day

* test: assert 1 day on multisg step
  • Loading branch information
0xrajath authored Dec 10, 2024
1 parent c27424d commit a475a61
Show file tree
Hide file tree
Showing 4 changed files with 395 additions and 0 deletions.
132 changes: 132 additions & 0 deletions script/releases/v0.5.2-rewardsv2/1-eoa.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {EOADeployer} from "zeus-templates/templates/EOADeployer.sol";
import {RewardsCoordinator} from "src/contracts/core/RewardsCoordinator.sol";
import {IDelegationManager} from "src/contracts/interfaces/IDelegationManager.sol";
import {DelegationManager} from "src/contracts/core/DelegationManager.sol";
import {StrategyManager} from "src/contracts/core/StrategyManager.sol";
import {EigenLabsUpgrade} from "../EigenLabsUpgrade.s.sol";
import {Test, console} from "forge-std/Test.sol";
import {IPauserRegistry} from "src/contracts/interfaces/IPauserRegistry.sol";

contract Deploy is EOADeployer {
using EigenLabsUpgrade for *;

function _runAsEOA() internal override {
zUpdateUint16(string("REWARDS_COORDINATOR_DEFAULT_OPERATOR_SPLIT_BIPS"), uint16(1000));
zUpdateUint32(string("REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"), uint32(1 days));

vm.startBroadcast();
deploySingleton(
address(
new RewardsCoordinator(
IDelegationManager(zDeployedProxy(type(DelegationManager).name)),
StrategyManager(zDeployedProxy(type(StrategyManager).name)),
zUint32("REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"),
zUint32("REWARDS_COORDINATOR_MAX_REWARDS_DURATION"),
zUint32("REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH"),
zUint32("REWARDS_COORDINATOR_MAX_FUTURE_LENGTH"),
zUint32("REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP")
)
),
this.impl(type(RewardsCoordinator).name)
);

vm.stopBroadcast();
}

function testDeploy() public virtual {
// Deploy RewardsCoordinator Implementation
address oldImpl = zDeployedImpl(type(RewardsCoordinator).name);
runAsEOA();
address newImpl = zDeployedImpl(type(RewardsCoordinator).name);
assertTrue(oldImpl != newImpl, "impl should be different");

Deployment[] memory deploys = deploys();

// sanity check that zDeployedImpl is returning our deployment.
assertEq(deploys[0].deployedTo, zDeployedImpl(type(RewardsCoordinator).name));

RewardsCoordinator rewardsCoordinatorImpl = RewardsCoordinator(zDeployedImpl(type(RewardsCoordinator).name));

address owner = this._operationsMultisig();
IPauserRegistry pauserRegistry = IPauserRegistry(this._pauserRegistry());
uint64 initPausedStatus = zUint64("REWARDS_COORDINATOR_INIT_PAUSED_STATUS");
address rewardsUpdater = zAddress("REWARDS_COORDINATOR_UPDATER");
uint32 activationDelay = zUint32("REWARDS_COORDINATOR_ACTIVATION_DELAY");
uint16 defaultOperatorSplitBips = zUint16("REWARDS_COORDINATOR_DEFAULT_OPERATOR_SPLIT_BIPS");

// Ensure that the implementation contract cannot be initialized.
vm.expectRevert("Initializable: contract is already initialized");
rewardsCoordinatorImpl.initialize(
owner,
pauserRegistry,
initPausedStatus,
rewardsUpdater,
activationDelay,
defaultOperatorSplitBips
);

// Assert Immutables and State Variables set through initialize
assertEq(rewardsCoordinatorImpl.owner(), address(0), "expected owner");
assertEq(address(rewardsCoordinatorImpl.pauserRegistry()), address(0), "expected pauserRegistry");
assertEq(address(rewardsCoordinatorImpl.rewardsUpdater()), address(0), "expected rewardsUpdater");
assertEq(rewardsCoordinatorImpl.activationDelay(), 0, "expected activationDelay");
assertEq(rewardsCoordinatorImpl.defaultOperatorSplitBips(), 0, "expected defaultOperatorSplitBips");

assertEq(
address(rewardsCoordinatorImpl.delegationManager()),
zDeployedProxy(type(DelegationManager).name),
"expected delegationManager"
);
assertEq(
address(rewardsCoordinatorImpl.strategyManager()),
zDeployedProxy(type(StrategyManager).name),
"expected strategyManager"
);

assertEq(
rewardsCoordinatorImpl.CALCULATION_INTERVAL_SECONDS(),
zUint32("REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"),
"expected REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"
);
assertEq(
rewardsCoordinatorImpl.CALCULATION_INTERVAL_SECONDS(),
1 days,
"expected REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"
);
assertGt(
rewardsCoordinatorImpl.CALCULATION_INTERVAL_SECONDS(),
0,
"expected non-zero REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"
);

assertEq(rewardsCoordinatorImpl.MAX_REWARDS_DURATION(), zUint32("REWARDS_COORDINATOR_MAX_REWARDS_DURATION"));
assertGt(rewardsCoordinatorImpl.MAX_REWARDS_DURATION(), 0);

assertEq(
rewardsCoordinatorImpl.MAX_RETROACTIVE_LENGTH(),
zUint32("REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH")
);
assertGt(rewardsCoordinatorImpl.MAX_RETROACTIVE_LENGTH(), 0);

assertEq(rewardsCoordinatorImpl.MAX_FUTURE_LENGTH(), zUint32("REWARDS_COORDINATOR_MAX_FUTURE_LENGTH"));
assertGt(rewardsCoordinatorImpl.MAX_FUTURE_LENGTH(), 0);

assertEq(
rewardsCoordinatorImpl.GENESIS_REWARDS_TIMESTAMP(),
zUint32("REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP")
);
assertGt(rewardsCoordinatorImpl.GENESIS_REWARDS_TIMESTAMP(), 0);

assertEq(deploys.length, 1, "expected exactly 1 deployment");
assertEq(
keccak256(bytes(deploys[0].name)),
keccak256(bytes(this.impl(type(RewardsCoordinator).name))),
"zeusTest: Deployment name is not RewardsCoordinator"
);
assertTrue(deploys[0].singleton == true, "zeusTest: RewardsCoordinator should be a singleton.");
assertNotEq(deploys[0].deployedTo, address(0), "zeusTest: Should deploy to non-zero address.");
}
}
82 changes: 82 additions & 0 deletions script/releases/v0.5.2-rewardsv2/2-multisig.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 {MultisigCall, MultisigCallUtils, MultisigBuilder} from "zeus-templates/templates/MultisigBuilder.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {Deploy} from "./1-eoa.s.sol";
import {RewardsCoordinator} from "src/contracts/core/RewardsCoordinator.sol";
import {EigenLabsUpgrade} from "../EigenLabsUpgrade.s.sol";
import {IPauserRegistry} from "src/contracts/interfaces/IPauserRegistry.sol";
import {ITimelock} from "zeus-templates/interfaces/ITimelock.sol";
import {console} from "forge-std/console.sol";
import {EncGnosisSafe} from "zeus-templates/utils/EncGnosisSafe.sol";
import {MultisigCallUtils, MultisigCall} from "zeus-templates/utils/MultisigCallUtils.sol";
import {IMultiSend} from "zeus-templates/interfaces/IMultiSend.sol";
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";

/**
* Purpose: enqueue a multisig transaction which tells the ProxyAdmin to upgrade RewardsCoordinator.
*/
contract Queue is MultisigBuilder, Deploy {
using MultisigCallUtils for MultisigCall[];
using EigenLabsUpgrade for *;
using EncGnosisSafe for *;
using MultisigCallUtils for *;

MultisigCall[] private _executorCalls;
MultisigCall[] private _opsCalls;

function options() internal virtual override view returns (MultisigOptions memory) {
return MultisigOptions(
this._operationsMultisig(),
Operation.Call
);
}

function _getMultisigTransactionCalldata() internal view returns (bytes memory) {
ProxyAdmin pa = ProxyAdmin(this._proxyAdmin());

bytes memory proxyAdminCalldata = abi.encodeCall(
pa.upgrade,
(
TransparentUpgradeableProxy(payable(zDeployedProxy(type(RewardsCoordinator).name))),
zDeployedImpl(type(RewardsCoordinator).name)
)
);

bytes memory executorMultisigCalldata = address(this._timelock()).calldataToExecTransaction(
this._proxyAdmin(),
proxyAdminCalldata,
EncGnosisSafe.Operation.Call
);

return (executorMultisigCalldata);
}

function runAsMultisig() internal virtual override {
bytes memory executorMultisigCalldata = _getMultisigTransactionCalldata();

TimelockController timelock = TimelockController(payable(this._timelock()));
timelock.schedule(
this._executorMultisig(),
0 /* value */,
executorMultisigCalldata,
0 /* predecessor */,
bytes32(0) /* salt */,
timelock.getMinDelay()
);
}

function testDeploy() public virtual override {
runAsEOA();

execute();
TimelockController timelock = TimelockController(payable(this._timelock()));

bytes memory multisigTxnData = _getMultisigTransactionCalldata();
bytes32 txHash = timelock.hashOperation(this._executorMultisig(), 0, multisigTxnData, 0, 0);

assertEq(timelock.isOperationPending(txHash), true, "Transaction should be queued.");
}
}
162 changes: 162 additions & 0 deletions script/releases/v0.5.2-rewardsv2/3-multisig.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {MultisigCall, MultisigCallUtils, MultisigBuilder} from "zeus-templates/templates/MultisigBuilder.sol";
import {SafeTx, SafeTxUtils} from "zeus-templates/utils/SafeTxUtils.sol";
import {Queue} from "./2-multisig.s.sol";
import {EigenLabsUpgrade} from "../EigenLabsUpgrade.s.sol";
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
import {RewardsCoordinator} from "src/contracts/core/RewardsCoordinator.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {IPauserRegistry} from "src/contracts/interfaces/IPauserRegistry.sol";
import {DelegationManager} from "src/contracts/core/DelegationManager.sol";
import {StrategyManager} from "src/contracts/core/StrategyManager.sol";
import {console} from "forge-std/console.sol";

contract Execute is Queue {
using MultisigCallUtils for MultisigCall[];
using SafeTxUtils for SafeTx;
using EigenLabsUpgrade for *;

event Upgraded(address indexed implementation);

function options() internal view override returns (MultisigOptions memory) {
return MultisigOptions(this._protocolCouncilMultisig(), Operation.Call);
}

/**
* @dev Overrides the previous _execute function to execute the queued transactions.
*/
function runAsMultisig() internal override {
bytes memory executorMultisigCalldata = _getMultisigTransactionCalldata();
TimelockController timelock = TimelockController(payable(this._timelock()));
timelock.execute(
this._executorMultisig(),
0 /* value */,
executorMultisigCalldata,
0 /* predecessor */,
bytes32(0) /* salt */
);
}

function testDeploy() public override {
// save the previous implementation address to assert its change later
address prevRewardsCoordinator = zDeployedImpl(type(RewardsCoordinator).name);

// 0. Deploy the Implementation contract.
runAsEOA();

// 1. run the queue script.
vm.startPrank(this._operationsMultisig());
super.runAsMultisig();
vm.stopPrank();

RewardsCoordinator rewardsCoordinatorProxy = RewardsCoordinator(zDeployedProxy(type(RewardsCoordinator).name));
uint256 pausedStatusBefore = rewardsCoordinatorProxy.paused();
TimelockController timelock = this._timelock();

// 2. run the execute script above.
bytes memory multisigTxnData = _getMultisigTransactionCalldata();
bytes32 txHash = timelock.hashOperation(this._executorMultisig(), 0, multisigTxnData, 0, 0);

assertEq(timelock.isOperationPending(txHash), true, "Transaction should be queued and pending.");
vm.warp(block.timestamp + timelock.getMinDelay()); // 1 tick after ETA.

assertEq(timelock.isOperationReady(txHash), true, "Transaction should be executable.");

vm.expectEmit(true, true, true, true, address(rewardsCoordinatorProxy));
emit Upgraded(zDeployedImpl(type(RewardsCoordinator).name));
execute();

// 3. assert that the execute did something
assertEq(timelock.isOperationDone(txHash), true, "Transaction should be executed.");

// assert that the proxy implementation was updated.
ProxyAdmin admin = ProxyAdmin(this._proxyAdmin());
address rewardsCoordinatorImpl = admin.getProxyImplementation(
TransparentUpgradeableProxy(payable(zDeployedProxy(type(RewardsCoordinator).name)))
);
assertEq(rewardsCoordinatorImpl, zDeployedImpl(type(RewardsCoordinator).name));
assertNotEq(prevRewardsCoordinator, rewardsCoordinatorImpl, "expected rewardsCoordinatorImpl to be different");

uint256 pausedStatusAfter = rewardsCoordinatorProxy.paused();
address owner = this._operationsMultisig();
IPauserRegistry pauserRegistry = IPauserRegistry(this._pauserRegistry());
uint64 initPausedStatus = zUint64("REWARDS_COORDINATOR_INIT_PAUSED_STATUS");
address rewardsUpdater = zAddress("REWARDS_COORDINATOR_UPDATER");
uint32 activationDelay = zUint32("REWARDS_COORDINATOR_ACTIVATION_DELAY");
uint16 defaultOperatorSplitBips = zUint16("REWARDS_COORDINATOR_DEFAULT_OPERATOR_SPLIT_BIPS");

// Ensure that the proxy contract cannot be re-initialized.
vm.expectRevert("Initializable: contract is already initialized");
rewardsCoordinatorProxy.initialize(
owner,
pauserRegistry,
initPausedStatus,
rewardsUpdater,
activationDelay,
defaultOperatorSplitBips
);

// Assert Immutables and State Variables set through initialize
assertEq(rewardsCoordinatorProxy.owner(), owner, "expected owner");
assertEq(address(rewardsCoordinatorProxy.pauserRegistry()), address(pauserRegistry), "expected pauserRegistry");
assertEq(address(rewardsCoordinatorProxy.rewardsUpdater()), rewardsUpdater, "expected rewardsUpdater");
assertEq(rewardsCoordinatorProxy.activationDelay(), activationDelay, "expected activationDelay");
assertEq(
rewardsCoordinatorProxy.defaultOperatorSplitBips(),
defaultOperatorSplitBips,
"expected defaultOperatorSplitBips"
);
assertEq(
pausedStatusBefore,
pausedStatusAfter,
"expected paused status to be the same before and after initialization"
);
assertEq(
address(rewardsCoordinatorProxy.delegationManager()),
zDeployedProxy(type(DelegationManager).name),
"expected delegationManager"
);
assertEq(
address(rewardsCoordinatorProxy.strategyManager()),
zDeployedProxy(type(StrategyManager).name),
"expected strategyManager"
);

assertEq(
rewardsCoordinatorProxy.CALCULATION_INTERVAL_SECONDS(),
zUint32("REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"),
"expected REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"
);
assertEq(
rewardsCoordinatorProxy.CALCULATION_INTERVAL_SECONDS(),
1 days,
"expected REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"
);
assertGt(
rewardsCoordinatorProxy.CALCULATION_INTERVAL_SECONDS(),
0,
"expected non-zero REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS"
);

assertEq(rewardsCoordinatorProxy.MAX_REWARDS_DURATION(), zUint32("REWARDS_COORDINATOR_MAX_REWARDS_DURATION"));
assertGt(rewardsCoordinatorProxy.MAX_REWARDS_DURATION(), 0);

assertEq(
rewardsCoordinatorProxy.MAX_RETROACTIVE_LENGTH(),
zUint32("REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH")
);
assertGt(rewardsCoordinatorProxy.MAX_RETROACTIVE_LENGTH(), 0);

assertEq(rewardsCoordinatorProxy.MAX_FUTURE_LENGTH(), zUint32("REWARDS_COORDINATOR_MAX_FUTURE_LENGTH"));
assertGt(rewardsCoordinatorProxy.MAX_FUTURE_LENGTH(), 0);

assertEq(
rewardsCoordinatorProxy.GENESIS_REWARDS_TIMESTAMP(),
zUint32("REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP")
);
assertGt(rewardsCoordinatorProxy.GENESIS_REWARDS_TIMESTAMP(), 0);
}
}
19 changes: 19 additions & 0 deletions script/releases/v0.5.2-rewardsv2/upgrade.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "rewards-v2-patch",
"from": "~0.0.0",
"to": "0.5.2",
"phases": [
{
"type": "eoa",
"filename": "1-eoa.s.sol"
},
{
"type": "multisig",
"filename": "2-multisig.s.sol"
},
{
"type": "multisig",
"filename": "3-multisig.s.sol"
}
]
}

0 comments on commit a475a61

Please sign in to comment.