Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@
[submodule "lib/chainlink-brownie-contracts"]
path = lib/chainlink-brownie-contracts
url = https://github.com/smartcontractkit/chainlink-brownie-contracts
[submodule "lib/v3-core"]
path = lib/v3-core
url = https://github.com/Uniswap/v3-core.git
branch = 0.8
1 change: 1 addition & 0 deletions lib/v3-core
Submodule v3-core added at 6562c5
112 changes: 112 additions & 0 deletions manager/src/manual/system/transferProxyAdminOwnership.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import 'dotenv/config'

import { OperationType } from '@safe-global/types-kit'
import { encodeFunctionData, parseAbi, getAddress } from 'viem/utils'
import { apiKit, protocolKitOwnerAdmin } from '../../utils/safe'
import { ADMIN, proposeSafeTransaction } from '../../utils/forge'

/**
* Creates a proposal for transferring ProxyAdmin ownership to enable V1-V2 migration
* This should be executed BEFORE running the migration script in private hardhat repo
*
* @param proxyAdminAddress - Address of the ProxyAdmin contract
* @param newOwnerAddress - Address of the deployer who will execute the migration
* @returns
*/
export async function transferProxyAdminForMigration(proxyAdminAddress: string, newOwnerAddress: string) {
try {
if (!ADMIN) throw new Error('Env vars not set correctly.')

// Setup task params
const contractAddress = proxyAdminAddress
const abi = parseAbi(['function transferOwnership(address)'])
const metadata = {
title: `Transfer ProxyAdmin Ownership for V2 Migration`,
description: `Proposal to transfer ProxyAdmin ownership from multisig (${ADMIN}) to deployer (${newOwnerAddress}) to enable V1-V2 migration. The deployer will automatically transfer ownership back to multisig after migration completion.`
}

// Setup transaction data
const data = encodeFunctionData({
abi,
functionName: 'transferOwnership',
args: [getAddress(newOwnerAddress)]
})
const metaTransactionData = {
to: getAddress(contractAddress),
value: '0',
data: data,
operation: OperationType.Call
}

// Create transaction
const nonce = Number(await apiKit.getNextNonce(ADMIN))
const safeTransaction = await protocolKitOwnerAdmin.createTransaction({
transactions: [metaTransactionData],
options: { nonce }
})

// Propose transactions to multisig
await proposeSafeTransaction(safeTransaction, metadata)

console.log(` Proposal created to transfer ProxyAdmin ownership`)
console.log(` From: ${ADMIN} (multisig)`)
console.log(` To: ${newOwnerAddress} (deployer)`)
console.log(` ProxyAdmin: ${proxyAdminAddress}`)
console.log(``)
console.log(` NEXT STEPS:`)
console.log(` 1. Execute this multisig proposal`)
console.log(` 2. Run migration script with the deployer account`)
console.log(` 3. Migration script will automatically transfer ownership back to multisig`)

} catch (error) {
console.log('Error: ', error)
return []
}
}

/**
* Convenience function to restore ProxyAdmin ownership back to multisig
* This is not needed as the migration script handles it automatically in our hardhat part,
* but provided as a backup option
*
* @param proxyAdminAddress - Address of the ProxyAdmin contract
* @param deployerAddress - Current owner (deployer) who will transfer back to multisig
* @returns
*/
export async function restoreProxyAdminOwnership(proxyAdminAddress: string, deployerAddress: string) {
try {
if (!ADMIN) throw new Error('Env vars not set correctly.')

// Setup task params
const contractAddress = proxyAdminAddress
const abi = parseAbi(['function transferOwnership(address)'])
const metadata = {
title: `Restore ProxyAdmin Ownership to Multisig`,
description: `Emergency proposal to restore ProxyAdmin ownership from deployer (${deployerAddress}) back to multisig (${ADMIN}). This is typically handled automatically by the migration script.`
}

// Setup transaction data - NOTE: This would need to be signed by the deployer, not multisig
const data = encodeFunctionData({
abi,
functionName: 'transferOwnership',
args: [getAddress(ADMIN)]
})
const metaTransactionData = {
to: getAddress(contractAddress),
value: '0',
data: data,
operation: OperationType.Call
}

console.log(` WARNING: This transaction must be executed by the deployer (${deployerAddress}), not the multisig!`)
console.log(` Transaction data: ${data}`)
console.log(` Target: ${contractAddress}`)

// This is mainly for reference -EXC NEEDTOBEDONE BY DEPLOYER
return metaTransactionData

} catch (error) {
console.log('Error: ', error)
return []
}
}
3 changes: 2 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ lib/eigenlayer-contracts/=lib/eigenlayer-contracts/
@openzeppelin-upgradeable/contracts/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/
@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol
@openzeppelin/contracts/proxy/beacon/IBeacon.sol=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/proxy/beacon/IBeacon.sol
@chainlink/contracts/src/interfaces/feeds/=lib/foundry-chainlink-toolkit/src/interfaces/feeds/
@chainlink/contracts/src/interfaces/feeds/=lib/foundry-chainlink-toolkit/src/interfaces/feeds/
@uniswap/v3-core/=lib/v3-core/
105 changes: 100 additions & 5 deletions script/deploy/holesky/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
TO BE DEPRECATED
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

Expand All @@ -20,9 +25,12 @@ import {TokenRegistryOracle} from "../../../src/utils/TokenRegistryOracle.sol";
import {ITokenRegistryOracle} from "../../../src/interfaces/ITokenRegistryOracle.sol";
import {LiquidTokenManager} from "../../../src/core/LiquidTokenManager.sol";
import {ILiquidTokenManager} from "../../../src/interfaces/ILiquidTokenManager.sol";
import {ILSTSwapRouter} from "../../../src/interfaces/ILSTSwapRouter.sol";
import {StakerNode} from "../../../src/core/StakerNode.sol";
import {StakerNodeCoordinator} from "../../../src/core/StakerNodeCoordinator.sol";
import {IStakerNodeCoordinator} from "../../../src/interfaces/IStakerNodeCoordinator.sol";
import {WithdrawalManager} from "../../../src/core/WithdrawalManager.sol";
import {IWithdrawalManager} from "../../../src/interfaces/IWithdrawalManager.sol";

/// @dev To load env file:
// source .env
Expand Down Expand Up @@ -89,13 +97,15 @@ contract Deploy is Script, Test {
TokenRegistryOracle tokenRegistryOracleImpl;
LiquidTokenManager liquidTokenManagerImpl;
StakerNodeCoordinator stakerNodeCoordinatorImpl;
WithdrawalManager withdrawalManagerImpl;
StakerNode stakerNodeImpl;

// Proxy contracts
LiquidToken liquidToken;
TokenRegistryOracle tokenRegistryOracle;
LiquidTokenManager liquidTokenManager;
StakerNodeCoordinator stakerNodeCoordinator;
WithdrawalManager withdrawalManager;

// Deployment blocks and timestamps
uint256 public proxyAdminDeployBlock;
Expand All @@ -109,6 +119,8 @@ contract Deploy is Script, Test {
uint256 public liquidTokenManagerImplDeployTimestamp;
uint256 public stakerNodeCoordinatorImplDeployBlock;
uint256 public stakerNodeCoordinatorImplDeployTimestamp;
uint256 public withdrawalManagerImplDeployBlock;
uint256 public withdrawalManagerImplDeployTimestamp;
uint256 public stakerNodeImplDeployBlock;
uint256 public stakerNodeImplDeployTimestamp;

Expand All @@ -120,6 +132,8 @@ contract Deploy is Script, Test {
uint256 public liquidTokenManagerProxyDeployTimestamp;
uint256 public stakerNodeCoordinatorProxyDeployBlock;
uint256 public stakerNodeCoordinatorProxyDeployTimestamp;
uint256 public withdrawalManagerProxyDeployBlock;
uint256 public withdrawalManagerProxyDeployTimestamp;

// Initialization timestamps and blocks
uint256 public tokenRegistryOracleInitBlock;
Expand All @@ -130,6 +144,8 @@ contract Deploy is Script, Test {
uint256 public liquidTokenManagerInitTimestamp;
uint256 public stakerNodeCoordinatorInitBlock;
uint256 public stakerNodeCoordinatorInitTimestamp;
uint256 public withdrawalManagerInitBlock;
uint256 public withdrawalManagerInitTimestamp;
uint256 public oracleSalt;

function run(string memory deployConfigFileName) external {
Expand All @@ -156,7 +172,7 @@ contract Deploy is Script, Test {
}

// Helper function to count array entries
function _countTokens(string memory deployConfigData) internal returns (uint256) {
function _countTokens(string memory deployConfigData) internal view returns (uint256) {
uint256 i = 0;
while (true) {
string memory prefix = string.concat(".tokens[", vm.toString(i), "].addresses.token");
Expand Down Expand Up @@ -263,6 +279,10 @@ contract Deploy is Script, Test {
stakerNodeCoordinatorImplDeployTimestamp = block.timestamp;
stakerNodeCoordinatorImpl = new StakerNodeCoordinator();

withdrawalManagerImplDeployBlock = block.number;
withdrawalManagerImplDeployTimestamp = block.timestamp;
withdrawalManagerImpl = new WithdrawalManager();

stakerNodeImplDeployBlock = block.number;
stakerNodeImplDeployTimestamp = block.timestamp;
stakerNodeImpl = new StakerNode();
Expand All @@ -278,7 +298,7 @@ contract Deploy is Script, Test {
liquidTokenManagerProxyDeployBlock = block.number;
liquidTokenManagerProxyDeployTimestamp = block.timestamp;
liquidTokenManager = LiquidTokenManager(
address(new TransparentUpgradeableProxy(address(liquidTokenManagerImpl), address(proxyAdmin), ""))
payable(address(new TransparentUpgradeableProxy(address(liquidTokenManagerImpl), address(proxyAdmin), "")))
);

stakerNodeCoordinatorProxyDeployBlock = block.number;
Expand All @@ -292,13 +312,20 @@ contract Deploy is Script, Test {
liquidToken = LiquidToken(
address(new TransparentUpgradeableProxy(address(liquidTokenImpl), address(proxyAdmin), ""))
);

withdrawalManagerProxyDeployBlock = block.number;
withdrawalManagerProxyDeployTimestamp = block.timestamp;
withdrawalManager = WithdrawalManager(
address(new TransparentUpgradeableProxy(address(withdrawalManagerImpl), address(proxyAdmin), ""))
);
}

function initializeProxies() internal {
_initializeTokenRegistryOracle();
_initializeLiquidTokenManager();
_initializeStakerNodeCoordinator();
_initializeLiquidToken();
_initializeWithdrawalManager();
}

function _initializeTokenRegistryOracle() internal {
Expand Down Expand Up @@ -327,6 +354,8 @@ contract Deploy is Script, Test {
delegationManager: IDelegationManager(delegationManager),
stakerNodeCoordinator: stakerNodeCoordinator,
tokenRegistryOracle: ITokenRegistryOracle(address(tokenRegistryOracle)),
withdrawalManager: withdrawalManager,
lstSwapRouter: ILSTSwapRouter(address(0)), // Will be set later
initialOwner: msg.sender, // burner, will transfer to admin
strategyController: admin,
priceUpdater: address(tokenRegistryOracle)
Expand All @@ -340,6 +369,7 @@ contract Deploy is Script, Test {
stakerNodeCoordinator.initialize(
IStakerNodeCoordinator.Init({
liquidTokenManager: liquidTokenManager,
withdrawalManager: withdrawalManager,
strategyManager: IStrategyManager(strategyManager),
delegationManager: IDelegationManager(delegationManager),
maxNodes: STAKER_NODE_COORDINATOR_MAX_NODES,
Expand All @@ -362,7 +392,22 @@ contract Deploy is Script, Test {
initialOwner: admin,
pauser: pauser,
liquidTokenManager: ILiquidTokenManager(address(liquidTokenManager)),
tokenRegistryOracle: ITokenRegistryOracle(address(tokenRegistryOracle))
tokenRegistryOracle: ITokenRegistryOracle(address(tokenRegistryOracle)),
withdrawalManager: withdrawalManager
})
);
}

function _initializeWithdrawalManager() internal {
withdrawalManagerInitBlock = block.number;
withdrawalManagerInitTimestamp = block.timestamp;
withdrawalManager.initialize(
IWithdrawalManager.Init({
initialOwner: admin,
delegationManager: IDelegationManager(delegationManager),
liquidToken: liquidToken,
liquidTokenManager: liquidTokenManager,
stakerNodeCoordinator: stakerNodeCoordinator
})
);
}
Expand Down Expand Up @@ -460,6 +505,12 @@ contract Deploy is Script, Test {
_getImplementationFromProxy(address(tokenRegistryOracle)) == address(tokenRegistryOracleImpl),
"TokenRegistryOracle proxy implementation mismatch"
);

// WithdrawalManager
require(
_getImplementationFromProxy(address(withdrawalManager)) == address(withdrawalManagerImpl),
"WithdrawalManager proxy implementation mismatch"
);
}

function _verifyContractConnections() internal view {
Expand Down Expand Up @@ -511,6 +562,24 @@ contract Deploy is Script, Test {
"TokenRegistryOracle: wrong liquidTokenManager"
);

// WithdrawalManager
require(
address(withdrawalManager.delegationManager()) == address(delegationManager),
"WithdrawalManager: wrong delegationManager"
);
require(
address(withdrawalManager.liquidToken()) == address(liquidToken),
"WithdrawalManager: wrong liquidToken"
);
require(
address(withdrawalManager.liquidTokenManager()) == address(liquidTokenManager),
"WithdrawalManager: wrong liquidTokenManager"
);
require(
address(withdrawalManager.stakerNodeCoordinator()) == address(stakerNodeCoordinator),
"WithdrawalManager: wrong stakerNodeCoordinator"
);

// Assets and strategies
IERC20[] memory registeredTokens = liquidTokenManager.getSupportedTokens();
TokenConfig[] memory addableTokens = tokens;
Expand Down Expand Up @@ -594,11 +663,13 @@ contract Deploy is Script, Test {
tokenRegistryOracle.hasRole(tokenRegistryOracle.RATE_UPDATER_ROLE(), priceUpdater),
"Rate Updater role not assigned to priceUpdater in TokenRegistryOracle"
);

require(
tokenRegistryOracle.hasRole(tokenRegistryOracle.RATE_UPDATER_ROLE(), address(liquidToken)),
"Rate Updater role not assigned to LiquidToken in TokenRegistryOracle"
);

// WithdrawalManager
require(withdrawalManager.hasRole(adminRole, admin), "Admin role not assigned in WithdrawalManager");
}

function writeDeploymentOutput() internal {
Expand Down Expand Up @@ -663,9 +734,20 @@ contract Deploy is Script, Test {
tokenRegistryOracleImplDeployTimestamp * 1000
);

// WithdrawalManager implementation
string memory withdrawalManagerImpl_obj = "withdrawalManager";
vm.serializeAddress(withdrawalManagerImpl_obj, "address", address(withdrawalManagerImpl));
vm.serializeUint(withdrawalManagerImpl_obj, "block", withdrawalManagerImplDeployBlock);
string memory withdrawalManagerImpl_output = vm.serializeUint(
withdrawalManagerImpl_obj,
"timestamp",
withdrawalManagerImplDeployTimestamp * 1000
);

// Combine all implementation objects
vm.serializeString(implementation, "liquidTokenManager", liquidTokenManagerImpl_output);
vm.serializeString(implementation, "stakerNodeCoordinator", stakerNodeCoordinatorImpl_output);
vm.serializeString(implementation, "withdrawalManager", withdrawalManagerImpl_output);
vm.serializeString(implementation, "stakerNode", stakerNodeImpl_output);
string memory implementation_output = vm.serializeString(
implementation,
Expand Down Expand Up @@ -706,10 +788,21 @@ contract Deploy is Script, Test {
tokenRegistryOracleProxyDeployTimestamp * 1000
);

// WithdrawalManager proxy
string memory withdrawalManager_obj = "withdrawalManager";
vm.serializeAddress(withdrawalManager_obj, "address", address(withdrawalManager));
vm.serializeUint(withdrawalManager_obj, "block", withdrawalManagerProxyDeployBlock);
string memory withdrawalManager_output = vm.serializeUint(
withdrawalManager_obj,
"timestamp",
withdrawalManagerProxyDeployTimestamp * 1000
);

// Combine all proxy objects
vm.serializeString(proxy, "liquidTokenManager", liquidTokenManager_output);
vm.serializeString(proxy, "stakerNodeCoordinator", stakerNodeCoordinator_output);
string memory proxy_output = vm.serializeString(proxy, "tokenRegistryOracle", tokenRegistryOracle_output);
vm.serializeString(proxy, "tokenRegistryOracle", tokenRegistryOracle_output);
string memory proxy_output = vm.serializeString(proxy, "withdrawalManager", withdrawalManager_output);

// Combine implementation and proxy under contractDeployments
vm.serializeString(contractDeployments, "implementation", implementation_output);
Expand Down Expand Up @@ -769,3 +862,5 @@ contract Deploy is Script, Test {
);
}
}

*/
Loading
Loading