Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3ac8cdd
init
pankajjagtapp Jan 22, 2026
7811d33
refactor: Update PriorityWithdrawalQueue contract to improve withdraw…
pankajjagtapp Jan 28, 2026
73b0ed4
refactor: Update LiquidityPool contract to use immutable priorityWith…
pankajjagtapp Jan 28, 2026
fe06cb4
refactor: Update LiquidityPool and PriorityWithdrawalQueue tests for …
pankajjagtapp Jan 28, 2026
59c6819
refactor: Optimize
pankajjagtapp Jan 28, 2026
27daab0
refactor: Enhance LiquidityPool and PriorityWithdrawalQueue for impro…
pankajjagtapp Jan 28, 2026
f199f40
refactor: Simplify PriorityWithdrawalQueue contract
pankajjagtapp Jan 28, 2026
3a27a08
refactor: Update PriorityWithdrawalQueue to use immutable MIN_DELAY
pankajjagtapp Jan 28, 2026
d31e074
refactor: Clean up PriorityWithdrawalQueue contract by removing redun…
pankajjagtapp Jan 28, 2026
1152b54
refactor: Updated claimWithdraw and batchClaimWithdraw functions to …
pankajjagtapp Jan 29, 2026
365b62e
refactor: Improve cancellation logic in PriorityWithdrawalQueue contract
pankajjagtapp Jan 29, 2026
1c07a43
feat: Add minAmountOut parameter for withdrawal requests
pankajjagtapp Jan 29, 2026
89c23e7
refactor: Eliminated ethAmountLockedForPriorityWithdrawal and related…
pankajjagtapp Jan 29, 2026
30d87da
revert: liquidityPool updated checks
pankajjagtapp Jan 29, 2026
307698f
feat: Integrate PriorityWithdrawalQueue into EtherFiRedemptionManager
pankajjagtapp Jan 29, 2026
80b99a3
feat: Updated the permit handling logic to revert with a specific err…
pankajjagtapp Jan 29, 2026
7385ac9
feat: Add deployment and transaction scripts for PriorityWithdrawalQueue
pankajjagtapp Feb 2, 2026
61b4d23
Merge remote-tracking branch 'origin/master' into pankaj/feat/priorit…
pankajjagtapp Feb 2, 2026
ac99058
refactor: Update test setups and scripts to fix broken tests
pankajjagtapp Feb 2, 2026
79386cd
feat: Integrate EtherFiRedemptionManager into deployment and transact…
pankajjagtapp Feb 2, 2026
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: 2 additions & 2 deletions script/upgrades/CrossPodApproval/transactions.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,13 @@ contract CrossPodApprovalScript is Script, Deployed, Utils {
}

function verifyBytecode() internal {
LiquidityPool newLiquidityPoolImplementation = new LiquidityPool();
// LiquidityPool newLiquidityPoolImplementation = new LiquidityPool();
EtherFiNodesManager newEtherFiNodesManagerImplementation = new EtherFiNodesManager(
address(STAKING_MANAGER),
address(ROLE_REGISTRY),
address(ETHERFI_RATE_LIMITER)
);
contractCodeChecker.verifyContractByteCodeMatch(liquidityPoolImpl, address(newLiquidityPoolImplementation));
// contractCodeChecker.verifyContractByteCodeMatch(liquidityPoolImpl, address(newLiquidityPoolImplementation));
contractCodeChecker.verifyContractByteCodeMatch(etherFiNodesManagerImpl, address(newEtherFiNodesManagerImplementation));

console2.log("[OK] Bytecode verified successfully");
Expand Down
133 changes: 133 additions & 0 deletions script/upgrades/priority-queue/deployPriorityQueue.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import "forge-std/Script.sol";
import {LiquidityPool} from "../../../src/LiquidityPool.sol";
import {PriorityWithdrawalQueue} from "../../../src/PriorityWithdrawalQueue.sol";
import {UUPSProxy} from "../../../src/UUPSProxy.sol";
import {Utils, ICreate2Factory} from "../../utils/utils.sol";
import {EtherFiRedemptionManager} from "../../../src/EtherFiRedemptionManager.sol";

contract DeployPriorityQueue is Script, Utils {
ICreate2Factory constant factory = ICreate2Factory(0x356d1B83970CeF2018F2c9337cDdb67dff5AEF99);

address priorityWithdrawalQueueImpl;
address priorityWithdrawalQueueProxy;
address liquidityPoolImpl;
address etherFiRedemptionManagerImpl;
bytes32 commitHashSalt = hex"45312df178d6eb8143604e47b7aa9e618779c0de"; // TODO: Update with actual commit hash

uint32 constant MIN_DELAY = 1 hours; // TODO: Set appropriate min delay (e.g., 1 hours = 3600)

function dryRun() public view {
console2.log("================================================");
console2.log("============= DRY RUN - CONFIG ============");
console2.log("================================================");
console2.log("");

console2.log("Constructor Args for PriorityWithdrawalQueue:");
console2.log(" _liquidityPool:", LIQUIDITY_POOL);
console2.log(" _eETH:", EETH);
console2.log(" _roleRegistry:", ROLE_REGISTRY);
console2.log(" _treasury:", TREASURY);
console2.log(" _minDelay:", MIN_DELAY);
console2.log("");

console2.log("Constructor Args for LiquidityPool:");
console2.log(" _priorityWithdrawalQueue: <computed from Create2>");
console2.log("");

console2.log("Salt:", vm.toString(commitHashSalt));
console2.log("");

console2.log("To compute exact addresses, run with mainnet fork:");
console2.log(" forge script script/upgrades/priority-queue/deployPriorityQueue.s.sol:DeployPriorityQueue --sig 'dryRunWithFork()' --fork-url <RPC_URL>");
}

function run() public {
console2.log("================================================");
console2.log("======== Deploying Priority Queue & LP =========");
console2.log("================================================");
console2.log("");

vm.startBroadcast();

// Step 1: Deploy PriorityWithdrawalQueue implementation
{
string memory contractName = "PriorityWithdrawalQueue";
bytes memory constructorArgs = abi.encode(
LIQUIDITY_POOL,
EETH,
ROLE_REGISTRY,
TREASURY,
MIN_DELAY
);
bytes memory bytecode = abi.encodePacked(
type(PriorityWithdrawalQueue).creationCode,
constructorArgs
);
priorityWithdrawalQueueImpl = deploy(contractName, constructorArgs, bytecode, commitHashSalt, true, factory);
}

// Step 2: Deploy PriorityWithdrawalQueue proxy with initialization
{
string memory contractName = "UUPSProxy"; // Use actual contract name for artifact lookup
// Encode initialize() call for proxy deployment
bytes memory initData = abi.encodeWithSelector(PriorityWithdrawalQueue.initialize.selector);
bytes memory constructorArgs = abi.encode(priorityWithdrawalQueueImpl, initData);
bytes memory bytecode = abi.encodePacked(
type(UUPSProxy).creationCode,
constructorArgs
);
priorityWithdrawalQueueProxy = deploy(contractName, constructorArgs, bytecode, commitHashSalt, true, factory);
}

// Step 3: Deploy EtherFiRedemptionManager implementation
{
string memory contractName = "EtherFiRedemptionManager";
bytes memory constructorArgs = abi.encode(
LIQUIDITY_POOL,
EETH,
WEETH,
TREASURY,
ROLE_REGISTRY,
ETHERFI_RESTAKER,
priorityWithdrawalQueueProxy
);
bytes memory bytecode = abi.encodePacked(
type(EtherFiRedemptionManager).creationCode,
constructorArgs
);
etherFiRedemptionManagerImpl = deploy(contractName, constructorArgs, bytecode, commitHashSalt, true, factory);
}

// Step 4: Deploy LiquidityPool implementation with predicted proxy address
{
string memory contractName = "LiquidityPool";
bytes memory constructorArgs = abi.encode(priorityWithdrawalQueueProxy);
bytes memory bytecode = abi.encodePacked(
type(LiquidityPool).creationCode,
constructorArgs
);
liquidityPoolImpl = deploy(contractName, constructorArgs, bytecode, commitHashSalt, true, factory);
}

vm.stopBroadcast();

// Summary
console2.log("");
console2.log("================================================");
console2.log("============== DEPLOYMENT SUMMARY ==============");
console2.log("================================================");
console2.log("LiquidityPool Implementation:", liquidityPoolImpl);
console2.log("PriorityWithdrawalQueue Implementation:", priorityWithdrawalQueueImpl);
console2.log("PriorityWithdrawalQueue Proxy:", priorityWithdrawalQueueProxy);
console2.log("EtherFiRedemptionManager Implementation:", etherFiRedemptionManagerImpl);
console2.log("");
console2.log("NEXT STEPS:");
console2.log("1. Initialize PriorityWithdrawalQueue proxy");
console2.log("2. Upgrade LiquidityPool proxy to new implementation");
console2.log("3. Upgrade EtherFiRedemptionManager proxy to new implementation");
console2.log("4. Grant necessary roles in RoleRegistry");
}
}
226 changes: 226 additions & 0 deletions script/upgrades/priority-queue/transactionsPriorityQueue.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import "../../utils/utils.sol";
import "../../../src/EtherFiTimelock.sol";
import "../../../src/EtherFiRedemptionManager.sol";
import "../../../src/LiquidityPool.sol";
import "../../../src/PriorityWithdrawalQueue.sol";
import "../../../src/RoleRegistry.sol";
import "@openzeppelin-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import "forge-std/Script.sol";
import "forge-std/console2.sol";

/// @title PriorityQueueTransactions
/// @notice Generates timelock transactions for upgrading LiquidityPool and granting roles for PriorityWithdrawalQueue
/// @dev Run with: forge script script/upgrades/priority-queue/transactionsPriorityQueue.s.sol --fork-url $MAINNET_RPC_URL
contract PriorityQueueTransactions is Script, Utils {
//--------------------------------------------------------------------------------------
//------------------------------- EXISTING CONTRACTS -----------------------------------
//--------------------------------------------------------------------------------------
EtherFiTimelock etherFiTimelock = EtherFiTimelock(payable(UPGRADE_TIMELOCK));
RoleRegistry roleRegistryContract = RoleRegistry(ROLE_REGISTRY);
LiquidityPool liquidityPool = LiquidityPool(payable(LIQUIDITY_POOL));
EtherFiRedemptionManager etherFiRedemptionManager = EtherFiRedemptionManager(payable(ETHERFI_REDEMPTION_MANAGER));

//--------------------------------------------------------------------------------------
//------------------------------- NEW DEPLOYMENTS --------------------------------------
//--------------------------------------------------------------------------------------

// TODO: Update these addresses with actual deployed addresses
address constant liquidityPoolImpl = 0x5598b8c76BA17253459e069041349704c28d33DF;
address constant priorityWithdrawalQueueProxy = 0x79Eb9c078fA5a5Bd1Ee8ba84937acd48AA5F90A8;
address constant priorityWithdrawalQueueImpl = 0xB149ce3957370066D7C03e5CA81A7997Fe00cAF6;
address constant etherFiRedemptionManagerImpl = 0x335E9Cf5A2b13621b66D01F8b889174AD75DE045;
//--------------------------------------------------------------------------------------
//------------------------------- ROLES ------------------------------------------------
//--------------------------------------------------------------------------------------

bytes32 public PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE;
bytes32 public PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE;
bytes32 public PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE;

function run() public {
console2.log("================================================");
console2.log("Running Priority Queue Transactions");
console2.log("================================================");
console2.log("");

// string memory forkUrl = vm.envString("MAINNET_RPC_URL");
// vm.selectFork(vm.createFork(forkUrl));

// Get role hashes from the implementation
PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE = PriorityWithdrawalQueue(payable(priorityWithdrawalQueueImpl)).PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE();
PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE = PriorityWithdrawalQueue(payable(priorityWithdrawalQueueImpl)).PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE();
PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE = PriorityWithdrawalQueue(payable(priorityWithdrawalQueueImpl)).PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE();

executeUpgrade();
forkTest();
}

function executeUpgrade() public {
console2.log("Generating Upgrade Transactions");
console2.log("================================================");

address[] memory targets = new address[](5);
bytes[] memory data = new bytes[](targets.length);
uint256[] memory values = new uint256[](targets.length); // Default to 0

//--------------------------------------------------------------------------------------
//------------------------------- CONTRACT UPGRADES -----------------------------------
//--------------------------------------------------------------------------------------

// Upgrade LiquidityPool to new implementation with priorityWithdrawalQueue support
targets[0] = LIQUIDITY_POOL;
data[0] = abi.encodeWithSelector(UUPSUpgradeable.upgradeTo.selector, liquidityPoolImpl);

// Upgrade EtherFiRedemptionManager to new implementation
targets[1] = ETHERFI_REDEMPTION_MANAGER;
data[1] = abi.encodeWithSelector(UUPSUpgradeable.upgradeTo.selector, etherFiRedemptionManagerImpl);

//--------------------------------------------------------------------------------------
//---------------------------------- Grant Roles ---------------------------------------
//--------------------------------------------------------------------------------------
console2.log("PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE:", vm.toString(PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE));
console2.log("PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE:", vm.toString(PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE));
console2.log("PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE:", vm.toString(PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE));

// Grant PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE to ADMIN_EOA
targets[2] = ROLE_REGISTRY;
data[2] = _encodeRoleGrant(
PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE,
ETHERFI_OPERATING_ADMIN
);

// Grant PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE to ADMIN_EOA
targets[3] = ROLE_REGISTRY;
data[3] = _encodeRoleGrant(
PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE,
ETHERFI_OPERATING_ADMIN
);

// Grant PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE to ADMIN_EOA
targets[4] = ROLE_REGISTRY;
data[4] = _encodeRoleGrant(
PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE,
ADMIN_EOA
);

bytes32 timelockSalt = keccak256(abi.encode(targets, data, block.number));

// Generate schedule calldata
bytes memory scheduleCalldata = abi.encodeWithSelector(
etherFiTimelock.scheduleBatch.selector,
targets,
values,
data,
bytes32(0), // predecessor
timelockSalt,
MIN_DELAY_TIMELOCK // 72 hours
);

console2.log("================================================");
console2.log("Timelock Address:", address(etherFiTimelock));
console2.log("================================================");
console2.log("");

console2.log("Schedule Tx (call from UPGRADE_ADMIN):");
console2.logBytes(scheduleCalldata);
console2.log("================================================");
console2.log("");

// Generate execute calldata
bytes memory executeCalldata = abi.encodeWithSelector(
etherFiTimelock.executeBatch.selector,
targets,
values,
data,
bytes32(0), // predecessor
timelockSalt
);
console2.log("Execute Tx (after 72 hours):");
console2.logBytes(executeCalldata);
console2.log("================================================");
console2.log("");

// Log individual transactions for clarity
console2.log("Transaction Details:");
console2.log("--------------------");
console2.log("1. Upgrade LiquidityPool to:", liquidityPoolImpl);
console2.log("2. Grant PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE to:", ETHERFI_OPERATING_ADMIN);
console2.log("3. Grant PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE to:", ETHERFI_OPERATING_ADMIN);
console2.log("4. Grant PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE to:", ADMIN_EOA);
console2.log("================================================");
console2.log("");

// Execute on fork for testing
console2.log("=== SCHEDULING BATCH ON FORK ===");
vm.startPrank(ETHERFI_UPGRADE_ADMIN);
etherFiTimelock.scheduleBatch(targets, values, data, bytes32(0), timelockSalt, MIN_DELAY_TIMELOCK);

vm.warp(block.timestamp + MIN_DELAY_TIMELOCK + 1);
etherFiTimelock.executeBatch(targets, values, data, bytes32(0), timelockSalt);
vm.stopPrank();

console2.log("Upgrade executed successfully on fork");
console2.log("================================================");
}

function forkTest() public {
console2.log("Running Fork Tests");
console2.log("================================================");

// Verify LiquidityPool upgrade
address impl = liquidityPool.getImplementation();
require(impl == liquidityPoolImpl, "LiquidityPool implementation mismatch");
console2.log("LiquidityPool implementation verified:", impl);

// Verify priorityWithdrawalQueue is set correctly in LiquidityPool
address pwq = liquidityPool.priorityWithdrawalQueue();
require(pwq == priorityWithdrawalQueueProxy, "PriorityWithdrawalQueue address mismatch");
console2.log("PriorityWithdrawalQueue in LiquidityPool:", pwq);

// Verify roles granted
require(
roleRegistryContract.hasRole(PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE, ETHERFI_OPERATING_ADMIN),
"ADMIN_EOA does not have PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE"
);
console2.log("PRIORITY_WITHDRAWAL_QUEUE_ADMIN_ROLE granted to ADMIN_EOA");

require(
roleRegistryContract.hasRole(PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE, ETHERFI_OPERATING_ADMIN),
"ADMIN_EOA does not have PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE"
);
console2.log("PRIORITY_WITHDRAWAL_QUEUE_WHITELIST_MANAGER_ROLE granted to ADMIN_EOA");

require(
roleRegistryContract.hasRole(PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE, ADMIN_EOA),
"ADMIN_EOA does not have PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE"
);
console2.log("PRIORITY_WITHDRAWAL_QUEUE_REQUEST_MANAGER_ROLE granted to ADMIN_EOA");

// Test PriorityWithdrawalQueue is accessible via proxy
PriorityWithdrawalQueue pwqContract = PriorityWithdrawalQueue(payable(priorityWithdrawalQueueProxy));
require(address(pwqContract.liquidityPool()) == LIQUIDITY_POOL, "LiquidityPool reference mismatch in PriorityWithdrawalQueue");
console2.log("PriorityWithdrawalQueue liquidityPool reference verified");

console2.log("");
console2.log("All fork tests passed!");
console2.log("================================================");
}

//--------------------------------------------------------------------------------------
//------------------------------- HELPER FUNCTIONS -----------------------------------
//--------------------------------------------------------------------------------------

function _encodeRoleGrant(
bytes32 role,
address account
) internal pure returns (bytes memory) {
return abi.encodeWithSelector(
RoleRegistry.grantRole.selector,
role,
account
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ contract ReauditFixesTransactions is Utils {
console2.log("");

EtherFiNode newEtherFiNodeImplementation = new EtherFiNode(address(LIQUIDITY_POOL), address(ETHERFI_NODES_MANAGER), address(EIGENLAYER_POD_MANAGER), address(EIGENLAYER_DELEGATION_MANAGER), address(ROLE_REGISTRY));
EtherFiRedemptionManager newEtherFiRedemptionManagerImplementation = new EtherFiRedemptionManager(address(LIQUIDITY_POOL), address(EETH), address(WEETH), address(TREASURY), address(ROLE_REGISTRY), address(ETHERFI_RESTAKER));
EtherFiRedemptionManager newEtherFiRedemptionManagerImplementation = new EtherFiRedemptionManager(address(LIQUIDITY_POOL), address(EETH), address(WEETH), address(TREASURY), address(ROLE_REGISTRY), address(ETHERFI_RESTAKER), address(0x0));
EtherFiRestaker newEtherFiRestakerImplementation = new EtherFiRestaker(address(EIGENLAYER_REWARDS_COORDINATOR), address(ETHERFI_REDEMPTION_MANAGER));
EtherFiRewardsRouter newEtherFiRewardsRouterImplementation = new EtherFiRewardsRouter(address(LIQUIDITY_POOL), address(TREASURY), address(ROLE_REGISTRY));
Liquifier newLiquifierImplementation = new Liquifier();
Expand Down
Loading
Loading